Delete everything
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user