Merge branch 'bootloader' into 'master'
Add bootloader, change ci to use custom cc65 See merge request bslathi19/super6502!16
This commit is contained in:
@@ -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
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "sw/cc65"]
|
||||
path = sw/cc65
|
||||
url = https://git.byronlathi.com/bslathi19/cc65
|
||||
@@ -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
22
sw/Makefile
Normal 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
56
sw/bootloader/Makefile
Normal 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
54
sw/bootloader/boot.s
Normal 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
|
||||
16
sw/bootloader/devices/board_io.h
Normal file
16
sw/bootloader/devices/board_io.h
Normal 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
|
||||
71
sw/bootloader/devices/board_io.s
Normal file
71
sw/bootloader/devices/board_io.s
Normal 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
|
||||
60
sw/bootloader/devices/conio.s
Normal file
60
sw/bootloader/devices/conio.s
Normal 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
|
||||
15
sw/bootloader/devices/interrupt.h
Normal file
15
sw/bootloader/devices/interrupt.h
Normal 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
|
||||
58
sw/bootloader/devices/interrupt.s
Normal file
58
sw/bootloader/devices/interrupt.s
Normal 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
|
||||
18
sw/bootloader/devices/io.inc65
Normal file
18
sw/bootloader/devices/io.inc65
Normal 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
|
||||
12
sw/bootloader/devices/mapper.h
Normal file
12
sw/bootloader/devices/mapper.h
Normal 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
|
||||
|
||||
32
sw/bootloader/devices/mapper.s
Normal file
32
sw/bootloader/devices/mapper.s
Normal 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
|
||||
|
||||
75
sw/bootloader/devices/sd_card.c
Normal file
75
sw/bootloader/devices/sd_card.c
Normal 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");
|
||||
}
|
||||
18
sw/bootloader/devices/sd_card.h
Normal file
18
sw/bootloader/devices/sd_card.h
Normal 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
|
||||
66
sw/bootloader/devices/sd_card_asm.s
Normal file
66
sw/bootloader/devices/sd_card_asm.s
Normal 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
|
||||
13
sw/bootloader/devices/uart.h
Normal file
13
sw/bootloader/devices/uart.h
Normal 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
|
||||
36
sw/bootloader/devices/uart.s
Normal file
36
sw/bootloader/devices/uart.s
Normal 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
|
||||
208
sw/bootloader/filesystem/fat.c
Normal file
208
sw/bootloader/filesystem/fat.c
Normal 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;
|
||||
}
|
||||
122
sw/bootloader/filesystem/fat.h
Normal file
122
sw/bootloader/filesystem/fat.h
Normal 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
|
||||
28
sw/bootloader/filesystem/o65.c
Normal file
28
sw/bootloader/filesystem/o65.c
Normal 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");
|
||||
}
|
||||
65
sw/bootloader/filesystem/o65.h
Normal file
65
sw/bootloader/filesystem/o65.h
Normal 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
24
sw/bootloader/irq.c
Normal 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
35
sw/bootloader/link.ld
Normal 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
62
sw/bootloader/main.c
Normal 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;
|
||||
}
|
||||
89
sw/bootloader/tests/test_main.c
Normal file
89
sw/bootloader/tests/test_main.c
Normal 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
14
sw/bootloader/vectors.s
Normal 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
1
sw/cc65
Submodule
Submodule sw/cc65 added at 23a984f0dd
1
sw/fsdir/hello.txt
Normal file
1
sw/fsdir/hello.txt
Normal file
@@ -0,0 +1 @@
|
||||
hello, world!
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@ -52,7 +52,7 @@ void exec(char* filename) {
|
||||
|
||||
ret = 0;
|
||||
|
||||
ret = (*exec)();
|
||||
//ret = (*exec)();
|
||||
|
||||
cprintf("ret: %x\n", ret);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
19
sw/script/copy_files.sh
Normal 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
23
sw/script/format_disk.sh
Normal 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)"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user