diff --git a/forth/link.fs b/forth/link.fs index e319016..e13fa8d 100644 --- a/forth/link.fs +++ b/forth/link.fs @@ -110,11 +110,11 @@ ( TODO implement RLCELL ) ( Copy dict from target wordref, including header, up to HERE. - We're going to compact the space between that word and its - prev word. To do this, we're copying this whole memory area - in HERE and then iterate through that copied area and call - RLWORD on each word. That results in a dict that can be - concatenated to target's prev entry in a more compact way. + We're going relocate those words by specified offset. To do + this, we're copying this whole memory area in HERE and then + iterate through that copied area and call RLWORD on each + word. That results in a dict that can be concatenated to + target's prev entry in a more compact way. This copy of data doesn't allocate anything, so H@ doesn't move. Moreover, we reserve 4 bytes at H@ to write our target @@ -129,19 +129,16 @@ possible to reliably detect its end. If you need that last word, define a dummy word before calling RLDICT. ) -( target -- ) +( target offset -- ) : RLDICT ( First of all, let's get our offset. It's easy, it's target's prev field, which is already an offset, minus its name length. We expect, in RLDICT that a target's prev word is a "hook word", that is, an empty word. ) - ( H@ == target ) - DUP H@ ! - DUP 1- C@ 0x7f AND ( t namelen ) - SWAP 3 - @ ( namelen po ) - -^ ( o ) ( H@+2 == offset ) - H@ 2+ ! ( ) + H@ 2+ ! ( target ) + ( H@ == target ) + H@ ! ( ) ( We have our offset, now let's copy our memory chunk ) H@ @ WORD( ( src ) DUP H@ -^ ( src u ) @@ -180,5 +177,9 @@ ( Relink a regular Forth full interpreter. ) : RLCORE - LIT< H@ (find) DROP RLDICT + LIT< H@ (find) DROP ( target ) + DUP 3 - @ ( t prevoff ) + ( subtract H@ name length ) + 2- ( t o ) + RLDICT ; diff --git a/recipes/rc2014/README.md b/recipes/rc2014/README.md index 7832e3e..5c55902 100644 --- a/recipes/rc2014/README.md +++ b/recipes/rc2014/README.md @@ -210,22 +210,49 @@ That's it! our binary is ready to run! ../../emul/hw/rc2014/classic stage2r.bin -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` and `adev.fs` to stage2 so that you have a full-featured -interpreter. +And there you have it, a stage2 binary that you've assembled yourself. -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. +### Assembling stage 3 -Here's a little cheatsheet, but seriously, you should figure most of it -yourself. Tough love they call it. +Stage 2 gives you a useable prompt, but bare. Because 8K isn't a lot of space +to cram source code, we're limited in what we can include for this stage. -* `cat stage2.bin ../../forth/readln.fs ../../forth/adev.fs run.fs > stage2r.bin` -* Don't forget `RDLN$` and `ADEV$`. -* `RLDICT` is like `RLCORE` but with a chosen target. -* `stripfc` can help you deal with size constraints. +However, now that we have a usable prompt, we can do a lot (be cautious though: +there is no `readln` yet, so you have no backspace), for example, build a +stage 3 with `readln`. + +Copy the unit's source + + cat ../../forth/readln.fs | ../../tools/stripfc | xclip + +and just paste it in your terminal. 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 `/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 +need to relocate it in the same way you did for stage 2, but instead of using +`RLCORE`, which is a convenience word hardcoded for stage 1, we'll parametrize +`RLDICT`, the word doing the real work. + +`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 +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 +is, `' INBUFSZ WORD(` minus the offset of the last word (which should be a hook +word) in the ROM binary. + +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 +offset value is: + + ' INBUFSZ WORD( 0x08 @ - + +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 +initializes `RDLN$` instead of creating a minimal `(c<)`. + +Keep that `stage3.bin` around, you will need it for further recipes. [rc2014]: https://rc2014.co.uk [romwrite]: https://github.com/hsoft/romwrite diff --git a/recipes/rc2014/run.fs b/recipes/rc2014/run.fs index 4d59f6f..5b26b59 100644 --- a/recipes/rc2014/run.fs +++ b/recipes/rc2014/run.fs @@ -1,7 +1,7 @@ : (c<) KEY DUP EMIT ; : INIT ACIA$ - ." Collapse OS" CR LF + ." Collapse OS" CRLF ( 0c == CINPTR ) ['] (c<) 0x0c RAM+ ! ;