Compare commits

...

2 Commits

Author SHA1 Message Date
Virgil Dupras
6c51ea1ebb recipes/rc2014/selfhost: complete instructions
I have yet to test the whole process on real hardware. Soon.
2020-04-26 20:20:36 -04:00
Virgil Dupras
f690cb2e5b recipes/rc2014/sdcard: use driver from blkfs
This completes the migration of all Collapse OS code into blkfs!
2020-04-26 19:50:38 -04:00
3 changed files with 50 additions and 240 deletions

View File

@ -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!
;

View File

@ -19,7 +19,7 @@ design.
## Gathering parts
* A RC2014 Classic
* `stage3.bin` from the base recipe
* `stage2.bin` from the base recipe
* A MicroSD breakout board. I use Adafruit's.
* A proto board + header pins with 39 positions so we can make a RC2014 card.
* 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
instead.
## Building your stage 4
## Building your stage 3
Using the same technique as you used for building your stage 3, you can append
required words to your boot binary. Required units are `forth/blk.fs` and
`drv/sdc.fs`. You also need `drv/sdc.z80` but to save you the troubles of
rebuilding from stage 1 for this recipe, we took the liberty of already having
included it in the base recipe.
Using the same technique as you used in the `eeprom` recipe, you can append
required words to your boot binary. Required units `blk` (B464) and the SD Card
driver (B370). You only need the Forth part. You of course actually need
Z80 SDC words but to save you the troubles of rebuilding from stage 1 for this
recipe, we took the liberty of already having included it in the base recipe.
## Testing in the emulator
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
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`.

View File

@ -6,31 +6,60 @@ either for another RC2014 or for an OS upgrade.
## Gathering parts
* stage4 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.
* stage3 from `sdcard` recipe. If you want to write to EEPROM as the final step,
you'll need a hybrid stage3 that also includes stuff from the `eeprom` recipe.
## Building stage 1
### Part 1
Building the first part of stage 1 (the binary part, before the inlined-source
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
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
`Makefile`, you'll see `cat xcomp.fs | $(STAGE2)`. That's the thing. Open
`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
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.
The meaning of these commands is not explained here. You are encouraged to read
the in-system documentation for more information.
I'm not going to explain in detail what each command do, but only give you an
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
slow, some of these commands take a long time. Multiple minutes. Be patient.
The first part is configuration of your new system. When RAM starts, where RSP
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
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?
@ -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
of that word. That offset goes in `HERE`. Once you've done that, relaunch your
LOAD.
### Part 2
TODO