Delete everything
This commit is contained in:
58
sw/.gitignore
vendored
58
sw/.gitignore
vendored
@@ -1,58 +0,0 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.o65
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
lists/
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.bin
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# Filesystem Images
|
||||
*.fat
|
||||
23
sw/Makefile
23
sw/Makefile
@@ -1,23 +0,0 @@
|
||||
.PHONY: all install bios kernel clean distclean
|
||||
|
||||
all: toolchain bios kernel
|
||||
|
||||
install: all
|
||||
sh script/format_disk.sh
|
||||
sh script/copy_files.sh
|
||||
|
||||
toolchain:
|
||||
@$(MAKE) -j4 -C cc65
|
||||
|
||||
bios:
|
||||
@$(MAKE) -C bios
|
||||
|
||||
kernel:
|
||||
@$(MAKE) -C kernel
|
||||
|
||||
distclean: clean
|
||||
@$(MAKE) -C cc65 --no-print-directory $@
|
||||
|
||||
clean:
|
||||
@$(MAKE) -C bios --no-print-directory $@
|
||||
@$(MAKE) -C kernel --no-print-directory $@
|
||||
@@ -1,58 +0,0 @@
|
||||
CC=../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02" -DRTL_SIM
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
FSDIR=$(REPO_TOP)/sw/fsdir
|
||||
|
||||
NAME=bios
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
FPGA_IMG=$(REPO_TOP)/hw/efinix_fpga/init_hex.mem
|
||||
EFX_RUN=/home/byron/Software/efinity/2023.1/scripts/efx_run.py
|
||||
EFX_PRJ=/home/byron/Projects/super6502/hw/efinix_fpga/super6502.xml
|
||||
|
||||
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)))
|
||||
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN) $(FSDIR)
|
||||
objcopy --input-target=binary --output-target=verilog $(BIN) $(HEX)
|
||||
cp boot2.bin $(FSDIR)
|
||||
cmp $(HEX) $(FPGA_IMG); \
|
||||
RETVAL=$$?; \
|
||||
if [ $$RETVAL -eq 0 ]; then \
|
||||
echo "SAME"; \
|
||||
else \
|
||||
echo "NOT SAME"; \
|
||||
cp bios.hex ../../hw/efinix_fpga/init_hex.mem; \
|
||||
echo "Update ROM or rebuild FPGA image!"; \
|
||||
fi
|
||||
|
||||
$(FSDIR):
|
||||
mkdir $(FSDIR)
|
||||
|
||||
|
||||
$(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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
|
||||
352
sw/bios/boot2.s
352
sw/bios/boot2.s
@@ -1,352 +0,0 @@
|
||||
.importzp sp, ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, sreg, data_start
|
||||
|
||||
.autoimport on
|
||||
|
||||
.export fatbuf
|
||||
|
||||
.feature string_escapes
|
||||
|
||||
.MACPACK generic
|
||||
|
||||
fatbuf = $A000
|
||||
filebuf = $B000
|
||||
|
||||
.bss
|
||||
|
||||
tbase: .res 2
|
||||
tlen: .res 2
|
||||
dbase: .res 2
|
||||
dlen: .res 2
|
||||
olen: .res 1
|
||||
otype: .res 1
|
||||
|
||||
filesiz: .res 1
|
||||
cluster: .res 2
|
||||
|
||||
.zeropage
|
||||
|
||||
userptr: .res 2
|
||||
|
||||
.segment "BOOTLOADER"
|
||||
|
||||
sectors_per_cluster = $800D
|
||||
reserved_sectors = $800E
|
||||
fat_count = $8010
|
||||
sectors_per_fat = $8024
|
||||
|
||||
O65_NO_C65 = $00
|
||||
O65_MAGIC = $02
|
||||
O65_VERSION = $05
|
||||
O65_MODE = $06
|
||||
O65_TBASE = $08
|
||||
O65_TLEN = $0a
|
||||
O65_DBASE = $0c
|
||||
O65_DLEN = $0e
|
||||
O65_BBASE = $10
|
||||
O65_BLEN = $12
|
||||
O65_ZBASE = $14
|
||||
O65_ZLEN = $16
|
||||
O65_STACK = $18
|
||||
O65_OPT_START = $1A
|
||||
|
||||
_start:
|
||||
lda #<str
|
||||
ldx #>str
|
||||
jsr _cputs
|
||||
|
||||
; Read root directory entry into fatbuf
|
||||
lda data_start
|
||||
ldx data_start + 1
|
||||
jsr pushax
|
||||
stz sreg
|
||||
stz sreg+1
|
||||
jsr pusheax
|
||||
lda #<fatbuf
|
||||
ldx #>fatbuf
|
||||
jsr pushax
|
||||
lda #<ptr1
|
||||
ldx #>ptr1
|
||||
jsr _SD_readSingleBlock
|
||||
|
||||
; lda #<fatbuf
|
||||
; ldx #>fatbuf
|
||||
; jsr _SD_printBuf
|
||||
|
||||
lda #$20 ; Start at first directory entry (first is a disk label)
|
||||
sta ptr3
|
||||
lda #>fatbuf
|
||||
sta ptr3 + 1
|
||||
ldy #$0b ; look for attributes
|
||||
@1: lda (ptr3),y
|
||||
|
||||
cmp #$0f ; if attribute is 0xf, this is a lfn
|
||||
bne @2 ; if not an lfn, then try to read filename
|
||||
@next: clc ; otherwise, go to the next entry (+0x20)
|
||||
lda ptr3
|
||||
adc #$20
|
||||
sta ptr3
|
||||
bcc @4
|
||||
inc ptr3 + 1
|
||||
@4: lda #<word_str
|
||||
ldx #>word_str
|
||||
jsr pushax
|
||||
lda ptr3
|
||||
ldx ptr3 + 1
|
||||
pha
|
||||
phx
|
||||
jsr pushax
|
||||
phy
|
||||
ldy #$4
|
||||
jsr _cprintf
|
||||
ply
|
||||
plx
|
||||
stx ptr3 + 1
|
||||
pla
|
||||
sta ptr3
|
||||
bra @1
|
||||
|
||||
@2: ldy #11 ; ignore the attributes. Write null to make a string
|
||||
lda #$00
|
||||
sta (ptr3),y
|
||||
lda ptr3 ; store address of the filename string on the stack
|
||||
pha
|
||||
ldx ptr3 + 1
|
||||
phx
|
||||
jsr _cputs ; print out short filenames as we read them
|
||||
lda #$0d
|
||||
jsr _cputc
|
||||
lda #$0a
|
||||
jsr _cputc
|
||||
lda #<kernel_str ; load the string "KERNEL O65"
|
||||
ldx #>kernel_str
|
||||
jsr pushax
|
||||
plx ; then push the string we read earlier
|
||||
pla
|
||||
jsr _strcmp
|
||||
bne @next ; if they are not equal then try next entry
|
||||
lda #<_good ; print match if we found it
|
||||
ldx #>_good
|
||||
jsr _cputs ; otherwise continue on
|
||||
|
||||
lda #<word_str
|
||||
ldx #>word_str
|
||||
jsr pushax
|
||||
|
||||
lda ptr3
|
||||
pha
|
||||
lda ptr3 + 1
|
||||
pha
|
||||
|
||||
ldy #$1d ; load file size (256)
|
||||
lda (ptr3),y
|
||||
lsr ; divide by 2 to get file size (512)
|
||||
sta filesiz
|
||||
jsr pusha0
|
||||
ldy #$4
|
||||
jsr _cprintf
|
||||
|
||||
pla
|
||||
sta ptr3 + 1
|
||||
pla
|
||||
sta ptr3
|
||||
|
||||
ldy #$1b ; load high byte of low first cluster
|
||||
lda (ptr3),y
|
||||
tax
|
||||
dey
|
||||
lda (ptr3),y ; load low byte of low first cluster
|
||||
|
||||
sec
|
||||
sbc #$02 ; don't handle carry, assume low byte is not 0 or 1
|
||||
clc
|
||||
sta tmp1
|
||||
ldx data_start + 1 ; load x as high data start
|
||||
phx
|
||||
ldx sectors_per_cluster ; multiply cluster num (minus 2) by sectors_per_cluster
|
||||
lda #$00
|
||||
@8: adc tmp1
|
||||
dex
|
||||
bne @8
|
||||
plx
|
||||
clc
|
||||
adc data_start ; add that to low data start
|
||||
bcc @5 ; handle carry
|
||||
inx
|
||||
@5: sta cluster
|
||||
stx cluster + 1
|
||||
|
||||
lda #<filebuf
|
||||
ldx #>filebuf
|
||||
sta userptr
|
||||
stx userptr + 1
|
||||
|
||||
@read_sd:
|
||||
lda cluster
|
||||
ldx cluster + 1
|
||||
stz sreg
|
||||
stz sreg+1
|
||||
jsr pusheax
|
||||
lda userptr
|
||||
ldx userptr + 1
|
||||
jsr pushax
|
||||
lda #<ptr1
|
||||
ldx #>ptr1
|
||||
jsr _SD_readSingleBlock
|
||||
|
||||
; lda userptr
|
||||
; ldx userptr + 1
|
||||
; jsr _SD_printBuf
|
||||
|
||||
dec filesiz
|
||||
bmi @doneload
|
||||
inc cluster
|
||||
inc userptr + 1
|
||||
inc userptr + 1
|
||||
bra @read_sd
|
||||
|
||||
@doneload:
|
||||
ldy #O65_TBASE
|
||||
lda filebuf,y
|
||||
sta tbase
|
||||
iny
|
||||
ldx filebuf,y
|
||||
stx tbase + 1
|
||||
|
||||
ldy #O65_TLEN
|
||||
lda filebuf,y
|
||||
sta tlen
|
||||
iny
|
||||
ldx filebuf,y
|
||||
stx tlen + 1
|
||||
|
||||
|
||||
ldy #O65_DBASE
|
||||
lda filebuf,y
|
||||
sta dbase
|
||||
iny
|
||||
ldx filebuf,y
|
||||
stx dbase + 1
|
||||
|
||||
ldy #O65_DLEN
|
||||
lda filebuf,y
|
||||
sta dlen
|
||||
iny
|
||||
ldx filebuf,y
|
||||
stx dlen + 1
|
||||
|
||||
ldy #O65_OPT_START
|
||||
phy
|
||||
@opt_len:
|
||||
lda #<opt_str
|
||||
ldx #>opt_str
|
||||
jsr pushax
|
||||
ply
|
||||
lda filebuf,y
|
||||
beq @opt_end
|
||||
sta olen
|
||||
phy
|
||||
jsr pusha0
|
||||
ply
|
||||
iny
|
||||
lda filebuf,y
|
||||
sta otype
|
||||
phy
|
||||
jsr pusha0
|
||||
ldy #$6
|
||||
jsr _cprintf
|
||||
|
||||
lda #<word_str
|
||||
ldx #>word_str
|
||||
jsr pushax
|
||||
|
||||
pla
|
||||
clc
|
||||
adc olen
|
||||
dec
|
||||
pha
|
||||
bra @opt_len
|
||||
|
||||
@opt_end:
|
||||
iny ; account for reading size
|
||||
phy
|
||||
lda #<opt_done
|
||||
ldx #>opt_done
|
||||
jsr pushax
|
||||
pla
|
||||
pha
|
||||
jsr pusha0
|
||||
ldy #$4
|
||||
jsr _cprintf
|
||||
|
||||
clc
|
||||
pla
|
||||
ldx #>filebuf
|
||||
adc #<filebuf
|
||||
bcc @6
|
||||
inx
|
||||
@6: sta userptr
|
||||
stx userptr + 1
|
||||
lda #<word_str
|
||||
ldx #>word_str
|
||||
jsr pushax
|
||||
lda userptr
|
||||
ldx userptr + 1
|
||||
jsr pushax
|
||||
ldy #$4
|
||||
jsr _cprintf
|
||||
|
||||
lda tbase
|
||||
ldx tbase + 1
|
||||
jsr pushax
|
||||
lda userptr
|
||||
ldx userptr + 1
|
||||
jsr pushax
|
||||
lda tlen
|
||||
ldx tlen + 1
|
||||
jsr _memcpy
|
||||
|
||||
; lda #<$1000
|
||||
; ldx #>$1000
|
||||
; jsr _SD_printBuf
|
||||
|
||||
clc
|
||||
lda userptr + 1
|
||||
adc tlen + 1
|
||||
tax
|
||||
lda userptr
|
||||
adc tlen
|
||||
bcc @7
|
||||
inx
|
||||
@7: sta userptr
|
||||
stx userptr + 1
|
||||
lda #<word_str
|
||||
ldx #>word_str
|
||||
jsr pushax
|
||||
lda userptr
|
||||
ldx userptr + 1
|
||||
jsr pushax
|
||||
ldy #$4
|
||||
jsr _cprintf
|
||||
|
||||
lda dbase
|
||||
ldx dbase + 1
|
||||
jsr pushax
|
||||
lda userptr
|
||||
ldx userptr + 1
|
||||
jsr pushax
|
||||
lda dlen
|
||||
ldx dlen + 1
|
||||
jsr _memcpy
|
||||
|
||||
jmp $1000
|
||||
|
||||
@end: bra @end
|
||||
|
||||
|
||||
str: .asciiz "boot2\n"
|
||||
kernel_str: .asciiz "KERNEL O65"
|
||||
_good: .asciiz "Found KERNEL\n"
|
||||
word_str: .asciiz "Word Value: %x\n"
|
||||
|
||||
opt_str: .asciiz "Opt Len: %x, Opt Type: %x\n"
|
||||
opt_done: .asciiz "Options done. total option length: %x\n"
|
||||
@@ -1,201 +0,0 @@
|
||||
.importzp sp, ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, sreg
|
||||
.exportzp data_start
|
||||
|
||||
.autoimport on
|
||||
|
||||
.feature string_escapes
|
||||
|
||||
.MACPACK generic
|
||||
.MACPACK longbranch
|
||||
|
||||
_console_clear = $0
|
||||
_console_read_char = $2
|
||||
_console_write_char = $4
|
||||
_sd_readblock = $6
|
||||
|
||||
sectors_per_cluster = $800D
|
||||
reserved_sectors = $800E
|
||||
fat_count = $8010
|
||||
sectors_per_fat = $8024
|
||||
|
||||
buf = $8200
|
||||
addrh = $0000
|
||||
addrl = $0000
|
||||
|
||||
.zeropage
|
||||
|
||||
data_start: .res 2
|
||||
|
||||
|
||||
.segment "BOOTSECTOR"
|
||||
|
||||
_start:
|
||||
jmp _main
|
||||
|
||||
.byte "SUPR6502"
|
||||
|
||||
_preamble:
|
||||
|
||||
.res (11+_start-_preamble)
|
||||
|
||||
_bpb: .res 60
|
||||
|
||||
_main:
|
||||
lda #<str
|
||||
ldx #>str
|
||||
jsr _cputs
|
||||
|
||||
lda fat_count
|
||||
cmp #$2
|
||||
jne @fail
|
||||
lda sectors_per_fat
|
||||
asl
|
||||
pha
|
||||
lda sectors_per_fat + 1
|
||||
rol
|
||||
tax
|
||||
pla
|
||||
adc reserved_sectors
|
||||
bcc @a
|
||||
inx
|
||||
@a: sta data_start
|
||||
stx data_start + 1
|
||||
jsr pushax
|
||||
stz sreg
|
||||
stz sreg+1
|
||||
jsr pusheax
|
||||
lda #<buf
|
||||
ldx #>buf
|
||||
jsr pushax
|
||||
lda #<ptr1
|
||||
ldx #>ptr1
|
||||
jsr _SD_readSingleBlock
|
||||
|
||||
; lda #<buf
|
||||
; ldx #>buf
|
||||
; jsr _SD_printBuf
|
||||
|
||||
|
||||
lda #$20 ; Start at first directory entry (first is a disk label)
|
||||
sta ptr3
|
||||
lda #>buf
|
||||
sta ptr3 + 1
|
||||
ldy #$0b ; look for attributes
|
||||
@1: lda (ptr3),y
|
||||
|
||||
cmp #$0f ; if attribute is 0xf, this is a lfn
|
||||
bne @2 ; if not an lfn, then try to read filename
|
||||
clc ; otherwise, go to the next entry (+0x20)
|
||||
lda ptr3
|
||||
adc #$20
|
||||
sta ptr3
|
||||
bra @1
|
||||
|
||||
@2: ldy #11 ; ignore the attributes. Write null to make a string
|
||||
lda #$00
|
||||
sta (ptr3),y
|
||||
lda ptr3 ; store address of the filename string on the stack
|
||||
pha
|
||||
ldx ptr3 + 1
|
||||
phx
|
||||
lda #<_boot2_str ; load the string "BOOT2 BIN"
|
||||
ldx #>_boot2_str
|
||||
jsr pushax
|
||||
plx ; then push the string we read earlier
|
||||
pla
|
||||
jsr _strcmp
|
||||
bne @fail ; if they are not equal then fail
|
||||
lda #<_good ; TODO: We should try the next entry
|
||||
ldx #>_good
|
||||
jsr _cputs ; otherwise continue on
|
||||
|
||||
|
||||
ldy #$1b ; load the high byte of the low first cluster
|
||||
lda (ptr3),y
|
||||
tax
|
||||
dey
|
||||
lda (ptr3),y ; load the low byte of the low first cluster
|
||||
|
||||
sec
|
||||
sbc #$02 ; don't handle carry, assume low byte is not 0 or 1
|
||||
clc
|
||||
sta tmp1
|
||||
ldx data_start + 1 ; load x as high data start
|
||||
phx
|
||||
ldx sectors_per_cluster ; multiply cluster num (minus 2) by sectors_per_cluster
|
||||
lda #$00
|
||||
@4: adc tmp1
|
||||
dex
|
||||
bne @4
|
||||
plx
|
||||
clc
|
||||
adc data_start ; add that to low data start
|
||||
bcc @3 ; handle carry
|
||||
inx
|
||||
@3: stz sreg
|
||||
stz sreg+1
|
||||
phx
|
||||
pha
|
||||
|
||||
|
||||
|
||||
jsr pusheax
|
||||
lda #<buf
|
||||
ldx #>buf
|
||||
jsr pushax
|
||||
lda #<ptr1
|
||||
ldx #>ptr1
|
||||
jsr _SD_readSingleBlock
|
||||
|
||||
stz sreg
|
||||
stz sreg+1
|
||||
pla
|
||||
plx
|
||||
inc
|
||||
jsr pusheax
|
||||
lda #<buf
|
||||
ldx #>buf
|
||||
inx
|
||||
inx
|
||||
jsr pushax
|
||||
lda #<ptr1
|
||||
ldx #>ptr1
|
||||
jsr _SD_readSingleBlock
|
||||
|
||||
|
||||
jmp buf
|
||||
|
||||
bra @end
|
||||
|
||||
; Now we have the cluster number of the bootloader (3)
|
||||
; this means we need to read from address 00ef_e000 + ((3 -2) * 8 * 512)
|
||||
|
||||
; 00eff000 is the address we want, which is efe000 + 4096
|
||||
|
||||
|
||||
@fail: lda #<_fail
|
||||
ldx #>_fail
|
||||
jsr _cputs
|
||||
|
||||
@end: bra @end
|
||||
|
||||
str: .asciiz "boot\n"
|
||||
_boot2_str: .asciiz "BOOT2 BIN"
|
||||
_fail: .asciiz "not bootloader\n"
|
||||
_good: .asciiz "found bootloader!\n"
|
||||
_cluster: .asciiz "cluster: %lx\n"
|
||||
_addr: .asciiz "addr: %x\n"
|
||||
_end:
|
||||
|
||||
.res (440+_start-_end)
|
||||
|
||||
.res 6
|
||||
|
||||
.res 16
|
||||
.res 16
|
||||
.res 16
|
||||
.res 16
|
||||
|
||||
.byte $55
|
||||
.byte $AA
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef _BOARD_IO_H
|
||||
#define _BOARD_IO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t sw_read();
|
||||
|
||||
void led_set(uint8_t val);
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
.include "io.inc65"
|
||||
|
||||
.importzp sp, sreg
|
||||
|
||||
.export _sw_read
|
||||
.export _led_set
|
||||
|
||||
.autoimport on
|
||||
|
||||
.code
|
||||
|
||||
; @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
|
||||
@@ -1,60 +0,0 @@
|
||||
.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
|
||||
@@ -1,15 +0,0 @@
|
||||
#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
|
||||
@@ -1,27 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; interrupt.s
|
||||
; ---------------------------------------------------------------------------
|
||||
;
|
||||
; Interrupt handler.
|
||||
;
|
||||
; Checks for a BRK instruction and returns from all valid interrupts.
|
||||
|
||||
.export _irq_int, _nmi_int
|
||||
|
||||
|
||||
IRQ_VECTOR = $220
|
||||
NMI_VECTOR = $222
|
||||
|
||||
.segment "CODE"
|
||||
|
||||
.PC02 ; Force 65C02 assembly mode
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Non-maskable interrupt (NMI) service routine
|
||||
|
||||
_nmi_int: jmp (NMI_VECTOR)
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Maskable interrupt (IRQ) service routine
|
||||
|
||||
_irq_int: jmp (IRQ_VECTOR)
|
||||
@@ -1,13 +0,0 @@
|
||||
UART = $efe6
|
||||
UART_TXB = UART
|
||||
UART_RXB = UART
|
||||
UART_STATUS = UART + 1
|
||||
|
||||
LED = $efff
|
||||
SW = LED
|
||||
|
||||
SPI_BAUD = $efd8
|
||||
SPI_INPUT = $efd9
|
||||
SPI_OUTPUT = $efda
|
||||
SPI_CTRL = $efdb
|
||||
SPI_STATUS = SPI_CTRL
|
||||
@@ -1,445 +0,0 @@
|
||||
#include <conio.h>
|
||||
|
||||
#include "sd_card.h"
|
||||
#include "sd_print.h"
|
||||
#include "spi.h"
|
||||
|
||||
/*******************************************************************************
|
||||
Initialize SD card
|
||||
*******************************************************************************/
|
||||
uint8_t SD_init()
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
uint8_t res[5], cmdAttempts = 0;
|
||||
|
||||
SD_powerUpSeq();
|
||||
|
||||
while((res[0] = SD_goIdleState()) != SD_IN_IDLE_STATE)
|
||||
{
|
||||
cmdAttempts++;
|
||||
if(cmdAttempts == CMD0_MAX_ATTEMPTS)
|
||||
{
|
||||
cputs("Go IDLE\n");
|
||||
return SD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef RTL_SIM
|
||||
for (i = 0; i < 1000; i++);
|
||||
#endif
|
||||
|
||||
SD_sendIfCond(res);
|
||||
if(res[0] != SD_IN_IDLE_STATE)
|
||||
{
|
||||
cputs("IF Cond\n");
|
||||
return SD_ERROR;
|
||||
}
|
||||
|
||||
if(res[4] != 0xAA)
|
||||
{
|
||||
return SD_ERROR;
|
||||
}
|
||||
|
||||
cmdAttempts = 0;
|
||||
do
|
||||
{
|
||||
if(cmdAttempts == CMD55_MAX_ATTEMPTS)
|
||||
{
|
||||
cputs("op_cond error\n");
|
||||
return SD_ERROR;
|
||||
}
|
||||
|
||||
res[0] = SD_sendApp();
|
||||
if(SD_R1_NO_ERROR(res[0]))
|
||||
{
|
||||
res[0] = SD_sendOpCond();
|
||||
}
|
||||
|
||||
#ifndef RTL_SIM
|
||||
for (i = 0; i < 1000; i++);
|
||||
#endif
|
||||
|
||||
cmdAttempts++;
|
||||
}
|
||||
while(res[0] != SD_READY);
|
||||
|
||||
#ifndef RTL_SIM
|
||||
for (i = 0; i < 1000; i++);
|
||||
#endif
|
||||
|
||||
SD_readOCR(res);
|
||||
|
||||
return SD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
// Send a command with starting end ending clock pulses
|
||||
uint8_t res1_cmd(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
{
|
||||
uint8_t res1;
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD0
|
||||
SD_command(cmd, arg, crc);
|
||||
|
||||
// read response
|
||||
res1 = SD_readRes1();
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
return res1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Run power up sequence
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_powerUpSeq()
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t j;
|
||||
|
||||
// make sure card is deselected
|
||||
spi_deselect(0);
|
||||
|
||||
// give SD card time to power up
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
|
||||
// select SD card
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
|
||||
// send 80 clock cycles to synchronize
|
||||
for(j = 0; j < SD_INIT_CYCLES; j++)
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Send command to SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
{
|
||||
// transmit command to sd card
|
||||
spi_exchange(cmd|0x40);
|
||||
|
||||
// transmit argument
|
||||
spi_exchange((uint8_t)(arg >> 24));
|
||||
spi_exchange((uint8_t)(arg >> 16));
|
||||
spi_exchange((uint8_t)(arg >> 8));
|
||||
spi_exchange((uint8_t)(arg));
|
||||
|
||||
// transmit crc
|
||||
spi_exchange(crc|0x01);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R1 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
uint8_t SD_readRes1()
|
||||
{
|
||||
uint8_t i = 0, res1;
|
||||
|
||||
// keep polling until actual data received
|
||||
while((res1 = spi_exchange(0xFF)) == 0xFF)
|
||||
{
|
||||
i++;
|
||||
|
||||
// if no data received for 8 bytes, break
|
||||
if(i > 8) break;
|
||||
}
|
||||
|
||||
return res1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R2 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readRes2(uint8_t *res)
|
||||
{
|
||||
// read response 1 in R2
|
||||
res[0] = SD_readRes1();
|
||||
|
||||
// read final byte of response
|
||||
res[1] = spi_exchange(0xFF);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R3 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readRes3(uint8_t *res)
|
||||
{
|
||||
// read response 1 in R3
|
||||
res[0] = SD_readRes1();
|
||||
|
||||
// if error reading R1, return
|
||||
if(res[0] > 1) return;
|
||||
|
||||
// read remaining bytes
|
||||
SD_readBytes(res + 1, R3_BYTES);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R7 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readRes7(uint8_t *res)
|
||||
{
|
||||
// read response 1 in R7
|
||||
res[0] = SD_readRes1();
|
||||
|
||||
// if error reading R1, return
|
||||
if(res[0] > 1) return;
|
||||
|
||||
// read remaining bytes
|
||||
SD_readBytes(res + 1, R7_BYTES);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read specified number of bytes from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readBytes(uint8_t *res, uint8_t n)
|
||||
{
|
||||
while(n--) *res++ = spi_exchange(0xFF);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Command Idle State (CMD0)
|
||||
*******************************************************************************/
|
||||
uint8_t SD_goIdleState()
|
||||
{
|
||||
return res1_cmd(CMD0, CMD0_ARG, CMD0_CRC);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Send Interface Conditions (CMD8)
|
||||
*******************************************************************************/
|
||||
void SD_sendIfCond(uint8_t *res)
|
||||
{
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD8
|
||||
SD_command(CMD8, CMD8_ARG, CMD8_CRC);
|
||||
|
||||
// read response
|
||||
SD_readRes7(res);
|
||||
//SD_readBytes(res + 1, R7_BYTES);
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Read Status
|
||||
*******************************************************************************/
|
||||
void SD_sendStatus(uint8_t *res)
|
||||
{
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD13
|
||||
SD_command(CMD13, CMD13_ARG, CMD13_CRC);
|
||||
|
||||
// read response
|
||||
SD_readRes2(res);
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Read single 512 byte block
|
||||
token = 0xFE - Successful read
|
||||
token = 0x0X - Data error
|
||||
token = 0xFF - timeout
|
||||
*******************************************************************************/
|
||||
// uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token)
|
||||
// {
|
||||
// uint8_t res1, read;
|
||||
// uint16_t readAttempts;
|
||||
// uint16_t i;
|
||||
|
||||
// // set token to none
|
||||
// *token = 0xFF;
|
||||
|
||||
// // assert chip select
|
||||
// spi_exchange(0xFF);
|
||||
// spi_select(0);
|
||||
// spi_exchange(0xFF);
|
||||
|
||||
// // send CMD17
|
||||
// SD_command(CMD17, addr, CMD17_CRC);
|
||||
|
||||
// // read R1
|
||||
// res1 = SD_readRes1();
|
||||
|
||||
// // if response received from card
|
||||
// if(res1 != 0xFF)
|
||||
// {
|
||||
// // wait for a response token (timeout = 100ms)
|
||||
// readAttempts = 0;
|
||||
// while(++readAttempts != SD_MAX_READ_ATTEMPTS)
|
||||
// if((read = spi_exchange(0xFF)) != 0xFF) break;
|
||||
|
||||
// cprintf("read attempts: %d\n", readAttempts);
|
||||
|
||||
// // if response token is 0xFE
|
||||
// if(read == SD_START_TOKEN)
|
||||
// {
|
||||
// // read 512 byte block
|
||||
// for(i = 0; i < SD_BLOCK_LEN; i++) *buf++ = spi_exchange(0xFF);
|
||||
|
||||
// // read 16-bit CRC
|
||||
// spi_exchange(0xFF);
|
||||
// spi_exchange(0xFF);
|
||||
// }
|
||||
|
||||
// // set token to card response
|
||||
// *token = read;
|
||||
// }
|
||||
|
||||
// // deassert chip select
|
||||
// spi_exchange(0xFF);
|
||||
// spi_deselect(0);
|
||||
// spi_exchange(0xFF);
|
||||
|
||||
// return res1;
|
||||
// }
|
||||
|
||||
#define SD_MAX_WRITE_ATTEMPTS 3907
|
||||
|
||||
/*******************************************************************************
|
||||
Write single 512 byte block
|
||||
token = 0x00 - busy timeout
|
||||
token = 0x05 - data accepted
|
||||
token = 0xFF - response timeout
|
||||
*******************************************************************************/
|
||||
uint8_t SD_writeSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token)
|
||||
{
|
||||
uint16_t readAttempts;
|
||||
uint8_t res1, read;
|
||||
uint16_t i;
|
||||
|
||||
/*
|
||||
|
||||
// set token to none
|
||||
*token = 0xFF;
|
||||
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD24
|
||||
SD_command(CMD24, addr, CMD24_CRC);
|
||||
|
||||
// read response
|
||||
res1 = SD_readRes1();
|
||||
|
||||
// if no error
|
||||
if(res1 == SD_READY)
|
||||
{
|
||||
// send start token
|
||||
spi_exchange(SD_START_TOKEN);
|
||||
|
||||
// write buffer to card
|
||||
for(i = 0; i < SD_BLOCK_LEN; i++) spi_exchange(buf[i]);
|
||||
|
||||
// wait for a response (timeout = 250ms)
|
||||
readAttempts = 0;
|
||||
while(++readAttempts != SD_MAX_WRITE_ATTEMPTS)
|
||||
if((read = spi_exchange(0xFF)) != 0xFF) { *token = 0xFF; break; }
|
||||
|
||||
// if data accepted
|
||||
if((read & 0x1F) == 0x05)
|
||||
{
|
||||
// set token to data accepted
|
||||
*token = 0x05;
|
||||
|
||||
// wait for write to finish (timeout = 250ms)
|
||||
readAttempts = 0;
|
||||
while(spi_exchange(0xFF) == 0x00)
|
||||
if(++readAttempts == SD_MAX_WRITE_ATTEMPTS) { *token = 0x00; break; }
|
||||
}
|
||||
}
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
*/
|
||||
|
||||
return res1;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Reads OCR from SD Card
|
||||
*******************************************************************************/
|
||||
void SD_readOCR(uint8_t *res)
|
||||
{
|
||||
uint8_t tmp;
|
||||
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
tmp = spi_exchange(0xFF);
|
||||
|
||||
if(tmp != 0xFF) while(spi_exchange(0xFF) != 0xFF) ;
|
||||
|
||||
// send CMD58
|
||||
SD_command(CMD58, CMD58_ARG, CMD58_CRC);
|
||||
|
||||
// read response
|
||||
SD_readRes3(res);
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Send application command (CMD55)
|
||||
*******************************************************************************/
|
||||
uint8_t SD_sendApp()
|
||||
{
|
||||
return res1_cmd(CMD55, CMD55_ARG, CMD55_CRC);;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Send operating condition (ACMD41)
|
||||
*******************************************************************************/
|
||||
uint8_t SD_sendOpCond()
|
||||
{
|
||||
return res1_cmd(ACMD41, ACMD41_ARG, ACMD41_CRC);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#ifndef _SD_CARD_H
|
||||
#define _SD_CARD_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// command definitions
|
||||
#define CMD0 0
|
||||
#define CMD0_ARG 0x00000000
|
||||
#define CMD0_CRC 0x94
|
||||
#define CMD8 8
|
||||
#define CMD8_ARG 0x0000001AA
|
||||
#define CMD8_CRC 0x86
|
||||
#define CMD9 9
|
||||
#define CMD9_ARG 0x00000000
|
||||
#define CMD9_CRC 0x00
|
||||
#define CMD10 9
|
||||
#define CMD10_ARG 0x00000000
|
||||
#define CMD10_CRC 0x00
|
||||
#define CMD13 13
|
||||
#define CMD13_ARG 0x00000000
|
||||
#define CMD13_CRC 0x00
|
||||
#define CMD17 17
|
||||
#define CMD17_CRC 0x00
|
||||
#define CMD24 24
|
||||
#define CMD24_CRC 0x00
|
||||
#define CMD55 55
|
||||
#define CMD55_ARG 0x00000000
|
||||
#define CMD55_CRC 0x00
|
||||
#define CMD58 58
|
||||
#define CMD58_ARG 0x00000000
|
||||
#define CMD58_CRC 0x00
|
||||
#define ACMD41 41
|
||||
#define ACMD41_ARG 0x40000000
|
||||
#define ACMD41_CRC 0x00
|
||||
|
||||
#define SD_IN_IDLE_STATE 0x01
|
||||
#define SD_READY 0x00
|
||||
#define SD_R1_NO_ERROR(X) X < 0x02
|
||||
|
||||
#define R3_BYTES 4
|
||||
#define R7_BYTES 4
|
||||
|
||||
#define CMD0_MAX_ATTEMPTS 255
|
||||
#define CMD55_MAX_ATTEMPTS 255
|
||||
#define SD_ERROR 1
|
||||
#define SD_SUCCESS 0
|
||||
#define SD_MAX_READ_ATTEMPTS 1563
|
||||
#define SD_READ_START_TOKEN 0xFE
|
||||
#define SD_INIT_CYCLES 80
|
||||
|
||||
#define SD_START_TOKEN 0xFE
|
||||
#define SD_ERROR_TOKEN 0x00
|
||||
|
||||
#define SD_DATA_ACCEPTED 0x05
|
||||
#define SD_DATA_REJECTED_CRC 0x0B
|
||||
#define SD_DATA_REJECTED_WRITE 0x0D
|
||||
|
||||
#define SD_BLOCK_LEN 512
|
||||
|
||||
// SD functions
|
||||
uint8_t SD_init();
|
||||
void SD_powerUpSeq();
|
||||
void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc);
|
||||
uint8_t SD_readRes1();
|
||||
void SD_readRes2(uint8_t *res);
|
||||
void SD_readRes3(uint8_t *res);
|
||||
void SD_readRes7(uint8_t *res);
|
||||
void SD_readBytes(uint8_t *res, uint8_t n);
|
||||
uint8_t SD_goIdleState();
|
||||
void SD_sendIfCond(uint8_t *res);
|
||||
void SD_sendStatus(uint8_t *res);
|
||||
void SD_readOCR(uint8_t *res);
|
||||
uint8_t SD_sendApp();
|
||||
uint8_t SD_sendOpCond();
|
||||
uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *error);
|
||||
uint8_t SD_writeSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *res);
|
||||
|
||||
uint8_t res1_cmd(uint8_t cmd, uint32_t arg, uint8_t crc);
|
||||
|
||||
#endif
|
||||
@@ -1,303 +0,0 @@
|
||||
.export _SD_command
|
||||
.export _SD_readRes1
|
||||
.export _SD_readRes2
|
||||
.export _SD_readRes3
|
||||
.export _SD_readRes7
|
||||
.export _SD_readBytes
|
||||
.export _SD_powerUpSeq
|
||||
.export _res1_cmd
|
||||
.export _SD_readSingleBlock
|
||||
|
||||
.importzp sp, ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3
|
||||
|
||||
.autoimport on
|
||||
|
||||
.MACPACK generic
|
||||
|
||||
; void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
|
||||
; The plan: push crc to stack, load arg into tmp1 through 4
|
||||
|
||||
.proc _SD_command: near
|
||||
|
||||
pha ; Push CRC to cpu stack
|
||||
ldy #$04
|
||||
lda (sp),y ; Load CMD
|
||||
ora #$40 ; start bit
|
||||
jsr _spi_exchange
|
||||
|
||||
dey
|
||||
arg_loop: ; send ARG
|
||||
lda (sp),y ; is this sending only 3?
|
||||
jsr _spi_exchange
|
||||
dey
|
||||
bpl arg_loop
|
||||
|
||||
pla ; Pull CRC from stack
|
||||
ora #$01 ; stop bit
|
||||
jsr _spi_exchange
|
||||
jsr incsp5 ; pop all off stack
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; uint8_t SD_readRes1 (void)
|
||||
|
||||
.proc _SD_readRes1: near
|
||||
; Try to read/write up to 8 times, then return value
|
||||
|
||||
ldx #$08
|
||||
|
||||
tryread:
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
cmp #$ff
|
||||
bne end
|
||||
dex
|
||||
bne tryread
|
||||
|
||||
end: ; x will be 0 here anyway
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_readRes2(uint8_t *res)
|
||||
|
||||
.proc _SD_readRes2: near
|
||||
|
||||
sta ptr1 ; store res in ptr1
|
||||
stx ptr1 + 1
|
||||
|
||||
jsr _SD_readRes1 ; get first response 1
|
||||
sta (ptr1)
|
||||
|
||||
lda #$ff
|
||||
jsr _spi_exchange ; get final byte of response
|
||||
ldy #$01
|
||||
sta (ptr1),y
|
||||
jsr incsp2
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_readBytes(uint8_t *res, uint8_t n)
|
||||
|
||||
.proc _SD_readBytes: near
|
||||
|
||||
tax
|
||||
jsr popptr1 ; store res in ptr1
|
||||
|
||||
read:
|
||||
lda #$ff ; read data first
|
||||
jsr _spi_exchange
|
||||
sta (ptr1)
|
||||
inc ptr1 ; then increment res
|
||||
bne @L1
|
||||
inc ptr1 + 1
|
||||
@L1: dex ; then decrement x
|
||||
bne read ; and if x is zero we are done
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_readRes7(uint8_t *res)
|
||||
_SD_readRes7:
|
||||
; void SD_readRes3(uint8_t *res)
|
||||
.proc _SD_readRes3: near
|
||||
|
||||
sta ptr1 ; store res in ptr1
|
||||
stx ptr1 + 1
|
||||
|
||||
jsr _SD_readRes1 ; read respopnse 1 in R3
|
||||
cmp #$02 ; if error reading R1, return
|
||||
bge @L1
|
||||
|
||||
inc ptr1 ; read remaining bytes
|
||||
bne @L2
|
||||
inc ptr1
|
||||
@L2: lda ptr1 ; push low byte
|
||||
ldx ptr1 + 1
|
||||
jsr pushax
|
||||
lda #$04 ; R3_BYTES
|
||||
jsr _SD_readBytes
|
||||
|
||||
@L1: rts
|
||||
|
||||
.endproc
|
||||
|
||||
; uint8_t res1_cmd(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
|
||||
.proc _res1_cmd: near
|
||||
|
||||
pha ; push crc to processor stack
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_select
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
pla
|
||||
jsr _SD_command ; rely on command to teardown stack
|
||||
|
||||
jsr _SD_readRes1
|
||||
tay ; spi doesn't touch y
|
||||
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_deselect
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
tya
|
||||
ldx #$00 ; Promote to integer
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_powerUpSeq(void)
|
||||
|
||||
.proc _SD_powerUpSeq: near
|
||||
|
||||
lda #$00
|
||||
jsr _spi_deselect
|
||||
jsr _sd_delay
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00
|
||||
jsr _spi_deselect
|
||||
|
||||
ldx #$50 ; SD_INIT_CYCLES
|
||||
@L1: lda #$ff
|
||||
jsr _spi_exchange
|
||||
dex
|
||||
bne @L1
|
||||
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
|
||||
; 1ms delay approx. saves no registers
|
||||
.proc _sd_delay: near
|
||||
ldx #$01 ; delay loop: A*X*10 + 4
|
||||
@L1: lda #$c8 ; 1ms at 2MHz
|
||||
@L2: dec ; 2
|
||||
bne @L2 ; 3
|
||||
dex ; 2
|
||||
bne @L1 ; 3
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; ;uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token)
|
||||
.proc _SD_readSingleBlock: near
|
||||
; token address in a/x
|
||||
; buf address next on stack
|
||||
; sd address above that
|
||||
|
||||
; ptr2 = *token
|
||||
sta ptr2
|
||||
stx ptr2 + 1
|
||||
|
||||
lda #$ff
|
||||
sta (ptr2)
|
||||
|
||||
; ptr1 = *buf
|
||||
jsr popptr1
|
||||
|
||||
; 4 bytes on stack are addr
|
||||
|
||||
; Move addr down on the stack
|
||||
lda sp
|
||||
sta ptr3
|
||||
lda sp + 1
|
||||
sta ptr3 + 1
|
||||
|
||||
; find a way to do this in a loop?
|
||||
jsr decsp1
|
||||
ldy #$0
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_select
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
; push cmd17
|
||||
lda #$11
|
||||
ldy #$4
|
||||
sta (sp),y
|
||||
|
||||
; crc, 0
|
||||
lda #$00
|
||||
jsr _SD_command ; rely on command to teardown stack
|
||||
|
||||
jsr _SD_readRes1
|
||||
|
||||
cmp #$ff ; if 0xFF then you failed
|
||||
beq end
|
||||
sta tmp3 ; tmp3 = read
|
||||
|
||||
; y = read_attempts
|
||||
ldy #$0
|
||||
resp_loop:
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
sta tmp2 ; tmp2 = read
|
||||
lda tmp2
|
||||
cmp #$ff
|
||||
bne got_resp
|
||||
iny
|
||||
bne resp_loop
|
||||
bra after_read
|
||||
|
||||
got_resp:
|
||||
ldx #$2
|
||||
ldy #$00
|
||||
load_loop:
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
sta (ptr1)
|
||||
inc ptr1
|
||||
bne @2
|
||||
inc ptr1 + 1
|
||||
@2: dey
|
||||
bne load_loop
|
||||
ldy #$00
|
||||
dex
|
||||
bne load_loop
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
after_read:
|
||||
lda tmp2
|
||||
sta (ptr2)
|
||||
lda tmp3
|
||||
|
||||
end:
|
||||
pha
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_deselect
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
pla
|
||||
rts
|
||||
|
||||
.endproc
|
||||
@@ -1,26 +0,0 @@
|
||||
#include <conio.h>
|
||||
|
||||
#include "sd_print.h"
|
||||
#include "sd_card.h"
|
||||
|
||||
|
||||
void SD_printBuf(uint8_t *buf)
|
||||
{
|
||||
uint8_t colCount = 0;
|
||||
uint16_t i;
|
||||
for(i = 0; i < SD_BLOCK_LEN; i++)
|
||||
{
|
||||
cprintf("%2x", *buf++);
|
||||
if(colCount == 31)
|
||||
{
|
||||
cputs("\n");
|
||||
colCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cputc(' ');
|
||||
colCount++;
|
||||
}
|
||||
}
|
||||
cputs("\n");
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef SD_PRINT_H
|
||||
#define SD_PRINT_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* R1 MACROS */
|
||||
#define PARAM_ERROR(X) X & 0b01000000
|
||||
#define ADDR_ERROR(X) X & 0b00100000
|
||||
#define ERASE_SEQ_ERROR(X) X & 0b00010000
|
||||
#define CRC_ERROR(X) X & 0b00001000
|
||||
#define ILLEGAL_CMD(X) X & 0b00000100
|
||||
#define ERASE_RESET(X) X & 0b00000010
|
||||
#define IN_IDLE(X) X & 0b00000001
|
||||
|
||||
/* R2 MACROS */
|
||||
#define OUT_OF_RANGE(X) X & 0b10000000
|
||||
#define ERASE_PARAM(X) X & 0b01000000
|
||||
#define WP_VIOLATION(X) X & 0b00100000
|
||||
#define CARD_ECC_FAILED(X) X & 0b00010000
|
||||
#define CC_ERROR(X) X & 0b00001000
|
||||
#define ERROR(X) X & 0b00000100
|
||||
#define WP_ERASE_SKIP(X) X & 0b00000010
|
||||
#define CARD_LOCKED(X) X & 0b00000001
|
||||
|
||||
/* R3 MACROS */
|
||||
#define POWER_UP_STATUS(X) X & 0x40
|
||||
#define CCS_VAL(X) X & 0x40
|
||||
#define VDD_2728(X) X & 0b10000000
|
||||
#define VDD_2829(X) X & 0b00000001
|
||||
#define VDD_2930(X) X & 0b00000010
|
||||
#define VDD_3031(X) X & 0b00000100
|
||||
#define VDD_3132(X) X & 0b00001000
|
||||
#define VDD_3233(X) X & 0b00010000
|
||||
#define VDD_3334(X) X & 0b00100000
|
||||
#define VDD_3435(X) X & 0b01000000
|
||||
#define VDD_3536(X) X & 0b10000000
|
||||
|
||||
/* R7 MACROS */
|
||||
#define CMD_VER(X) ((X >> 4) & 0xF0)
|
||||
#define VOL_ACC(X) (X & 0x1F)
|
||||
#define VOLTAGE_ACC_27_33 0b00000001
|
||||
#define VOLTAGE_ACC_LOW 0b00000010
|
||||
#define VOLTAGE_ACC_RES1 0b00000100
|
||||
#define VOLTAGE_ACC_RES2 0b00001000
|
||||
|
||||
/* DATA ERROR TOKEN */
|
||||
#define SD_TOKEN_OOR(X) X & 0b00001000
|
||||
#define SD_TOKEN_CECC(X) X & 0b00000100
|
||||
#define SD_TOKEN_CC(X) X & 0b00000010
|
||||
#define SD_TOKEN_ERROR(X) X & 0b00000001
|
||||
|
||||
void SD_printR1(uint8_t res);
|
||||
void SD_printR2(uint8_t *res);
|
||||
void SD_printR3(uint8_t *res);
|
||||
void SD_printR7(uint8_t *res);
|
||||
void SD_printBuf(uint8_t *buf);
|
||||
void SD_printDataErrToken(uint8_t token);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef _SPI_H
|
||||
#define _SPI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void spi_select(uint8_t id);
|
||||
void spi_deselect(uint8_t id);
|
||||
uint8_t spi_read();
|
||||
void spi_write(uint8_t data);
|
||||
uint8_t spi_exchange(uint8_t data);
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
.include "io.inc65"
|
||||
|
||||
.importzp zp, sreg
|
||||
|
||||
.export _spi_select, _spi_deselect
|
||||
.export _spi_read, _spi_write, _spi_exchange
|
||||
|
||||
.autoimport on
|
||||
|
||||
.code
|
||||
|
||||
; void spi_select(uint8_t id)
|
||||
; Select a (the) slave by pulling its CS line down
|
||||
; TODO allow active high or active low CS
|
||||
; TODO allow more than one slave
|
||||
_spi_select:
|
||||
lda #$1 ; Ignore whatever id is, 1 is the only option
|
||||
sta SPI_CTRL
|
||||
rts
|
||||
|
||||
; void spi_deslect(uint8_t id)
|
||||
; Deslect a slave by pulling its CS line up
|
||||
; TODO allow active high or active low CS
|
||||
_spi_deselect:
|
||||
stz SPI_CTRL
|
||||
rts
|
||||
|
||||
; uint8_t spi_read()
|
||||
_spi_read:
|
||||
lda #$0
|
||||
; void spi_write(uint8_t data)
|
||||
_spi_write:
|
||||
; uint8_t spi_exchange(uint8_t data)
|
||||
_spi_exchange:
|
||||
sta SPI_OUTPUT
|
||||
@1: lda SPI_CTRL
|
||||
bmi @1
|
||||
lda SPI_INPUT
|
||||
rts
|
||||
@@ -1,13 +0,0 @@
|
||||
#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
|
||||
@@ -1,36 +0,0 @@
|
||||
.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[1] to be 0
|
||||
bit #$02
|
||||
bne @1
|
||||
pla
|
||||
rts
|
||||
|
||||
_uart_rxb:
|
||||
lda UART_RXB ; Read value
|
||||
ldx #$00
|
||||
rts
|
||||
|
||||
_uart_status:
|
||||
lda UART_STATUS
|
||||
ldx #$00
|
||||
rts
|
||||
@@ -1,40 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
KERNEL: start = $1000, size = $7000, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
BOOTSECTOR: start = $8000, size = $200, type = rw, define = yes, file = "bootloader.bin";
|
||||
BOOTLOADER: start = $8200, size = $1000, type = rw, define = yes, file = "boot2.bin";
|
||||
ROM: start = $F000, size = $1000, 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;
|
||||
BOOTSECTOR: load = BOOTSECTOR, type = rw, start = $8000;
|
||||
BOOTLOADER: load = BOOTLOADER, type = rw;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <conio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "devices/board_io.h"
|
||||
#include "devices/uart.h"
|
||||
#include "devices/sd_card.h"
|
||||
#include "devices/sd_print.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0xD000
|
||||
|
||||
//uint8_t buf[512];
|
||||
uint8_t *buf = (uint8_t*)0x8000;
|
||||
|
||||
int main() {
|
||||
// array to hold responses
|
||||
uint8_t res[5], token;
|
||||
uint32_t addr = 0x00000000;
|
||||
uint16_t i;
|
||||
|
||||
cputs("Start\n");
|
||||
|
||||
// initialize sd card
|
||||
if(SD_init() != SD_SUCCESS)
|
||||
{
|
||||
cputs("Error\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
cputs("Success\n");
|
||||
|
||||
|
||||
res[0] = SD_readSingleBlock(addr, buf, &token);
|
||||
// if no error, print buffer
|
||||
if((res[0] == 0x00) && (token == SD_START_TOKEN)) {
|
||||
#ifndef RTL_SIM
|
||||
SD_printBuf(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
//else if error token received, print
|
||||
else if(!(token & 0xF0))
|
||||
{
|
||||
cputs("Error\n");
|
||||
} else {
|
||||
cprintf("bad token: %x\n", token);
|
||||
}
|
||||
|
||||
__asm__ ("jmp (%v)", buf);
|
||||
}
|
||||
|
||||
while(1) ;
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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
1
sw/cc65
Submodule sw/cc65 deleted from 9824f6e3d4
@@ -1 +0,0 @@
|
||||
This is a text file, which is composed of text.
|
||||
@@ -1,33 +0,0 @@
|
||||
very large text file with a very long name
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
|
||||
~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?~!@#$%^&*()_+`1234567890-=[]\{}|;':",./<>?
|
||||
@@ -1,40 +0,0 @@
|
||||
CC=../cc65/bin/cl65
|
||||
LD=../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=kernel
|
||||
|
||||
O65 = $(NAME).o65
|
||||
|
||||
FSDIR=$(REPO_TOP)/sw/fsdir
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(O65) $(FSDIR)
|
||||
cp $(O65) $(FSDIR)
|
||||
|
||||
$(FSDIR):
|
||||
mkdir $(FSDIR)
|
||||
|
||||
$(O65): $(OBJS)
|
||||
$(LD) $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(O65) $(LISTS) $(NAME).map
|
||||
@@ -1,53 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; crt0.s
|
||||
; ---------------------------------------------------------------------------
|
||||
;
|
||||
; Startup code for cc65 (Single Board Computer version)
|
||||
|
||||
.export _init, _exit
|
||||
.import _main, _cputc
|
||||
|
||||
.export __STARTUP__ : absolute = 1 ; Mark as startup
|
||||
.import __STACKSTART__, __STACKSIZE__ ; 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 #<(__STACKSTART__ + __STACKSIZE__)
|
||||
STA sp
|
||||
LDA #>(__STACKSTART__ + __STACKSIZE__)
|
||||
STA sp+1
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Initialize memory storage
|
||||
|
||||
JSR zerobss ; Clear BSS segment (no longer fails)
|
||||
; JSR copydata ; Initialize DATA segment (this also fails. but prints something)
|
||||
JSR initlib ; Run constructors (This one works)
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Call main()
|
||||
cli
|
||||
JSR _main
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Back from main (this is also the _exit entry): force a software break
|
||||
|
||||
_exit: JSR donelib ; Run destructors
|
||||
BRK
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef _BOARD_IO_H
|
||||
#define _BOARD_IO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t sw_read();
|
||||
|
||||
void led_set(uint8_t val);
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
.include "io.inc65"
|
||||
|
||||
.importzp sp, sreg
|
||||
|
||||
.export _sw_read
|
||||
.export _led_set
|
||||
|
||||
.autoimport on
|
||||
|
||||
.code
|
||||
|
||||
; @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
|
||||
@@ -1,60 +0,0 @@
|
||||
.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
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef _INTERRUPT_CONTROLLER_H
|
||||
#define _INTERRUPT_CONTROLLER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// These need to be copied in interrupt_controller.s
|
||||
|
||||
#define IRQ_CMD_ADDR 0xeffc
|
||||
#define IRQ_DAT_ADDR 0xeffd
|
||||
|
||||
#define IRQ_CMD_MASK 0xe0
|
||||
#define IRQ_REG_MASK 0x1f
|
||||
|
||||
#define IRQ_CMD_READIRQ 0x00
|
||||
#define IRQ_CMD_ENABLE 0x20
|
||||
#define IRQ_CMD_TYPE 0x40
|
||||
#define IRQ_CMD_EOI 0xff
|
||||
|
||||
#define IRQ_EDGE 0
|
||||
#define IRQ_LEVEL 1
|
||||
|
||||
|
||||
|
||||
void init_interrupt_controller();
|
||||
|
||||
void enable_irq(uint8_t type, uint8_t irqnum);
|
||||
void disable_irq(uint8_t irqnum);
|
||||
|
||||
// This should accept irqnum later.
|
||||
void send_eoi();
|
||||
|
||||
#endif
|
||||
@@ -1,148 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.autoimport
|
||||
|
||||
.importzp tmp1, tmp2
|
||||
|
||||
.export _init_interrupt_controller
|
||||
.export _enable_irq
|
||||
.export _disable_irq
|
||||
.export _send_eoi
|
||||
|
||||
.import irq_int, nmi_int
|
||||
|
||||
IRQ_CMD_ADDR = $effc
|
||||
IRQ_DAT_ADDR = $effd
|
||||
|
||||
IRQ_CMD_MASK = $e0
|
||||
IRQ_REG_MASK = $1f
|
||||
IRQ_CMD_READIRQ = $00
|
||||
IRQ_CMD_ENABLE = $20
|
||||
IRQ_CMD_TYPE = $40
|
||||
IRQ_CMD_EOI = $ff
|
||||
|
||||
IRQ_VECTOR = $220
|
||||
NMI_VECTOR = $222
|
||||
|
||||
.code
|
||||
|
||||
; void init_irq();
|
||||
; mask all IRQs, set all type to edge.
|
||||
.proc _init_interrupt_controller
|
||||
lda #<irq_int
|
||||
sta IRQ_VECTOR
|
||||
lda #>irq_int
|
||||
sta IRQ_VECTOR+1
|
||||
|
||||
lda #<nmi_int
|
||||
sta NMI_VECTOR
|
||||
lda #>nmi_int
|
||||
sta NMI_VECTOR+1
|
||||
|
||||
ldx #$20 ; enable
|
||||
ldy #00
|
||||
jsr cmd_all
|
||||
ldx #$40 ; edge type
|
||||
ldy #$00
|
||||
jsr cmd_all
|
||||
rts
|
||||
|
||||
cmd_all: ; Send the same value to all 32 bytes
|
||||
txa
|
||||
add #$10
|
||||
sta tmp1
|
||||
loop:
|
||||
txa
|
||||
sta IRQ_CMD_ADDR
|
||||
tya
|
||||
sta IRQ_DAT_ADDR
|
||||
inx
|
||||
cpx tmp1
|
||||
blt loop
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
; void enable_irq(uint8_t type, uint8_t irqnum);
|
||||
; in A:
|
||||
.proc _enable_irq
|
||||
; Decide which byte we need to modify by dividing by 8 (>> 3)
|
||||
pha
|
||||
lsr
|
||||
lsr
|
||||
lsr ; A is now bytesel
|
||||
sta tmp2 ; tmp2 is now bytesel
|
||||
add #IRQ_CMD_ENABLE
|
||||
sta IRQ_CMD_ADDR
|
||||
lda IRQ_DAT_ADDR
|
||||
sta tmp1
|
||||
pla
|
||||
and #$07 ; A is now 0-7
|
||||
tax
|
||||
inx ; X is now 1-8
|
||||
lda #$01
|
||||
L1: dex
|
||||
beq L2
|
||||
asl
|
||||
bra L1
|
||||
L2: pha ; Push bit mask to stack
|
||||
ora tmp1 ; A is now 1 << (0-7) | enable
|
||||
sta IRQ_DAT_ADDR
|
||||
|
||||
|
||||
lda tmp2
|
||||
add #IRQ_CMD_TYPE
|
||||
sta IRQ_CMD_ADDR
|
||||
lda IRQ_DAT_ADDR
|
||||
sta tmp1
|
||||
jsr popa ; A is now type
|
||||
beq bit0
|
||||
bit1: ; set `bit` to 1
|
||||
pla
|
||||
ora tmp1
|
||||
bra L3
|
||||
bit0: ; set `bit` to 0
|
||||
pla
|
||||
eor #$ff
|
||||
and tmp1
|
||||
L3: sta IRQ_DAT_ADDR
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; TODO this is mostly the same as enable, why copy?
|
||||
.proc _disable_irq
|
||||
; Decide which byte we need to modify by dividing by 32 (>> 5)
|
||||
pha
|
||||
lsr
|
||||
lsr
|
||||
lsr ; A is now bytesel
|
||||
add #IRQ_CMD_ENABLE
|
||||
sta IRQ_CMD_ADDR
|
||||
lda IRQ_DAT_ADDR
|
||||
sta tmp1
|
||||
pla
|
||||
and $07 ; A is now 0-7
|
||||
tax
|
||||
inx ; X is now 1-8
|
||||
lda #$01
|
||||
L1: dex
|
||||
beq L2
|
||||
asl
|
||||
bra L1
|
||||
L2: eor #$ff ; Invert to set enable to 0
|
||||
and tmp1 ; a is now ~(1 << (0-7)) & enable
|
||||
sta IRQ_DAT_ADDR
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; This should accept irqnum later.
|
||||
; void send_eoi();
|
||||
.proc _send_eoi
|
||||
lda #IRQ_CMD_EOI
|
||||
sta IRQ_CMD_ADDR
|
||||
lda #$1
|
||||
sta IRQ_DAT_ADDR
|
||||
rts
|
||||
.endproc
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
UART = $efe6
|
||||
UART_TXB = UART
|
||||
UART_RXB = UART
|
||||
UART_STATUS = UART + 1
|
||||
|
||||
LED = $efff
|
||||
SW = LED
|
||||
|
||||
SPI_BAUD = $efd8
|
||||
SPI_INPUT = $efd9
|
||||
SPI_OUTPUT = $efda
|
||||
SPI_CTRL = $efdb
|
||||
SPI_STATUS = SPI_CTRL
|
||||
|
||||
MULTIPLIER_BASE = $eff0
|
||||
|
||||
MULTIPLIER_AL = MULTIPLIER_BASE + 0
|
||||
MULTIPLIER_AH = MULTIPLIER_BASE + 1
|
||||
MULTIPLIER_BL = MULTIPLIER_BASE + 2
|
||||
MULTIPLIER_BH = MULTIPLIER_BASE + 3
|
||||
|
||||
MULTIPLIER_OLL = MULTIPLIER_BASE + 4
|
||||
MULTIPLIER_OLH = MULTIPLIER_BASE + 5
|
||||
MULTIPLIER_OHL = MULTIPLIER_BASE + 6
|
||||
MULTIPLIER_OHH = MULTIPLIER_BASE + 7
|
||||
|
||||
GOLDEN_OUTPUT_0 = $03
|
||||
GOLDEN_OUTPUT_1 = $0a
|
||||
GOLDEN_OUTPUT_2 = $08
|
||||
GOLDEN_OUTPUT_3 = $00
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef _MAPPER_H
|
||||
#define _MAPPER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void init_mapper();
|
||||
|
||||
void map(uint16_t p_page, uint8_t v_page);
|
||||
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.autoimport
|
||||
|
||||
.export _init_mapper
|
||||
.export _map
|
||||
|
||||
MAPPER_BASE = $200
|
||||
|
||||
.code
|
||||
|
||||
; void init_paging();
|
||||
; This should be identity mapped at reset, but we can do it again anyway
|
||||
.proc _init_mapper
|
||||
ldx #$00
|
||||
L1:
|
||||
txa
|
||||
lsr
|
||||
sta MAPPER_BASE,x
|
||||
lda #$00
|
||||
sta MAPPER_BASE+1,x
|
||||
inx
|
||||
inx
|
||||
cpx #$20
|
||||
blt L1
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; void map(uint16_t p_page, uint8_t v_page);
|
||||
.proc _map
|
||||
asl
|
||||
tax ; x = v_page * 2
|
||||
jsr popa ; low byte of p_page
|
||||
sta MAPPER_BASE,x ; write low byte to mm_low
|
||||
jsr popa ; high byte of p_page
|
||||
sta MAPPER_BASE+1,x ; write high byte to mm_high
|
||||
rts
|
||||
.endproc
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef _MULTIPLER_H
|
||||
#define _MULTIPLER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Multiply 2 integers into 1 long */
|
||||
uint32_t lmulii(uint16_t a, uint16_t b);
|
||||
|
||||
/* Multiply 2 integers into 1 integer, discarding upper bits. */
|
||||
uint16_t imulii(uint16_t a, uint16_t b);
|
||||
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
.include "io.inc65"
|
||||
|
||||
.MACPACK generic
|
||||
|
||||
.import popax
|
||||
.importzp sreg
|
||||
|
||||
.export _lmulii, _imulii
|
||||
|
||||
.code
|
||||
|
||||
.proc _lmulii
|
||||
sta MULTIPLIER_BL
|
||||
stx MULTIPLIER_BH
|
||||
jsr popax
|
||||
sta MULTIPLIER_AL
|
||||
stx MULTIPLIER_AH
|
||||
lda MULTIPLIER_OHL
|
||||
sta sreg
|
||||
lda MULTIPLIER_OHH
|
||||
sta sreg+1
|
||||
lda MULTIPLIER_OLL
|
||||
ldx MULTIPLIER_OLH
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc _imulii
|
||||
sta MULTIPLIER_BL
|
||||
stx MULTIPLIER_BH
|
||||
jsr popax
|
||||
sta MULTIPLIER_AL
|
||||
stx MULTIPLIER_AH
|
||||
lda MULTIPLIER_OLL
|
||||
ldx MULTIPLIER_OLH
|
||||
rts
|
||||
.endproc
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef _RTC_H
|
||||
#define _RTC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define RTC_CMD_ADDR 0xeffe
|
||||
#define RTC_DAT_ADDR 0xefff
|
||||
|
||||
#define RTC_THRESHOLD 0x00
|
||||
#define RTC_INCREMENT 0x10
|
||||
#define RTC_IRQ_THRESHOLD 0x20
|
||||
#define RTC_OUTPUT 0x30
|
||||
#define RTC_CONTROL 0x30
|
||||
|
||||
/* initialize RTC with default values */
|
||||
void init_rtc(void);
|
||||
|
||||
/* handle RTC interrupts */
|
||||
void handle_rtc(void);
|
||||
|
||||
|
||||
void rtc_set(uint32_t val, uint8_t idx);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.importzp tmp1
|
||||
|
||||
.import popa
|
||||
|
||||
.export _init_rtc
|
||||
.export _handle_rtc
|
||||
.export _rtc_set
|
||||
|
||||
RTC_CMD = $effe
|
||||
RTC_DAT = $efff
|
||||
|
||||
RTC_THRESHOLD = $00
|
||||
RTC_INCREMENT = $10
|
||||
RTC_IRQ_THRESHOLD = $20
|
||||
RTC_OUTPUT = $30
|
||||
RTC_CONTROL = $30
|
||||
|
||||
THRESHOLD_0 = $a0
|
||||
THRESHOLD_1 = $0f
|
||||
; THRESHOLD_1 = $00
|
||||
THRESHOLD_2 = $00
|
||||
THRESHOLD_3 = $00
|
||||
|
||||
IRQ_THRESHOLD_0 = $32
|
||||
; IRQ_THRESHOLD_0 = $10
|
||||
IRQ_THRESHOLD_1 = $00
|
||||
IRQ_THRESHOLD_2 = $00
|
||||
IRQ_THRESHOLD_3 = $00
|
||||
|
||||
; void init_rtc(void);
|
||||
; Initialize rtc and generate 50ms interrupts
|
||||
.proc _init_rtc
|
||||
lda #RTC_INCREMENT+0 ; Set increment to 1
|
||||
sta RTC_CMD
|
||||
lda #$01
|
||||
sta RTC_DAT
|
||||
lda #RTC_INCREMENT+1
|
||||
sta RTC_CMD
|
||||
lda #$00
|
||||
sta RTC_DAT
|
||||
lda #RTC_INCREMENT+2
|
||||
sta RTC_CMD
|
||||
lda #$00
|
||||
sta RTC_DAT
|
||||
lda #RTC_INCREMENT+3
|
||||
sta RTC_CMD
|
||||
lda #$00
|
||||
sta RTC_DAT
|
||||
|
||||
lda #RTC_THRESHOLD+0 ; Set threshold to 4000 ($fa0)
|
||||
sta RTC_CMD
|
||||
lda #THRESHOLD_0
|
||||
sta RTC_DAT
|
||||
lda #RTC_THRESHOLD+1
|
||||
sta RTC_CMD
|
||||
lda #THRESHOLD_1
|
||||
sta RTC_DAT
|
||||
lda #RTC_THRESHOLD+2
|
||||
sta RTC_CMD
|
||||
lda #THRESHOLD_2
|
||||
sta RTC_DAT
|
||||
lda #RTC_THRESHOLD+3
|
||||
sta RTC_CMD
|
||||
lda #THRESHOLD_3
|
||||
sta RTC_DAT
|
||||
|
||||
lda #RTC_IRQ_THRESHOLD+0 ; Set irq threshold to 50 ($32)
|
||||
sta RTC_CMD
|
||||
lda #IRQ_THRESHOLD_0
|
||||
sta RTC_DAT
|
||||
lda #RTC_IRQ_THRESHOLD+1
|
||||
sta RTC_CMD
|
||||
lda #IRQ_THRESHOLD_1
|
||||
sta RTC_DAT
|
||||
lda #RTC_IRQ_THRESHOLD+2
|
||||
sta RTC_CMD
|
||||
lda #IRQ_THRESHOLD_2
|
||||
sta RTC_DAT
|
||||
lda #RTC_IRQ_THRESHOLD+3
|
||||
sta RTC_CMD
|
||||
lda #IRQ_THRESHOLD_3
|
||||
sta RTC_DAT
|
||||
|
||||
lda #$30
|
||||
sta RTC_CMD
|
||||
lda #$3
|
||||
sta RTC_DAT
|
||||
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; void rtc_set(uint32_t val, uint8_t idx);
|
||||
.proc _rtc_set
|
||||
sta tmp1 ; store idx in tmp1
|
||||
ldx #$04
|
||||
L1: lda tmp1
|
||||
sta RTC_CMD ; store cmd+idx to CMD
|
||||
jsr popa ; pop 1 byte of argument
|
||||
sta RTC_DAT ; write it to data
|
||||
inc tmp1 ; increase index
|
||||
dex
|
||||
bne L1 ; repeat 4 times
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
.proc _handle_rtc
|
||||
nop
|
||||
rti
|
||||
.endproc
|
||||
@@ -1,445 +0,0 @@
|
||||
#include <conio.h>
|
||||
|
||||
#include "sd_card.h"
|
||||
#include "sd_print.h"
|
||||
#include "spi.h"
|
||||
|
||||
/*******************************************************************************
|
||||
Initialize SD card
|
||||
*******************************************************************************/
|
||||
uint8_t SD_init()
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
uint8_t res[5], cmdAttempts = 0;
|
||||
|
||||
SD_powerUpSeq();
|
||||
|
||||
while((res[0] = SD_goIdleState()) != SD_IN_IDLE_STATE)
|
||||
{
|
||||
cmdAttempts++;
|
||||
if(cmdAttempts == CMD0_MAX_ATTEMPTS)
|
||||
{
|
||||
cputs("Go IDLE\r\n");
|
||||
return SD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
SD_sendIfCond(res);
|
||||
if(res[0] != SD_IN_IDLE_STATE)
|
||||
{
|
||||
cputs("IF Cond\r\n");
|
||||
return SD_ERROR;
|
||||
}
|
||||
|
||||
if(res[4] != 0xAA)
|
||||
{
|
||||
return SD_ERROR;
|
||||
}
|
||||
|
||||
cmdAttempts = 0;
|
||||
do
|
||||
{
|
||||
if(cmdAttempts == CMD55_MAX_ATTEMPTS)
|
||||
{
|
||||
cputs("op_cond error\r\n");
|
||||
return SD_ERROR;
|
||||
}
|
||||
|
||||
res[0] = SD_sendApp();
|
||||
if(SD_R1_NO_ERROR(res[0]))
|
||||
{
|
||||
res[0] = SD_sendOpCond();
|
||||
}
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
cmdAttempts++;
|
||||
}
|
||||
while(res[0] != SD_READY);
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
SD_readOCR(res);
|
||||
|
||||
return SD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
// Send a command with starting end ending clock pulses
|
||||
uint8_t res1_cmd(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
{
|
||||
uint8_t res1;
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD0
|
||||
SD_command(cmd, arg, crc);
|
||||
|
||||
// read response
|
||||
res1 = SD_readRes1();
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
return res1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Run power up sequence
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_powerUpSeq()
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t j;
|
||||
|
||||
// make sure card is deselected
|
||||
spi_deselect(0);
|
||||
|
||||
// give SD card time to power up
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
|
||||
// select SD card
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
|
||||
// send 80 clock cycles to synchronize
|
||||
for(j = 0; j < SD_INIT_CYCLES; j++)
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Send command to SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
{
|
||||
// transmit command to sd card
|
||||
spi_exchange(cmd|0x40);
|
||||
|
||||
// transmit argument
|
||||
spi_exchange((uint8_t)(arg >> 24));
|
||||
spi_exchange((uint8_t)(arg >> 16));
|
||||
spi_exchange((uint8_t)(arg >> 8));
|
||||
spi_exchange((uint8_t)(arg));
|
||||
|
||||
// transmit crc
|
||||
spi_exchange(crc|0x01);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R1 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
uint8_t SD_readRes1()
|
||||
{
|
||||
uint8_t i = 0, res1;
|
||||
|
||||
// keep polling until actual data received
|
||||
while((res1 = spi_exchange(0xFF)) == 0xFF)
|
||||
{
|
||||
i++;
|
||||
|
||||
// if no data received for 8 bytes, break
|
||||
if(i > 8) break;
|
||||
}
|
||||
|
||||
return res1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R2 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readRes2(uint8_t *res)
|
||||
{
|
||||
// read response 1 in R2
|
||||
res[0] = SD_readRes1();
|
||||
|
||||
// read final byte of response
|
||||
res[1] = spi_exchange(0xFF);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R3 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readRes3(uint8_t *res)
|
||||
{
|
||||
// read response 1 in R3
|
||||
res[0] = SD_readRes1();
|
||||
|
||||
// if error reading R1, return
|
||||
if(res[0] > 1) return;
|
||||
|
||||
// read remaining bytes
|
||||
SD_readBytes(res + 1, R3_BYTES);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read R7 from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readRes7(uint8_t *res)
|
||||
{
|
||||
// read response 1 in R7
|
||||
res[0] = SD_readRes1();
|
||||
|
||||
// if error reading R1, return
|
||||
if(res[0] > 1) return;
|
||||
|
||||
// read remaining bytes
|
||||
SD_readBytes(res + 1, R7_BYTES);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Read specified number of bytes from SD card
|
||||
*******************************************************************************/
|
||||
/*
|
||||
void SD_readBytes(uint8_t *res, uint8_t n)
|
||||
{
|
||||
while(n--) *res++ = spi_exchange(0xFF);
|
||||
}
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
Command Idle State (CMD0)
|
||||
*******************************************************************************/
|
||||
uint8_t SD_goIdleState()
|
||||
{
|
||||
return res1_cmd(CMD0, CMD0_ARG, CMD0_CRC);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Send Interface Conditions (CMD8)
|
||||
*******************************************************************************/
|
||||
void SD_sendIfCond(uint8_t *res)
|
||||
{
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD8
|
||||
SD_command(CMD8, CMD8_ARG, CMD8_CRC);
|
||||
|
||||
// read response
|
||||
SD_readRes7(res);
|
||||
//SD_readBytes(res + 1, R7_BYTES);
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Read Status
|
||||
*******************************************************************************/
|
||||
void SD_sendStatus(uint8_t *res)
|
||||
{
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD13
|
||||
SD_command(CMD13, CMD13_ARG, CMD13_CRC);
|
||||
|
||||
// read response
|
||||
SD_readRes2(res);
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Read single 512 byte block
|
||||
token = 0xFE - Successful read
|
||||
token = 0x0X - Data error
|
||||
token = 0xFF - timeout
|
||||
*******************************************************************************/
|
||||
// uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token)
|
||||
// {
|
||||
// uint8_t res1, read;
|
||||
// uint16_t readAttempts;
|
||||
// uint16_t i;
|
||||
|
||||
// // set token to none
|
||||
// *token = 0xFF;
|
||||
|
||||
// // assert chip select
|
||||
// spi_exchange(0xFF);
|
||||
// spi_select(0);
|
||||
// spi_exchange(0xFF);
|
||||
|
||||
// // send CMD17
|
||||
// SD_command(CMD17, addr, CMD17_CRC);
|
||||
|
||||
// // read R1
|
||||
// res1 = SD_readRes1();
|
||||
|
||||
// // if response received from card
|
||||
// if(res1 != 0xFF)
|
||||
// {
|
||||
// // wait for a response token (timeout = 100ms)
|
||||
// readAttempts = 0;
|
||||
// while(++readAttempts != SD_MAX_READ_ATTEMPTS)
|
||||
// if((read = spi_exchange(0xFF)) != 0xFF) break;
|
||||
|
||||
// cprintf("read attempts: %d\r\n", readAttempts);
|
||||
|
||||
// // if response token is 0xFE
|
||||
// if(read == SD_START_TOKEN)
|
||||
// {
|
||||
// // read 512 byte block
|
||||
// for(i = 0; i < SD_BLOCK_LEN; i++) *buf++ = spi_exchange(0xFF);
|
||||
|
||||
// // read 16-bit CRC
|
||||
// spi_exchange(0xFF);
|
||||
// spi_exchange(0xFF);
|
||||
// }
|
||||
|
||||
// // set token to card response
|
||||
// *token = read;
|
||||
// }
|
||||
|
||||
// // deassert chip select
|
||||
// spi_exchange(0xFF);
|
||||
// spi_deselect(0);
|
||||
// spi_exchange(0xFF);
|
||||
|
||||
// return res1;
|
||||
// }
|
||||
|
||||
#define SD_MAX_WRITE_ATTEMPTS 3907
|
||||
|
||||
/*******************************************************************************
|
||||
Write single 512 byte block
|
||||
token = 0x00 - busy timeout
|
||||
token = 0x05 - data accepted
|
||||
token = 0xFF - response timeout
|
||||
*******************************************************************************/
|
||||
uint8_t SD_writeSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token)
|
||||
{
|
||||
|
||||
(void)addr;
|
||||
(void)buf;
|
||||
(void)token;
|
||||
|
||||
/*
|
||||
uint16_t readAttempts;
|
||||
uint8_t res1, read;
|
||||
uint16_t i;
|
||||
|
||||
// set token to none
|
||||
*token = 0xFF;
|
||||
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
// send CMD24
|
||||
SD_command(CMD24, addr, CMD24_CRC);
|
||||
|
||||
// read response
|
||||
res1 = SD_readRes1();
|
||||
|
||||
// if no error
|
||||
if(res1 == SD_READY)
|
||||
{
|
||||
// send start token
|
||||
spi_exchange(SD_START_TOKEN);
|
||||
|
||||
// write buffer to card
|
||||
for(i = 0; i < SD_BLOCK_LEN; i++) spi_exchange(buf[i]);
|
||||
|
||||
// wait for a response (timeout = 250ms)
|
||||
readAttempts = 0;
|
||||
while(++readAttempts != SD_MAX_WRITE_ATTEMPTS)
|
||||
if((read = spi_exchange(0xFF)) != 0xFF) { *token = 0xFF; break; }
|
||||
|
||||
// if data accepted
|
||||
if((read & 0x1F) == 0x05)
|
||||
{
|
||||
// set token to data accepted
|
||||
*token = 0x05;
|
||||
|
||||
// wait for write to finish (timeout = 250ms)
|
||||
readAttempts = 0;
|
||||
while(spi_exchange(0xFF) == 0x00)
|
||||
if(++readAttempts == SD_MAX_WRITE_ATTEMPTS) { *token = 0x00; break; }
|
||||
}
|
||||
}
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
|
||||
return res1;
|
||||
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Reads OCR from SD Card
|
||||
*******************************************************************************/
|
||||
void SD_readOCR(uint8_t *res)
|
||||
{
|
||||
uint8_t tmp;
|
||||
|
||||
// assert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_select(0);
|
||||
tmp = spi_exchange(0xFF);
|
||||
|
||||
if(tmp != 0xFF) while(spi_exchange(0xFF) != 0xFF) ;
|
||||
|
||||
// send CMD58
|
||||
SD_command(CMD58, CMD58_ARG, CMD58_CRC);
|
||||
|
||||
// read response
|
||||
SD_readRes3(res);
|
||||
|
||||
// deassert chip select
|
||||
spi_exchange(0xFF);
|
||||
spi_deselect(0);
|
||||
spi_exchange(0xFF);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Send application command (CMD55)
|
||||
*******************************************************************************/
|
||||
uint8_t SD_sendApp()
|
||||
{
|
||||
return res1_cmd(CMD55, CMD55_ARG, CMD55_CRC);;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Send operating condition (ACMD41)
|
||||
*******************************************************************************/
|
||||
uint8_t SD_sendOpCond()
|
||||
{
|
||||
return res1_cmd(ACMD41, ACMD41_ARG, ACMD41_CRC);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#ifndef _SD_CARD_H
|
||||
#define _SD_CARD_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// command definitions
|
||||
#define CMD0 0
|
||||
#define CMD0_ARG 0x00000000
|
||||
#define CMD0_CRC 0x94
|
||||
#define CMD8 8
|
||||
#define CMD8_ARG 0x0000001AA
|
||||
#define CMD8_CRC 0x86
|
||||
#define CMD9 9
|
||||
#define CMD9_ARG 0x00000000
|
||||
#define CMD9_CRC 0x00
|
||||
#define CMD10 9
|
||||
#define CMD10_ARG 0x00000000
|
||||
#define CMD10_CRC 0x00
|
||||
#define CMD13 13
|
||||
#define CMD13_ARG 0x00000000
|
||||
#define CMD13_CRC 0x00
|
||||
#define CMD17 17
|
||||
#define CMD17_CRC 0x00
|
||||
#define CMD24 24
|
||||
#define CMD24_CRC 0x00
|
||||
#define CMD55 55
|
||||
#define CMD55_ARG 0x00000000
|
||||
#define CMD55_CRC 0x00
|
||||
#define CMD58 58
|
||||
#define CMD58_ARG 0x00000000
|
||||
#define CMD58_CRC 0x00
|
||||
#define ACMD41 41
|
||||
#define ACMD41_ARG 0x40000000
|
||||
#define ACMD41_CRC 0x00
|
||||
|
||||
#define SD_IN_IDLE_STATE 0x01
|
||||
#define SD_READY 0x00
|
||||
#define SD_R1_NO_ERROR(X) X < 0x02
|
||||
|
||||
#define R3_BYTES 4
|
||||
#define R7_BYTES 4
|
||||
|
||||
#define CMD0_MAX_ATTEMPTS 255
|
||||
#define CMD55_MAX_ATTEMPTS 255
|
||||
#define SD_ERROR 1
|
||||
#define SD_SUCCESS 0
|
||||
#define SD_MAX_READ_ATTEMPTS 1563
|
||||
#define SD_READ_START_TOKEN 0xFE
|
||||
#define SD_INIT_CYCLES 80
|
||||
|
||||
#define SD_START_TOKEN 0xFE
|
||||
#define SD_ERROR_TOKEN 0x00
|
||||
|
||||
#define SD_DATA_ACCEPTED 0x05
|
||||
#define SD_DATA_REJECTED_CRC 0x0B
|
||||
#define SD_DATA_REJECTED_WRITE 0x0D
|
||||
|
||||
#define SD_BLOCK_LEN 512
|
||||
|
||||
// SD functions
|
||||
uint8_t SD_init();
|
||||
void SD_powerUpSeq();
|
||||
void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc);
|
||||
uint8_t SD_readRes1();
|
||||
void SD_readRes2(uint8_t *res);
|
||||
void SD_readRes3(uint8_t *res);
|
||||
void SD_readRes7(uint8_t *res);
|
||||
void SD_readBytes(uint8_t *res, uint8_t n);
|
||||
uint8_t SD_goIdleState();
|
||||
void SD_sendIfCond(uint8_t *res);
|
||||
void SD_sendStatus(uint8_t *res);
|
||||
void SD_readOCR(uint8_t *res);
|
||||
uint8_t SD_sendApp();
|
||||
uint8_t SD_sendOpCond();
|
||||
uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *error);
|
||||
uint8_t SD_writeSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *res);
|
||||
|
||||
uint8_t res1_cmd(uint8_t cmd, uint32_t arg, uint8_t crc);
|
||||
|
||||
#endif
|
||||
@@ -1,303 +0,0 @@
|
||||
.export _SD_command
|
||||
.export _SD_readRes1
|
||||
.export _SD_readRes2
|
||||
.export _SD_readRes3
|
||||
.export _SD_readRes7
|
||||
.export _SD_readBytes
|
||||
.export _SD_powerUpSeq
|
||||
.export _res1_cmd
|
||||
.export _SD_readSingleBlock
|
||||
|
||||
.importzp sp, ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3
|
||||
|
||||
.autoimport on
|
||||
|
||||
.MACPACK generic
|
||||
|
||||
; void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
|
||||
; The plan: push crc to stack, load arg into tmp1 through 4
|
||||
|
||||
.proc _SD_command: near
|
||||
|
||||
pha ; Push CRC to cpu stack
|
||||
ldy #$04
|
||||
lda (sp),y ; Load CMD
|
||||
ora #$40 ; start bit
|
||||
jsr _spi_exchange
|
||||
|
||||
dey
|
||||
arg_loop: ; send ARG
|
||||
lda (sp),y ; is this sending only 3?
|
||||
jsr _spi_exchange
|
||||
dey
|
||||
bpl arg_loop
|
||||
|
||||
pla ; Pull CRC from stack
|
||||
ora #$01 ; stop bit
|
||||
jsr _spi_exchange
|
||||
jsr incsp5 ; pop all off stack
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; uint8_t SD_readRes1 (void)
|
||||
|
||||
.proc _SD_readRes1: near
|
||||
; Try to read/write up to 8 times, then return value
|
||||
|
||||
ldx #$08
|
||||
|
||||
tryread:
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
cmp #$ff
|
||||
bne end
|
||||
dex
|
||||
bne tryread
|
||||
|
||||
end: ; x will be 0 here anyway
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_readRes2(uint8_t *res)
|
||||
|
||||
.proc _SD_readRes2: near
|
||||
|
||||
sta ptr1 ; store res in ptr1
|
||||
stx ptr1 + 1
|
||||
|
||||
jsr _SD_readRes1 ; get first response 1
|
||||
sta (ptr1)
|
||||
|
||||
lda #$ff
|
||||
jsr _spi_exchange ; get final byte of response
|
||||
ldy #$01
|
||||
sta (ptr1),y
|
||||
jsr incsp2
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_readBytes(uint8_t *res, uint8_t n)
|
||||
|
||||
.proc _SD_readBytes: near
|
||||
|
||||
tax
|
||||
jsr popptr1 ; store res in ptr1
|
||||
|
||||
read:
|
||||
lda #$ff ; read data first
|
||||
jsr _spi_exchange
|
||||
sta (ptr1)
|
||||
inc ptr1 ; then increment res
|
||||
bne @L1
|
||||
inc ptr1 + 1
|
||||
@L1: dex ; then decrement x
|
||||
bne read ; and if x is zero we are done
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_readRes7(uint8_t *res)
|
||||
_SD_readRes7:
|
||||
; void SD_readRes3(uint8_t *res)
|
||||
.proc _SD_readRes3: near
|
||||
|
||||
sta ptr1 ; store res in ptr1
|
||||
stx ptr1 + 1
|
||||
|
||||
jsr _SD_readRes1 ; read respopnse 1 in R3
|
||||
cmp #$02 ; if error reading R1, return
|
||||
bge @L1
|
||||
|
||||
inc ptr1 ; read remaining bytes
|
||||
bne @L2
|
||||
inc ptr1
|
||||
@L2: lda ptr1 ; push low byte
|
||||
ldx ptr1 + 1
|
||||
jsr pushax
|
||||
lda #$04 ; R3_BYTES
|
||||
jsr _SD_readBytes
|
||||
|
||||
@L1: rts
|
||||
|
||||
.endproc
|
||||
|
||||
; uint8_t res1_cmd(uint8_t cmd, uint32_t arg, uint8_t crc)
|
||||
|
||||
.proc _res1_cmd: near
|
||||
|
||||
pha ; push crc to processor stack
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_select
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
pla
|
||||
jsr _SD_command ; rely on command to teardown stack
|
||||
|
||||
jsr _SD_readRes1
|
||||
tay ; spi doesn't touch y
|
||||
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_deselect
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
tya
|
||||
ldx #$00 ; Promote to integer
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
; void SD_powerUpSeq(void)
|
||||
|
||||
.proc _SD_powerUpSeq: near
|
||||
|
||||
lda #$00
|
||||
jsr _spi_deselect
|
||||
jsr _sd_delay
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00
|
||||
jsr _spi_deselect
|
||||
|
||||
ldx #$50 ; SD_INIT_CYCLES
|
||||
@L1: lda #$ff
|
||||
jsr _spi_exchange
|
||||
dex
|
||||
bne @L1
|
||||
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
|
||||
; 1ms delay approx. saves no registers
|
||||
.proc _sd_delay: near
|
||||
ldx #$01 ; delay loop: A*X*10 + 4
|
||||
@L1: lda #$c8 ; 1ms at 2MHz
|
||||
@L2: dec ; 2
|
||||
bne @L2 ; 3
|
||||
dex ; 2
|
||||
bne @L1 ; 3
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; ;uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token)
|
||||
.proc _SD_readSingleBlock: near
|
||||
; token address in a/x
|
||||
; buf address next on stack
|
||||
; sd address above that
|
||||
|
||||
; ptr2 = *token
|
||||
sta ptr2
|
||||
stx ptr2 + 1
|
||||
|
||||
lda #$ff
|
||||
sta (ptr2)
|
||||
|
||||
; ptr1 = *buf
|
||||
jsr popptr1
|
||||
|
||||
; 4 bytes on stack are addr
|
||||
|
||||
; Move addr down on the stack
|
||||
lda sp
|
||||
sta ptr3
|
||||
lda sp + 1
|
||||
sta ptr3 + 1
|
||||
|
||||
; find a way to do this in a loop?
|
||||
jsr decsp1
|
||||
ldy #$0
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
iny
|
||||
lda (ptr3),y
|
||||
sta (sp),y
|
||||
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_select
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
; push cmd17
|
||||
lda #$11
|
||||
ldy #$4
|
||||
sta (sp),y
|
||||
|
||||
; crc, 0
|
||||
lda #$00
|
||||
jsr _SD_command ; rely on command to teardown stack
|
||||
|
||||
jsr _SD_readRes1
|
||||
|
||||
cmp #$ff ; if 0xFF then you failed
|
||||
beq end
|
||||
sta tmp3 ; tmp3 = read
|
||||
|
||||
; y = read_attempts
|
||||
ldy #$0
|
||||
resp_loop:
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
sta tmp2 ; tmp2 = read
|
||||
lda tmp2
|
||||
cmp #$ff
|
||||
bne got_resp
|
||||
iny
|
||||
bne resp_loop
|
||||
bra after_read
|
||||
|
||||
got_resp:
|
||||
ldx #$2
|
||||
ldy #$00
|
||||
load_loop:
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
sta (ptr1)
|
||||
inc ptr1
|
||||
bne @2
|
||||
inc ptr1 + 1
|
||||
@2: dey
|
||||
bne load_loop
|
||||
ldy #$00
|
||||
dex
|
||||
bne load_loop
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
|
||||
after_read:
|
||||
lda tmp2
|
||||
sta (ptr2)
|
||||
lda tmp3
|
||||
|
||||
end:
|
||||
pha
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
lda #$00 ; this gets ignored anyway
|
||||
jsr _spi_deselect
|
||||
lda #$ff
|
||||
jsr _spi_exchange
|
||||
pla
|
||||
rts
|
||||
|
||||
.endproc
|
||||
@@ -1,26 +0,0 @@
|
||||
#include <conio.h>
|
||||
|
||||
#include "sd_print.h"
|
||||
#include "sd_card.h"
|
||||
|
||||
|
||||
void SD_printBuf(uint8_t *buf)
|
||||
{
|
||||
uint8_t colCount = 0;
|
||||
uint16_t i;
|
||||
for(i = 0; i < SD_BLOCK_LEN; i++)
|
||||
{
|
||||
cprintf("%2x", *buf++);
|
||||
if(colCount == 31)
|
||||
{
|
||||
cputs("\r\n");
|
||||
colCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cputc(' ');
|
||||
colCount++;
|
||||
}
|
||||
}
|
||||
cputs("\r\n");
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef SD_PRINT_H
|
||||
#define SD_PRINT_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* R1 MACROS */
|
||||
#define PARAM_ERROR(X) X & 0b01000000
|
||||
#define ADDR_ERROR(X) X & 0b00100000
|
||||
#define ERASE_SEQ_ERROR(X) X & 0b00010000
|
||||
#define CRC_ERROR(X) X & 0b00001000
|
||||
#define ILLEGAL_CMD(X) X & 0b00000100
|
||||
#define ERASE_RESET(X) X & 0b00000010
|
||||
#define IN_IDLE(X) X & 0b00000001
|
||||
|
||||
/* R2 MACROS */
|
||||
#define OUT_OF_RANGE(X) X & 0b10000000
|
||||
#define ERASE_PARAM(X) X & 0b01000000
|
||||
#define WP_VIOLATION(X) X & 0b00100000
|
||||
#define CARD_ECC_FAILED(X) X & 0b00010000
|
||||
#define CC_ERROR(X) X & 0b00001000
|
||||
#define ERROR(X) X & 0b00000100
|
||||
#define WP_ERASE_SKIP(X) X & 0b00000010
|
||||
#define CARD_LOCKED(X) X & 0b00000001
|
||||
|
||||
/* R3 MACROS */
|
||||
#define POWER_UP_STATUS(X) X & 0x40
|
||||
#define CCS_VAL(X) X & 0x40
|
||||
#define VDD_2728(X) X & 0b10000000
|
||||
#define VDD_2829(X) X & 0b00000001
|
||||
#define VDD_2930(X) X & 0b00000010
|
||||
#define VDD_3031(X) X & 0b00000100
|
||||
#define VDD_3132(X) X & 0b00001000
|
||||
#define VDD_3233(X) X & 0b00010000
|
||||
#define VDD_3334(X) X & 0b00100000
|
||||
#define VDD_3435(X) X & 0b01000000
|
||||
#define VDD_3536(X) X & 0b10000000
|
||||
|
||||
/* R7 MACROS */
|
||||
#define CMD_VER(X) ((X >> 4) & 0xF0)
|
||||
#define VOL_ACC(X) (X & 0x1F)
|
||||
#define VOLTAGE_ACC_27_33 0b00000001
|
||||
#define VOLTAGE_ACC_LOW 0b00000010
|
||||
#define VOLTAGE_ACC_RES1 0b00000100
|
||||
#define VOLTAGE_ACC_RES2 0b00001000
|
||||
|
||||
/* DATA ERROR TOKEN */
|
||||
#define SD_TOKEN_OOR(X) X & 0b00001000
|
||||
#define SD_TOKEN_CECC(X) X & 0b00000100
|
||||
#define SD_TOKEN_CC(X) X & 0b00000010
|
||||
#define SD_TOKEN_ERROR(X) X & 0b00000001
|
||||
|
||||
void SD_printR1(uint8_t res);
|
||||
void SD_printR2(uint8_t *res);
|
||||
void SD_printR3(uint8_t *res);
|
||||
void SD_printR7(uint8_t *res);
|
||||
void SD_printBuf(uint8_t *buf);
|
||||
void SD_printDataErrToken(uint8_t token);
|
||||
|
||||
#endif
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef _SERIAL_H
|
||||
#define _SERIAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void serial_handle_irq();
|
||||
|
||||
void serial_init();
|
||||
|
||||
void serial_putc(char c);
|
||||
void serial_puts(char* s);
|
||||
|
||||
|
||||
char serial_getc();
|
||||
char serial_getc_nb();
|
||||
|
||||
#endif
|
||||
@@ -1,94 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.autoimport
|
||||
|
||||
.import _enable_irq, _send_eoi, _uart_txb_block
|
||||
|
||||
.importzp tmp1, ptr1
|
||||
|
||||
.export _serial_init
|
||||
.export _serial_handle_irq
|
||||
|
||||
.export _serial_putc, _serial_puts, _serial_getc, _serial_getc_nb
|
||||
|
||||
.zeropage
|
||||
|
||||
last_char: .res 1
|
||||
|
||||
|
||||
.code
|
||||
|
||||
UART = $efe6
|
||||
UART_TXB = UART
|
||||
UART_RXB = UART
|
||||
UART_STATUS = UART + 1
|
||||
|
||||
; Initialize Serial Port
|
||||
; No initialization needed, just register irq handler.
|
||||
.proc _serial_init
|
||||
lda #<_serial_handle_irq
|
||||
ldx #>_serial_handle_irq
|
||||
jsr pushax
|
||||
lda #$01
|
||||
jsr _register_irq
|
||||
stz last_char
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; Serial Port IRQ Handler
|
||||
; Get the character and store it.
|
||||
.proc _serial_handle_irq
|
||||
lda UART_RXB
|
||||
ora #$80 ; set msb
|
||||
sta last_char
|
||||
jsr _send_eoi
|
||||
rti
|
||||
.endproc
|
||||
|
||||
; Serial Port Get Character
|
||||
; If a character has not been received, block until one is.
|
||||
.proc _serial_getc
|
||||
L1: lda last_char
|
||||
bpl L1
|
||||
and #$7f
|
||||
sta last_char
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; Serial Port Get Character Non-Blocking
|
||||
; return last character, even if it has already been read.
|
||||
; If the character is new, we still clear the new flag.
|
||||
.proc _serial_getc_nb
|
||||
lda last_char
|
||||
bpl L1
|
||||
and #$7f
|
||||
sta last_char
|
||||
L1: rts
|
||||
.endproc
|
||||
|
||||
|
||||
; Serial Port Put Character
|
||||
; send a single character over the serial port.
|
||||
.proc _serial_putc
|
||||
jsr _uart_txb_block
|
||||
cmp #$0a
|
||||
bne @1
|
||||
lda #$0d
|
||||
jsr _uart_txb_block
|
||||
@1: rts
|
||||
.endproc
|
||||
|
||||
; Send a string over the serial port. Needs stlen
|
||||
.proc _serial_puts
|
||||
sta ptr1 ; Store pointer in ptr1
|
||||
stx ptr1+1
|
||||
ldy #$00 ; initialize y to 0
|
||||
L1: lda (ptr1),y ; load character from string
|
||||
beq L2 ; Quit if NULL
|
||||
jsr _serial_putc ; send character (does not change y or ptr1)
|
||||
iny ; increment y
|
||||
bne L1 ; If Y == 0, increment high byte of pointer
|
||||
inc ptr1+1
|
||||
bne L1 ; if high byte wraps around, give up
|
||||
L2: rts
|
||||
.endproc
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef _SPI_H
|
||||
#define _SPI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void spi_select(uint8_t id);
|
||||
void spi_deselect(uint8_t id);
|
||||
uint8_t spi_read();
|
||||
void spi_write(uint8_t data);
|
||||
uint8_t spi_exchange(uint8_t data);
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
.include "io.inc65"
|
||||
|
||||
.importzp zp, sreg
|
||||
|
||||
.export _spi_select, _spi_deselect
|
||||
.export _spi_read, _spi_write, _spi_exchange
|
||||
|
||||
.autoimport on
|
||||
|
||||
.code
|
||||
|
||||
; void spi_select(uint8_t id)
|
||||
; Select a (the) slave by pulling its CS line down
|
||||
; TODO allow active high or active low CS
|
||||
; TODO allow more than one slave
|
||||
_spi_select:
|
||||
lda #$1 ; Ignore whatever id is, 1 is the only option
|
||||
sta SPI_CTRL
|
||||
rts
|
||||
|
||||
; void spi_deslect(uint8_t id)
|
||||
; Deslect a slave by pulling its CS line up
|
||||
; TODO allow active high or active low CS
|
||||
_spi_deselect:
|
||||
stz SPI_CTRL
|
||||
rts
|
||||
|
||||
; uint8_t spi_read()
|
||||
_spi_read:
|
||||
lda #$0
|
||||
; void spi_write(uint8_t data)
|
||||
_spi_write:
|
||||
; uint8_t spi_exchange(uint8_t data)
|
||||
_spi_exchange:
|
||||
sta SPI_OUTPUT
|
||||
@1: lda SPI_CTRL
|
||||
bmi @1
|
||||
lda SPI_INPUT
|
||||
rts
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef _TERMINAL_H
|
||||
#define _TERMINAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int8_t terminal_read(uint8_t fd, void* buf, uint8_t nbytes);
|
||||
int8_t terminal_write(uint8_t fd, const void* buf, uint8_t nbytes);
|
||||
int8_t terminal_open(const uint8_t* filename);
|
||||
int8_t terminal_close(uint8_t fd);
|
||||
|
||||
|
||||
#endif /* _TERMINAL_H */
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.autoimport
|
||||
|
||||
.importzp tmp1, ptr1
|
||||
|
||||
.import _serial_getc
|
||||
.export _terminal_read, _terminal_write, _terminal_open, _terminal_close
|
||||
|
||||
.data
|
||||
|
||||
terminal_buf: .res 128
|
||||
|
||||
.code
|
||||
|
||||
; int8_t terminal_read(uint8_t fd, void* buf, uint8_t nbytes);
|
||||
; Read up to size-1 (127 max) before the enter key is pressed.
|
||||
; A newline character is automatically added.
|
||||
; Inputs: int8_t* buf - where input characters are stored
|
||||
; uint8_t n - number of characters to read (max buf size minux 1)
|
||||
; Return Value: number of characters read on success, -1 on failure
|
||||
; Function: Reads keyboard input
|
||||
.proc _terminal_read
|
||||
cmp #$00 ; Check that nbytes is > 0 and < 128
|
||||
beq FAIL
|
||||
cmp #$81
|
||||
bge FAIL
|
||||
sta tmp1 ; Store nbytes in tmp1
|
||||
|
||||
jsr popax ; Check that buf != NULL
|
||||
cmp #$00
|
||||
bne L1
|
||||
cpx #$00
|
||||
bne L1
|
||||
bra FAIL
|
||||
|
||||
|
||||
; while i < nbytes, store getc into terminal_buf y
|
||||
L1: sta ptr1
|
||||
stx ptr1+1
|
||||
ldy #$00
|
||||
LOOP: cpy tmp1
|
||||
bge END
|
||||
jsr _serial_getc
|
||||
sta terminal_buf,y
|
||||
|
||||
cmp #$0d ; If newline, do something
|
||||
bne L2
|
||||
lda #$0a ; hacky serial, we want $0a, not $0d
|
||||
jsr _serial_putc
|
||||
bra END
|
||||
|
||||
L2: cmp #$08 ; Handle backspace
|
||||
bne L3
|
||||
lda tmp1
|
||||
beq LOOP
|
||||
lda #$08
|
||||
jsr _serial_putc
|
||||
dey
|
||||
lda #$00
|
||||
sta terminal_buf,y
|
||||
bra LOOP
|
||||
|
||||
L3: lda terminal_buf,y ; Normal character
|
||||
sta (ptr1),y
|
||||
jsr _serial_putc
|
||||
iny
|
||||
bra LOOP
|
||||
|
||||
END: phy ; Zero out terminal buffer
|
||||
ldy #$00
|
||||
lda #$00
|
||||
L4: sta terminal_buf,y
|
||||
iny
|
||||
cpy #$80
|
||||
blt L4
|
||||
|
||||
L5: ply ; End string with NULL
|
||||
lda #$0a
|
||||
sta (ptr1),y
|
||||
iny
|
||||
cpy #$80 ; But not if we are at max
|
||||
bge L6
|
||||
lda #$00
|
||||
sta (ptr1),y
|
||||
|
||||
L6: lda #$00 ; Return - on success
|
||||
rts
|
||||
|
||||
FAIL: lda #$ff ; return -1 on fail
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; int8_t terminal_write(uint8_t fd, const void* buf, uint8_t nbytes);
|
||||
; write characters to the terminal
|
||||
; Inputs: int8_t* buf - buffer of characters to write
|
||||
; uint8_t n - number of characters to write
|
||||
; Return Value: 0 on success, -1 on failure
|
||||
; Writes to screen. Only stops after n chars written.
|
||||
; This seems to not care about null termination?
|
||||
.proc _terminal_write
|
||||
sta tmp1 ; put nbytes in tmp1
|
||||
|
||||
jsr popax ; check that buf is not null
|
||||
cmp #$00
|
||||
bne L1
|
||||
cpx #$00
|
||||
bne L1
|
||||
bra FAIL
|
||||
L1: sta ptr1
|
||||
stx ptr1+1
|
||||
ldy #$00
|
||||
LOOP: lda (ptr1),y ; Loop through buffer and print
|
||||
jsr _serial_putc
|
||||
iny
|
||||
cpy tmp1
|
||||
blt LOOP
|
||||
lda #$00
|
||||
rts
|
||||
|
||||
FAIL: lda #$ff ; old code didn't fail, but new code does.
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; terminal_open
|
||||
; open terminal device
|
||||
; Inputs: uint8_t* filename
|
||||
; Outputs: none
|
||||
; Return Value: 0 on success
|
||||
; Function: none.
|
||||
.proc _terminal_open
|
||||
lda #$0
|
||||
rts
|
||||
.endproc
|
||||
|
||||
; terminal_close
|
||||
; close terminal device
|
||||
; Inputs: int32_t fd
|
||||
; Outputs: none
|
||||
; Return Value: 0 on success (but this always failes)
|
||||
; Function: none.
|
||||
.proc _terminal_close
|
||||
lda #$ff ; -1
|
||||
rts
|
||||
.endproc
|
||||
@@ -1,13 +0,0 @@
|
||||
#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
|
||||
@@ -1,36 +0,0 @@
|
||||
.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[1] to be 0
|
||||
bit #$02
|
||||
bne @1
|
||||
pla
|
||||
rts
|
||||
|
||||
_uart_rxb:
|
||||
lda UART_RXB ; Read value
|
||||
ldx #$00
|
||||
rts
|
||||
|
||||
_uart_status:
|
||||
lda UART_STATUS
|
||||
ldx #$00
|
||||
rts
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef _FAT32_H
|
||||
#define _FAT32_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void fat32_init();
|
||||
|
||||
extern uint32_t root_cluster;
|
||||
extern uint16_t fat_start_sector;
|
||||
extern uint32_t data_start_sector;
|
||||
extern uint32_t fat_size;
|
||||
extern uint8_t* sd_buf;
|
||||
extern uint8_t sectors_per_cluster;
|
||||
extern uint8_t log2_sectors_per_cluster;
|
||||
|
||||
struct fat32_directory_entry {
|
||||
char file_name[8];
|
||||
char file_ext[3];
|
||||
uint8_t attr1;
|
||||
uint8_t attr2;
|
||||
uint8_t create_time_10ms;
|
||||
uint16_t create_time;
|
||||
uint16_t create_date;
|
||||
uint16_t access_date;
|
||||
uint16_t cluster_high;
|
||||
uint16_t modified_time;
|
||||
uint16_t modified_date;
|
||||
uint16_t cluster_low;
|
||||
uint32_t file_size;
|
||||
};
|
||||
|
||||
struct lfn_entry {
|
||||
uint8_t sequence_number;
|
||||
uint16_t name_0[5];
|
||||
uint8_t attributes;
|
||||
uint8_t type;
|
||||
uint8_t checksum;
|
||||
uint16_t name_1[6];
|
||||
uint16_t cluster_low;
|
||||
uint16_t name_2[2];
|
||||
};
|
||||
|
||||
int8_t fat32_get_cluster_by_name(const char* name, struct fat32_directory_entry* dentry);
|
||||
int8_t fat32_read_sector(uint32_t cluster, uint32_t sector, void* buf);
|
||||
uint32_t fat32_next_cluster(uint32_t cluster);
|
||||
|
||||
int8_t fat32_file_open(const char* filename);
|
||||
size_t fat32_file_read(int8_t fd, void* buf, size_t nbytes);
|
||||
size_t fat32_file_write(int8_t fd, const void* buf, size_t nbytes);
|
||||
int8_t fat32_file_close(int8_t fd);
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.autoimport
|
||||
.feature string_escapes
|
||||
|
||||
.importzp ptr1, sreg
|
||||
|
||||
.import _SD_readSingleBlock
|
||||
|
||||
.export _fat32_init
|
||||
|
||||
.export _root_cluster, _fat_start_sector, _data_start_sector
|
||||
.export _fat_size, _sd_buf, _sectors_per_cluster, _log2_sectors_per_cluster
|
||||
|
||||
|
||||
.data
|
||||
_root_cluster: .res 4
|
||||
_fat_start_sector: .res 2
|
||||
_data_start_sector: .res 4
|
||||
_fat_size: .res 4
|
||||
_sectors_per_cluster: .res 1
|
||||
_log2_sectors_per_cluster: .res 1
|
||||
|
||||
_sd_buf: .res 512
|
||||
|
||||
data_start_sect_str: .asciiz "Data sector start: 0x%lx\n"
|
||||
starting_cluster_str: .asciiz "Root cluster num: %lx\n";
|
||||
value_str: .asciiz "Value: 0x%x\n"
|
||||
|
||||
.code
|
||||
|
||||
bytes_per_sector = _sd_buf + $0B
|
||||
sectors_per_cluster = _sd_buf + $0D
|
||||
reserved_sectors = _sd_buf + $0E
|
||||
fat_count = _sd_buf + $10
|
||||
sectors_per_fat = _sd_buf + $24
|
||||
root_cluster_offs = _sd_buf + $2C
|
||||
|
||||
.proc _fat32_init
|
||||
; load sector 0 into sd_buf
|
||||
lda #$00
|
||||
ldx #$00
|
||||
stz sreg
|
||||
stz sreg+1
|
||||
jsr pusheax
|
||||
lda #<_sd_buf
|
||||
ldx #>_sd_buf
|
||||
jsr pushax
|
||||
lda #<ptr1
|
||||
ldx #>ptr1
|
||||
jsr _SD_readSingleBlock
|
||||
|
||||
lda sectors_per_cluster
|
||||
sta _sectors_per_cluster
|
||||
|
||||
ldx #$0
|
||||
@1: bit #$01
|
||||
bne L0
|
||||
inx
|
||||
lsr
|
||||
bra @1
|
||||
|
||||
L0: txa
|
||||
sta _log2_sectors_per_cluster
|
||||
|
||||
ldx #$00
|
||||
L1: lda root_cluster_offs,x
|
||||
sta _root_cluster,x
|
||||
inx
|
||||
cpx #$4
|
||||
blt L1
|
||||
|
||||
; Multiply reserved sectors and bytes per sector, then divide by 512 to get sd sectors
|
||||
lda reserved_sectors
|
||||
jsr pusha0
|
||||
lda bytes_per_sector
|
||||
ldx bytes_per_sector+1
|
||||
jsr _imulii
|
||||
txa
|
||||
lsr
|
||||
sta _fat_start_sector
|
||||
stz _fat_start_sector + 1
|
||||
|
||||
; multiply fat size and number of fats to get total fat size
|
||||
lda fat_count
|
||||
jsr pusha0
|
||||
lda sectors_per_fat
|
||||
ldx sectors_per_fat+1
|
||||
jsr _lmulii
|
||||
sta _fat_size
|
||||
stx _fat_size+1
|
||||
lda sreg
|
||||
sta _fat_size+2
|
||||
lda sreg+1
|
||||
sta _fat_size+3
|
||||
|
||||
|
||||
; Add fat size to starting fat sector to get data start sector
|
||||
clc
|
||||
lda _fat_size
|
||||
adc _fat_start_sector
|
||||
sta _data_start_sector
|
||||
lda _fat_size+1
|
||||
adc _fat_start_sector+1
|
||||
sta _data_start_sector+1
|
||||
lda _fat_size+2
|
||||
sta _data_start_sector+2
|
||||
lda _fat_size+3
|
||||
sta _data_start_sector+3
|
||||
|
||||
rts
|
||||
.endproc
|
||||
@@ -1,207 +0,0 @@
|
||||
#include <devices/sd_card.h>
|
||||
#include <process/process.h>
|
||||
#include <conio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fat32.h"
|
||||
#include "fs.h"
|
||||
|
||||
static struct fops fat32_file_ops = {fat32_file_open, fat32_file_close, fat32_file_read, fat32_file_write};
|
||||
|
||||
int8_t fd_val;
|
||||
|
||||
|
||||
//TODO
|
||||
size_t fat32_file_write(int8_t fd, const void* buf, size_t nbytes) {
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)nbytes;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* file_close
|
||||
* DESCRIPTION: close device abstracted as file
|
||||
* INPUTS: fd -- file descriptor for file to be closed
|
||||
* OUTPUTS: none
|
||||
* RETURN VALUE: none
|
||||
* SIDE EFFECTS: none
|
||||
*/
|
||||
int8_t fat32_file_close(int8_t fd) {
|
||||
struct pcb* pcb;
|
||||
pcb = get_pcb_ptr();
|
||||
|
||||
/* update pcb to remove process */
|
||||
pcb->file_desc_array[fd].flags = !IN_USE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t fat32_file_open(const char* filename) {
|
||||
int8_t ret;
|
||||
int8_t i;
|
||||
int8_t fd;
|
||||
|
||||
struct fat32_directory_entry dentry;
|
||||
|
||||
struct pcb* pcb = get_pcb_ptr();
|
||||
|
||||
ret = fat32_get_cluster_by_name(filename, &dentry);
|
||||
if (ret) {
|
||||
cprintf("Error finding cluster for filename");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* try to find an empty file desciptor, fail otherwise */
|
||||
//TODO We start at 3 here because 0, 1, 2 will be reserved later
|
||||
for (i = 3; i < FILE_DESC_SIZE; i++) {
|
||||
if (pcb->file_desc_array[i].flags == !IN_USE) {
|
||||
fd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fd == -1){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add process */
|
||||
pcb->file_desc_array[fd].f32_dentry = dentry;
|
||||
pcb->file_desc_array[fd].flags = IN_USE;
|
||||
pcb->file_desc_array[fd].file_pos = 0;
|
||||
|
||||
pcb->file_desc_array[fd].file_ops = &fat32_file_ops;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
size_t fat32_file_read(int8_t fd, void* buf, size_t nbytes) {
|
||||
uint16_t i;
|
||||
size_t offset;
|
||||
size_t leftover_length;
|
||||
size_t bytes_read = 0;
|
||||
size_t clusters;
|
||||
uint32_t sector;
|
||||
struct pcb* pcb = get_pcb_ptr();
|
||||
struct file_desc* fdesc = &pcb->file_desc_array[fd];
|
||||
|
||||
uint32_t cluster_seq = fdesc->file_pos >> (9 + log2_sectors_per_cluster);
|
||||
|
||||
uint32_t cluster = ((uint32_t)fdesc->f32_dentry.cluster_high << 16) | fdesc->f32_dentry.cluster_low;
|
||||
|
||||
/* validate starting position isn't past end of file */
|
||||
if (fdesc->file_pos >= fdesc->f32_dentry.file_size){
|
||||
return 0;
|
||||
}
|
||||
/* validate final pos isn't past end of file */
|
||||
if (fdesc->file_pos+nbytes > fdesc->f32_dentry.file_size){
|
||||
nbytes = fdesc->f32_dentry.file_size - fdesc->file_pos;
|
||||
}
|
||||
|
||||
|
||||
// This can stay for now, as long as cluster_seq is correct.
|
||||
for (i = 0; i < cluster_seq; i++) {
|
||||
cluster = fat32_next_cluster(cluster);
|
||||
}
|
||||
|
||||
clusters = nbytes >> (9 + log2_sectors_per_cluster);
|
||||
|
||||
|
||||
/* Handle first unaligned block */
|
||||
offset = fdesc->file_pos % 512; // This is the offset into the sector, not the cluster
|
||||
leftover_length = 512 - offset;
|
||||
|
||||
sector = (fdesc->file_pos >> 9) & (sectors_per_cluster-1);
|
||||
|
||||
if (leftover_length != 0) {
|
||||
if (nbytes <= leftover_length) {
|
||||
|
||||
fat32_read_sector(cluster, sector, sd_buf);
|
||||
memcpy(buf, sd_buf + offset, nbytes);
|
||||
bytes_read += nbytes;
|
||||
fdesc->file_pos += bytes_read;
|
||||
return bytes_read;
|
||||
} else {
|
||||
fat32_read_sector(cluster, sector, sd_buf);
|
||||
memcpy(buf, sd_buf + offset, leftover_length);
|
||||
bytes_read += leftover_length;
|
||||
fdesc->file_pos += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Handle middle aligned blocks */
|
||||
for (i = 0; i < clusters; i++) {
|
||||
cluster = fat32_next_cluster(cluster);
|
||||
if (cluster >= 0xffffff00) {
|
||||
// cprintf("Last cluster in file!\n");
|
||||
}
|
||||
|
||||
if (nbytes - bytes_read > 512) {
|
||||
leftover_length = 512;
|
||||
} else {
|
||||
leftover_length = nbytes - bytes_read;
|
||||
}
|
||||
|
||||
fat32_read_sector(cluster, cluster, sd_buf);
|
||||
memcpy((uint8_t*)buf+bytes_read, sd_buf, leftover_length);
|
||||
bytes_read += leftover_length;
|
||||
fdesc->file_pos += bytes_read;
|
||||
if (bytes_read == nbytes) {
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
// Read the sector offset from a given cluster into buf
|
||||
// Why do we need this though, this is just doing a single multiplication?
|
||||
// No, it is also doing an addition
|
||||
int8_t fat32_read_sector(uint32_t cluster, uint32_t sector, void* buf) {
|
||||
uint8_t error;
|
||||
uint32_t addr = (cluster - 2) * sectors_per_cluster + sector + data_start_sector;
|
||||
SD_readSingleBlock(addr, buf, &error);
|
||||
return error;
|
||||
}
|
||||
|
||||
// This will not handle clusters numbers that leaves a sector
|
||||
uint32_t fat32_next_cluster(uint32_t cluster) {
|
||||
uint8_t error;
|
||||
uint32_t addr = fat_start_sector;
|
||||
uint32_t cluster_val;
|
||||
SD_readSingleBlock(addr, sd_buf, &error);
|
||||
cluster_val = ((uint32_t*)sd_buf)[cluster];
|
||||
return cluster_val;
|
||||
}
|
||||
|
||||
int8_t fat32_get_cluster_by_name(const char* name, struct fat32_directory_entry* dentry) {
|
||||
struct fat32_directory_entry* local_entry;
|
||||
int i = 0;
|
||||
|
||||
uint32_t cluster;
|
||||
|
||||
cluster = fat32_next_cluster(root_cluster);
|
||||
|
||||
cprintf("Sectors per cluster: %hhx\n", sectors_per_cluster);
|
||||
|
||||
fat32_read_sector(root_cluster, 0, sd_buf);
|
||||
for (i = 0; i < 16; i++){
|
||||
local_entry = (struct fat32_directory_entry*)(sd_buf + i*32);
|
||||
if (local_entry->attr1 == 0xf || local_entry->attr1 & 0x8 || !local_entry->attr1) {
|
||||
continue;
|
||||
}
|
||||
cprintf("Name: %.11s\n", local_entry->file_name, local_entry->file_ext);
|
||||
if (!strncmp(local_entry->file_name, name, 11)) {
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != -1) {
|
||||
cprintf("Failed to find file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cprintf("Found file!\n");
|
||||
memcpy(dentry, local_entry, 32);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef _FS_H
|
||||
#define _FS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <process/process.h>
|
||||
|
||||
/* syscalls for files */
|
||||
size_t file_read(int8_t fd, void* buf, size_t nbytes);
|
||||
size_t file_write(int8_t fd, const void* buf, size_t nbytes);
|
||||
int8_t file_open(const char* filename);
|
||||
int8_t file_close(int8_t fd);
|
||||
|
||||
/* syscalls for directories */
|
||||
size_t directory_read(int8_t fd, void* buf, size_t nbytes);
|
||||
size_t directory_write(int8_t fd, const void* buf, size_t nbytes);
|
||||
int8_t directory_open(const char* filename);
|
||||
int8_t directory_close(int8_t fd);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef _INTERRUPT_H
|
||||
#define _INTERRUPT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BUTTON (1 << 0)
|
||||
#define UART (1 << 1)
|
||||
|
||||
void init_interrupts();
|
||||
|
||||
void register_irq(void* addr, uint8_t irqn);
|
||||
|
||||
uint8_t irq_get_status();
|
||||
void irq_set_status(uint8_t);
|
||||
|
||||
#endif
|
||||
@@ -1,76 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.autoimport
|
||||
|
||||
.import _enable_irq
|
||||
.import _map
|
||||
|
||||
.export irq_int, nmi_int
|
||||
.export _register_irq
|
||||
.export _init_interrupts
|
||||
|
||||
IRQ_CMD_ADDR = $effc
|
||||
IRQ_DAT_ADDR = $effd
|
||||
|
||||
IRQ_CMD_READIRQ = $00
|
||||
|
||||
; void init_interrupts();
|
||||
; remap the upper page into ram,
|
||||
; then load the new vector addresses.
|
||||
.proc _init_interrupts
|
||||
; map(001f, f);
|
||||
lda #$1f
|
||||
jsr pushax
|
||||
lda #$f
|
||||
jsr _map
|
||||
|
||||
lda #<irq_int
|
||||
sta $fffe
|
||||
lda #>irq_int
|
||||
sta $ffff
|
||||
|
||||
lda #<nmi_int
|
||||
sta $fffa
|
||||
lda #>nmi_int
|
||||
sta $fffb
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.proc nmi_int
|
||||
rti
|
||||
.endproc
|
||||
|
||||
|
||||
; irq_int
|
||||
.proc irq_int
|
||||
; Load IRQ number
|
||||
lda #IRQ_CMD_READIRQ
|
||||
sta IRQ_CMD_ADDR
|
||||
lda IRQ_DAT_ADDR
|
||||
; shift by 2 (oh so only 128 interrupts are supported lol)
|
||||
asl
|
||||
tax
|
||||
jmp (irq_table,x)
|
||||
; use that to index jump table
|
||||
.endproc
|
||||
|
||||
; void register_irq(void* addr, uint8_t irqn);
|
||||
.proc _register_irq
|
||||
asl
|
||||
tax
|
||||
jsr popa
|
||||
sta irq_table,x
|
||||
jsr popa
|
||||
sta irq_table+1,x
|
||||
|
||||
lda #$00
|
||||
jsr pusha
|
||||
txa
|
||||
lsr
|
||||
jsr _enable_irq
|
||||
rts
|
||||
.endproc
|
||||
|
||||
.data
|
||||
; interrupt handler jump table
|
||||
irq_table: .res 256
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "interrupts/interrupt.h"
|
||||
#include "devices/uart.h"
|
||||
|
||||
|
||||
|
||||
void handle_irq() {
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#include <conio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "devices/interrupt_controller.h"
|
||||
#include "interrupts/interrupt.h"
|
||||
#include "devices/mapper.h"
|
||||
#include "devices/rtc.h"
|
||||
#include "devices/serial.h"
|
||||
#include "devices/terminal.h"
|
||||
|
||||
#include "filesystems/fat32.h"
|
||||
|
||||
|
||||
void handle_rtc_interrupt() {
|
||||
// cputs("In IRQ interrupt!\n");
|
||||
// cputc('A');
|
||||
send_eoi();
|
||||
asm volatile ("rti");
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
|
||||
int main() {
|
||||
int8_t fd;
|
||||
size_t nbytes, i;
|
||||
|
||||
cputs("Kernel\n");
|
||||
|
||||
cputs("Init Mapper\n");
|
||||
init_mapper();
|
||||
|
||||
cputs("Initialize Interrupts\n");
|
||||
init_interrupts();
|
||||
|
||||
cputs("Initialize Interrupt Controller\n");
|
||||
init_interrupt_controller();
|
||||
|
||||
cputs("Initialize RTC\n");
|
||||
init_rtc();
|
||||
|
||||
register_irq(&handle_rtc_interrupt, 0);
|
||||
|
||||
rtc_set(0xaaaa, RTC_THRESHOLD);
|
||||
rtc_set(0xbbbb, RTC_IRQ_THRESHOLD);
|
||||
|
||||
asm volatile("cli");
|
||||
|
||||
cputs("Initialize Serial\n");
|
||||
serial_init();
|
||||
|
||||
serial_puts("Hello from serial!\n");
|
||||
|
||||
fat32_init();
|
||||
|
||||
/* This is what is going to be part of open */
|
||||
fd = fat32_file_open("VERYLA~1TXT");
|
||||
cprintf("fd: %x\n", fd);
|
||||
|
||||
nbytes = fat32_file_read(fd, buf, 23);
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
cprintf("%c", buf[i]);
|
||||
}
|
||||
|
||||
while ((nbytes = fat32_file_read(fd, buf, 128))){
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
cprintf("%c", buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
STACK: start = $200, size = $E00, type = rw, define = yes;
|
||||
KERNEL: start = $1000, size = $7000, type = rw, define = yes, file = %O;
|
||||
USER: start = $8000, size = $6000, type = rw, define = yes;
|
||||
IO: start = $E000, size = $1000, type = rw, define = yes;
|
||||
ROM: start = $f000, size = $1000, type = rw, define = yes; #rw for vectors
|
||||
}
|
||||
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp, define = yes;
|
||||
STARTUP: load = KERNEL, type = ro;
|
||||
ONCE: load = KERNEL, type = ro, optional = yes;
|
||||
CODE: load = KERNEL, type = ro;
|
||||
RODATA: load = KERNEL, type = ro;
|
||||
DATA: load = KERNEL, type = rw, define = yes;
|
||||
BSS: load = KERNEL, type = rw, define = yes;
|
||||
HEAP: load = KERNEL, type = rw, define = yes, optional = yes;
|
||||
}
|
||||
|
||||
FILES
|
||||
{
|
||||
%O: format = o65;
|
||||
}
|
||||
|
||||
FORMATS
|
||||
{
|
||||
o65: os = super, version = 0, type = small,
|
||||
export = _init;
|
||||
}
|
||||
|
||||
FEATURES {
|
||||
CONDES: segment = STARTUP,
|
||||
type = constructor,
|
||||
label = __CONSTRUCTOR_TABLE__,
|
||||
count = __CONSTRUCTOR_COUNT__;
|
||||
CONDES: segment = STARTUP,
|
||||
type = destructor,
|
||||
label = __DESTRUCTOR_TABLE__,
|
||||
count = __DESTRUCTOR_COUNT__;
|
||||
}
|
||||
|
||||
SYMBOLS {
|
||||
__STACKSIZE__: value = $0200, type = weak;
|
||||
__STACKSTART__: type = weak, value = $0800;
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#include <process/process.h>
|
||||
|
||||
|
||||
struct pcb fake_pcb;
|
||||
|
||||
//TODO
|
||||
struct pcb* get_pcb_ptr() {
|
||||
return &fake_pcb;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef _PROCESS_H
|
||||
#define _PROCESS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <filesystems/fat32.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FILE_DESC_SIZE 8
|
||||
|
||||
|
||||
#define IN_USE 1
|
||||
|
||||
|
||||
struct fops {
|
||||
int8_t (*open)(const char* filename);
|
||||
int8_t (*close)(int8_t fd);
|
||||
size_t (*read)(int8_t fd, void* buf, size_t nbytes);
|
||||
size_t (*write)(int8_t fd, const void* buf, size_t nbytes);
|
||||
};
|
||||
|
||||
struct file_desc {
|
||||
struct fops* file_ops;
|
||||
uint8_t fs_type;
|
||||
union {
|
||||
struct fat32_directory_entry f32_dentry;
|
||||
};
|
||||
uint32_t file_pos;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/* Process Control Block struct */
|
||||
struct pcb {
|
||||
struct file_desc file_desc_array[FILE_DESC_SIZE];
|
||||
int32_t is_vidmapped;
|
||||
uint8_t args[128];
|
||||
uint16_t execute_return;
|
||||
uint16_t pid;
|
||||
uint16_t parent_pid;
|
||||
uint16_t parent_esp;
|
||||
};
|
||||
|
||||
|
||||
struct pcb* get_pcb_ptr();
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
DEVICE=/dev/mmcblk0
|
||||
TMPMOUNT=/tmp/sd
|
||||
FSDIR=../fsdir
|
||||
|
||||
V=-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
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
BOOTLOADER=$REPO_TOP/sw/bios/bootloader.bin
|
||||
FILE=$REPO_TOP/sw/script/fs.fat
|
||||
|
||||
TMPMOUNT=/tmp/lo
|
||||
FSDIR=$REPO_TOP/sw/fsdir
|
||||
|
||||
MNT=/run/media/$USER/SUPER6502
|
||||
|
||||
V=-v
|
||||
|
||||
# Smallest number of blocks where mkfs doesn't complain
|
||||
BLOCKS=33296
|
||||
|
||||
rm $FILE
|
||||
|
||||
echo "$(tput bold setaf 11)Creating Filesystem$(tput sgr 0)"
|
||||
mkfs.vfat $V -I -F32 -C $FILE -n SUPER6502 $BLOCKS
|
||||
echo
|
||||
|
||||
echo "$(tput bold setaf 11)Modifying Boot Sector$(tput sgr 0)"
|
||||
dd if=$BOOTLOADER of=$FILE bs=1 conv=notrunc count=11 $STATUS
|
||||
dd if=$BOOTLOADER of=$FILE bs=1 conv=notrunc count=380 seek=71 skip=71 $STATUS
|
||||
|
||||
|
||||
LOOP=$(udisksctl loop-setup -f $FILE | grep -o "/dev/loop\([0-9]\)\+")
|
||||
MNT=$(udisksctl mount -b $LOOP $TMPMOUNT | grep -o "\([A-Za-z/-]*/\)SUPER6502")
|
||||
|
||||
echo "$(tput bold setaf 11)Copying Files$(tput sgr 0)"
|
||||
cp $V -r $FSDIR/* $MNT
|
||||
echo
|
||||
|
||||
udisksctl unmount -b $LOOP
|
||||
|
||||
udisksctl loop-delete -b $LOOP
|
||||
|
||||
echo "$(tput bold setaf 10)Done!$(tput sgr 0)"
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
BOOTLOADER=$REPO_TOP/sw/bios/bootloader.bin
|
||||
DEVICE=/dev/mmcblk0
|
||||
TMPBOOTSECT=/tmp/bootsect
|
||||
TMPMOUNT=/tmp/sd
|
||||
|
||||
V=-v
|
||||
# STATUS="status=none"
|
||||
STATUS=
|
||||
|
||||
echo "$(tput bold setaf 11)Creating Filesystem$(tput sgr 0)"
|
||||
sudo mkfs.vfat -I -F32 $DEVICE -n SUPER6502 $V
|
||||
echo
|
||||
|
||||
echo "$(tput bold setaf 11)Modifying Boot Sector$(tput sgr 0)"
|
||||
sudo dd if=$BOOTLOADER of=$DEVICE bs=1 count=11 $STATUS
|
||||
sudo dd if=$BOOTLOADER of=$DEVICE bs=1 count=380 seek=71 skip=71 $STATUS
|
||||
|
||||
echo "$(tput bold setaf 10)Done!$(tput sgr 0)"
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
import io
|
||||
|
||||
class O65():
|
||||
|
||||
header: dict[str, int] = {}
|
||||
options: list[(int, int, bytes)] = []
|
||||
text: bytes
|
||||
data: bytes
|
||||
undef_ref_cnt: int
|
||||
text_reloc: list[(int, int, int)] = []
|
||||
data_reloc: list[(int, int, int)] = []
|
||||
exports: list[(str, int, int)] = []
|
||||
|
||||
def __init__(self, filename: str) -> None:
|
||||
with open(filename, "rb") as _file:
|
||||
self.header["no_c64"] = int.from_bytes(_file.read(2))
|
||||
self.header["magic"] = int.from_bytes(_file.read(3))
|
||||
self.header["version"] = int.from_bytes(_file.read(1))
|
||||
self.header["mode"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["tbase"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["tlen"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["dbase"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["dlen"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["bbase"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["blen"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["zbase"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["zlen"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.header["stack"] = int.from_bytes(_file.read(2), byteorder="little")
|
||||
|
||||
olen = int.from_bytes(_file.read(1))
|
||||
while olen != 0:
|
||||
otype = int.from_bytes(_file.read(1))
|
||||
obytes = _file.read(olen - 2)
|
||||
self.options.append((olen, otype, obytes))
|
||||
olen = int.from_bytes(_file.read(1))
|
||||
|
||||
text_offs = _file.tell()
|
||||
print(f"Text offset: {text_offs}")
|
||||
|
||||
self.text = _file.read(self.header["tlen"])
|
||||
self.data = _file.read(self.header["dlen"])
|
||||
|
||||
self.undef_ref_cnt = _file.read(2)
|
||||
|
||||
self.text_reloc = self._parse_reloc(_file)
|
||||
self.data_reloc = self._parse_reloc(_file)
|
||||
|
||||
export_count = int.from_bytes(_file.read(2), byteorder="little")
|
||||
for _ in range(export_count):
|
||||
name: bytearray = bytearray()
|
||||
data = 0
|
||||
while True:
|
||||
data = _file.read(1)
|
||||
if data != b"\x00":
|
||||
name.extend(data)
|
||||
else:
|
||||
break
|
||||
segment = int.from_bytes(_file.read(1))
|
||||
value = int.from_bytes(_file.read(2), byteorder="little")
|
||||
self.exports.append((name.decode(), segment, value))
|
||||
|
||||
def _parse_reloc(self, fd: io.BufferedReader) -> list[(int, int, int)]:
|
||||
reloc: list[(int, int, int)] = []
|
||||
offset = fd.read(1)
|
||||
while offset != b'\x00':
|
||||
offset_val = 0
|
||||
while offset == b'\xff':
|
||||
offset = fd.read(1)
|
||||
offset_val += int.from_bytes(offset) - 1
|
||||
offset_val += int.from_bytes(offset)
|
||||
typebyte = int.from_bytes(fd.read(1))
|
||||
lobyte = None
|
||||
if typebyte & 0x40:
|
||||
lobyte = int.from_bytes(fd.read(1))
|
||||
reloc.append((offset_val, typebyte, lobyte))
|
||||
offset = fd.read(1)
|
||||
return reloc
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if len(sys.argv) < 2:
|
||||
print("Please supply a filename")
|
||||
return
|
||||
filename = sys.argv[1]
|
||||
print(filename)
|
||||
o65 = O65(filename)
|
||||
for item, value in o65.header.items():
|
||||
print(f"{item}:\t{value:#x}")
|
||||
|
||||
total_olen = 0
|
||||
for option in o65.options:
|
||||
print(f"Length: {option[0]:#x} Type: {option[1]:#x}, Data: {option[2]}")
|
||||
total_olen += option[0]
|
||||
|
||||
print(f"Total option length: {total_olen:#x}")
|
||||
|
||||
print(f"Text size: {len(o65.text)}")
|
||||
print(f"Data size: {len(o65.data)}")
|
||||
|
||||
for item in o65.exports:
|
||||
print(f"Name: {item[0]} Addr: {item[2]:#x}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=devices_setup_test
|
||||
|
||||
DEVICES=$(REPO_TOP)/sw/kernel/devices
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(DEVICES)/rtc.s $(DEVICES)/interrupt_controller.s
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
.export _init, nmi_int, irq_int
|
||||
|
||||
.autoimport
|
||||
|
||||
.import _init_interrupt_controller
|
||||
.import _init_rtc
|
||||
|
||||
.zeropage
|
||||
|
||||
finish: .res 1
|
||||
|
||||
.code
|
||||
|
||||
nmi_int:
|
||||
irq_int:
|
||||
lda #$6d
|
||||
sta $00
|
||||
|
||||
_init:
|
||||
ldx #$ff
|
||||
txs
|
||||
|
||||
LDA #<(__STACKSTART__ + __STACKSIZE__)
|
||||
STA sp
|
||||
LDA #>(__STACKSTART__ + __STACKSIZE__)
|
||||
STA sp+1
|
||||
|
||||
jsr _init_interrupt_controller
|
||||
jsr _init_rtc
|
||||
|
||||
; enable interrupt 0
|
||||
lda #$00
|
||||
jsr pusha
|
||||
lda #$0
|
||||
jsr _enable_irq
|
||||
|
||||
cli
|
||||
|
||||
@end: bra @end
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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,49 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
SIM=../../cc65/bin/sim65
|
||||
CFLAGS=-T -t sim65c02 -I. -I $(REPO_TOP)/sw/kernel
|
||||
LDFLAGS=-m $(NAME).map
|
||||
|
||||
NAME=fs_test
|
||||
|
||||
SIMARGS=
|
||||
|
||||
BIN=$(NAME).bin
|
||||
|
||||
FS=$(REPO_TOP)/sw/script/fs.fat
|
||||
|
||||
LISTS=lists
|
||||
|
||||
EXT_SRCS=$(REPO_TOP)/sw/kernel/filesystems/fat32.s $(REPO_TOP)/sw/kernel/filesystems/fat32_c.c
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
SRCS+=$(EXT_SRCS)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
run: all
|
||||
$(SIM) $(SIMARGS) $(BIN)
|
||||
|
||||
all: fs.fat $(BIN)
|
||||
|
||||
$(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 $@
|
||||
|
||||
fs.fat: $(FS)
|
||||
cp $^ .
|
||||
|
||||
|
||||
$(LISTS):
|
||||
mkdir -p $(addprefix $(LISTS)/,$(sort $(dir $(SRCS))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.import _printf
|
||||
.export _cprintf
|
||||
|
||||
_cprintf:
|
||||
jmp _printf
|
||||
@@ -1,32 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <process/process.h>
|
||||
|
||||
#define FILE_PATH "fs.fat"
|
||||
|
||||
struct pcb fake_pcb;
|
||||
|
||||
//TODO
|
||||
struct pcb* get_pcb_ptr() {
|
||||
return &fake_pcb;
|
||||
}
|
||||
|
||||
uint32_t lmulii(uint16_t a, uint16_t b) {
|
||||
printf("lmulii: %x * %x = %x\n", a, b, a*b);
|
||||
return a * b;
|
||||
}
|
||||
|
||||
uint16_t imulii(uint16_t a, uint16_t b) {
|
||||
printf("imulii: %x * %x = %x\n", a, b, a*b);
|
||||
return a * b;
|
||||
}
|
||||
|
||||
uint8_t SD_readSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *error) {
|
||||
FILE* f = fopen(FILE_PATH, "rb");
|
||||
(void)error;
|
||||
fseek(f, addr * 512, SEEK_SET);
|
||||
fread(buf, 512, 1, f);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <filesystems/fat32.h>
|
||||
#include <conio.h>
|
||||
|
||||
void fat32_init(void);
|
||||
|
||||
char data [256];
|
||||
|
||||
int main(void) {
|
||||
int8_t fd;
|
||||
size_t i;
|
||||
size_t nbytes;
|
||||
fat32_init();
|
||||
|
||||
cprintf("log2 sectors per cluster: %x\n", log2_sectors_per_cluster);
|
||||
|
||||
/* This is what is going to be part of open */
|
||||
fd = fat32_file_open("VERYLA~1TXT");
|
||||
cprintf("fd: %x\n", fd);
|
||||
|
||||
nbytes = fat32_file_read(fd, data, 123);
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
cprintf("%c", data[i]);
|
||||
}
|
||||
|
||||
while ((nbytes = fat32_file_read(fd, data, 256))){
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
cprintf("%c", data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=indirect_test
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
.export _init, _nmi_int, _irq_int
|
||||
|
||||
.code
|
||||
|
||||
_nmi_int:
|
||||
_irq_int:
|
||||
|
||||
_init:
|
||||
ldx #$ff
|
||||
txs
|
||||
|
||||
lda #$aa
|
||||
sta $01
|
||||
lda #$bb
|
||||
sta $00
|
||||
ldy #$1
|
||||
lda #$cc
|
||||
sta ($00),y
|
||||
|
||||
@end: bra @end
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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,39 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=irq_test
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.export _init, _nmi_int, _irq_int
|
||||
|
||||
.importzp tmp1
|
||||
|
||||
CMD = $effc
|
||||
DAT = $effd
|
||||
|
||||
.zeropage
|
||||
finish: .res 1
|
||||
curr_irq: .res 1
|
||||
|
||||
.code
|
||||
|
||||
_nmi_int:
|
||||
_irq_int:
|
||||
; We should have triggered interrupt 1
|
||||
stz CMD
|
||||
lda DAT
|
||||
cmp curr_irq
|
||||
bne @bad
|
||||
|
||||
lda #$ff
|
||||
sta CMD
|
||||
lda #$1
|
||||
sta DAT
|
||||
|
||||
inc curr_irq
|
||||
beq @good
|
||||
cli
|
||||
rti
|
||||
|
||||
@good:
|
||||
lda #$6d
|
||||
sta finish
|
||||
|
||||
@bad:
|
||||
lda #$bd
|
||||
sta finish
|
||||
|
||||
_init:
|
||||
ldx #$ff
|
||||
txs
|
||||
ldx #$20 ; enable
|
||||
ldy #$ff
|
||||
jsr cmd_all
|
||||
ldx #$40 ; edge type
|
||||
ldy #$00
|
||||
jsr cmd_all
|
||||
stz curr_irq
|
||||
cli
|
||||
jmp wait
|
||||
|
||||
cmd_all:
|
||||
txa
|
||||
add #$10
|
||||
sta tmp1
|
||||
loop:
|
||||
txa
|
||||
sta CMD
|
||||
tya
|
||||
sta DAT
|
||||
inx
|
||||
cpx tmp1
|
||||
blt loop
|
||||
rts
|
||||
|
||||
wait:
|
||||
bra wait
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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,39 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=jsr_test
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
.export _init, _nmi_int, _irq_int
|
||||
|
||||
.code
|
||||
|
||||
_nmi_int:
|
||||
_irq_int:
|
||||
|
||||
_init:
|
||||
ldx #$ff
|
||||
txs
|
||||
lda #$00
|
||||
jsr subroutine
|
||||
sta $00
|
||||
@1: bra @1
|
||||
|
||||
subroutine:
|
||||
inc
|
||||
jsr suborutine2
|
||||
rts
|
||||
|
||||
suborutine2:
|
||||
inc
|
||||
rts
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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,39 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=loop_test
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
.export _init, _nmi_int, _irq_int
|
||||
|
||||
.code
|
||||
|
||||
_nmi_int:
|
||||
_irq_int:
|
||||
|
||||
_init:
|
||||
lda #$00
|
||||
@1: inc
|
||||
sta $01
|
||||
lda $01
|
||||
cmp $01
|
||||
beq @1
|
||||
|
||||
@end: bra @end
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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,39 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=mapper_test
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
.export _init, _nmi_int, _irq_int
|
||||
|
||||
.code
|
||||
|
||||
_nmi_int:
|
||||
_irq_int:
|
||||
|
||||
MAPPER_BASE = $200
|
||||
|
||||
_init:
|
||||
ldx #$ff
|
||||
txs
|
||||
|
||||
lda #$10
|
||||
sta MAPPER_BASE + 2
|
||||
|
||||
; This should store 0x55aa to memory $010000, instead of $001000
|
||||
|
||||
lda #$aa
|
||||
sta $1000
|
||||
lda #$55
|
||||
sta $1001
|
||||
|
||||
lda #$01
|
||||
sta MAPPER_BASE + 2
|
||||
|
||||
; This should store 0xddcc to memory $001000
|
||||
|
||||
lda #$cc
|
||||
sta $1000
|
||||
lda #$dd
|
||||
sta $1001
|
||||
|
||||
lda #$10
|
||||
sta MAPPER_BASE + 2
|
||||
|
||||
lda $1000
|
||||
cmp #$aa
|
||||
bne @bad
|
||||
lda $1001
|
||||
cmp #$55
|
||||
bne @bad
|
||||
|
||||
lda #$01
|
||||
sta MAPPER_BASE + 2
|
||||
|
||||
lda $1000
|
||||
cmp #$cc
|
||||
bne @bad
|
||||
lda $1001
|
||||
cmp #$dd
|
||||
bne @bad
|
||||
|
||||
@end:
|
||||
lda #$6d
|
||||
sta $00
|
||||
bra @end
|
||||
|
||||
|
||||
@bad:
|
||||
lda #$bd
|
||||
sta $00
|
||||
bra @bad
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; 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,39 +0,0 @@
|
||||
CC=../../cc65/bin/cl65
|
||||
LD=../../cc65/bin/cl65
|
||||
CFLAGS=-T -t none -I. --cpu "65C02"
|
||||
LDFLAGS=-C link.ld -m $(NAME).map
|
||||
|
||||
NAME=multiplier_test
|
||||
|
||||
BIN=$(NAME).bin
|
||||
HEX=$(NAME).hex
|
||||
|
||||
LISTS=lists
|
||||
|
||||
SRCS=$(wildcard *.s) $(wildcard *.c)
|
||||
SRCS+=$(wildcard **/*.s) $(wildcard **/*.c)
|
||||
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
|
||||
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
|
||||
|
||||
# Make sure the kernel linked to correct address, no relocation!
|
||||
all: $(HEX)
|
||||
|
||||
$(HEX): $(BIN)
|
||||
objcopy --input-target=binary --output-target=verilog $(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))))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
MEMORY
|
||||
{
|
||||
ZP: start = $0, size = $100, type = rw, define = yes;
|
||||
SDRAM: start = $9200, size = $4d00, type = rw, define = yes;
|
||||
ROM: start = $F000, size = $1000, 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
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
.MACPACK generic
|
||||
|
||||
.export _init, _nmi_int, _irq_int
|
||||
|
||||
MULTIPLIER_BASE = $eff0
|
||||
|
||||
MULTIPLIER_AL = MULTIPLIER_BASE + 0
|
||||
MULTIPLIER_AH = MULTIPLIER_BASE + 1
|
||||
MULTIPLIER_BL = MULTIPLIER_BASE + 2
|
||||
MULTIPLIER_BH = MULTIPLIER_BASE + 3
|
||||
|
||||
MULTIPLIER_OLL = MULTIPLIER_BASE + 4
|
||||
MULTIPLIER_OLH = MULTIPLIER_BASE + 5
|
||||
MULTIPLIER_OHL = MULTIPLIER_BASE + 6
|
||||
MULTIPLIER_OHH = MULTIPLIER_BASE + 7
|
||||
|
||||
GOLDEN_OUTPUT_0 = $03
|
||||
GOLDEN_OUTPUT_1 = $0a
|
||||
GOLDEN_OUTPUT_2 = $08
|
||||
GOLDEN_OUTPUT_3 = $00
|
||||
|
||||
.zeropage
|
||||
finish: .res 1
|
||||
|
||||
.data
|
||||
|
||||
output: .res 4
|
||||
|
||||
.code
|
||||
|
||||
_nmi_int:
|
||||
_irq_int:
|
||||
|
||||
_init:
|
||||
ldx #$ff
|
||||
txs
|
||||
|
||||
lda #$01
|
||||
sta MULTIPLIER_AL
|
||||
lda #$02
|
||||
sta MULTIPLIER_AH
|
||||
|
||||
lda #$03
|
||||
sta MULTIPLIER_BL
|
||||
lda #$04
|
||||
sta MULTIPLIER_BH
|
||||
|
||||
ldx #$00
|
||||
L1: lda MULTIPLIER_OLL,x
|
||||
sta output,x
|
||||
inx
|
||||
cpx #$4
|
||||
bne L1
|
||||
|
||||
lda output
|
||||
cmp #GOLDEN_OUTPUT_0
|
||||
bne fail
|
||||
lda output+1
|
||||
cmp #GOLDEN_OUTPUT_1
|
||||
bne fail
|
||||
lda output+2
|
||||
cmp #GOLDEN_OUTPUT_2
|
||||
bne fail
|
||||
lda output+3
|
||||
cmp #GOLDEN_OUTPUT_3
|
||||
bne fail
|
||||
|
||||
lda #$6d
|
||||
sta finish
|
||||
|
||||
fail:
|
||||
lda #$bd
|
||||
sta finish
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user