Small utility programs for MineOS


Here are some small words and programs that are intended to be used interactively for debugging etc. For words that can be used by other programs, use the ControlLibrary page. Be aware the programs here may use the words from that page, though.

Utilities for Control

Word .MEM1 print 16 bytes of memory at address, nicely formatted in hex and ASCII.
: .MEM1 \ addr --
\ Write 16 bytes of memory at addr in hex and ASCII
  CR DUP .W 58 EMIT DUP
  16 + OVER DO I DUP 3 AND 0= IF SPACE THEN C@ .B LOOP SPACE
  DUP 16 + SWAP DO I C@ EMIT LOOP ;

Word .MEM2 will print 256 bytes of memory, nicely formatted. It takes a higher byte of memory address.
: .MEM2 \ block --
\ Write out a 256 byte long block of memory
  8 << DUP 256 + SWAP DO I .MEM1 16 +LOOP ;

CHARSET will display a nicely formatted character set.
: CHARSET \ --
\ Display the character set neatly
  CR ."    "
  16 0 DO SPACE I HEXDIGIT EMIT LOOP CR CR
  256 0 DO I .B 58 EMIT
  16 0 DO I J + SPACE EMIT LOOP
  CR CR 16 +LOOP ;

This is another memory probing word. It is 100% reliable, non-destructive and goes by 8K blocks.
: MEMCAP  \ -- max-addr
\ Return highest address available
  8192 BEGIN DUP DUP @ 2DUP INVERT SWAP ! OVER @ SWAP ROT
  2DUP ! -ROT XOR SWAP 0<> AND WHILE 8192 + REPEAT 1- ;

Clear the memory from HERE. Useful before saving the image.
: MEMCLR  \ --
\ Clear memory from HERE to maximum
  HERE MEMCAP OVER - 1+ 0 FILL ;

Change the value of a constant without recreating it. CONST works with signed values, whereas UCONST uses an unsigned value.
: CONST \ CONST <name-of-constant> <new-value>
TIBWORD FIND TIBWORD ATOI SWAP 3 + ! ;
 
: UCONST \ UCONST <name-of-constant> <new-value>
TIBWORD FIND TIBWORD UATOI SWAP 3 + ! ;
 

Allocate sector buffer for block editor at the end of memory instead of eating up 1k memory in between your code.
: HIMEM.SYS \ --
TOP @ 1024 - DUP TOP ! 1+ (blkbuf) ! ;


Utilities for IOX

I find it useful to define a short word to introduce some wait, so when I debug frames, I don't need a direct view from control console to the frame motor I need to debug.
: W \ --
\ Wait some time, for debugging
  50 TICKS ;

The SCOPE word is an "oscilloscope", it will read the IOX inputs each tick and on its change, it will show the new value and both absolute and relative timings in ticks. Very useful to time tubings and other events. It takes one argument which is how many ticks you want it to scan the IOX.
: SCOPELINE \ oldtime newtime value -- newtime value
\ Used in SCOPE
  CR DUP .W ." : " -ROT TUCK TUCK . - . SWAP ;
: SCOPE  \ time --
\ Display and time inputs from IOX for time ticks
  0 0 ROT 0 DO IOX@ TUCK
  <> IF I SWAP SCOPELINE
  THEN TICK LOOP 2DROP ;

Program debugging

