From dfaa1dc1011f0ef32160feba386684ef9b8a79a4 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Sun, 19 Apr 2020 16:28:40 -0400 Subject: [PATCH] link: add "offset" argument to RLDICT As long as our target was the first word of the "user" dict, using target's prev to compute offset was fine, but when the target is not the first word, this system breaks down. This is the case when, instead of including source code in our boot binary, we paste it in Collapse OS' prompt. Also, adjust RC2014 recipe to include stage 3 assembling instructions with the "paste into prompt" method. --- forth/link.fs | 27 ++++++++++---------- recipes/rc2014/README.md | 53 ++++++++++++++++++++++++++++++---------- recipes/rc2014/run.fs | 2 +- 3 files changed, 55 insertions(+), 27 deletions(-) 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+ ! ;