. An Interactive Memory Dump Utility for RetroForth

Rick Carlino

Personal blog of Rick Carlino, senior software engineer at Qualia Labs, co-founder of Fox.Build Makerspace. Former co-founder of FarmBot.

An Interactive Memory Dump Utility for RetroForth

NOTE: This is a literate program. A runnable version can be found here.

dump - A Memory Inspector for RetroForth

Two words are provided below: a regular dump word, plus a dump-s word for dealing with strings.

Example output:

> #16 [ 'Hello,_world! s:put nl ] dump
3C4C: 0x801
3C4D: 0xE97
3C4E: H
3C4F: e
3C50: l
3C51: l
3C52: o
3C53: ,
3C55: w
3C56: o
3C57: r
3C58: l
3C59: d
3C5A: !
3C5B: 0x0

dump (na-) prints a finite number of cells to STDOUT.

dump-s (s-) prints all cells in a null terminated memory region. It stops printing when a 0x0 value is encountered.



I create a private accumulator variable and helpers. The accumulator holds the address of the next cell I want to dump:

  'current-cell var

  :fetch-cell     (-a) @current-cell fetch ;
  :increment-cell (-)  @current-cell n:inc !current-cell ;
  :cell-is-null?  (-f) fetch-cell #0 eq? ;

Cell Presentation

When dumping memory regions, it is helpful to differentiate binary data from text.

Binary data is printed in hex format. A best effort guess is made to determine if a region contains ASCII.

I define several helpers to guess if a char is printable.

:is-char? (n-nf) dup #31 #127 n:between? ;

When a char is printable, I call c:get and output a newline:

:printable (c-) c:put nl ;

If the char is not printable, print it as hex with a 0x in front.

:non-printing (n-) '0x s:put hex n:put nl decimal ;

Then I create a word to contextually decides which way to print a value.

Again, binary data is formatted as hex and ASCII format is printed as a char:

:print-cell-content (-)  is-char? &printable &non-printing choose ;

Lastly, we need a way to pretty-print the cell’s address on the left side of the screen.

:print-cell-address (a-a) @current-cell hex n:put ':_ s:put ;

Inspecting Cells

To dump the next memory address, I fetch the accumulator’s value and then increment it. I print the memory address and contents to the screen in a way that makes sense.

:raw-dump (-)

  :dump-next (-f)

Public Interface


:dump-s  (a-)
  !current-cell &dump-next until

:dump (na-)
  &raw-dump times



Now that we have a working dump implementation, let’s try inspecting different types of data:

[ 'Hello,_world! s:put nl ] dump
'Works_on_anything          dump
here #100 -                 dump
&c:put                      dump
'Tests_complete.            s:put nl