mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 10:20:55 +11:00
Compare commits
No commits in common. "4c7dfe0dfe8b1f4e5aadd1c715b90c3a01a5642d" and "d6c9ab3f32e6e54f23b32b59b32eddff29d814bd" have entirely different histories.
4c7dfe0dfe
...
d6c9ab3f32
@ -21,23 +21,6 @@ directly, but as part of another 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 ***
|
||||
(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.
|
||||
@ -122,16 +105,6 @@ HERE -- a Push HERE's address
|
||||
H@ -- a HERE @
|
||||
MOVE a1 a2 u -- Copy u bytes from a1 to a2, starting with a1, going
|
||||
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 ***
|
||||
|
||||
|
17
drv/at28.fs
17
drv/at28.fs
@ -1,17 +0,0 @@
|
||||
( 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 RDLN$ Z80A$ INTERPRET ;
|
||||
: INIT (c<$) INTERPRET ;
|
||||
|
Binary file not shown.
@ -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
|
||||
;
|
@ -8,23 +8,33 @@
|
||||
routine. )
|
||||
|
||||
64 CONSTANT INBUFSZ
|
||||
: RDLNMEM+ 0x53 RAM+ @ + ;
|
||||
( current position in INBUF )
|
||||
: IN> 0 RDLNMEM+ ;
|
||||
( points to INBUF )
|
||||
: IN( 2 RDLNMEM+ ;
|
||||
: IN( 0x53 RAM+ ;
|
||||
( points to INBUF's end )
|
||||
: IN) INBUFSZ 2 + RDLNMEM+ ;
|
||||
: IN) 0x55 RAM+ ;
|
||||
( current position in INBUF )
|
||||
: IN> 0x57 RAM+ ;
|
||||
|
||||
( flush input buffer )
|
||||
( 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
|
||||
emit SPC + BS )
|
||||
: (inbs)
|
||||
( already at IN( ? )
|
||||
IN> @ IN( = IF EXIT THEN
|
||||
IN> @ IN( @ = IF EXIT THEN
|
||||
IN> @ 1 - IN> !
|
||||
SPC BS
|
||||
;
|
||||
@ -33,7 +43,7 @@
|
||||
should continue, that is, whether CR was not met. )
|
||||
: (rdlnc) ( -- f )
|
||||
( 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 )
|
||||
DUP 0x7f = IF DROP 0x8 THEN
|
||||
( lf? same as cr )
|
||||
@ -59,26 +69,14 @@
|
||||
FLAGS @ 0x1 AND NOT IF '>' EMIT SPC THEN
|
||||
(infl)
|
||||
BEGIN (rdlnc) NOT UNTIL
|
||||
LF IN( IN> !
|
||||
LF IN( @ IN> !
|
||||
;
|
||||
|
||||
( And finally, implement a replacement for the (c<) routine )
|
||||
: (rdln<)
|
||||
: (c<)
|
||||
IN> @ C@ ( c )
|
||||
( not EOL? good, inc and return )
|
||||
DUP IF 1 IN> +! EXIT THEN ( c )
|
||||
( EOL ? readline. we still return typed char though )
|
||||
(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,11 +1,21 @@
|
||||
( Z80 assembler )
|
||||
|
||||
: Z80AMEM+ 0x59 RAM+ @ + ;
|
||||
( Splits word into msb/lsb, lsb being on TOS )
|
||||
: SPLITB
|
||||
256 /MOD SWAP
|
||||
;
|
||||
|
||||
|
||||
( H@ offset at which we consider our PC 0. Used to compute
|
||||
PC. To have a proper PC, call "H@ ORG !" at the beginning
|
||||
of your assembly process. )
|
||||
: ORG 0 Z80AMEM+ ;
|
||||
: ORG 0x59 RAM+ ;
|
||||
: 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
|
||||
calculations. Backward labels are easy. It is only a matter
|
||||
@ -17,31 +27,13 @@
|
||||
To avoid using dict memory in compilation targets, we
|
||||
pre-declare label variables here, which means we have a
|
||||
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+ ;
|
||||
|
||||
: Z80A$
|
||||
( 59 == z80a's memory )
|
||||
H@ 0x59 RAM+ !
|
||||
14 ALLOT
|
||||
;
|
||||
|
||||
( 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, ;
|
||||
: L1 0x5b RAM+ ;
|
||||
: L2 0x5d RAM+ ;
|
||||
: L3 0x5f RAM+ ;
|
||||
: L4 0x61 RAM+ ;
|
||||
: L5 0x63 RAM+ ;
|
||||
: L6 0x65 RAM+ ;
|
||||
|
||||
( There are 2 label types: backward and forward. For each
|
||||
type, there are two actions: set and write. Setting a label
|
||||
|
16
notes.txt
16
notes.txt
@ -89,11 +89,17 @@ RAMSTART INITIAL_SP
|
||||
+2e BOOT C< PTR
|
||||
+4e INTJUMP
|
||||
+51 CURRENTPTR
|
||||
+53 readln's variables
|
||||
+55 adev's variables
|
||||
+57 FUTURE USES
|
||||
+59 z80a's variables
|
||||
+5b FUTURE USES
|
||||
+53 readln's IN(
|
||||
+55 readln's IN)
|
||||
+57 readln's IN>
|
||||
+59 z80a's ORG
|
||||
+5b z80a's L1
|
||||
+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
|
||||
+80 RAMEND
|
||||
|
||||
|
@ -214,17 +214,6 @@ 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
|
||||
`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
|
||||
[romwrite]: https://github.com/hsoft/romwrite
|
||||
[stage2]: ../../emul
|
||||
|
36
usage.txt
36
usage.txt
@ -86,39 +86,3 @@ flag to true. For example, "<>{ <>}" yields true.
|
||||
To check whether A is in between B and C inclusively, you would write:
|
||||
|
||||
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