mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-26 15:48:05 +11:00
Compare commits
5 Commits
d6c9ab3f32
...
4c7dfe0dfe
Author | SHA1 | Date | |
---|---|---|---|
|
4c7dfe0dfe | ||
|
76e4422796 | ||
|
d996dd8c9e | ||
|
d4f65911c0 | ||
|
420836276d |
@ -21,6 +21,23 @@ directly, but as part of another word.
|
|||||||
|
|
||||||
"*I*" in description indicates an IMMEDIATE word.
|
"*I*" in description indicates an IMMEDIATE word.
|
||||||
|
|
||||||
|
*** Symbols ***
|
||||||
|
|
||||||
|
Throughout words, different symbols are used in different contexts, but we try
|
||||||
|
to been consistent in their use. Here's their definitions:
|
||||||
|
|
||||||
|
! - Store
|
||||||
|
@ - Fetch
|
||||||
|
$ - Initialize
|
||||||
|
^ - Arguments in their opposite order
|
||||||
|
< - Input
|
||||||
|
> - 1. Pointer in a buffer 2. Opposite of "<".
|
||||||
|
( - Lower boundary
|
||||||
|
) - Upper boundary
|
||||||
|
* - Word indirection (pointer to word)
|
||||||
|
~ - Container for native code. Usually not an executable word.
|
||||||
|
? - Is it ...? (example: IMMED?)
|
||||||
|
|
||||||
*** Defining words ***
|
*** Defining words ***
|
||||||
(find) a -- a f Read at a and find it in dict. If found, f=1 and
|
(find) a -- a f Read at a and find it in dict. If found, f=1 and
|
||||||
a = wordref. If not found, f=0 and a = string addr.
|
a = wordref. If not found, f=0 and a = string addr.
|
||||||
@ -105,6 +122,16 @@ HERE -- a Push HERE's address
|
|||||||
H@ -- a HERE @
|
H@ -- a HERE @
|
||||||
MOVE a1 a2 u -- Copy u bytes from a1 to a2, starting with a1, going
|
MOVE a1 a2 u -- Copy u bytes from a1 to a2, starting with a1, going
|
||||||
up.
|
up.
|
||||||
|
*** Addressed devices ***
|
||||||
|
|
||||||
|
See usage.txt for details.
|
||||||
|
|
||||||
|
ADEV$ -- Initialize adev subsystem
|
||||||
|
A@ a -- c Indirect C@
|
||||||
|
A! c a -- Indirect C!
|
||||||
|
A@* -- a Address for A@ word
|
||||||
|
A!* -- a Address for A! word
|
||||||
|
AMOVE src dst u -- Same as MOVE, but with A@ and A!
|
||||||
|
|
||||||
*** Arithmetic / Bits ***
|
*** Arithmetic / Bits ***
|
||||||
|
|
||||||
|
17
drv/at28.fs
Normal file
17
drv/at28.fs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
( With dst being assumed to be an AT28 EEPROM, perform !
|
||||||
|
operation while doing the right thing. Checks data integrity
|
||||||
|
and ABORT on mismatch.
|
||||||
|
)
|
||||||
|
( a n -- )
|
||||||
|
: AT28!
|
||||||
|
2DUP C! SWAP
|
||||||
|
( 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
|
||||||
|
value twice. )
|
||||||
|
BEGIN ( n1 a )
|
||||||
|
DUP C@ ( n1 a n2 )
|
||||||
|
OVER C@ ( n1 a n2 n3 )
|
||||||
|
= UNTIL
|
||||||
|
( We're finished writing. do we have a mismatch? )
|
||||||
|
C@ = NOT IF ABORT" mismatch" THEN
|
||||||
|
;
|
@ -1 +1 @@
|
|||||||
: INIT (c<$) INTERPRET ;
|
: INIT RDLN$ Z80A$ INTERPRET ;
|
||||||
|
Binary file not shown.
34
forth/adev.fs
Normal file
34
forth/adev.fs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
( 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
|
||||||
|
;
|
@ -8,33 +8,23 @@
|
|||||||
routine. )
|
routine. )
|
||||||
|
|
||||||
64 CONSTANT INBUFSZ
|
64 CONSTANT INBUFSZ
|
||||||
( points to INBUF )
|
: RDLNMEM+ 0x53 RAM+ @ + ;
|
||||||
: IN( 0x53 RAM+ ;
|
|
||||||
( points to INBUF's end )
|
|
||||||
: IN) 0x55 RAM+ ;
|
|
||||||
( current position in INBUF )
|
( current position in INBUF )
|
||||||
: IN> 0x57 RAM+ ;
|
: IN> 0 RDLNMEM+ ;
|
||||||
|
( points to INBUF )
|
||||||
|
: IN( 2 RDLNMEM+ ;
|
||||||
|
( points to INBUF's end )
|
||||||
|
: IN) INBUFSZ 2 + RDLNMEM+ ;
|
||||||
|
|
||||||
( flush input buffer )
|
( flush input buffer )
|
||||||
( set IN> to IN( and set IN> @ to null )
|
( set IN> to IN( and set IN> @ to null )
|
||||||
: (infl) 0 IN( @ DUP IN> ! ! ;
|
: (infl) 0 IN( DUP IN> ! ! ;
|
||||||
|
|
||||||
( Initializes the readln subsystem )
|
|
||||||
: (c<$)
|
|
||||||
H@ IN( !
|
|
||||||
INBUFSZ ALLOT
|
|
||||||
H@ IN) !
|
|
||||||
( We need two extra bytes. 1 for the last typed 0x0a and
|
|
||||||
one for the following NULL. )
|
|
||||||
2 ALLOT
|
|
||||||
(infl)
|
|
||||||
;
|
|
||||||
|
|
||||||
( handle backspace: go back one char in IN>, if possible, then
|
( handle backspace: go back one char in IN>, if possible, then
|
||||||
emit SPC + BS )
|
emit SPC + BS )
|
||||||
: (inbs)
|
: (inbs)
|
||||||
( already at IN( ? )
|
( already at IN( ? )
|
||||||
IN> @ IN( @ = IF EXIT THEN
|
IN> @ IN( = IF EXIT THEN
|
||||||
IN> @ 1 - IN> !
|
IN> @ 1 - IN> !
|
||||||
SPC BS
|
SPC BS
|
||||||
;
|
;
|
||||||
@ -43,7 +33,7 @@
|
|||||||
should continue, that is, whether CR was not met. )
|
should continue, that is, whether CR was not met. )
|
||||||
: (rdlnc) ( -- f )
|
: (rdlnc) ( -- f )
|
||||||
( buffer overflow? same as if we typed a newline )
|
( buffer overflow? same as if we typed a newline )
|
||||||
IN> @ IN) @ = IF 0x0a ELSE KEY THEN ( c )
|
IN> @ IN) = IF 0x0a ELSE KEY THEN ( c )
|
||||||
( del? same as backspace )
|
( del? same as backspace )
|
||||||
DUP 0x7f = IF DROP 0x8 THEN
|
DUP 0x7f = IF DROP 0x8 THEN
|
||||||
( lf? same as cr )
|
( lf? same as cr )
|
||||||
@ -69,14 +59,26 @@
|
|||||||
FLAGS @ 0x1 AND NOT IF '>' EMIT SPC THEN
|
FLAGS @ 0x1 AND NOT IF '>' EMIT SPC THEN
|
||||||
(infl)
|
(infl)
|
||||||
BEGIN (rdlnc) NOT UNTIL
|
BEGIN (rdlnc) NOT UNTIL
|
||||||
LF IN( @ IN> !
|
LF IN( IN> !
|
||||||
;
|
;
|
||||||
|
|
||||||
( And finally, implement a replacement for the (c<) routine )
|
( And finally, implement a replacement for the (c<) routine )
|
||||||
: (c<)
|
: (rdln<)
|
||||||
IN> @ C@ ( c )
|
IN> @ C@ ( c )
|
||||||
( not EOL? good, inc and return )
|
( not EOL? good, inc and return )
|
||||||
DUP IF 1 IN> +! EXIT THEN ( c )
|
DUP IF 1 IN> +! EXIT THEN ( c )
|
||||||
( EOL ? readline. we still return typed char though )
|
( EOL ? readline. we still return typed char though )
|
||||||
(rdln) ( c )
|
(rdln) ( c )
|
||||||
;
|
;
|
||||||
|
|
||||||
|
( Initializes the readln subsystem )
|
||||||
|
: RDLN$
|
||||||
|
( 53 == rdln's memory )
|
||||||
|
H@ 0x53 RAM+ !
|
||||||
|
( 2 for IN>, plus 2 for extra bytes after buffer: 1 for
|
||||||
|
the last typed 0x0a and one for the following NULL. )
|
||||||
|
INBUFSZ 4 + ALLOT
|
||||||
|
(infl)
|
||||||
|
['] (rdln<) 0x0c RAM+ !
|
||||||
|
;
|
||||||
|
|
||||||
|
@ -1,21 +1,11 @@
|
|||||||
( Z80 assembler )
|
( Z80 assembler )
|
||||||
|
|
||||||
( Splits word into msb/lsb, lsb being on TOS )
|
: Z80AMEM+ 0x59 RAM+ @ + ;
|
||||||
: SPLITB
|
|
||||||
256 /MOD SWAP
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
( H@ offset at which we consider our PC 0. Used to compute
|
( H@ offset at which we consider our PC 0. Used to compute
|
||||||
PC. To have a proper PC, call "H@ ORG !" at the beginning
|
PC. To have a proper PC, call "H@ ORG !" at the beginning
|
||||||
of your assembly process. )
|
of your assembly process. )
|
||||||
: ORG 0x59 RAM+ ;
|
: ORG 0 Z80AMEM+ ;
|
||||||
: PC H@ ORG @ - ;
|
|
||||||
|
|
||||||
( A, spits an assembled byte, A,, spits an assembled word
|
|
||||||
Both increase PC. To debug, change C, to .X )
|
|
||||||
: A, C, ;
|
|
||||||
: A,, SPLITB A, A, ;
|
|
||||||
|
|
||||||
( Labels are a convenient way of managing relative jump
|
( Labels are a convenient way of managing relative jump
|
||||||
calculations. Backward labels are easy. It is only a matter
|
calculations. Backward labels are easy. It is only a matter
|
||||||
@ -27,13 +17,31 @@
|
|||||||
To avoid using dict memory in compilation targets, we
|
To avoid using dict memory in compilation targets, we
|
||||||
pre-declare label variables here, which means we have a
|
pre-declare label variables here, which means we have a
|
||||||
limited number of it. For now, 6 ought to be enough. )
|
limited number of it. For now, 6 ought to be enough. )
|
||||||
|
: L1 2 Z80AMEM+ ;
|
||||||
|
: L2 4 Z80AMEM+ ;
|
||||||
|
: L3 6 Z80AMEM+ ;
|
||||||
|
: L4 8 Z80AMEM+ ;
|
||||||
|
: L5 10 Z80AMEM+ ;
|
||||||
|
: L6 12 Z80AMEM+ ;
|
||||||
|
|
||||||
: L1 0x5b RAM+ ;
|
: Z80A$
|
||||||
: L2 0x5d RAM+ ;
|
( 59 == z80a's memory )
|
||||||
: L3 0x5f RAM+ ;
|
H@ 0x59 RAM+ !
|
||||||
: L4 0x61 RAM+ ;
|
14 ALLOT
|
||||||
: L5 0x63 RAM+ ;
|
;
|
||||||
: L6 0x65 RAM+ ;
|
|
||||||
|
( Splits word into msb/lsb, lsb being on TOS )
|
||||||
|
: SPLITB
|
||||||
|
256 /MOD SWAP
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
: PC H@ ORG @ - ;
|
||||||
|
|
||||||
|
( A, spits an assembled byte, A,, spits an assembled word
|
||||||
|
Both increase PC. To debug, change C, to .X )
|
||||||
|
: A, C, ;
|
||||||
|
: A,, SPLITB A, A, ;
|
||||||
|
|
||||||
( There are 2 label types: backward and forward. For each
|
( There are 2 label types: backward and forward. For each
|
||||||
type, there are two actions: set and write. Setting a label
|
type, there are two actions: set and write. Setting a label
|
||||||
|
16
notes.txt
16
notes.txt
@ -89,17 +89,11 @@ RAMSTART INITIAL_SP
|
|||||||
+2e BOOT C< PTR
|
+2e BOOT C< PTR
|
||||||
+4e INTJUMP
|
+4e INTJUMP
|
||||||
+51 CURRENTPTR
|
+51 CURRENTPTR
|
||||||
+53 readln's IN(
|
+53 readln's variables
|
||||||
+55 readln's IN)
|
+55 adev's variables
|
||||||
+57 readln's IN>
|
+57 FUTURE USES
|
||||||
+59 z80a's ORG
|
+59 z80a's variables
|
||||||
+5b z80a's L1
|
+5b FUTURE USES
|
||||||
+5d z80a's L2
|
|
||||||
+5f z80a's L3
|
|
||||||
+61 z80a's L4
|
|
||||||
+63 z80a's L5
|
|
||||||
+65 z80a's L6
|
|
||||||
+67 FUTURE USES
|
|
||||||
+70 DRIVERS
|
+70 DRIVERS
|
||||||
+80 RAMEND
|
+80 RAMEND
|
||||||
|
|
||||||
|
@ -214,6 +214,17 @@ And there you have it, a stage2 binary that you've assembled yourself. Now,
|
|||||||
here's for your homework: use the same technique to add the contents of
|
here's for your homework: use the same technique to add the contents of
|
||||||
`readln.fs` to stage2 so that you have a full-featured interpreter.
|
`readln.fs` to stage2 so that you have a full-featured interpreter.
|
||||||
|
|
||||||
|
Name it `stage3.bin` (the version without any source code appended and no
|
||||||
|
`INIT` word defined), you'll need this binary for sub-recipes written for the
|
||||||
|
RC2014.
|
||||||
|
|
||||||
|
Here's a little cheatsheet, but seriously, you should figure most of it
|
||||||
|
yourself. Tough love they call it.
|
||||||
|
|
||||||
|
* `cat stage2.bin pre.fs ../../forth/readln.fs run.fs > stage2r.bin`
|
||||||
|
* Don't forget `(c<$)`.
|
||||||
|
* `RLDICT` is like `RLCORE` but with a chosen target.
|
||||||
|
|
||||||
[rc2014]: https://rc2014.co.uk
|
[rc2014]: https://rc2014.co.uk
|
||||||
[romwrite]: https://github.com/hsoft/romwrite
|
[romwrite]: https://github.com/hsoft/romwrite
|
||||||
[stage2]: ../../emul
|
[stage2]: ../../emul
|
||||||
|
36
usage.txt
36
usage.txt
@ -86,3 +86,39 @@ flag to true. For example, "<>{ <>}" yields true.
|
|||||||
To check whether A is in between B and C inclusively, you would write:
|
To check whether A is in between B and C inclusively, you would write:
|
||||||
|
|
||||||
A <>{ B 1 - &> C 1 + &< <>}
|
A <>{ B 1 - &> C 1 + &< <>}
|
||||||
|
|
||||||
|
*** Addressed devices
|
||||||
|
|
||||||
|
The adev unit provides a simple but powerful abstraction over C@ and C!: A@ and
|
||||||
|
A!. These work the same way as C@ and C! (but for performance reasons, aren't
|
||||||
|
used in core words), but are indirect calls.
|
||||||
|
|
||||||
|
Upon initialization, the default to C@ and C!, but can be set to any word
|
||||||
|
through A@* and A!*.
|
||||||
|
|
||||||
|
On top of that, it provides a few core-like words such as AMOVE.
|
||||||
|
|
||||||
|
Let's demonstrate its use through a toy example:
|
||||||
|
|
||||||
|
> : F! SWAP 1 + SWAP C! ;
|
||||||
|
> 8 H@ DUMP
|
||||||
|
|
||||||
|
:54 0000 0000 0000 0000 ........
|
||||||
|
> 9 H@ A!
|
||||||
|
> 8 H@ DUMP
|
||||||
|
|
||||||
|
:54 0900 0000 0000 0000 ........
|
||||||
|
> ' F! A!* !
|
||||||
|
> 9 H@ 1 + A!
|
||||||
|
> 8 H@ DUMP
|
||||||
|
|
||||||
|
:54 090a 0000 0000 0000 ........
|
||||||
|
> H@ H@ 2 + 2 AMOVE
|
||||||
|
> 8 H@ DUMP
|
||||||
|
|
||||||
|
:54 090a 0a0b 0000 0000 ........
|
||||||
|
>
|
||||||
|
|
||||||
|
Of course, you might want to end up using adev in this kind of ad-hoc way to
|
||||||
|
have some kind of mapping function, but what you'll mostly want to to is to
|
||||||
|
plug device drivers into those words.
|
||||||
|
Loading…
Reference in New Issue
Block a user