sdc: support 24-bit addressing
Needed if we want to compile the kernel and zasm from within a SD card. I didn't go straight for 32-bit because it was significantly more complex and 24-bit give us 16M. Enough to go on for a while...
This commit is contained in:
parent
605c631dc0
commit
92a04f4627
@ -5,7 +5,12 @@ sdctMain:
|
||||
ld de, SDCT_RAMSTART
|
||||
.wLoop:
|
||||
ld a, (de)
|
||||
call sdcPutC
|
||||
; To avoid overwriting important data and to test the 24-bit addressing,
|
||||
; we set DE to 12 instead of zero
|
||||
push de ; <|
|
||||
ld de, 12 ; |
|
||||
call sdcPutC ; |
|
||||
pop de ; <|
|
||||
jr nz, .error
|
||||
inc hl
|
||||
inc de
|
||||
@ -23,7 +28,10 @@ sdctMain:
|
||||
ld hl, 0
|
||||
ld de, SDCT_RAMSTART
|
||||
.rLoop:
|
||||
call sdcGetC
|
||||
push de ; <|
|
||||
ld de, 12 ; |
|
||||
call sdcGetC ; |
|
||||
pop de ; <|
|
||||
jr nz, .error
|
||||
ex de, hl
|
||||
cp (hl)
|
||||
|
137
kernel/sdc.asm
137
kernel/sdc.asm
@ -59,16 +59,16 @@
|
||||
; This is a pointer to the currently selected buffer. This points to the BUFSEC
|
||||
; part, that is, two bytes before actual content begins.
|
||||
.equ SDC_BUFPTR SDC_RAMSTART
|
||||
; Sector number currently in SDC_BUF1.
|
||||
; Sector number currently in SDC_BUF1. Little endian like any other z80 word.
|
||||
.equ SDC_BUFSEC1 SDC_BUFPTR+2
|
||||
; Whether the buffer has been written to. 0 means clean. 1 means dirty.
|
||||
.equ SDC_BUFDIRTY1 SDC_BUFSEC1+1
|
||||
.equ SDC_BUFDIRTY1 SDC_BUFSEC1+2
|
||||
; The contents of the buffer.
|
||||
.equ SDC_BUF1 SDC_BUFDIRTY1+1
|
||||
|
||||
; second buffer has the same structure as the first.
|
||||
.equ SDC_BUFSEC2 SDC_BUF1+SDC_BLKSIZE
|
||||
.equ SDC_BUFDIRTY2 SDC_BUFSEC2+1
|
||||
.equ SDC_BUFDIRTY2 SDC_BUFSEC2+2
|
||||
.equ SDC_BUF2 SDC_BUFDIRTY2+1
|
||||
.equ SDC_RAMEND SDC_BUF2+SDC_BLKSIZE
|
||||
|
||||
@ -301,21 +301,18 @@ sdcSetBlkSize:
|
||||
pop hl
|
||||
ret
|
||||
|
||||
; Read block index specified in A and place the contents in buffer pointed to
|
||||
; Read block index specified in DE and place the contents in buffer pointed to
|
||||
; by (SDC_BUFPTR).
|
||||
; Doesn't check CRC. If the operation is a success, updates buffer's sector to
|
||||
; the value of A.
|
||||
; the value of DE.
|
||||
; Returns 0 in A if success, non-zero if error.
|
||||
sdcReadBlk:
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
|
||||
out (SDC_PORT_CSLOW), a
|
||||
ld hl, 0 ; read single block at addr A
|
||||
ld d, 0
|
||||
ld e, a ; E isn't touched in the rest of the routine
|
||||
; and holds onto our original A
|
||||
ld hl, 0
|
||||
; DE already has the correct value
|
||||
ld a, 0b01010001 ; CMD17
|
||||
call sdcCmd
|
||||
or a ; cp 0
|
||||
@ -341,7 +338,10 @@ sdcReadBlk:
|
||||
; actual data, but at this point, we don't have any error conditions
|
||||
; left, success is guaranteed. To avoid needlesssly INCing hl, let's
|
||||
; set sector and dirty along the way
|
||||
ld a, e ; sector number
|
||||
ld a, e ; sector number LSB
|
||||
ld (hl), a
|
||||
inc hl ; sector number MSB
|
||||
ld a, d
|
||||
ld (hl), a
|
||||
inc hl ; dirty flag
|
||||
xor a ; unset
|
||||
@ -368,7 +368,6 @@ sdcReadBlk:
|
||||
.end:
|
||||
out (SDC_PORT_CSHIGH), a
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
ret
|
||||
|
||||
@ -377,7 +376,8 @@ sdcReadBlk:
|
||||
; A returns 0 in A on success (with Z set), non-zero (with Z unset) on error.
|
||||
sdcWriteBlk:
|
||||
push hl
|
||||
ld hl, (SDC_BUFPTR) ; HL points to sector
|
||||
ld hl, (SDC_BUFPTR) ; HL points to sector LSB
|
||||
inc hl ; sector MSB
|
||||
inc hl ; now to dirty flag
|
||||
xor a
|
||||
cp (hl)
|
||||
@ -389,11 +389,13 @@ sdcWriteBlk:
|
||||
push de
|
||||
|
||||
out (SDC_PORT_CSLOW), a
|
||||
dec hl ; sector
|
||||
dec hl ; sector MSB
|
||||
ld a, (hl)
|
||||
ld d, a
|
||||
dec hl ; sector LSB
|
||||
ld a, (hl)
|
||||
ld hl, 0 ; write single block at addr A
|
||||
ld d, 0
|
||||
ld e, a
|
||||
ld hl, 0 ; high addr word always zero, DE already set
|
||||
ld a, 0b01011000 ; CMD24
|
||||
call sdcCmd
|
||||
or a ; cp 0
|
||||
@ -411,6 +413,7 @@ sdcWriteBlk:
|
||||
; Sending our data token!
|
||||
ld bc, SDC_BLKSIZE
|
||||
ld hl, (SDC_BUFPTR)
|
||||
inc hl ; sector MSB
|
||||
inc hl ; dirty flag
|
||||
inc hl ; beginning of contents
|
||||
|
||||
@ -434,6 +437,7 @@ sdcWriteBlk:
|
||||
call sdcWaitResp
|
||||
; Success! Now let's unset the dirty flag
|
||||
ld hl, (SDC_BUFPTR)
|
||||
inc hl ; sector MSB
|
||||
inc hl ; dirty flag
|
||||
xor a
|
||||
ld (hl), a
|
||||
@ -456,72 +460,83 @@ sdcWriteBlk:
|
||||
pop hl
|
||||
ret
|
||||
|
||||
; Considering the first 7 bits of HL, select the most appropriate of our two
|
||||
; Considering the first 15 bits of EHL, select the most appropriate of our two
|
||||
; buffers and, if necessary, sync that buffer with the SD card. If the selected
|
||||
; buffer doesn't have the same sector as what HL asks, load that buffer from
|
||||
; buffer doesn't have the same sector as what EHL asks, load that buffer from
|
||||
; the SD card.
|
||||
; If the dirty flag is set, we write the content of the in-memory buffer to the
|
||||
; SD card before we read a new sector.
|
||||
; Returns Z on success, not-Z on error (with the error code from either
|
||||
; sdcReadBlk or sdcWriteBlk)
|
||||
sdcSync:
|
||||
; HL points to the character we're supposed to read or right now. Let's
|
||||
; extract the wanted sector from this.
|
||||
push de
|
||||
; Given a 24-bit address in EHL, extracts the 15-bit sector from it and
|
||||
; place it in DE.
|
||||
; We need to shift both E and H right by one bit
|
||||
srl e ; sets Carry
|
||||
ld d, e
|
||||
ld a, h
|
||||
srl a ; A --> the requested sector number
|
||||
push hl ; Save the requested addr for later
|
||||
ld l, a
|
||||
rra ; takes Carry
|
||||
ld e, a
|
||||
|
||||
; Let's first see if our first buffer has our sector
|
||||
ld a, (SDC_BUFSEC1)
|
||||
cp l
|
||||
ld a, (SDC_BUFSEC1) ; sector LSB
|
||||
cp e
|
||||
jr nz, .notBuf1
|
||||
ld a, (SDC_BUFSEC1+1) ; sector MSB
|
||||
cp d
|
||||
jr z, .buf1Ok
|
||||
|
||||
.notBuf1:
|
||||
; Ok, let's check for buf2 then
|
||||
ld a, (SDC_BUFSEC2)
|
||||
cp l
|
||||
ld a, (SDC_BUFSEC2) ; sector LSB
|
||||
cp e
|
||||
jr nz, .notBuf2
|
||||
ld a, (SDC_BUFSEC2+1) ; sector MSB
|
||||
cp d
|
||||
jr z, .buf2Ok
|
||||
|
||||
.notBuf2:
|
||||
; None of our two buffers have the sector we need, we'll need to load
|
||||
; a new one.
|
||||
|
||||
; We select our buffer depending on which is dirty. If both are on the
|
||||
; same status of dirtiness, we pick any (the first in our case). If one
|
||||
; of them is dirty, we pick the clean one.
|
||||
ld hl, SDC_BUFSEC1
|
||||
ld a, (SDC_BUFDIRTY1)
|
||||
or a ; is buf1 dirty?
|
||||
jr z, .ready ; no? good, that's our buffer
|
||||
; yes? then buf2 is our buffer.
|
||||
ld hl, SDC_BUFSEC2
|
||||
|
||||
.ready:
|
||||
; At this point, HL points to one of our two buffers, the good one.
|
||||
; Let's save it to SDC_BUFPTR
|
||||
ld (SDC_BUFPTR), hl
|
||||
|
||||
; You remember that HL we saved a long time ago? Now's the time to
|
||||
; bring it back.
|
||||
pop hl
|
||||
push de ; <|
|
||||
ld de, SDC_BUFSEC1 ; |
|
||||
ld a, (SDC_BUFDIRTY1) ; |
|
||||
or a ; | is buf1 dirty?
|
||||
jr z, .ready ; | no? good, that's our buffer
|
||||
; yes? then buf2 is our buffer. ; |
|
||||
ld de, SDC_BUFSEC2 ; |
|
||||
; |
|
||||
.ready: ; |
|
||||
; At this point, DE points to one o|f our two buffers, the good one.
|
||||
; Let's save it to SDC_BUFPTR |
|
||||
ld (SDC_BUFPTR), de ; |
|
||||
; |
|
||||
pop de ; <|
|
||||
|
||||
; We have to read a new sector, but first, let's write the current one
|
||||
; if needed.
|
||||
call sdcWriteBlk
|
||||
ret nz ; error
|
||||
; Let's read our new sector
|
||||
ld a, h
|
||||
srl a
|
||||
jp sdcReadBlk ; returns
|
||||
jr nz, .end ; error
|
||||
; Let's read our new sector in DE
|
||||
call sdcReadBlk
|
||||
jr .end
|
||||
|
||||
.buf1Ok:
|
||||
ld hl, SDC_BUFSEC1
|
||||
ld (SDC_BUFPTR), hl
|
||||
pop hl
|
||||
ret
|
||||
ld de, SDC_BUFSEC1
|
||||
ld (SDC_BUFPTR), de
|
||||
jr .end
|
||||
|
||||
.buf2Ok:
|
||||
ld hl, SDC_BUFSEC2
|
||||
ld (SDC_BUFPTR), hl
|
||||
pop hl
|
||||
ld de, SDC_BUFSEC2
|
||||
ld (SDC_BUFPTR), de
|
||||
; to .end
|
||||
.end:
|
||||
pop de
|
||||
ret
|
||||
|
||||
; *** shell cmds ***
|
||||
@ -539,12 +554,13 @@ sdcInitializeCmd:
|
||||
; way, no need for special conditions.
|
||||
; initialize variables
|
||||
ld hl, SDC_BUFSEC1
|
||||
xor a
|
||||
ld (SDC_BUFPTR), hl
|
||||
ld de, 0
|
||||
call sdcReadBlk ; read sector 0 in buf1
|
||||
ret nz
|
||||
ld hl, SDC_BUFSEC2
|
||||
inc a
|
||||
ld (SDC_BUFPTR), hl
|
||||
inc de
|
||||
jp sdcReadBlk ; read sector 1 in buf2, returns
|
||||
|
||||
; Flush the current SDC buffer if dirty
|
||||
@ -561,13 +577,17 @@ sdcFlushCmd:
|
||||
; *** blkdev routines ***
|
||||
|
||||
; Make HL point to its proper place in SDC_BUF.
|
||||
; HL currently is an offset to read in the SD card. Load the proper sector in
|
||||
; memory and make HL point to the correct data in the memory buffer.
|
||||
; EHL currently is a 24-bit offset to read in the SD card. E=high byte,
|
||||
; HL=low word. Load the proper sector in memory and make HL point to the
|
||||
; correct data in the memory buffer.
|
||||
_sdcPlaceBuf:
|
||||
call sdcSync
|
||||
ret nz ; error
|
||||
; At this point, we have the proper buffer in place and synced in
|
||||
; (SDC_BUFPTR). Only the 9 low bits of HL are important.
|
||||
push de
|
||||
ld de, (SDC_BUFPTR)
|
||||
inc de ; sector LSB
|
||||
inc de ; dirty flag
|
||||
inc de ; contents
|
||||
ld a, h ; high byte
|
||||
@ -617,6 +637,7 @@ sdcPutC:
|
||||
; Now, let's set the dirty flag
|
||||
ld a, 1
|
||||
ld hl, (SDC_BUFPTR)
|
||||
inc hl ; sector MSB
|
||||
inc hl ; point to dirty flag
|
||||
ld (hl), a ; set dirty flag
|
||||
xor a ; ensure Z
|
||||
|
@ -1,4 +1,9 @@
|
||||
CFSTARGETS = cfsin/zasm cfsin/sdct cfsin/user.h
|
||||
# source files required to build os.bin. We copy them in cfsin so that we can
|
||||
# build the same kernel from within the RC2014.
|
||||
KERNEL_SRCS = err.h acia.asm blockdev.asm blockdev_cmds.asm core.asm fs.asm \
|
||||
fs_cmds.asm mmap.asm parse.asm pgm.asm sdc.asm shell.asm stdio.asm
|
||||
|
||||
CFSTARGETS = $(addprefix cfsin/, zasm sdct at28w user.h $(KERNEL_SRCS))
|
||||
BASE = ../../..
|
||||
TOOLS = $(BASE)/tools
|
||||
ZASM = $(TOOLS)/zasm.sh
|
||||
@ -24,5 +29,16 @@ cfsin/zasm: $(ZASMBIN)
|
||||
cfsin/sdct: $(ZASMBIN)
|
||||
$(ZASM) $(APPS) user.h < $(APPS)/sdct/glue.asm > $@
|
||||
|
||||
cfsin/at28w: $(ZASMBIN)
|
||||
$(ZASM) $(APPS) $(KERNEL) user.h < $(APPS)/at28w/glue.asm > $@
|
||||
|
||||
cfsin/user.h: user.h
|
||||
cp $< $@
|
||||
cfsin/err.h: $(KERNEL)/err.h
|
||||
cp $< $@
|
||||
cfsin/%.asm: $(KERNEL)/%.asm
|
||||
cp $< $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(CFSTARGETS) sdcard.cfs os.bin
|
||||
|
@ -1,10 +1,10 @@
|
||||
; classic RC2014 setup (8K ROM + 32K RAM) and a stock Serial I/O module
|
||||
; The RAM module is selected on A15, so it has the range 0x8000-0xffff
|
||||
.equ RAMSTART 0x8000
|
||||
; kernel RAM usage, because of SDC, is a bit high and bring us almost to 0x9c00
|
||||
; kernel RAM usage, because of SDC, is a bit high and bring us almost to 0x9e00
|
||||
; We allocate at least 0x100 bytes for RAM, which is why we have this threshold.
|
||||
; for the stack.
|
||||
.equ RAMEND 0x9d00
|
||||
.equ RAMEND 0xa000
|
||||
.equ PGM_CODEADDR RAMEND
|
||||
.equ ACIA_CTL 0x80 ; Control and status. RS off.
|
||||
.equ ACIA_IO 0x81 ; Transmit. RS on.
|
||||
@ -44,11 +44,12 @@ jp aciaInt
|
||||
jp printHexPair
|
||||
jp sdcGetC
|
||||
jp sdcPutC
|
||||
jp blkGetC
|
||||
|
||||
#include "err.h"
|
||||
#include "core.asm"
|
||||
#include "parse.asm"
|
||||
.equ ACIA_RAMSTART RAMSTART
|
||||
.equ ACIA_RAMSTART RAMSTART
|
||||
#include "acia.asm"
|
||||
.equ BLOCKDEV_RAMSTART ACIA_RAMEND
|
||||
.equ BLOCKDEV_COUNT 4
|
||||
|
@ -1,4 +1,4 @@
|
||||
.equ USER_CODE 0x9d00
|
||||
.equ USER_CODE 0xa000
|
||||
.equ USER_RAMSTART USER_CODE+0x1800
|
||||
.equ FS_HANDLE_SIZE 6
|
||||
.equ BLOCKDEV_SIZE 8
|
||||
@ -31,3 +31,4 @@
|
||||
.equ printHexPair 0x4d
|
||||
.equ sdcGetC 0x50
|
||||
.equ sdcPutC 0x53
|
||||
.equ blkGetC 0x56
|
||||
|
Loading…
Reference in New Issue
Block a user