Merge branch 'bootloader' into 'master'

Add bootloader, change ci to use custom cc65

See merge request bslathi19/super6502!16
This commit is contained in:
Byron Lathi
2022-04-20 19:02:02 +00:00
39 changed files with 1383 additions and 33 deletions

View File

@@ -2,16 +2,50 @@ default:
tags:
- docker
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- build_toolchain
- build_sw
- build_hw
- test
build-cc65:
stage: build_toolchain
image: gcc
script:
- cd sw
- make toolchain
artifacts:
paths:
- sw/cc65/bin
- sw/cc65/lib
build-kernel:
stage: build
image: a2geek/cc65-pipeline
stage: build_sw
image: gcc
script:
- cd sw/kernel
- make
build-bootloader:
stage: build_sw
image: gcc
script:
- cd sw/bootloader
- make
artifacts:
paths:
- sw/bootloader/bootloader.hex
expire_in: 1 week
build-fpga:
stage: build
stage: build_hw
dependencies:
- build-bootloader
image: bslathi19/modelsim_18.1:lite
script:
- cd hw/fpga/
@@ -34,7 +68,7 @@ test_bb_spi:
test-sw:
stage: test
image: a2geek/cc65-pipeline
image: gcc
script:
- cd sw/kernel
- make test

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "sw/cc65"]
path = sw/cc65
url = https://git.byronlathi.com/bslathi19/cc65

View File

