Move AT28 driver to blkfs
And adjust rc2014/eeprom recipe
This commit is contained in:
parent
7c692c1111
commit
865f4f9256
4
blk/001
4
blk/001
@ -2,7 +2,8 @@ MASTER INDEX
|
|||||||
|
|
||||||
3 Usage 30 Dictionary
|
3 Usage 30 Dictionary
|
||||||
70 Implementation notes 100 Block editor
|
70 Implementation notes 100 Block editor
|
||||||
120 Linker
|
120 Linker 140 Addressed devices
|
||||||
|
150 AT28 Driver
|
||||||
200 Z80 assembler 260 Cross compilation
|
200 Z80 assembler 260 Cross compilation
|
||||||
280 Z80 boot code 350 ACIA driver
|
280 Z80 boot code 350 ACIA driver
|
||||||
370 SD Card driver 390 Inner core
|
370 SD Card driver 390 Inner core
|
||||||
@ -14,4 +15,3 @@ MASTER INDEX
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
10
blk/140
Normal file
10
blk/140
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Addressed devices
|
||||||
|
|
||||||
|
Abstractions to read and write to devices that allow addressed
|
||||||
|
access. At all times, we have one active "fetch" device and
|
||||||
|
one active "store" device, A@ and A!.
|
||||||
|
|
||||||
|
Those words have the same signature as C@ and C!, and in fact,
|
||||||
|
initially default to proxy of those words.
|
||||||
|
|
||||||
|
Load with "142 LOAD"
|
15
blk/143
Normal file
15
blk/143
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
: ADEVMEM+ 0x55 RAM+ @ + ;
|
||||||
|
: A@* 0 ADEVMEM+ ;
|
||||||
|
: A!* 2 ADEVMEM+ ;
|
||||||
|
|
||||||
|
: ADEV$
|
||||||
|
H@ 0x55 RAM+ !
|
||||||
|
4 ALLOT
|
||||||
|
['] C@ A@* !
|
||||||
|
['] C! A!* !
|
||||||
|
;
|
||||||
|
|
||||||
|
: A@ A@* @ EXECUTE ;
|
||||||
|
: A! A!* @ EXECUTE ;
|
||||||
|
|
||||||
|
|
11
blk/144
Normal file
11
blk/144
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
( Same as MOVE, but with A@ and A! )
|
||||||
|
( src dst u -- )
|
||||||
|
: AMOVE
|
||||||
|
( u ) 0 DO
|
||||||
|
SWAP DUP I + A@ ( dst src x )
|
||||||
|
ROT SWAP OVER I + ( src dst x dst )
|
||||||
|
A! ( src dst )
|
||||||
|
LOOP
|
||||||
|
2DROP
|
||||||
|
;
|
||||||
|
|
6
blk/150
Normal file
6
blk/150
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
AT28 Driver
|
||||||
|
|
||||||
|
Write to an AT28 EEPROM while making sure that proper timing
|
||||||
|
is followed and verify data integrity.
|
||||||
|
|
||||||
|
Load with "151 LOAD"
|
@ -1,9 +1,7 @@
|
|||||||
( With dst being assumed to be an AT28 EEPROM, perform !
|
( With dst being assumed to be an AT28 EEPROM, perform !
|
||||||
operation while doing the right thing. Checks data integrity
|
operation while doing the right thing. Checks data integrity
|
||||||
and ABORT on mismatch.
|
and ABORT on mismatch. )
|
||||||
)
|
: AT28! ( n a -- )
|
||||||
( n a -- )
|
|
||||||
: AT28!
|
|
||||||
2DUP C!
|
2DUP C!
|
||||||
( as long as writing operation is running, IO/6 will toggle at each
|
( as long as writing operation is running, IO/6 will toggle at each
|
||||||
read attempt. We know that write is finished when we read the same
|
read attempt. We know that write is finished when we read the same
|
69
drv/acia.fs
69
drv/acia.fs
@ -1,69 +0,0 @@
|
|||||||
( ACIA
|
|
||||||
|
|
||||||
Manage I/O from an asynchronous communication interface adapter
|
|
||||||
(ACIA). provides "EMIT" to put c char on the ACIA as well as
|
|
||||||
an input buffer. You have to call "~ACIA" on interrupt for
|
|
||||||
this module to work well.
|
|
||||||
|
|
||||||
CONFIGURATION
|
|
||||||
|
|
||||||
ACIA_CTL: IO port for the ACIA's control registers
|
|
||||||
ACIA_IO: IO port for the ACIA's data registers
|
|
||||||
ACIA_MEM: Address in memory that can be used variables shared
|
|
||||||
with ACIA's native words. 8 bytes used.
|
|
||||||
)
|
|
||||||
|
|
||||||
0x20 CONSTANT ACIABUFSZ
|
|
||||||
|
|
||||||
( Points to ACIA buf )
|
|
||||||
: ACIA( [ ACIA_MEM 4 + LITN ] ;
|
|
||||||
( Points to ACIA buf end )
|
|
||||||
: ACIA) [ ACIA_MEM 6 + LITN ] ;
|
|
||||||
( Read buf pointer. Pre-inc )
|
|
||||||
: ACIAR> [ ACIA_MEM LITN ] ;
|
|
||||||
( Write buf pointer. Post-inc )
|
|
||||||
: ACIAW> [ ACIA_MEM 2 + LITN ] ;
|
|
||||||
( This means that if W> == R>, buffer is full.
|
|
||||||
If R>+1 == W>, buffer is empty. )
|
|
||||||
|
|
||||||
|
|
||||||
: ACIA$
|
|
||||||
H@ DUP DUP ACIA( ! ACIAR> !
|
|
||||||
1+ ACIAW> ! ( write index starts one position later )
|
|
||||||
ACIABUFSZ ALLOT
|
|
||||||
H@ ACIA) !
|
|
||||||
( setup ACIA
|
|
||||||
CR7 (1) - Receive Interrupt enabled
|
|
||||||
CR6:5 (00) - RTS low, transmit interrupt disabled.
|
|
||||||
CR4:2 (101) - 8 bits + 1 stop bit
|
|
||||||
CR1:0 (10) - Counter divide: 64
|
|
||||||
)
|
|
||||||
0b10010110 ACIA_CTL PC!
|
|
||||||
|
|
||||||
( setup interrupt )
|
|
||||||
( 4e == INTJUMP )
|
|
||||||
0xc3 0x4e RAM+ C! ( JP upcode )
|
|
||||||
['] ~ACIA 0x4f RAM+ !
|
|
||||||
(im1)
|
|
||||||
;
|
|
||||||
|
|
||||||
: KEY
|
|
||||||
( inc then fetch )
|
|
||||||
ACIAR> @ 1+ DUP ACIA) @ = IF
|
|
||||||
DROP ACIA( @
|
|
||||||
THEN
|
|
||||||
|
|
||||||
( As long as R> == W>-1, it means that buffer is empty )
|
|
||||||
BEGIN DUP ACIAW> @ = NOT UNTIL
|
|
||||||
|
|
||||||
ACIAR> !
|
|
||||||
ACIAR> @ C@
|
|
||||||
;
|
|
||||||
|
|
||||||
: EMIT
|
|
||||||
( As long at CTL bit 1 is low, we are transmitting. wait )
|
|
||||||
BEGIN ACIA_CTL PC@ 0x02 AND UNTIL
|
|
||||||
( The way is clear, go! )
|
|
||||||
ACIA_IO PC!
|
|
||||||
;
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
# Forth
|
|
||||||
|
|
||||||
**WIP** A Forth interpreter. Far from complete, but you can do stuff like
|
|
||||||
|
|
||||||
KEY EMIT KEY EMIT
|
|
||||||
|
|
||||||
See dictionary.txt for a word reference.
|
|
@ -1,34 +0,0 @@
|
|||||||
( Addressed devices.
|
|
||||||
|
|
||||||
Abstractions to read and write to devices that allow addressed
|
|
||||||
access. At all times, we have one active "fetch" device and
|
|
||||||
one active "store" device, A@ and A!.
|
|
||||||
|
|
||||||
Those words have the same signature as C@ and C!, and in fact,
|
|
||||||
initially default to proxy of those words.
|
|
||||||
)
|
|
||||||
|
|
||||||
: ADEVMEM+ 0x55 RAM+ @ + ;
|
|
||||||
: A@* 0 ADEVMEM+ ;
|
|
||||||
: A!* 2 ADEVMEM+ ;
|
|
||||||
|
|
||||||
: ADEV$
|
|
||||||
H@ 0x55 RAM+ !
|
|
||||||
4 ALLOT
|
|
||||||
['] C@ A@* !
|
|
||||||
['] C! A!* !
|
|
||||||
;
|
|
||||||
|
|
||||||
: A@ A@* @ EXECUTE ;
|
|
||||||
: A! A!* @ EXECUTE ;
|
|
||||||
|
|
||||||
( Same as MOVE, but with A@ and A! )
|
|
||||||
( src dst u -- )
|
|
||||||
: AMOVE
|
|
||||||
( u ) 0 DO
|
|
||||||
SWAP DUP I + A@ ( dst src x )
|
|
||||||
ROT SWAP OVER I + ( src dst x dst )
|
|
||||||
A! ( src dst )
|
|
||||||
LOOP
|
|
||||||
2DROP
|
|
||||||
;
|
|
@ -183,9 +183,15 @@ So, the end of our compiled dict is actually `99de`. Alright, let's extract it:
|
|||||||
dd if=memdump bs=1 skip=36192 count=3198 > dict.bin
|
dd if=memdump bs=1 skip=36192 count=3198 > dict.bin
|
||||||
|
|
||||||
`36192` is `8d60` and `3198` is `99de-8d60`. This needs to be prepended by the
|
`36192` is `8d60` and `3198` is `99de-8d60`. This needs to be prepended by the
|
||||||
boot binary. But that one, we already have. It's `z80c.bin`
|
boot binary. We already have `stage1.bin`, but this binary contains bootstrap
|
||||||
|
source code we don't need any more. To strip it, we'll need to `dd` it out to
|
||||||
|
`LATEST`, in my case `098b`:
|
||||||
|
|
||||||
cat z80c.bin dict.bin > stage2.bin
|
dd if=stage1.bin bs=1 count=2443 > s1pre.bin
|
||||||
|
|
||||||
|
Now we can combine our binaries:
|
||||||
|
|
||||||
|
cat s1pre.bin dict.bin > stage2.bin
|
||||||
|
|
||||||
Is it ready to run yet? no. There are 3 adjustments we need to manually make
|
Is it ready to run yet? no. There are 3 adjustments we need to manually make
|
||||||
using our hex editor.
|
using our hex editor.
|
||||||
@ -203,7 +209,12 @@ using our hex editor.
|
|||||||
|
|
||||||
Now are we ready yet? ALMOST! There's one last thing we need to do: add runtime
|
Now are we ready yet? ALMOST! There's one last thing we need to do: add runtime
|
||||||
source. In our case, because we have a compiled dict, the only source we need
|
source. In our case, because we have a compiled dict, the only source we need
|
||||||
to include is `run.fs`:
|
to include is initialization code. We've stripped it from our stage1 earlier,
|
||||||
|
we need to re-add it.
|
||||||
|
|
||||||
|
Look at `xcomp.fs`. You see that `," bla bla bla"` line? That's initialization
|
||||||
|
code. Copy it to a file like `run.fs` (without the `,"`) and build your final
|
||||||
|
binary:
|
||||||
|
|
||||||
cat stage2.bin run.fs > stage2r.bin
|
cat stage2.bin run.fs > stage2r.bin
|
||||||
|
|
||||||
|
@ -38,20 +38,19 @@ I don't think you need a schematic. It's really simple.
|
|||||||
Stage 2 gives you a full interpreter, but it's missing the "Addressed devices"
|
Stage 2 gives you a full interpreter, but it's missing the "Addressed devices"
|
||||||
module and the AT28 driver. We'll need to assemble a stage 3.
|
module and the AT28 driver. We'll need to assemble a stage 3.
|
||||||
|
|
||||||
TODO: fix these instructions. They are broken.
|
When you'll have a system with function disk block system, you'll be able to
|
||||||
|
directly `LOAD` them, but for this recipe, we can't assume you have, so what
|
||||||
|
you'll have to do is to manually paste the code from the appropriate blocks.
|
||||||
|
|
||||||
However, now that we have a usable prompt, we can do a lot (be cautious though:
|
Addressed devices are at B140. To know what you have to paste, open the loader
|
||||||
there is no `readln` yet, so you have no backspace), for example, build a
|
block (B142) and see what blocks it loads. For each of the blocks, copy/paste
|
||||||
stage 3 with `readln`.
|
the code in your interpreter.
|
||||||
|
|
||||||
Copy the unit's source
|
Do the same thing with the AT28 driver (B150)
|
||||||
|
|
||||||
cat ../../forth/readln.fs | ../../tools/stripfc | xclip
|
If you're doing the real thing and not using the emulator, pasting so much code
|
||||||
|
at once might freeze up the RC2014, so it is recommended that you use
|
||||||
and just paste it in your terminal. If you're doing the real thing and not
|
`/tools/exec` that let the other side enough time to breathe.
|
||||||
using the emulator, pasting so much code at once might freeze up the RC2014, so
|
|
||||||
it is recommended that you use `/tools/exec` that let the other side enough
|
|
||||||
time to breathe.
|
|
||||||
|
|
||||||
After your pasting, you'll have a compiled dict of that code in memory. You'll
|
After your pasting, you'll have a compiled dict of that code in memory. You'll
|
||||||
need to relocate it in the same way you did for stage 2, but instead of using
|
need to relocate it in the same way you did for stage 2, but instead of using
|
||||||
@ -59,23 +58,21 @@ need to relocate it in the same way you did for stage 2, but instead of using
|
|||||||
`RLDICT`, the word doing the real work.
|
`RLDICT`, the word doing the real work.
|
||||||
|
|
||||||
`RLDICT` takes 2 arguments, `target` and `offset`. `target` is the first word
|
`RLDICT` takes 2 arguments, `target` and `offset`. `target` is the first word
|
||||||
of your relocated dict. In our case, it's going to be `' INBUFSZ`. `offset` is
|
of your relocated dict. In our case, it's going to be `' ADEVMEM+`. `offset` is
|
||||||
the offset we'll apply to every eligible word references in our dict. In our
|
the offset we'll apply to every eligible word references in our dict. In our
|
||||||
case, that offset is the offset of the *beginning* of the `INBUFSZ` entry (that
|
case, that offset is the offset of the *beginning* of the `ADEVMEM+` entry (that
|
||||||
is, `' INBUFSZ WORD(` minus the offset of the last word (which should be a hook
|
is, `' ADEVMEM+ WORD(` minus the offset of the last word (which should be a hook
|
||||||
word) in the ROM binary.
|
word) in the ROM binary.
|
||||||
|
|
||||||
That offset can be conveniently fetched from code because it is the value of
|
That offset can be conveniently fetched from code because it is the value of
|
||||||
the `LATEST` constant in stable ABI, which is at offset `0x08`. Therefore, our
|
the `LATEST` constant in stable ABI, which is at offset `0x08`. Therefore, our
|
||||||
offset value is:
|
offset value is:
|
||||||
|
|
||||||
' INBUFSZ WORD( 0x08 @ -
|
' ADEVMEM+ WORD( 0x08 @ -
|
||||||
|
|
||||||
You can now run `RLDICT` and proceed with concatenation (and manual adjustments
|
You can now run `RLDICT` and proceed with concatenation (and manual adjustments
|
||||||
of course) as you did with stage 2. Don't forget to adjust `run.fs` so that it
|
of course) as you did with stage 2. Don't forget to adjust `run.fs` so that it
|
||||||
initializes `RDLN$` instead of creating a minimal `(c<)`.
|
runs `ADEV$`.
|
||||||
|
|
||||||
Keep that `stage3.bin` around, you will need it for further recipes.
|
|
||||||
|
|
||||||
## Writing contents to the AT28
|
## Writing contents to the AT28
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user