P2 ROM Monitor/Debugger (rev 1 & rev 2 silicon)
Cluso99
Posts: 18,069
P2 Monitor/Debugger
The Monitor/Debugger is loaded into the top 16KB of HUB RAM from the internal serial ROM by the booter software. The Monitor/Debugger code occupies HUB $FCA78-$FD025 inclusive (1454 bytes).
The Monitor/Debugger, along with TAQOZ and the autobaud booter, are all resident in HUB after power-up. Only an external serial terminal connected to Pins 63(in) and 62(out) is necessary to invoke the Monitor/Debugger or TAQOZ.
The Monitor/Debugger can be entered directly from power-up via the two character Serial autobaud sequence “> “ followed by Ctl-D. The Monitor/Debugger uses the serial connection via P63(in) and P62(out). The Monitor/Debugger supports the following commands at the input prompt…
Calling the Monitor/Debugger from User Programs
The Monitor/Debugger is callable from a users’ program.
The Monitor/Debugger Routines are also callable from a users’ program.
COG & HUB RAM Usage by the Debugger/Monitor
The Monitor/Debugger uses COG RAM $1E0-$1EF for variables.
The Receive String routines use HUB RAM $FC000-$FC04F as the input buffer unless lmm_bufad is initialised to point to a different HUB RAM address. Note: This buffer overwrites the booter code!
Below is a list of Routines that may be called by a user’s program…
Below is a list of the COG RAM variables and their usage…
The following are values passed in lmm_f for HEX, LIST and RXSTRING calls…
Note: The use of the lmm_ prefix is a carry over from when I first wrote the Monitor/Debugger way back in 2013. This was intended for the original P2 design which did not support HUBEXEC. So I used the LMM model as originally defined by Bill Henning. LMM stands for Large Memory Model, where a tiny routine in COG fetches each instruction from HUB and executes it in COG.
The Monitor/Debugger is loaded into the top 16KB of HUB RAM from the internal serial ROM by the booter software. The Monitor/Debugger code occupies HUB $FCA78-$FD025 inclusive (1454 bytes).
The Monitor/Debugger, along with TAQOZ and the autobaud booter, are all resident in HUB after power-up. Only an external serial terminal connected to Pins 63(in) and 62(out) is necessary to invoke the Monitor/Debugger or TAQOZ.
The Monitor/Debugger can be entered directly from power-up via the two character Serial autobaud sequence “> “ followed by Ctl-D. The Monitor/Debugger uses the serial connection via P63(in) and P62(out). The Monitor/Debugger supports the following commands at the input prompt…
--------------------------------------------------------------------------------------------- LMM DEBUGGER - SUPPORTED COMMANDS (Rev 1 & 2 silicon) --------------------------------------------------------------------------------------------- xxxxxx : xx xx xx xx ... <cr> DOWNLOAD: to cog/lut/hub {addr1} following {byte(s)} xxxxxx - [xxxxxx] [L] <cr> MEM LIST: from cog/lut/hub {addr1} to < {addr2} L=longs xxxxxx G <cr> GOTO: to cog/lut/hub {addr1} Q <cr> QUIT: Quit Rom Monitor and return to the User Program {addr} is on the stack Lfilename.xxx<cr> LOAD: Load file from SD (8.3 filename) returns "=" on success, "!" on failure Rfilename.xxx<cr> RUN: Run file from SD (8.3 filename) returns "!" on failure <esc><cr> TAQOZ: goto TAQOZ <cr> will repeat last MEM LIST command --------------------------------------------------------------------------------------------- Note: COG/LUT addresses are 3 digits or less and <$3FF, otherwise hub address is presumed. To list a low Hub address below $400, use a leading zero. (When calling from a user program use $1x_xxxx as only the lower 20 address bits are used)
Calling the Monitor/Debugger from User Programs
The Monitor/Debugger is callable from a users’ program.
The Monitor/Debugger Routines are also callable from a users’ program.
COG & HUB RAM Usage by the Debugger/Monitor
The Monitor/Debugger uses COG RAM $1E0-$1EF for variables.
The Receive String routines use HUB RAM $FC000-$FC04F as the input buffer unless lmm_bufad is initialised to point to a different HUB RAM address. Note: This buffer overwrites the booter code!
Below is a list of Routines that may be called by a user’s program…
-------------------------------------------------------------------------------------------- LMM DEBUGGER - Routines callable from users' programs -------------------------------------------------------------------------------------------- _SerialInit = $fcab8 'Serial Initialise (lmm_x & lmm_bufad must be set first) _HubTxCR = $fcae4 'Sends <cr><lf> (overwrites lmm_x) _HubTxRev = $fcaec 'Sends lmm_x with bytes reversed _HubTx = $fcaf0 'Sends lmm_x (can be up to 4 bytes) _HubHexRev = $fcb24 'Sends lmm_x with bytes reversed as Hex char(s) as defined in lmm_f _HubHex8 = $fcb28 'Sends lmm_x as Hex char(s) after setting lmm_f as 8 hex chars _HubHex = $fcb2c 'Sends lmm_x as Hex char(s) as defined in lmm_f _HubTxStrVer = $fcb9c 'Sends hub $0 terminated string at lmm_p address after setting lmm_p=##_str_vers _HubTxString = $fcba4 'Sends hub $0 terminated string at lmm_p address _HubListA2H = $fcbc4 'List/Dump line(s) from lmm_p address to lmm_p2 address after setting lmm_f=#_LIST+_ADDR2 _HubList = $fcbc8 'List/Dump line(s) from lmm_p address to lmm_p2 address according to lmm_f _HubRx = $fcb10 'Recv char into lmm_x _HubRxStrMon = $fccc4 'Recv string into hub address pointed to by lmm_bufad after setting prompt=lmm_x=#"*" & params=lmm_f=#_RXSTRING+_ECHO_+_PROMPT _HubRxString = $fcccc 'Recv string into hub address pointed to by lmm_p/lmm_bufad according to params in lmm_f _HubMonitor = $fcd78 'Calls the Monitor; uses lmm_bufad as the input buffer address _RdLongCogHub = $fcf34 'read cog/lut/hub long from lmm_p address into lmm_x, then lmm_p++ _str_vers = $fd014 'locn of the monitors hub string, $0 terminated -------------------------------------------------------------------------------------------- _HUBROM = $FC000 'ROM $FC000 _HUBBUF = $FC000 'use as RxString buffer (overwrites Booter) _HUBBUFSIZE = 80 'default size for _HUBBUF (can be 128) --------------------------------------------------------------------------------------------
Below is a list of the COG RAM variables and their usage…
-------------------------------------------------------------------------------------------- LMM DEBUGGER - COG VARIABLES $1E0-$1EF -------[ LMM parameters, etc ]-------------------------------------------------------------- lmm_x = $1e0 'parameter passed to/from LMM routine (typically a value) lmm_f = $1e1 'parameter passed to LMM routine (function options; returns unchanged) lmm_p = $1e2 'parameter passed to/from LMM routine (typically a hub/cog ptr/addr) lmm_p2 = $1e3 'parameter passed to/from LMM routine (typically a 2nd hub/cog address) lmm_c = $1e4 'parameter passed to/from LMM routine (typically a count) -------[ LMM additional workareas ]------------------------------------------- lmm_w = $1e5 'workarea (never saved - short term use between calls, except _HubTx) lmm_tx = $1e6 '_HubTx lmm_hx = $1e7 '_HubHex/_HubString lmm_hx2 = $1e8 '_HubHex lmm_hc = $1e9 ' " lmm_lx = $1ea '_HubList lmm_lf = $1eb ' " lmm_lp = $1ec ' " lmm_lp2 = $1ed ' " lmm_lc = $1ee ' " lmm_bufad = $1ef '_HubRxString --------------------------------------------------------------------------------------------
The following are values passed in lmm_f for HEX, LIST and RXSTRING calls…
-------------------------------------------------------------------------------------------- LMM DEBUGGER - lmm_f CALL Modes...(b4..b0 are modifier options) -------------------------------------------------------------------------------------------- _HEX_ = 2 << 5 ' hex... _REV_ = 1 << 4 ' - reverse byte order _SP = 1 << 3 ' - space between hex output pairs '_DIGITS = 7..0 ' no. of digits to display where 0 is 8 digits _LIST = 3 << 5 ' LIST memory line (1/4 longs) from cog/hub _ADDR2 = 1 << 4 ' 1= use lmm_p2 as to-address _LONG_ = 1 << 1 ' 1=display longs xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx _RXSTRING = 5 << 5 ' RXSTRING... _ECHO_ = 1 << 4 ' - echo char _PROMPT = 1 << 3 ' - prompt (lmm_x) _ADDR = 1 << 2 ' - addr of string buffer supplied _NOLF = 1 << 1 ' - strip <lf> --------------------------------------------------------------------------------------------
Note: The use of the lmm_ prefix is a carry over from when I first wrote the Monitor/Debugger way back in 2013. This was intended for the original P2 design which did not support HUBEXEC. So I used the LMM model as originally defined by Bill Henning. LMM stands for Large Memory Model, where a tiny routine in COG fetches each instruction from HUB and executes it in COG.
Comments
- [>][ ][Esc] to enter TAQOZ
- [>][ ][Ctrl + D] to enter P2 Monitor
Thanks, Cluso! It worked.
Kind regards, Samuel Lourenço
Please point me to an example of a call to _SerialInit and a description of the contents of lmm_x for that call. I plan to use _SerialInit, _HubTx, and _HubRx from Spin. Any suggestion or "gotcha"s.
Mike
forums.parallax.com/discussion/comment/1494072/#Comment_1494072
BUT then started getting weird results. Turns out spin2 uses the registers (lmm_x etc) that the ROM code uses
Warning: The ROM Monitor uses registers $1E0-$1EF which is also used by Spin2. Therefore, it is suggested you call the ROM Monitor/Debugger as a one-way event ie do not return to your spin2 code from the monitor
Once in the monitor, the usual monitor features are available eg examine/modify cog/lut/hub memory.
Putting this together with what Chip suggested, couldn't you copy $1E0-$1EF to a buffer somewhere before calling the ROM Monitor/Debugger, and then return to a stub that copies the saved content back to $1E0-$1EF before returning to Spin2?
Perhaps a 16 word buffer declared in HUBRAM with a SETQ WRLONG combo to save and a SETQ RDLONG combo to restore.
Have to get something working first!
I had embarked on using the Tx and TxString etc, but something was slightly messing up the results whereupon Chip said they were used by spin2. Been trying ever since to get something working reliably.
Ok. I was thinking that if you were to save the contentious range before monitor and debugger calls and restore them after that there'd be nothing else to do, but there's possibly something I'm missing.
I'm reminded of the zero page use under ProDOS on the Apple II, where we have to do the same thing to avoid ProDOS stomping on our zero page variables.
The monitor not only provides an interactive monitor, it also includes serial routines for outputting characters, string, hex, crlf, dumping cog/lut/hub, reading an input character or string, together with an optional prompt character. The dump has options for reversing and bytes or longs, and includes ascii output on the line.
The input also accepts a saved dump (download) to input to cog/lut/hub too.
All while still running Spin2 code? Impressive.
I'm offering an alternative to the solution of having to load a modified version of the ROM routines.
If you need to save the state of these variables between monitor calls then you need two buffers: One to hold Spin2's variables during each call, and one to hold the monitor's variables between calls. Then the code to call and return involves 8 extra instructions (probably inline pasm2):
Of course, if there are 8 spare longs available in the Spin2 memory footprint then building this into Spin2 would be more elegant. But then I seem to recall @cgracey saying something about the top 16k being wiped for debug. If so, I hope there's an opt-out for that or all of your work here will be for nothing.
Also I have to get the SD code working again, and include write too. It’s actually done but I’ve been waiting for spin2 to get the full FAT32 file interface done.
I am heavily reliant of having my monitor (debugger) working as I can check code operation along the way. It’s so easy to just display a register or hub value, or dump a piece of memory.
The calls to the monitor are extremely simple. Just load 1-5 registers and a call into hub.
lmm_x is the data register
lmm_f is an optional function register that selects options for the specific call
lmm_p and lmm_p2 are address registers (when required)
lmm_c is an optional count register (not sure if it is still used as some features were removed due to the rom size limits)
The ROM monitor can locate and load and optionally run a binary file from the SD card but the re-loaded monitor probably will not support these routines. They will be part of my full OS.
I am having trouble with the hex routines so no examples yet.
And I have to hard-code this due to a deficiency IMHO in Chip's compiler but Chip disagrees
The monitor code is contained within a pasm object and the register/calls/parameters are contained in another object.
The demo file gives simple examples of some of the calls available.
If you call the monitor from spin2, then typing "Q<cr>" at the "*" monitor prompt will return you to the spin code.
This code may also be called from pasm code. I'll need to provide a new example for that.
Serial Monitor calling examples PST output from above examples
The calls mon.TxListA2 and mon.TxListF...
* use the mon.TxListA2 call if you want the default address range and hex display (register mon.f is set by the routine)
* set mon.f to the bit options to control the format and then use the mon.TXListF call
From the call...
* any address < $200 will be cog
* any address < $400 but >= $200 will be lut
* otherwise it will be hub
But..
* an address > $1_0000 will be $00000 in hub
Note: both mon.p and mon.p2 must have this address $1_xxxxx set, otherwise only a single line will be displayed.
From the monitor...
* any address with 3 or less digits and < $200 will be cog
* any address with 3 or less digits and < $400 but >= $200 will be lut
* any address with more than 3 digits or >= $400 will be hub
* a <cr> will display the next list block
So, all of cog/lut/hub can be displayed (and it can be input ie changed too).
The use of the lmm prefix is because I wrote this back in 2013 before the P2 had hubexec so it was running in lmm mode back then. This was even before P2-HOT.
V1.4 is the ROM code compiled for soft-loading and uses different cog registers so it can be used with spin code.
Hello,
Syntax is not clear to me. I am just only trying the mem listing ('L') command and it fails. I don't know what I am doing wrong.
Please, can someone provide examples of ROM Monitor download, listing and 'G' GOTO?
Is it possible to download a simple Blink_LED program and run/execute ('G') that code?
Thank you !
You don't need/use the L command. It's likely an old writeup as I changed the code and missed the doc update.
For dumping cog ram valid addresses are 0-1EF
0-100
For dumping lut ram valid addresses are 200-3FF
200-280
For dumping hub ram
400-480
For dumping lower hub ram, use this trick
100000-100100
only 5 digits are recognised.
This also works when you are interactive (because you can call the monitor from your program) as the interactive version knows how many digits you entered
00000-00100
As for loading and running a binary file located on an SD card, you can do it but these days we have the tools so it's much easier to just download and run a binary (compiled program) wiht pnut, proptool or flexprop & loadp2.
The G command relies on you entering some code into memory and then jumping to it with the G command.
All commands follow the addresses.
The ? response is because the command could not be interpreted.
The [ and ] are enclosing optional parameters and the [ and ] should not be included in the command.
Sorry I don;t have time for a better explanation as I'm at work.