@@ -84,13 +84,13 @@ module rom (
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
`ifdef NO_PLI
altsyncram_component.init_file = "../../sw/bootrom.rif"
altsyncram_component.init_file = "../../sw/bootloader/bootloader.rif"
`else
altsyncram_component.init_file = "../../sw/bootrom.hex"
altsyncram_component.init_file = "../../sw/bootloader/bootloader.hex"
`endif
,
altsyncram_component.intended_device_family = "MAX 10",
altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=YES,INSTANCE_NAME=ROM0",
altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.numwords_a = 32768,
altsyncram_component.operation_mode = "ROM",
@@ -120,10 +120,10 @@ endmodule
// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10"
// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "1"
// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
// Retrieval info: PRIVATE: JTAG_ID STRING "ROM0"
// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
// Retrieval info: PRIVATE: MIFfilename STRING "../../sw/bootrom.hex"
// Retrieval info: PRIVATE: MIFfilename STRING "../../sw/bootloader/bootloader.hex"
// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "32768"
// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
// Retrieval info: PRIVATE: RegAddr NUMERIC "1"
@@ -138,9 +138,9 @@ endmodule
// Retrieval info: CONSTANT: ADDRESS_ACLR_A STRING "NONE"
// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS"
// Retrieval info: CONSTANT: INIT_FILE STRING "../../sw/bootrom.hex"
// Retrieval info: CONSTANT: INIT_FILE STRING "../../sw/bootloader/bootloader.hex"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10"
// Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=YES,INSTANCE_NAME=ROM0"
// Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO"
// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "32768"
// Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM"

22
sw/Makefile Normal file
View File

@@ -0,0 +1,22 @@
.PHONY: all install bootloader kernel clean
all: toolchain bootloader kernel
install: all
sh script/format_disk.sh
sh script/copy_files.sh
toolchain:
@$(MAKE) -j4 -C cc65
bootloader:
@$(MAKE) -C bootloader
kernel:
@$(MAKE) -C kernel
clean:
@$(MAKE) -C bootloader --no-print-directory $@
@$(MAKE) -C kernel --no-print-directory $@
@$(MAKE) -C cc65 --no-print-directory $@

56
sw/bootloader/Makefile Normal file
View File

@@ -0,0 +1,56 @@
CC=../cc65/bin/cl65
CFLAGS=-T -t none -I. --cpu "65C02"
test: CFLAGS=-T -t sim65c02 -I.
LDFLAGS=-C link.ld -m $(NAME).map
SIM=sim65
SIMARGS=-v -c -x 1000000
NAME=bootloader
TEST_BIN=test.bin
BIN=$(NAME).bin
HEX=$(NAME).hex
LISTS=lists
TESTS=tests
SRCS=$(wildcard *.s) $(wildcard *.c)
SRCS+=$(filter-out $(wildcard tests/*), $(wildcard **/*.s)) $(filter-out $(wildcard tests/*), $(wildcard **/*.c))
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
TEST_SRCS=$(wildcard $(TESTS)/*.s) $(wildcard $(TESTS)/*.c)
TEST_OBJS+=$(patsubst %.s,%.o,$(filter %s,$(TEST_SRCS)))
TEST_OBJS+=$(patsubst %.c,%.o,$(filter %c,$(TEST_SRCS)))
TEST_OBJS+=$(filter-out boot.o,$(filter-out main.o,$(filter-out vectors.o,$(OBJS))))
all: $(HEX)
test: $(TEST_BIN)
$(SIM) $(SIMARGS) $(TEST_BIN)
$(TEST_BIN): $(OBJS) $(TEST_OBJS)
$(CC) $(CFLAGS) $(TEST_OBJS) -o $@
$(HEX): $(BIN)
objcopy --input-target=binary --output-target=ihex $(BIN) $(HEX)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
%.o: %.c $(LISTS)
$(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@
%.o: %.s $(LISTS)
$(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@
$(LISTS):
mkdir -p $(addprefix $(LISTS)/,$(sort $(dir $(SRCS))))
mkdir $(LISTS)/$(sort $(dir $(TEST_SRCS)))
.PHONY: clean
clean:
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
rm -rf $(TEST_OBJS) $(TEST_BIN)

54
sw/bootloader/boot.s Normal file
View File

@@ -0,0 +1,54 @@
; ---------------------------------------------------------------------------
; crt0.s
; ---------------------------------------------------------------------------
;
; Startup code for cc65 (Single Board Computer version)
.export _init, _exit
.import _main
.export __STARTUP__ : absolute = 1 ; Mark as startup
.import __SDRAM_START__, __SDRAM_SIZE__ ; Linker generated
.import copydata, zerobss, initlib, donelib
.include "zeropage.inc"
; ---------------------------------------------------------------------------
; Place the startup code in a special segment
.segment "STARTUP"
; ---------------------------------------------------------------------------
; A little light 6502 housekeeping
_init: LDX #$FF ; Initialize stack pointer to $01FF
TXS
CLD ; Clear decimal mode
; ---------------------------------------------------------------------------
; Set cc65 argument stack pointer
LDA #<(__SDRAM_START__ + __SDRAM_SIZE__)
STA sp
LDA #>(__SDRAM_START__ + __SDRAM_SIZE__)
STA sp+1
; ---------------------------------------------------------------------------
; Initialize memory storage
JSR zerobss ; Clear BSS segment
JSR copydata ; Initialize DATA segment
JSR initlib ; Run constructors
; ---------------------------------------------------------------------------
; Call main()
cli
JSR _main
jmp ($fffc)
; ---------------------------------------------------------------------------
; Back from main (this is also the _exit entry): force a software break
_exit: JSR donelib ; Run destructors
BRK

View File

@@ -0,0 +1,16 @@
#ifndef _BOARD_IO_H
#define _BOARD_IO_H
#include <stdint.h>
uint8_t hex_set_8(uint8_t val, uint8_t idx);
uint8_t hex_set_16(uint16_t val);
uint8_t hex_set_24(uint32_t val);
void hex_enable(uint8_t mask);
uint8_t sw_read();
void led_set(uint8_t val);
#endif

View File

@@ -0,0 +1,71 @@
.include "io.inc65"
.importzp sp, sreg
.export _hex_set_8
.export _hex_set_16
.export _hex_set_24
.export _hex_enable
.export _sw_read
.export _led_set
.autoimport on
.code
; @in A: idx Stack[0]: val
; @out A: 0 for success, 1 for failure.
; Sets one of the 3 pairs of hex digits.
_hex_set_8:
phx
cmp #$3 ; If idx >= 3 then fail
bcc @1
plx
lda #$1
rts
@1: tax ; Move idx into x
jsr popa ; put val into a
sta SEVEN_SEG,x ; write to val
lda #$0
plx
rts
; @in A/X: val
; @out A: 0 for success, 1 for failure
; Sets the low 2 pairs of hex digits
_hex_set_16:
sta SEVEN_SEG
stx SEVEN_SEG+1
lda #$0
rts
; @in A/X/sreg: val
; @out A: 0 for success, 1 for failure
; Sets the 3 pairs of hex digits for a 24 bit value
_hex_set_24:
sta SEVEN_SEG
stx SEVEN_SEG+1
lda sreg
sta SEVEN_SEG+2
lda #$0
rts
; @in A: mask
; Set the mask for seven seg enables
_hex_enable:
sta SEVEN_SEG+3
rts
; @out A: The Value of the switches
; Reads the current values of the switches.
_sw_read:
lda SW
ldx #$0
rts
; @in A: val
; @out A: 0 for success, 1 for failure
; Sets the LEDs
_led_set:
sta LED
rts

View File

@@ -0,0 +1,60 @@
.importzp sp, sreg
.import _uart_txb_block
.import _lastchar
.export _cputc
.export gotoxy
.export _clrscr
.export _cgetc
.autoimport on
.code
; void __fastcall__ cputc (char c);
_cputc:
jsr _uart_txb_block
cmp #$0a
bne @1
lda #$0d
jsr _uart_txb_block
@1: rts
; void __fastcall__ gotoxy (unsigned char x, unsigned char y);
gotoxy:
phx
phy
tay ; Move y position to y
lda (sp)
tax ; Move x position to x
lda #$1b
jsr _uart_txb_block
lda #'['
jsr _uart_txb_block
tya
jsr _uart_txb_block
lda #';'
jsr _uart_txb_block
txa
jsr _uart_txb_block
lda #'H'
jsr _uart_txb_block
ply
plx
rts
_clrscr:
phx
lda #$1b
jsr _uart_txb_block
lda #'c'
jsr _uart_txb_block
pla
rts
_cgetc:
@2: lda _lastchar
beq @2
stz _lastchar
rts

View File

@@ -0,0 +1,15 @@
#ifndef _INTERRUPT_H
#define _INTERRUPT_H
#include <stdint.h>
#define BUTTON (1 << 0)
#define UART (1 << 1)
void irq_int();
void nmi_int();
uint8_t irq_get_status();
void irq_set_status(uint8_t);
#endif

View File

@@ -0,0 +1,58 @@
; ---------------------------------------------------------------------------
; interrupt.s
; ---------------------------------------------------------------------------
;
; Interrupt handler.
;
; Checks for a BRK instruction and returns from all valid interrupts.
.import _handle_irq
.export _irq_int, _nmi_int
.export _irq_get_status, _irq_set_status
.include "io.inc65"
.segment "CODE"
.PC02 ; Force 65C02 assembly mode
; ---------------------------------------------------------------------------
; Non-maskable interrupt (NMI) service routine
_nmi_int: RTI ; Return from all NMI interrupts
; ---------------------------------------------------------------------------
; Maskable interrupt (IRQ) service routine
_irq_int: PHX ; Save X register contents to stack
TSX ; Transfer stack pointer to X
PHA ; Save accumulator contents to stack
INX ; Increment X so it points to the status
INX ; register value saved on the stack
LDA $100,X ; Load status register contents
AND #$10 ; Isolate B status bit
BNE break ; If B = 1, BRK detected
; ---------------------------------------------------------------------------
; IRQ detected, return
irq: PLA ; Restore accumulator contents
PLX ; Restore X register contents
jsr _handle_irq ; Handle the IRQ
RTI ; Return from all IRQ interrupts
; ---------------------------------------------------------------------------
; BRK detected, stop
break: JMP break ; If BRK is detected, something very bad
; has happened, so stop running
_irq_get_status:
lda IRQ_STATUS
ldx #$00
rts
_irq_set_status:
sta IRQ_STATUS
rts

View File

@@ -0,0 +1,18 @@
SEVEN_SEG = $7ff0
UART = $7ff4
UART_TXB = UART
UART_RXB = UART
UART_STATUS = UART + 1
LED = $7ff6
SW = LED
MM_CTRL = $7ff7
MM_DATA = $7fe0
SD_ARG = $7ff8
SD_CMD = $7ffc
SD_DATA = $7ffd
IRQ_STATUS = $7fff

View File

@@ -0,0 +1,12 @@
#ifndef _MAPPER_H
#define _MAPPER_H
#include <stdint.h>
void mapper_enable(uint8_t en);
uint8_t mapper_read(uint8_t addr);
void mapper_write(uint8_t data, uint8_t addr);
#endif

View File

@@ -0,0 +1,32 @@
.include "io.inc65"
.importzp sp, sreg
.export _mapper_enable
.export _mapper_read, _mapper_write
.autoimport on
.code
; void mapper_enable(uint8_t en)
_mapper_enable:
sta MM_CTRL
rts
_mapper_read:
phx
tax
lda MM_DATA,x
ldx #$00
rts
_mapper_write:
phx
tax
jsr popa
sta MM_DATA,x
plx
rts

View File

@@ -0,0 +1,75 @@
#include <stdint.h>
#include <conio.h>
#include "devices/sd_card.h"
void sd_init() {
uint32_t resp;
sd_card_command(0, 0);
sd_card_command(0x000001aa, 8);
sd_card_resp(&resp);
cprintf("CMD8: %lx\n", resp);
sd_card_command(0, 55);
sd_card_command(0x40180000, 41);
sd_card_resp(&resp);
cprintf("CMD41: %lx\n", resp);
sd_card_command(0, 55);
sd_card_command(0x40180000, 41);
sd_card_resp(&resp);
cprintf("CMD41: %lx\n", resp);
sd_card_command(0, 2);
sd_card_resp(&resp);
cprintf("CMD2: %lx\n", resp);
}
uint16_t sd_get_rca() {
uint32_t resp;
sd_card_command(0, 3);
resp = 0;
sd_card_resp(&resp);
//cprintf("CMD3: %lx\n", resp);
return resp >> 16;
}
uint16_t sd_select_card(uint16_t rca) {
uint32_t resp;
sd_card_command((uint32_t)rca << 16, 7);
sd_card_resp(&resp);
return (uint16_t) resp;
}
uint16_t sd_get_status(uint16_t rca) {
uint32_t resp;
sd_card_command((uint32_t)rca << 16, 13);
sd_card_resp(&resp);
return (uint16_t) resp;
}
void sd_readblock(uint32_t addr, void* buf) {
uint32_t resp;
int i;
sd_card_command(addr, 17);
sd_card_resp(&resp);
//cprintf("CMD17: %lx\n", resp);
sd_card_wait_for_data();
//cprintf("Read data: \n");
for (i = 0; i < 512; i++){
((uint8_t*)buf)[i] = sd_card_read_byte();
}
//cprintf("\n");
}

View File

@@ -0,0 +1,18 @@
#ifndef _SD_CARD_H
#define _SD_CARD_H
#include <stdint.h>
void sd_init();
uint16_t sd_get_rca();
uint16_t sd_select_card(uint16_t rca);
uint16_t sd_get_status(uint16_t rca);
void sd_readblock(uint32_t addr, void* buf);
void sd_card_command(uint32_t arg, uint8_t cmd);
void sd_card_resp(uint32_t* resp);
uint8_t sd_card_read_byte();
void sd_card_wait_for_data();
#endif

View File

@@ -0,0 +1,66 @@
.include "io.inc65"
.importzp sp, sreg, ptr1
.export _sd_card_command
.export _sd_card_resp
.export _sd_card_read_byte
.export _sd_card_wait_for_data
.autoimport on
.code
; Send sd card command.
; command is in A register, the args are on the stack
; I think the order is high byte first?
_sd_card_command:
pha
jsr popeax
sta SD_ARG
stx SD_ARG+1
lda sreg
sta SD_ARG+2
lda sreg+1
sta SD_ARG+3
pla
sta SD_CMD
rts
; void sd_card_resp(uint32_t* resp);
_sd_card_resp:
phy
sta ptr1 ; store pointer
stx ptr1+1
@1: lda SD_CMD ; wait for status flag
and #$01
beq @1
lda SD_ARG
ldy #$0
sta (ptr1),y
lda SD_ARG+1
iny
sta (ptr1),y
lda SD_ARG+2
iny
sta (ptr1),y
lda SD_ARG+3
iny
sta (ptr1),y
ply
rts
_sd_card_read_byte:
lda SD_DATA
ldx #$00
rts
_sd_card_wait_for_data:
pha
@1: lda SD_CMD ; wait for status flag
and #$02
beq @1
pla
rts

View File

@@ -0,0 +1,13 @@
#ifndef _UART_H
#define _UART_H
#include <stdint.h>
void uart_txb(uint8_t val);
void uart_txb_block(uint8_t val);
uint8_t uart_rxb();
uint8_t uart_status();
#endif

View File

@@ -0,0 +1,36 @@
.include "io.inc65"
.importzp sp, sreg
.export _uart_txb, _uart_txb_block
.export _uart_rxb
.export _uart_status
.autoimport on
.code
; @in A: byte to transmit
; Transmits a byte over the UART
_uart_txb:
sta UART_TXB ; Just write value, don't wait
rts
_uart_txb_block:
pha
sta UART_TXB ; Write value
@1: lda UART_STATUS ; Wait for status[0] to be 0
bit #$01
bne @1
pla
rts
_uart_rxb:
lda UART_RXB ; Read value
ldx #$00
rts
_uart_status:
lda UART_STATUS
ldx #$00
rts

View File

@@ -0,0 +1,208 @@
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include "fat.h"
#include "devices/sd_card.h"
uint8_t fat_buf[512];
static uint32_t fat_end_of_chain;
static full_bpb_t bpb;
static uint32_t data_region_start;
void fat_init(){
int i;
sd_readblock(0, fat_buf);
memcpy(&bpb, &fat_buf[11], sizeof(full_bpb_t));
sd_readblock(1, fat_buf);
sd_readblock(32, fat_buf);
data_region_start = bpb.reserved_sectors + bpb.fat_count*bpb.sectors_per_fat_32;
sd_readblock(bpb.reserved_sectors, fat_buf);
//uncomment to view start of FAT
/*
for (i = 0; i < FAT_CLUSTERS_PER_SECTOR; i++) {
cprintf("%lx ", ((uint32_t*)fat_buf)[i]);
}
cprintf("\n\n");
*/
fat_end_of_chain = ((uint32_t*)fat_buf)[1] & FAT_EOC_CLUSTERMASK;
cprintf("End of chain indicator: %lx\n", fat_end_of_chain);
}
// make sure you have enough space.
void fat_read_cluster(uint16_t cluster, uint8_t* buf) {
uint8_t i;
for (i = 0; i < bpb.sectors_per_cluster; i++) {
sd_readblock(data_region_start + i + (cluster - 2) * 8, buf+i*bpb.bytes_per_sector);
}
}
uint32_t fat_get_chain_value(uint16_t cluster) {
sd_readblock(bpb.reserved_sectors, fat_buf);
return ((uint32_t*)fat_buf)[cluster];
}
//the dentry is a double pointer because we need to increment it.
void fat_parse_vfat_filenamename(vfat_dentry_t** vfat_dentry, char* name, uint32_t cluster) {
uint8_t i;
uint8_t overflows;
uint8_t done;
char* shift_name;
uint8_t sequence_number = (*vfat_dentry)->sequence_number;
overflows = 0;
for (;;){
shift_name = name + 13*((sequence_number & FAT_LFN_ENTRY_MASK) - 1);
done = 0;
for(i = 0; i < 5; i++) {
shift_name[i] = (*vfat_dentry)->filename0[i];
if (!shift_name[i]) {
done = 1;
break;
}
}
if (!done) {
for(i = 0; i < 6; i++) {
shift_name[i+5] = (*vfat_dentry)->filename1[i];
if (!shift_name[i+5]) {
done = 1;
break;
}
}
}
if (!done) {
for(i = 0; i < 2; i++) {
shift_name[i+11] = (*vfat_dentry)->filename2[i];
if (!shift_name[i+11]) {
done = 1;
break;
}
}
}
if ((sequence_number & FAT_LFN_ENTRY_MASK) == 1) {
break;
} else {
do {
(*vfat_dentry)++;
if ((uint8_t*)*vfat_dentry >= fat_buf + sizeof(fat_buf)) {
overflows++;
if (overflows == bpb.sectors_per_cluster) {
cprintf("Too many overflows, go back to fat!\n"); //TODO this
return;
}
sd_readblock(data_region_start + (cluster - 2) * 8 + overflows, fat_buf);
*vfat_dentry = (vfat_dentry_t*)fat_buf;
}
} while((*vfat_dentry)->sequence_number == 0xe5);
sequence_number = (*vfat_dentry)->sequence_number;
}
}
}
uint32_t fat_find_cluster_num(char* name, uint32_t cluster) {
vfat_dentry_t* vfat_dentry;
dos_dentry_t* dos_dentry;
char* vfat_name;
cprintf("Looking for file %s\n", name);
sd_readblock(data_region_start + (cluster - 2) * 8, fat_buf);
vfat_dentry = (vfat_dentry_t*)fat_buf;
vfat_name = (char*)malloc(FAT_MAX_FILE_NAME);
while(vfat_dentry->sequence_number == 0xe5)
vfat_dentry++;
vfat_name[0] = '\0';
while(vfat_dentry->sequence_number) {
fat_parse_vfat_filenamename(&vfat_dentry, vfat_name, cluster);
cprintf("Parsed filename: %s\n", vfat_name);
if (!strcmp(vfat_name, name)) { //TODO this is probably unsafe, use strncmp
cprintf("Found file %s\n", vfat_name);
break;
} else {
vfat_dentry += 2;
while(vfat_dentry->sequence_number == 0xe5)
vfat_dentry++;
}
}
free(vfat_name);
if (!vfat_dentry->sequence_number) {
cprintf("File not found.\n");
return -1;
}
dos_dentry = (dos_dentry_t*) vfat_dentry + 1; //dos entry follows last vfat entry
cluster = ((uint32_t)dos_dentry->first_cluster_h << 16) + dos_dentry->first_cluster_l;
cprintf("Cluster: %ld\n", cluster);
return cluster;
}
uint16_t fat_parse_path_to_cluster(char* filename) {
//basically start at the root folder and search through it
int i;
int len;
uint8_t dirs = 0;
char* spaced_filename;
char* fragment;
uint32_t cluster = 2; //root chain is chain 2
if (filename[0] != '/') {
cprintf("Filename does not begin with '/'\n");
return 0;
}
filename++;
len = strlen(filename);
spaced_filename = (char*)malloc(len+1); //need to account for null byte
for (i = 0; i <= len; i++) {
if (filename[i] == '/') {
spaced_filename[i] = '\0';
dirs++;
} else {
spaced_filename[i] = filename[i];
}
}
fragment = spaced_filename;
cprintf("Dirs: %d\n", dirs);
for (i = 0; i <= dirs; i++) {
cprintf("Fragment: %s\n", fragment);
cluster = fat_find_cluster_num(fragment, cluster);
fragment = spaced_filename + strlen(fragment) + 1;
}
free(spaced_filename);
return cluster;
}

View File

@@ -0,0 +1,122 @@
#ifndef _FAT_H
#define _FAT_H
#include <stdint.h>
extern uint8_t fat_buf[];
#define FAT_MAX_FILE_NAME 255
#define FAT_CLUSTERS_PER_SECTOR 128
#define FAT_CLUSTERMASK 0x0fffffff
#define FAT_EOC_CLUSTERMASK 0x0ffffff8
#define FAT_LAST_LFN_MASK (1 << 6)
#define FAT_LFN_ENTRY_MASK 0x1f
typedef struct {
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t fat_count;
uint16_t max_dir_entries;
uint16_t total_sector_count;
uint8_t media_descriptor;
uint16_t sectors_per_fat;
} dos_2_bpb_t;
typedef struct {
dos_2_bpb_t bpb2;
uint16_t sectors_per_track;
uint16_t head_count;
uint32_t hidden_sector_count;
uint32_t logical_sector_count;
uint32_t sectors_per_fat;
uint16_t extended_flags;
uint16_t version;
uint32_t root_cluster;
uint16_t system_information;
uint16_t backup_boot_sector;
uint8_t reserved[12];
} dos_3_bpb_t;
typedef struct {
dos_3_bpb_t bpb3;
uint8_t drive_num;
uint8_t reserved;
uint8_t extended_signature;
uint32_t volume_id;
uint8_t partition_label[11];
uint8_t filesystem_type[8];
} ebpb_t;
typedef struct {
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t fat_count;
uint16_t max_dir_entries;
uint16_t total_sector_count;
uint8_t media_descriptor;
uint16_t sectors_per_fat_16;
uint16_t sectors_per_track;
uint16_t head_count;
uint32_t hidden_sector_count;
uint32_t logical_sector_count;
uint32_t sectors_per_fat_32;
uint16_t extended_flags;
uint16_t version;
uint32_t root_cluster;
uint16_t system_information;
uint16_t backup_boot_sector;
uint8_t reserved[12];
uint8_t drive_num;
uint8_t reserved2;
uint8_t extended_signature;
uint32_t volume_id;
uint8_t partition_label[11];
uint8_t filesystem_type[8];
} full_bpb_t;
typedef struct {
uint32_t sig;
uint8_t reserved[480];
uint32_t sig2;
uint32_t free_data_clusters;
uint32_t last_allocated_data_cluster;
uint32_t reserved2;
uint32_t sig3;
} fs_info_sector_t;
typedef struct {
uint8_t sequence_number;
uint16_t filename0[5];
uint8_t attributes;
uint8_t type;
uint8_t checksum;
uint16_t filename1[6];
uint16_t reserved;
uint16_t filename2[2];
} vfat_dentry_t;
typedef struct {
uint8_t filename[8];
uint8_t extension[3];
uint8_t attributes;
uint8_t reserved;
uint8_t create_time_10ms;
uint32_t create_date;
uint16_t access_date;
uint16_t first_cluster_h;
uint32_t modify_cluster;
uint16_t first_cluster_l;
uint32_t file_size;
} dos_dentry_t;
void fat_init();
uint16_t fat_parse_path_to_cluster(char* filename);
void fat_read_cluster(uint16_t cluster, uint8_t* buf);
uint32_t fat_get_chain_value(uint16_t cluster);
#endif

View File

@@ -0,0 +1,28 @@
#include <conio.h>
#include "o65.h"
void o65_print_option(o65_opt_t* opt) {
int i;
cprintf("Option Length: %d\n", opt->olen);
cprintf("Option Type: %x ", opt->type);
switch (opt->type) {
case O65_OPT_FILENAME: cprintf("Filename\n"); break;
case O65_OPT_OS: cprintf("OS\n"); break;
case O65_OPT_ASSEMBLER: cprintf("Assembler\n"); break;
case O65_OPT_AUTHOR: cprintf("Author\n"); break;
case O65_OPT_DATE: cprintf("Creation Date\n"); break;
default: cprintf("Invalid\n"); break;
}
if (opt->type != O65_OPT_OS) {
for (i = 0; i < opt->olen - 2; i++) {
cprintf("%c", opt->data[i]);
}
} else {
cprintf("%x", opt->data[0]);
}
cprintf("\n\n");
}

View File

@@ -0,0 +1,65 @@
#ifndef _O65_H
#define _O65_H
#include <stdint.h>
#define O65_NON_C64 0x0001
#define O65_MAGIC_0 0x6f
#define O65_MAGIC_1 0x36
#define O65_MAGIC_2 0x35
#define O65_OPT_FILENAME 0
#define O65_OPT_OS 1
#define O65_OPT_ASSEMBLER 2
#define O65_OPT_AUTHOR 3
#define O65_OPT_DATE 4
#define O65_OS_OSA65 1
#define O65_OS_LUNIX 2
#define O65_OS_CC65 3
#define O65_OS_OPENCBM 4
#define O65_OS_SUPER6502 5
typedef union {
struct {
int cpu : 1;
int reloc : 1;
int size : 1;
int obj : 1;
int simple : 1;
int chain : 1;
int bsszero : 1;
int cpu2 : 4;
int align : 2;
};
uint16_t _mode;
} o65_mode_t;
typedef struct {
uint16_t c64_marker;
uint8_t magic[3];
uint8_t version;
o65_mode_t mode;
uint16_t tbase;
uint16_t tlen;
uint16_t dbase;
uint16_t dlen;
uint16_t bbase;
uint16_t blen;
uint16_t zbase;
uint16_t zlen;
uint16_t stack;
} o65_header_t;
typedef struct {
uint8_t olen;
uint8_t type;
uint8_t data[1]; //This is actually variable length
} o65_opt_t;
void o65_print_option(o65_opt_t* opt);
#endif

24
sw/bootloader/irq.c Normal file
View File

@@ -0,0 +1,24 @@
#include <stdint.h>
#include <conio.h>
#include "devices/interrupt.h"
#include "devices/uart.h"
char lastchar;
void handle_irq() {
uint8_t status;
status = irq_get_status();
if (status & BUTTON) {
cputs("Button Interrupt!\n");
irq_set_status(status & ~BUTTON);
}
if (status & UART) {
lastchar = uart_rxb();
irq_set_status(status & ~UART);
}
}

35
sw/bootloader/link.ld Normal file
View File

@@ -0,0 +1,35 @@
MEMORY
{
ZP: start = $0, size = $100, type = rw, define = yes;
SDRAM: start = $200, size = $7cf0, type = rw, define = yes;
ROM: start = $8000, size = $8000, file = %O;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, define = yes;
DATA: load = ROM, type = rw, define = yes, run = SDRAM;
BSS: load = SDRAM, type = bss, define = yes;
HEAP: load = SDRAM, type = bss, optional = yes;
STARTUP: load = ROM, type = ro;
ONCE: load = ROM, type = ro, optional = yes;
CODE: load = ROM, type = ro;
RODATA: load = ROM, type = ro;
VECTORS: load = ROM, type = ro, start = $FFFA;
}
FEATURES {
CONDES: segment = STARTUP,
type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__;
CONDES: segment = STARTUP,
type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
}
SYMBOLS {
# Define the stack size for the application
__STACKSIZE__: value = $0200, type = weak;
__STACKSTART__: type = weak, value = $0800; # 2k stack
}

62
sw/bootloader/main.c Normal file
View File

@@ -0,0 +1,62 @@
#include <stdint.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include "devices/board_io.h"
#include "devices/uart.h"
#include "devices/mapper.h"
#include "devices/sd_card.h"
#include "filesystem/fat.h"
#define KERNEL_LOAD_ADDR 0xD000
uint8_t buf[512];
int main() {
int i;
uint16_t rca;
char* filename;
uint32_t cluster;
uint8_t* kernel_load;
clrscr();
cprintf("boot\n");
for (i = 0; i < 16; i++){
//cprintf("Mapping %1xxxx to %2xxxx\n", i, i);
mapper_write(i, i);
}
cprintf("Enabling Mapper\n");
mapper_enable(1);
mapper_write(0x10, 0xd);
mapper_write(0x11, 0xe);
mapper_write(0x12, 0xf);
sd_init();
rca = sd_get_rca();
cprintf("rca: %x\n", rca);
sd_select_card(rca);
fat_init();
filename = (char*)malloc(FAT_MAX_FILE_NAME);
cluster = fat_parse_path_to_cluster("/kernel.bin");
for (kernel_load = (uint8_t*)KERNEL_LOAD_ADDR; cluster < FAT_CLUSTERMASK; kernel_load+=(8*512)) {
cprintf("cluster: %lx\n", cluster);
cprintf("Writing to %p\n", kernel_load);
fat_read_cluster(cluster, kernel_load);
cluster = fat_get_chain_value(cluster);
}
cprintf("Done!\n");
cprintf("Reset vector: %x\n", *((uint16_t*)0xfffc));
return 0;
}

View File

@@ -0,0 +1,89 @@
#include <stdio.h>
#include "devices/board_io.h"
#include "devices/uart.h"
#include "devices/interrupt.h"
int main(void)
{
int retval = 0;
int i;
printf("\nStarting tests...\n\n");
printf("Testing hex_set_8...\n");
for (i = 0; i < 3; i++) {
if (hex_set_8(i+1, i)) {
printf("Failed to write to idx %d!\n", i);
retval++;
}
if (*(uint8_t*)0x7ff0+i != i+1) {
printf("Incorrect value at idx %d!\n", i);
retval++;
}
}
if (!hex_set_8(0xab, 3)) {
printf("Writing to idx 3 should fail!\n");
retval++;
}
printf("Done!\n\n");
printf("Testing hex_set_16...\n");
if (hex_set_16(0xabcd)){
printf("Failed to write!\n");
}
if (*(uint16_t*)0x7ff0 != 0xabcd) {
printf("Incorrect value!\n", i);
retval++;
}
printf("Done!\n\n");
printf("Testing hex_set_24...\n");
if (hex_set_24(0xabcdef)){
printf("Failed to write!\n");
}
if (*(uint16_t*)0x7ff0 != 0xcdef && *(uint8_t*)0x7ff2 != 0xab) {
printf("Incorrect value!\n", i);
retval++;
}
printf("Done!\n\n");
printf("Testing hex_enable...\n");
hex_enable(0xa5);
if (*(uint8_t*)0x7ff3 != 0xa5) {
printf("Incorrect value!\n", i);
retval++;
}
printf("Done!\n\n");
printf("Testing uart_txb_block...\n");
*(uint8_t*)0x7ff5 = 0;
uart_txb_block(0xa5);
if (*(uint8_t*)0x7ff4 != 0xa5) {
printf("Incorrect value!\n", i);
retval++;
}
printf("Done!\n\n");
printf("Testing uart_status...\n");
*(uint8_t*)0x7ff5 = 0xa5;
if (uart_status() != 0xa5) {
printf("Incorrect value!\n", i);
retval++;
}
printf("Done!\n\n");
printf("Testing irq_get_status...\n");
*(uint8_t*)0x7fff = 0xa5;
if (irq_get_status() != 0xa5) {
printf("Incorrect value!\n", i);
retval++;
}
printf("Done!\n\n");
return retval != 0;
}

14
sw/bootloader/vectors.s Normal file
View File

@@ -0,0 +1,14 @@
; ---------------------------------------------------------------------------
; vectors.s
; ---------------------------------------------------------------------------
;
; Defines the interrupt vector table.
.import _init
.import _nmi_int, _irq_int
.segment "VECTORS"
.addr _nmi_int ; NMI vector
.addr _init ; Reset vector
.addr _irq_int ; IRQ/BRK vector

1
sw/cc65 Submodule

Submodule sw/cc65 added at 23a984f0dd

1
sw/fsdir/hello.txt Normal file
View File

@@ -0,0 +1 @@
hello, world!

View File

@@ -1,11 +1,13 @@
CC=cl65
CFLAGS=-T -t none -I. --cpu "65C02"
CC=../cc65/bin/cl65
CFLAGS=-T -t super6502 -I. --cpu "65C02"
test: CFLAGS=-T -t sim65c02 -I.
LDFLAGS=-C link.ld -m $(NAME).map
SIM=sim65
SIM=../cc65/bin/sim65
SIMARGS=-v -c -x 1000000
NAME=bootrom
FSDIR=../fsdir
NAME=kernel
TEST_BIN=test.bin
BIN=$(NAME).bin
@@ -24,7 +26,8 @@ TEST_OBJS+=$(patsubst %.s,%.o,$(filter %s,$(TEST_SRCS)))
TEST_OBJS+=$(patsubst %.c,%.o,$(filter %c,$(TEST_SRCS)))
TEST_OBJS+=$(filter-out boot.o,$(filter-out main.o,$(filter-out vectors.o,$(OBJS))))
all: $(HEX)
all: $(BIN)
cp $(BIN) $(FSDIR)
test: $(TEST_BIN)
$(SIM) $(SIMARGS) $(TEST_BIN)
@@ -53,4 +56,5 @@ $(LISTS):
clean:
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
rm -rf $(TEST_OBJS) $(TEST_BIN)
rm -rf $(FSDIR)/$(BIN)

View File

@@ -29,9 +29,10 @@ _init: LDX #$FF ; Initialize stack pointer to $01FF
; ---------------------------------------------------------------------------
; Set cc65 argument stack pointer
LDA #<(__SDRAM_START__ + __SDRAM_SIZE__)
;LDA #<(__SDRAM_START__ + __SDRAM_SIZE__)
lda #<($200 + $7cf0)
STA sp
LDA #>(__SDRAM_START__ + __SDRAM_SIZE__)
LDA #>($200 + $7cf0)
STA sp+1
; ---------------------------------------------------------------------------

View File

@@ -52,7 +52,7 @@ void exec(char* filename) {
ret = 0;
ret = (*exec)();
//ret = (*exec)();
cprintf("ret: %x\n", ret);

View File

@@ -45,7 +45,7 @@ void fat_print_pbp_info(full_bpb_t* bpb){
}
void fat_init(){
int i;
//int i;
sd_readblock(0, fat_buf);

View File

@@ -2,12 +2,16 @@ MEMORY
{
ZP: start = $0, size = $100, type = rw, define = yes;
SDRAM: start = $200, size = $7cf0, type = rw, define = yes;
ROM: start = $8000, size = $8000, fill = yes, fillval = $ff, file = %O;
ROM: start = $D000, size = $3000, type = rw, define = yes;
}
FILES {
%O: format = bin;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, define = yes;
DATA: load = ROM, type = rw, define = yes, run = SDRAM;
DATA: load = SDRAM, type = rw, define = yes;
BSS: load = SDRAM, type = bss, define = yes;
HEAP: load = SDRAM, type = bss, optional = yes;
STARTUP: load = ROM, type = ro;

View File

@@ -13,20 +13,11 @@
uint8_t buf[512];
int main() {
int i;
uint16_t rca;
char* filename;
clrscr();
cprintf("Hello, world!\n");
for (i = 0; i < 16; i++){
//cprintf("Mapping %1xxxx to %2xxxx\n", i, i);
mapper_write(i, i);
}
cprintf("Enabling Mapper\n");
mapper_enable(1);
cprintf("Hello, world! Modified\n");
sd_init();

19
sw/script/copy_files.sh Normal file
View File

@@ -0,0 +1,19 @@
DEVICE=/dev/mmcblk0
TMPMOUNT=/tmp/sd
FSDIR=fsdir
V=
echo "$(tput bold setaf 11)Mounting Device$(tput sgr 0)"
mkdir $V -p $TMPMOUNT
sudo mount $V $DEVICE $TMPMOUNT
echo
echo "$(tput bold setaf 11)Copying Files$(tput sgr 0)"
sudo cp $V -r $FSDIR/* $TMPMOUNT
echo
echo "$(tput bold setaf 11)Unmounting Device$(tput sgr 0)"
sudo umount $V $DEVICE
rmdir $V $TMPMOUNT
echo

23
sw/script/format_disk.sh Normal file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
BOOTLOADER=bootloader/bootloader.bin
DEVICE=/dev/mmcblk0
TMPBOOTSECT=/tmp/bootsect
TMPMOUNT=/tmp/sd
V=
STATUS="status=none"
echo "$(tput bold setaf 11)Creating Filesystem$(tput sgr 0)"
sudo mkfs.vfat -F32 $DEVICE -n SUPER6502 $V
echo
echo "$(tput bold setaf 11)Modifying Boot Sector$(tput sgr 0)"
sudo dd if=$DEVICE of=$TMPBOOTSECT bs=512 count=1 $STATUS
sudo dd conv=notrunc if=$BOOTLOADER of=$DEVICE bs=512 skip=0 count=1 $STATUS
sudo dd conv=notrunc if=$TMPBOOTSECT of=$DEVICE bs=1 skip=0 count=90 iflag=skip_bytes,count_bytes $STATUS
sudo dd conv=notrunc if=$BOOTLOADER of=$DEVICE bs=1 skip=0 count=3 iflag=skip_bytes,count_bytes $STATUS
echo
echo "$(tput bold setaf 10)Done!$(tput sgr 0)"

View File

@@ -1,5 +1,5 @@
CC=cl65
CFLAGS=-T -t none -I. --cpu "65C02"
CFLAGS=-T -t super6502 -I. --cpu "65C02"
test: CFLAGS=-T -t sim65c02 -I.
LDFLAGS=-C link.ld -m $(NAME).map
SIM=sim65