Compare commits
2 Commits
865f4f9256
...
6c51ea1ebb
Author | SHA1 | Date | |
---|---|---|---|
|
6c51ea1ebb | ||
|
f690cb2e5b |
215
drv/sdc.fs
215
drv/sdc.fs
@ -1,215 +0,0 @@
|
|||||||
( -- n )
|
|
||||||
: _idle 0xff _sdcSR ;
|
|
||||||
|
|
||||||
( -- n )
|
|
||||||
( _sdcSR 0xff until the response is something else than 0xff
|
|
||||||
for a maximum of 20 times. Returns 0xff if no response. )
|
|
||||||
: _wait
|
|
||||||
0 ( cnt )
|
|
||||||
BEGIN
|
|
||||||
_idle
|
|
||||||
DUP 0xff = IF DROP ELSE SWAP DROP EXIT THEN
|
|
||||||
1+
|
|
||||||
DUP 20 = UNTIL
|
|
||||||
DROP 0xff
|
|
||||||
;
|
|
||||||
|
|
||||||
( -- )
|
|
||||||
( The opposite of sdcWaitResp: we wait until response is 0xff.
|
|
||||||
After a successful read or write operation, the card will be
|
|
||||||
busy for a while. We need to give it time before interacting
|
|
||||||
with it again. Technically, we could continue processing on
|
|
||||||
our side while the card it busy, and maybe we will one day,
|
|
||||||
but at the moment, I'm having random write errors if I don't
|
|
||||||
do this right after a write, so I prefer to stay cautious
|
|
||||||
for now. )
|
|
||||||
: _ready BEGIN _idle 0xff = UNTIL ;
|
|
||||||
|
|
||||||
( c n -- c )
|
|
||||||
( Computes n into crc c with polynomial 0x09
|
|
||||||
Note that the result is "left aligned", that is, that 8th
|
|
||||||
bit to the "right" is insignificant (will be stop bit). )
|
|
||||||
: _crc7
|
|
||||||
XOR ( c )
|
|
||||||
8 0 DO
|
|
||||||
2 * ( <<1 )
|
|
||||||
DUP 255 > IF
|
|
||||||
( MSB was set, apply polynomial )
|
|
||||||
0xff AND
|
|
||||||
0x12 XOR ( 0x09 << 1, we apply CRC on high bits )
|
|
||||||
THEN
|
|
||||||
LOOP
|
|
||||||
;
|
|
||||||
|
|
||||||
( c n -- c )
|
|
||||||
( Computes n into crc c with polynomial 0x1021 )
|
|
||||||
: _crc16
|
|
||||||
SWAP DUP 256 / ( n c c>>8 )
|
|
||||||
ROT XOR ( c x )
|
|
||||||
DUP 16 / XOR ( c x^x>>4 )
|
|
||||||
SWAP 256 * ( x c<<8 )
|
|
||||||
OVER 4096 * XOR ( x c^x<<12 )
|
|
||||||
OVER 32 * XOR ( x c^x<<5 )
|
|
||||||
XOR ( c )
|
|
||||||
;
|
|
||||||
|
|
||||||
( send-and-crc7 )
|
|
||||||
( n c -- c )
|
|
||||||
: _s+crc SWAP DUP _sdcSR DROP _crc7 ;
|
|
||||||
|
|
||||||
( cmd arg1 arg2 -- resp )
|
|
||||||
( Sends a command to the SD card, along with arguments and
|
|
||||||
specified CRC fields. (CRC is only needed in initial commands
|
|
||||||
though).
|
|
||||||
This does *not* handle CS. You have to select/deselect the
|
|
||||||
card outside this routine. )
|
|
||||||
: _cmd
|
|
||||||
_wait DROP
|
|
||||||
ROT ( a1 a2 cmd )
|
|
||||||
0 _s+crc ( a1 a2 crc )
|
|
||||||
ROT 256 /MOD ( a2 crc h l )
|
|
||||||
ROT ( a2 h l crc )
|
|
||||||
_s+crc ( a2 h crc )
|
|
||||||
_s+crc ( a2 crc )
|
|
||||||
SWAP 256 /MOD ( crc h l )
|
|
||||||
ROT ( h l crc )
|
|
||||||
_s+crc ( h crc )
|
|
||||||
_s+crc ( crc )
|
|
||||||
( send CRC )
|
|
||||||
0x01 OR ( ensure stop bit )
|
|
||||||
_sdcSR DROP
|
|
||||||
( And now we just have to wait for a valid response... )
|
|
||||||
_wait
|
|
||||||
;
|
|
||||||
|
|
||||||
( cmd arg1 arg2 -- r )
|
|
||||||
( Send a command that expects a R1 response, handling CS. )
|
|
||||||
: SDCMDR1 _sdcSel _cmd _sdcDesel ;
|
|
||||||
|
|
||||||
( cmd arg1 arg2 -- r arg1 arg2 )
|
|
||||||
( Send a command that expects a R7 response, handling CS. A R7
|
|
||||||
is a R1 followed by 4 bytes. arg1 contains bytes 0:1, arg2
|
|
||||||
has 2:3 )
|
|
||||||
: SDCMDR7
|
|
||||||
_sdcSel
|
|
||||||
_cmd ( r )
|
|
||||||
_idle 256 * ( r h )
|
|
||||||
_idle + ( r arg1 )
|
|
||||||
_idle 256 * ( r arg1 h )
|
|
||||||
_idle + ( r arg1 arg2 )
|
|
||||||
_sdcDesel
|
|
||||||
;
|
|
||||||
|
|
||||||
: _err _sdcDesel ABORT" SDerr" ;
|
|
||||||
|
|
||||||
( Initialize a SD card. This should be called at least 1ms
|
|
||||||
after the powering up of the card. )
|
|
||||||
: SDC$
|
|
||||||
( Wake the SD card up. After power up, a SD card has to
|
|
||||||
receive at least 74 dummy clocks with CS and DI high. We
|
|
||||||
send 80. )
|
|
||||||
10 0 DO _idle DROP LOOP
|
|
||||||
|
|
||||||
( call cmd0 and expect a 0x01 response (card idle)
|
|
||||||
this should be called multiple times. we're actually
|
|
||||||
expected to. let's call this for a maximum of 10 times. )
|
|
||||||
0 ( dummy )
|
|
||||||
10 0 DO ( r )
|
|
||||||
DROP
|
|
||||||
0b01000000 0 0 ( CMD0 )
|
|
||||||
SDCMDR1
|
|
||||||
DUP 0x01 = IF LEAVE THEN
|
|
||||||
LOOP
|
|
||||||
0x01 = NOT IF _err THEN
|
|
||||||
|
|
||||||
( Then comes the CMD8. We send it with a 0x01aa argument
|
|
||||||
and expect a 0x01aa argument back, along with a 0x01 R1
|
|
||||||
response. )
|
|
||||||
0b01001000 0 0x1aa ( CMD8 )
|
|
||||||
SDCMDR7 ( r arg1 arg2 )
|
|
||||||
0x1aa = NOT IF _err THEN ( arg2 check )
|
|
||||||
0 = NOT IF _err THEN ( arg1 check )
|
|
||||||
0x01 = NOT IF _err THEN ( r check )
|
|
||||||
|
|
||||||
( Now we need to repeatedly run CMD55+CMD41 (0x40000000)
|
|
||||||
until the card goes out of idle mode, that is, when
|
|
||||||
it stops sending us 0x01 response and send us 0x00
|
|
||||||
instead. Any other response means that initialization
|
|
||||||
failed. )
|
|
||||||
BEGIN
|
|
||||||
0b01110111 0 0 ( CMD55 )
|
|
||||||
SDCMDR1
|
|
||||||
0x01 = NOT IF _err THEN
|
|
||||||
0b01101001 0x4000 0x0000 ( CMD41 )
|
|
||||||
SDCMDR1
|
|
||||||
DUP 0x01 > IF _err THEN
|
|
||||||
NOT UNTIL
|
|
||||||
( Out of idle mode! Success! )
|
|
||||||
;
|
|
||||||
|
|
||||||
( dstaddr blkno -- )
|
|
||||||
: _sdc@
|
|
||||||
_sdcSel
|
|
||||||
0x51 ( CMD17 )
|
|
||||||
0 ROT ( a cmd 0 blkno )
|
|
||||||
_cmd
|
|
||||||
IF _err THEN
|
|
||||||
_wait
|
|
||||||
0xfe = NOT IF _err THEN
|
|
||||||
0 SWAP ( crc a )
|
|
||||||
512 0 DO ( crc a )
|
|
||||||
DUP ( crc a a )
|
|
||||||
_idle ( crc a a n )
|
|
||||||
DUP ROT ( crc a n n a )
|
|
||||||
C! ( crc a n )
|
|
||||||
ROT SWAP ( a crc n )
|
|
||||||
_crc16 ( a crc )
|
|
||||||
SWAP 1+ ( crc a+1 )
|
|
||||||
LOOP
|
|
||||||
DROP ( crc1 )
|
|
||||||
_idle 256 *
|
|
||||||
_idle + ( crc2 )
|
|
||||||
_wait DROP
|
|
||||||
_sdcDesel
|
|
||||||
= NOT IF _err THEN
|
|
||||||
;
|
|
||||||
|
|
||||||
: SDC@
|
|
||||||
2 * DUP BLK( SWAP ( b a b )
|
|
||||||
_sdc@
|
|
||||||
1+ BLK( 512 + SWAP
|
|
||||||
_sdc@
|
|
||||||
;
|
|
||||||
|
|
||||||
( srcaddr blkno -- )
|
|
||||||
: _sdc!
|
|
||||||
_sdcSel
|
|
||||||
0x58 ( CMD24 )
|
|
||||||
0 ROT ( a cmd 0 blkno )
|
|
||||||
_cmd
|
|
||||||
IF _err THEN
|
|
||||||
_idle DROP
|
|
||||||
0xfe _sdcSR DROP
|
|
||||||
0 SWAP ( crc a )
|
|
||||||
512 0 DO ( crc a )
|
|
||||||
C@+ ( crc a+1 n )
|
|
||||||
ROT OVER ( a n crc n )
|
|
||||||
_crc16 ( a n crc )
|
|
||||||
SWAP ( a crc n )
|
|
||||||
_sdcSR DROP ( a crc )
|
|
||||||
SWAP ( crc a )
|
|
||||||
LOOP
|
|
||||||
DROP ( crc )
|
|
||||||
256 /MOD ( lsb msb )
|
|
||||||
_sdcSR DROP ( lsb )
|
|
||||||
_sdcSR DROP
|
|
||||||
_wait DROP
|
|
||||||
_sdcDesel
|
|
||||||
;
|
|
||||||
|
|
||||||
: SDC!
|
|
||||||
2 * DUP BLK( SWAP ( b a b )
|
|
||||||
_sdc!
|
|
||||||
1+ BLK( 512 + SWAP
|
|
||||||
_sdc!
|
|
||||||
;
|
|
@ -19,7 +19,7 @@ design.
|
|||||||
## Gathering parts
|
## Gathering parts
|
||||||
|
|
||||||
* A RC2014 Classic
|
* A RC2014 Classic
|
||||||
* `stage3.bin` from the base recipe
|
* `stage2.bin` from the base recipe
|
||||||
* A MicroSD breakout board. I use Adafruit's.
|
* A MicroSD breakout board. I use Adafruit's.
|
||||||
* A proto board + header pins with 39 positions so we can make a RC2014 card.
|
* A proto board + header pins with 39 positions so we can make a RC2014 card.
|
||||||
* Diodes, resistors and stuff
|
* Diodes, resistors and stuff
|
||||||
@ -69,20 +69,20 @@ matter. However, it *does* matter for the `SELECT` line, so I don't follow my
|
|||||||
own schematic with regards to the `M1` and `A2` lines and use two inverters
|
own schematic with regards to the `M1` and `A2` lines and use two inverters
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
## Building your stage 4
|
## Building your stage 3
|
||||||
|
|
||||||
Using the same technique as you used for building your stage 3, you can append
|
Using the same technique as you used in the `eeprom` recipe, you can append
|
||||||
required words to your boot binary. Required units are `forth/blk.fs` and
|
required words to your boot binary. Required units `blk` (B464) and the SD Card
|
||||||
`drv/sdc.fs`. You also need `drv/sdc.z80` but to save you the troubles of
|
driver (B370). You only need the Forth part. You of course actually need
|
||||||
rebuilding from stage 1 for this recipe, we took the liberty of already having
|
Z80 SDC words but to save you the troubles of rebuilding from stage 1 for this
|
||||||
included it in the base recipe.
|
recipe, we took the liberty of already having included it in the base recipe.
|
||||||
|
|
||||||
## Testing in the emulator
|
## Testing in the emulator
|
||||||
|
|
||||||
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
|
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
|
||||||
it by invoking it with a second argument:
|
it by invoking it with a second argument:
|
||||||
|
|
||||||
../../../emul/hw/rc2014/classic stage4.bin ../../../emul/blkfs
|
../../../emul/hw/rc2014/classic stage3.bin ../../../emul/blkfs
|
||||||
|
|
||||||
You will then run with a SD card having the contents from `/blk`.
|
You will then run with a SD card having the contents from `/blk`.
|
||||||
|
|
||||||
|
@ -6,31 +6,60 @@ either for another RC2014 or for an OS upgrade.
|
|||||||
|
|
||||||
## Gathering parts
|
## Gathering parts
|
||||||
|
|
||||||
* stage4 from `sdcard` recipe. If you want to write to EEPROM as the final step,
|
* stage3 from `sdcard` recipe. If you want to write to EEPROM as the final step,
|
||||||
you'll need a hybrid stage4 that also includes stuff from the `eeprom` recipe.
|
you'll need a hybrid stage3 that also includes stuff from the `eeprom` recipe.
|
||||||
|
|
||||||
## Building stage 1
|
## Building stage 1
|
||||||
|
|
||||||
### Part 1
|
Build Collapse OS' stage 1 from within Collapse OS is very similar to how we do
|
||||||
|
it from the makefile. If you take the time to look at the base recipe
|
||||||
Building the first part of stage 1 (the binary part, before the inlined-source
|
`Makefile`, you'll see `cat xcomp.fs | $(STAGE2)`. That's the thing. Open
|
||||||
part) from within Collapse OS is actually very similar from building it from a
|
|
||||||
modern environment. If you take the time to look at the base recipe `Makefile`,
|
|
||||||
you'll see `cat xcomp.fs | $(STAGE2)`. That command builds part 1. Open
|
|
||||||
`xcomp.fs` in a text editor and take a look at it.
|
`xcomp.fs` in a text editor and take a look at it.
|
||||||
|
|
||||||
To assemble stage 1 from RC2014, all you need to do is to type those commands
|
To assemble stage 1 from RC2014, all you need to do is to type those commands
|
||||||
in the same order, and replace the `H@ 256 /MOD 2 PC! 2 PC!` lines with `H@ .X`.
|
in the same order, and replace the `H@ 256 /MOD 2 PC! 2 PC!` lines with `H@ .X`.
|
||||||
Those commands will inform you of the begin/end offsets of the assembled binary.
|
Those commands will inform you of the begin/end offsets of the assembled binary.
|
||||||
|
|
||||||
The meaning of these commands is not explained here. You are encouraged to read
|
I'm not going to explain in detail what each command do, but only give you an
|
||||||
the in-system documentation for more information.
|
overview of what is happening. You are encouraged to read the in-system
|
||||||
|
documentation for more information.
|
||||||
|
|
||||||
However, one thing you should know is that because the SD card driver is a bit
|
The first part is configuration of your new system. When RAM starts, where RSP
|
||||||
slow, some of these commands take a long time. Multiple minutes. Be patient.
|
starts, what ports to use for what device, etc. These configuration declarations
|
||||||
|
are expected in the boot code and driver code.
|
||||||
|
|
||||||
|
Then, we load the Z80 assembler and the cross compiler (xcomp for short), which
|
||||||
|
we'll of course need for the task ahead.
|
||||||
|
|
||||||
|
Then come xcomp overrides, which are needed for xcomp to be effective.
|
||||||
|
|
||||||
|
At this point, we're about to begin spitting binary content, so we want to know
|
||||||
|
where we're at. That's why you'll need to type `H@ .X` and write down the
|
||||||
|
result. That's the starting offset.
|
||||||
|
|
||||||
|
Then, we assemble the boot binary, drivers' native words, then inner core,
|
||||||
|
close the binary with a hook word. We're finished with cross-compiling.
|
||||||
|
|
||||||
|
We're at the offset that will be `CURRENT` on boot, so we update `LATEST`.
|
||||||
|
|
||||||
|
Then, we spit the course code that will be interpreted by stage 1 on boot so
|
||||||
|
that it bootstraps itself to a full interpreter. Not all units are there
|
||||||
|
because they don't fit in 8K, but they're sufficient for our needs. We also
|
||||||
|
need the linker so that we can relink ourselves to stage 2.
|
||||||
|
|
||||||
|
Finally, we have initialization code, then a spit of the ending offset.
|
||||||
|
|
||||||
|
Go ahead, run that. However, one thing you should know is that because the SD
|
||||||
|
card driver is a bit slow, some of these commands take a long time. Multiple
|
||||||
|
minutes. Be patient.
|
||||||
|
|
||||||
Once all your commands are run and that you have your begin/end offset (write
|
Once all your commands are run and that you have your begin/end offset (write
|
||||||
them down somewhere), you're ready to assemble part 2.
|
them down somewhere), you're at the same point as you were after the `make`
|
||||||
|
part of the base recipe. The contents between your start and end offset is the
|
||||||
|
exact same as the contents of `stage1.bin` when you run `make`. Continue your
|
||||||
|
deployment from there.
|
||||||
|
|
||||||
|
Good luck!
|
||||||
|
|
||||||
### What to do on SDerr?
|
### What to do on SDerr?
|
||||||
|
|
||||||
@ -48,7 +77,3 @@ You're looking at the offset of the last wordref of the *previous* LOAD
|
|||||||
operation. That offset is going in `XCURRENT`. Then, you're looking at the end
|
operation. That offset is going in `XCURRENT`. Then, you're looking at the end
|
||||||
of that word. That offset goes in `HERE`. Once you've done that, relaunch your
|
of that word. That offset goes in `HERE`. Once you've done that, relaunch your
|
||||||
LOAD.
|
LOAD.
|
||||||
|
|
||||||
### Part 2
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
Loading…
Reference in New Issue
Block a user