• Please review our updated Terms and Rules here

Small ROM-able monitor/assembler for PC?

Hak Foo

Experienced Member
Joined
Jul 18, 2021
Messages
213
So the machine I'm working on (a V40-based XT cloneish sort of thing) has a 32k PROM mounted at F800:0000, and "practical purposes" are using about 12k of it (8k main BIOS, 4k option ROM to handle a special disk system).

I figure there's something more useful or whimsical I can fit into the remaining 20k. My dream was to use the space for a small debugger/monitor, along the lines of that included on early Zenith PCs. This would be a useful to try to kick the disc controller into submission sometimes, when you can't boot enough to get to DEBUG.

As a proof of concept, I modified the main BIOS to believe it had Cassette Basic at F900:0000. At that point, I put a little stub there that will copy whatever I stash from F900:0100 to F900:4FFF down to 0000:7C00 and execute it.

This seems to allow running self-contained boot-sector programs like https://github.com/daniel-e/tetros or https://github.com/nanochess/pillman.

With some additional setup (initializing the sector registers to 07C0, putting the code at 0000:7D00, and moving the jump to 07C0:0100, to give a "more realistic" environment), I was able to get a DOS .COM executable running (the Palo Alto Tiny Basic from https://www.vcfed.org/forum/forum/te...basic-download)

The problem now is finding something better to put in. Tiny Basic is cute and obviously a neat throwback to "real" Cassette Basic, but a real monitor still feels more desirable. I originally figured DEBUG.COM would be a perfect drop in-- after all, it's been there since the dawn of time, odds are it uses very little more than BIOS functionality. Wrong. The version from DOS 2.0 basically explodes on launch, and from the source release, it appears to start making operating system calls early in its lifecycle. (I figured it MIGHT crash when you tried to read or write disc files, but not before that :sigh:)

Has anyone else tried this path? What monitor did you use? I'm assuming there are some "ROM-ready" designs that require less pre-load shimming, but I'm guessing there are more options if I can load a .COM into RAM and start at address 100.

It looks like the s100computers.com one is very elaborate, but also fairly dependent on their unusual hardware/firmware setup, rather than just relying on the BIOS features you'd find on a conventional PC clone, so it might need a fair bit of rework to get to a usable state.

There are some other "vintage" monitor scripts floating around, likely designed for other non-IBM 8086 platforms (again requiring rework), and even a few "512 byte monitor in a boot sector" but many of them don't include even rudimentary (dis) assemblers, which feels like it would be very useful.
 
Hi. The author of Debug, Tim Paterson, describes the history of the program in the book "Undocumented DOS". A short excerpt is shown in the attached photo. He original wrote the program as a monitor to fit in a 2KB ROM. In the book Tim refers to the source files being included with a disk that was part of the book. I spent alot of time looking for those files! Here is a link to a Zip file containg all the source code programs he mentions in the excerpt.

http://www.mtmscientific.com/CHAP7.zip

If memory serves, there may be some calls to DOS functions in the code. I also played around with creating a standalone BIOS for the IBM 5150 PC. I called that MIOS, and is just fun to play around with. Ruud has a ton of stuff related to this, and maybe he will comment as well.

http://www.mtmscientific.com/mios.html

Michael undoc_excerpt.jpg
 
I took a bit of time and OCR'd the Keyboard Code.

Code:
00010 ;
00020 ;
00030 ; EXAMPLE OF CUSTOM KEYBOARD SUPPORT SOFTWARE
00040 ;
00050 STACK SEGMENT PARA STACK 'STACK'
00060 DB 256 DUP (0) ;256 BYTES OF STACK SPAACE
00070 STACK ENDS
00080 ;
00090 DATA SEGMENT PARA PUBLIC 'DATA'
00100 BUFFER DB 10 DUP (0) ;TEN BYTE KEYBOARD BUFFER
00110 BUFPTR1 DW 0 ;POINTS TO START OF BUFFER
00120 BUFPTR2 DW 0 ;POINTS TO END OF BUFFER
00130 ; NOTE: WHEN BUFPTR1 = BUFPTR2 , THEN THE BUFFER IS EMPTY
00140 ; SCANTABLE CONVERTS SCAN CODES RECEIVED FROM THE KEYBOARD
00150 ; INTO THEIR CORRESPONDING ASCII CHARACTER CODES:
00160 SCANTABIE DB 0,0,'1234567890-=',8,0
00170 DB 'QWERTYUIOP[]',0DH,0
00180 DB 'ASDFGHJKL;',0,0,0,0
00190 DB 'ZXCVBNM,./'.0,0,0
00200 DB ' ',0,0,0,0,0,0,0,0,0,0,0,0,0
00210 DB '789-456+1230.'
00220 DATA ENDS
00230 ; ,
00240 CODE SEGMENT PARA PUBLIC 'CODE'
00250 START PROC FAR
00260 ;
00270 ; STANDARD PROGRAM PROLOGUE
00280 ;
00290 ASSUME CS:CODE
00300 PUSH DS ;SAVE PSP SEG ADDR
00310 MOV AX,0
00320 PUSH AX ;SAVE RET ADDR OFFSET (PSP+0)
00330 MOV AX,DATA
00340 MOV DS,AX ;ESTABLISH DATA SEG ADDRESSABILITY
00350 ASSUME DS:DATA
00360 ;
00370 ; PART1: SETUP OUR OWN KEYBOARD INTERRUPT SERVICE ROUTINE
00380 ;
00390 CLI ;DISABLE ALL INTERRUPTS
00400 M0V AX,0
00410 MOV ES,AX ;POINT EXTRA SEGMENT AT THE...
00420 ; ...INTERRUPT SERVICE ROUTINE ADDRESS TABLE
00430 MOV DI,24H ;OFFSET OF ENTRY FOR TYPE CODE 09H
00440 MOV AX,OFFSET KBINT ;OFFSET OF OUR SERVICE ROUTINE
00450 CLD ; SET 'FORWARD' STRING OPERATIONS
00460 STOSW ;PLACE IT IN THE TABLE
00470 MOV AX,CS ;SEG OF OUR SERVICE ROUTINE
00480 STOSW ;PLACE IT IN THE TABLE
00490 MOV AL,0FCH ;ENABLE TIMER AND KYBD INTERRUPTS
00500 OUT 21H,AL ;WRITE INTERRUPT MASK REGISTER
00510 STI ;ENABLE INTERRUPTS TO THE 8088
00520 ;
00530 ; PART2: READ FROM KEYBOARD AND DISPLAY CHARACTERS ON SCREEN
00540 ;
00550 FOREVER: CALL KBGET ;WAIT FOR A CHARACTER FROM THE KEYBOARD
00560 PUSH AX ;SAVE THE CHARACTER
00570 CALL DISPCHAR ;DISPLAY THE CHARACTER RECEIVED
00580 POP AX ;RESTORE THE CHARACTER
00590 CMP AL,0DH ;WAS IT A CARRIAGE RETURN?
00600 JNZ FOREVER ;BRANCH IF NOT
00610 MOV AL,0AH ;YES IT WAS, WE MUST ALSO DISPLAY...
00620 CALL DISPCHAR ;...A LINE FEED!
00630 JMP FOREVER ;STAY IN THIS LOOP FOREVER
00640 ;
00650 ; CALL KBGET TO WA1T FOR A CHARACTER TO BE RECEIVED FROM
00660 ; THE KEYBOARD. THE CHARACTER IS RETURNED IN REG AL.
00670 KBGET PROC NEAR
00680 PUSH BX ;SAVE REGISTER BX
00690 CLI ;DISABLE INTERRUPTS
00700 MOV BX,BUFPTR1 ;START OF BUFFER
00710 CMP BX,BUFPTR2 ;IS BUFFER EMPTY?
00720 JNZ KBGET2 ;-->N0
00730 STI ; RE-ENABLE INTERRUPTS
00740 POP BX ;RESTORE REGISTER BX
00750 JMP KBGET ;WAIT UNTIL SOMETHING IN BUFFER
00760 ; THERE IS SOMETHING IN THE BUFFER, GET IT :
00770 KBGET2: MOV AL,[BUFFER+BX] ;GET CHAR AT BUFFER START
00780 INC BX ;INCREMENT BUFFER START
00790 CMP BX,10 ;HAVE WE WRAPPED AROUND?
00800 JC KBGET3 ;BRANCH IF NOT
00810 MOV BX,0 ;YES, WRAP AROUND
00820 KBGET3: MOV BUFFPTR1,BX ;INDICATE NEW START OF BUFFER
00830 STI ;RE-ENABLE INTERRUPTS
00840 POP BX ;RESTORE REGISTER BX
00850 RET ;RETURN FROM KBGET
00860 KBGET ENDP
00870 ;
00880 ; KBINT IS OUR OWN KEYBOARD INTERRUPT SERVICE ROUTINE:
00890 ;
00900 KBINT PROC FAR
00910 PUSH DS ;SAVE ALL ALTERED REGISTERS!!
00920 PUSH BX
00930 PUSH AX
00940 ;
00950 ; ESTABLISH ADDRESSABILITY TO OUR DATA SEGMENT:
00960 ;
00970 MOV AX,DATA
00980 MOV DS,AX
00990 ;
01000 ; READ THE KEYBOARD DATA AND SEND THE ACKNOWLEDGE SIGNAL:
01010 ;
01020 IN AL,60H ;READ KEYBOARD INPUT
01030 PUSH AX ;SAVE KEYBOARD INPUT
01040 IN AL,61H ;READ 8255 PORT PB
01050 OR AL,80H ;SET KEYBOARD ACKNOWLEDGE SIGNAL
01060 OUT 61H,AL ;SEND KEYBOARD ACKNOWLEDGE SIGNAL
01070 AND AL,7FH ;RESET KEYBOARD ACKNOWLEDGE SIGNAL
01080 OUT 61H,AL ;RESTORE ORIGINAL 8255 PORT PB
01090 ;
01100 ; DECODE THE SCAN CODE RECEIVED:
01110 ;
01120 POP AX ;REGAIN THE KEYBOARD INPUT (AL)
01130 TEST AL,80H ;IS IT A KEY BEING RELEASED?
01140 JNZ KBINT2 ;BRANCH IF YES, WE IGNORE THESE
01150 MOV BX,OFFSET SCANTABLE ;SCAN CODE - ASCII TABLE
01160 XLATB ;CONVERT THE SCAN CODE TO AN ASCII CHAR
01170 CMP AL,0 ;IS IT A VALID ASCII KEY?
01180 JZ KBINT2 ;BRANCH IF NOT
01190 ;
01200 ; PLACE THE ASCII CHARACTER INTO THE BUFFER:
01210 ;
01220 MOV BX,BUFPTR2 ;GET POINTER TO END OF BUFFER
01230 MOV [BUFFER+BX],AL ;PLACE CHAR IN BUFFER AT END
01240 INC BX ;INCREMENT BUFFER END
01250 CMP BX,10 ;HAVE WE WRAPPED AROUND?
01260 JC KBINT3 ;BRANCH IF NOT
01270 MOV BX,0 ;YES, WRAP AROUND
01280 KBINT3: CMP BX,BUFPTR1 ;IS BUFFER FULL?
01290 JZ KBINT2 ;BRANCH IF YES, WE LOSE THIS CHAR
01300 MOV BUFPTR2,BX ;INDICATE NEW END OF BUFFER
01310 ;
01320 ; NOW INDICATE "END OF INTERRUPT" TO THE INTERRUPT CONTROLLER:
01330 ;
01340 KBINT2: MOV AL,20H ;SEND "EOI" COMMAND...
01350 OUT 20H,AL ;...TO 8259 COMMAND REGISTER
01360 POP AX ;RESTORE ALL ALTERED REGISTERS!!
01370 POP BX
01380 POP DS
01390 IRET ;RETURN FROM INTERRUPT
01400 KBINT ENDP
01410 ;
01420 ; SUBROUTINE TO DISPLAY A CHARACFER ON THE SCREEN.
01430 ; ENTER WITH AL = CHARACTER TO BE DISPLAYED.
01440 ; USES VIDEO INTERFACE IN BIOS.
01450 ;
01460 DISPCHAR PROC NEAR
01470 PUSH BX ;SAVE BX REGISTER
01480 MOV BX,0 ;SELECT DISPLAY PAGE 0
01490 MOV AH,14 ;FUNCTION CODE FOR "WRITE"
01500 INT 10H ;CALL VIDEO DRIVER IN BIOS
01510 POP BX ;RESTORE BX REGISTER
01520 RET ;RETURN TO CALLER OF 'DISPCHAR'
01530 DISPCHAR ENDP
01540 ;
01550 START ENDP
01560 CODE ENDS
91570 END START

Hopefully, it doesn't have any errors.


Linux commands:

$ pdftk mios_kbd.pdf burst

$ convert -density 600 pg_0003.pdf -depth 8 pg_03.tiff
$ convert -density 600 pg_0004.pdf -depth 8 pg_04.tiff

Then use Irfanview & the KADMOS Plugin to OCR the *.tiff files.
Correct the OCR'd ERRORS.



Larry

pg01.txt
 

Attachments

  • pg01.txt
    6.8 KB · Views: 1
Last edited:
The original SCP 8086 monitor (which begat our beloved DEBUG.COM) was indeed written as a 2KB ROM monitor, communicating over the console/serial port of the SCP 8086 card. The source for this version is apparently in the public domain, here's the original manual with source code listing for it:

http://www.s100computers.com/Hardware Manuals/Seattle Computer Products/SCP 8086 Monitor.pdf

I've seen electronic versions of the source floating around as well (perhaps it was on Bitsavers?) and the code is designed to be assembled using the SCP 8086 assembler. You can get the assembler v2.44 (ASM.COM) from the 86DOS 1.14 floppies and run it directly under early MS-DOS (I'd recommend 1.x) to produce a binary. Would just need to tweak the monitor's I/O routines to use BIOS services for character output and keyboard input.