Note: These words were converted to MineOS 1.1 to utilize new words without testing. There may be bugs. Also note that ['] must be coded from the ControlLibrary page first.

PATCH can be used to replace already defined word with another version. Useful for bugfixing. Be careful, when using FORGET, that the original word will point to the word being defined.
: PATCH \ --
\ The currently defined word will replace the word specified after patch
  VOCAB @ DUP DUP 1- 1- @ VOCAB ! ' SWAP VOCAB !
  34 OVER C! 1+ TUCK ! 1+ 1+ ['] EXIT SWAP ! ; IMMEDIATE

Example of use:
: 2OVER PATCH 2OVER
\ Correct Forth 2OVER
  >R >R 2DUP R> -ROT R> -ROT ;

TRACE can be used during the word definition to print word name and stack trace during execution.
: (TRACE)  \ name-addr --
\ Print the given string and stack contents
  CR ." TRACE: " TYPE SPACE .S ;
: TRACE  \ --
\ Add code to function being compiled to print out its name and stack on call
  VOCAB @ >NAME ['] (lit) , , ['] (TRACE) , ; IMMEDIATE

TRACE+ is like TRACE, but will also print stack trace at the EXIT from the word. This may not work correctly for all the words, if they do wild things with interpreter.
: (TRACEX)  \ --
\ Print the string on return stack and stack contents, used by (TRACE+)
  R> CR ." EXIT: " TYPE SPACE .S ;
: (TRACE+)  \ name-addr --
\ Print the given string and stack contents and setup call to (TRACEX) on EXIT
  R> OVER >R ['] (TRACEX) 1+ >R >R (TRACE) ;
: TRACE+  \ --
\ Like TRACE, but the stack will be printed also on exit
  VOCAB @ >NAME ['] (lit) , , ['] (TRACE+) , ; IMMEDIATE

Example of use:
: PLUS1 TRACE+
  DUP 1+ ;

Compiling

Compiling from disk with the disk block handling mechanism in MineOS is limited and has some undesirable consequences. The 1k memory allocated for block reading remains allocated even if not used in the final compiled system. Also (blkno) must be set to zero before saving the system (with SAVE") or the block remains current when the disk is booted from, which will automatically write back to disk when the block handling words are used. The LOAD word uses the stack between iterations of each line to maintain its own progress (v1.1 only, v1.2 appears to use a variable). Compiling also uses the stack which can cause conflicts when LOAD is being used. If a branch or loop is begun on one line but closed on a following line the operation will fail, because LOAD assumes the top stack value to be its own. While the first two may be overcome by setting (blkbuf) with a high RAM address in the unused region, and ensuring (blkbuf) and (bklno) are set to zero before saving, the latter cannot be overcome without recompiling LOAD (see here).
The following provide alternatives to LOAD (which was removed from MineOS v1.2 standard version). Each use the free space at the top of RAM as a temporary buffer, which does not remain as part of the system. Care must be taken that enough RAM is installed to cater for the increase in the system as compiled (from HERE) and the temporary buffer size required. LOADEX requires 1025 bytes and SECTEX requires the count of sectors * 128 + 1 bytes. Note that these words cannot be used recursively (to running disk content that uses either of them).

LOADEX is effectively an alternative to LOAD (the disk contents must be block aligned). Remember that block numbers start at 1.
\ n -- ,  nBlock LOADEX
:  LOADEX
 
   \ buffer address
   TOP @ 1024 - TUCK
 
   OVER 1- 8 * DUP 8 + SWAP DO
      DUP I DISKRS
      128 +
      898 C@ IF LEAVE THEN
   LOOP
 
   0 SWAP C!
 
   CR ." LOADEX block " U.
 
   TIBPTR @ >R INTERPRET R> TIBPTR !
 
   ;
SECTEX provides a little more flexibility as any number of sectors can be run, starting at any sector. They must be consecutive, but do not need to be block aligned (the disk contents must be sector aligned). Remember sector numbers start at 0.
\ n n -- ,  nStart nCount SECTEX
:  SECTEX
 
   \ starting address
   TOP @ OVER 128 * - -ROT 2OVER
 
   2OVER 2OVER OVER + SWAP ?DO
      DUP I DISKRS
      128 +
      898 C@ IF LEAVE THEN
   LOOP
 
   0 SWAP C!
 
   CR ." SECTEX " U. ." sectors from " U.
 
   TIBPTR @ >R INTERPRET R> TIBPTR !
 
   ;
Compiling hints:
Ensure you start compiling with an empty stack (you can just call ABORT). After compiling call .S. If a branch or loop was not closed 2 values will be left on the stack. If over closed Empty Stack will appear after compiling.
If compiling stops due to an error before completing a word, the word will not be accessible by the system. Call REVEAL to make it accessible and then FORGET it.