If you look at the SCP monitor side-by-side with the DEBUG sources from MS-DOS 2.xx you'll find many sections where the code is unchanged. The Microsoft additions all use lowercase mnemonics while the original SCP code is in uppercase...
 
Dunno if this is interesting to you, but I just stumbled onto this thread, I've had a similar desire for the Z150 ROM Monitor in my XTjr 8088 machine so I disaseembled the Z150 BIOS ROMs in Ghidra and moved all the MFM-150 code I could to assemble again in NASM and it kinda works. Althought the Ctrl-Alt-Enter Break Debugger bit is unfished - the unassemble command doesn't know where you are and I can't trace or return to the code - I don't think I setup all the debugger variables just right. However, you can start it as a replacement for the CASSETTE BASIC ROM, that's how I was originally running it till I re-packaged it as an Option ROM which also inserts itself into int 18h BASIC Vector so that the BIOS.

Haven't actually tried it yet on my XTjr, only in Bochs using the same BIOS as my machine and it works pretty good.

Anyway, just posed the code up today if you're interested in assembling, testing, developing further...

 
That's super-nifty. What's the licensing status on this? (On a more historic basis, where did Zenith's BIOS and ROMs come from?)

I had been experimenting with MON88 from http://www.ht-lab.com/cpu86.htm -- it assumes no DOS stuff, so there's only a few functions that need to be patched to use BIOS calls, but it's also written for a weird commercial assembler syntax, and needs to be massaged to build on something like wasm, so I'm not sure how much subtle breakage happens in translation.

Not sure it's really designed to be a "pop up resident" monitor like the Zenith one, but I was mostly thinking in terms of "if the hard disc module doesn't fire up, boot into a monitor and poke its ports to see what's going on" sort of debugging.
 
I'm a bit clueless when it comes to licensing here, it's likely whoever owns Zenith these days? I got the ROM images from a vcfed forum post:


Which is used on PCjs:


I will happily remove the GitHub repo should anyone have any problems with it. I'm not doing this for any commercial interest and the Z150 machines are long since out of production.

MON88 sounds really intresting the link to the source didn't work on your link, but I'll maybe look elsewhere. I also just wanted to use the Monitor for the odd looking at memory addresses, in/out ports etc... and wasn't really interested in debugging code, so I didn't finish my reconstruction efforts to get that up and running properly.
 
You download the entire "CPU86 IP Source Files" package which apparently contains an 8088 soft core and tooling; the monitor is in cpu86/Software/Mon88 inside that. I was drawn to it because it had a disassembler and fit into about 12k of ROM, but I was sort of hoping it would have an assembler.

The major changes I needed, as I recall:

* Retool from A86 syntax to NASM syntax with bunch of probably-wrong search-and-replaces. There was some issue where it was looking for some constants for command names, which were stored big-endian instead of little-endian or vice versa-- it would run but the command names needed to be enterred backwards to be recognized :p
* Rewrite the character in/out functions to call BIOS I/O rather than serial port stuff
* Possibly remove some reimplementation of BIOS functions that already exist on a real PC.

There's probably some stub functionality left over (accepting an upload from another host) and a lot of untested stuff.
 
Here's a quick repository of the experimentation I did on MON88.


It's about as user-friendly as a land mine right now but seems to be capable of reading memory, disassembly, and poking things out of ports when I run it as a .COM file in DOSBox. I haven't bolted it into a real ROM yet.
 
Here's a quick repository of the experimentation I did on MON88.


It's about as user-friendly as a land mine right now but seems to be capable of reading memory, disassembly, and poking things out of ports when I run it as a .COM file in DOSBox. I haven't bolted it into a real ROM yet.
Very interesting, I will take a look! If I get time I'll try running it from ROM image too for fun!
 
Back
Top