gigatron/rom/Apps/WozMon/WozMon_v1.gcl
2025-01-28 19:17:01 +03:00

250 lines
10 KiB
Plaintext

{-----------------------------------------------------------------------+
| |
| Recreation of WozMon for Gigatron TTL microcomputer |
| |
+-----------------------------------------------------------------------}
gcl0x
{
2018-06-12 (marcelk) Initial version
2018-06-15 (marcelk) Mimic behaviour of original much better, while
avoiding spurious newlines to save vertical space.
Gracefully allow self-invocation ("200R").
2018-06-21 (marcelk) Simplifications ported back from Tiny BASIC
2018-06-22 (marcelk) Use the won space to echo user input in white
What works the same as the original:
- Type hex address to examine memory contents
- Type '.' and end address for block examine
- Type ':' and data bytes for writing into memory
- Type 'R' to start execution from last address
- Multiple commands in one line
- Any ASCII code below '.' is a blank
- Too long input is flushed
- Shows backslash prompt at error ('\')
Gigatron-specific differences:
- Welcome message is "*** WozMon" instead of error prompt ('\')
- Can use lowercase as well as uppercase for hex letters
- Delete shows effect on screen, no need for '_' (RUBOUT)
- Always print address at start of line in block examine mode
- Input buffer is bounded by the screen width
- Executed code can go back to monitor with RET instruction ($ff)
- Faster screen update, and cursor symbol instead of '@'
- A bit more careful with emitting empty lines
References:
Online Apple 1 Emulator (Hit [RESET] to enter WozMon):
https://www.scullinsteel.com/apple1/
Using The Woz Monitor:
https://www.sbprojects.net/projects/apple1/wozmon.php
Original MOS6502 source code:
https://github.com/jefftranter/6502/tree/master/asm/wozmon
https://www.sbprojects.com/projects/apple1/wozmon.txt
}
{-----------------------------------------------------------------------+
| RAM page 2 |
+-----------------------------------------------------------------------}
[def $2a# $2a# $20# $57# $6f# $7a# $4d# $6f# $6e# 0#] tmp= {** WozMon}
$01df deek Pos= {Bottom character row in screen memory}
{Slightly cheating with endianness}
{ Print ASCII character (32..127) on screen in 5x8 pixels }
{ Also advance cursor position }
[def
82- {Map ASCII code to offset in font table}
[if<0 50+ i= \font32up {ASCII 32..81}
else i= \font82up] k= {ASCII 82..127}
i 2<< i+ {Multiply by 5}
k+ k= {Add to page address to reach bitmap data}
\SYS_VDrawBits_134 \sysFn: {Prepare SYS calls}
\sysArgs6; \sysArgs0: {Apply caller-defined colors}
Pos \sysArgs4: {Position for character}
$fe%= {Temporarily park return value on the stack}
6+ Pos= {Advance position by 6 pixels}
5 [do i= {Draw 5 vertical slices}
k 0? \sysArgs2. {Get slice from ROM}
134!! {Invoke SYS function to draw pixels}
k<++ \sysArgs4<++ {Advance to next slice}
i 1- if>0loop] {Looping}
$fe% {Return effective position}
ret
] PrintChar=
{ Print a newline conditionally }
[def
Pos<, [if<>0 {If not at start already}
\SYS_VDrawBits_134 \sysFn: {Prepare SYS call}
$800 Pos<. {Go back to start}
Pos+ [if<0 $0800] Pos= {Go down 8 lines and wrap around if needed}
\sysArgs4: {sysArgs[4:5] is position on screen}
\sysArgs2. {All-zero output pattern}
[do
134!! {SYS call}
\sysArgs4<++ {Advance to next slice}
\sysArgs4, 160^ {Test for end of screen}
if<>0loop]
{Scroll up by modifying videoTable}
$01ee i= {Last entry in video table}
[do
i, 120- [if<0 128^
else 8^]
i. {Rotate by 8 in 8..127 range}
i 2- i= {Previous entry in video table}
$fe^ if<>0loop] {Until all done}
]
ret
] CNewline=
{ Print byte as hexadecimal value }
[def
push
tmp= {Save value}
\SYS_LSRW4_50 \sysFn: {Prepare SYS call for shift}
tmp 50!! {Shift right 4 bits}
10- [if>=0 7+] $3a+ {Convert to hex digit}
PrintChar!
tmp 15& {Low 4 bits}
10- [if>=0 7+] $3a+ {Convert to hex digit}
PrintChar!
pop ret
] PrintByte=
$300 call
{-----------------------------------------------------------------------+
| RAM page 3 |
+-----------------------------------------------------------------------}
$0300:
{ Process new input line }
[def
push
$80 Buffer= {One before begin of buffer}
CNewline!
[do {NEXTITEM}
Buffer<++ {Advance text pointer}
Buffer, if<>0 {While not at end of buffer}
$2e- if<0loop {Ignore everything below '.'}
[if=0 1 Mode= loop] {'.' Set Block Examine mode and continue}
$0c- [if=0 1- Mode= loop] {':' Set Store mode and continue}
$18- [if=0 Examine! loop] {'R' "Run" and continue in case of return}
0 tmp= {Stays zero if we don't see any hex digit}
[do {NEXTHEX} {Parsing hexadecimal number}
Value= {Update partial result}
4<< i= {Next term for adding hex digit}
Buffer, {Get character for hex test}
Buffer<++ {Already advance text pointer}
$30- {'0'} if>=0 {Bail out if out of range}
10- {'9'} [if<0 {Decimal digit}
tmp= {Non-zero to mark hex digits found}
10+ {Map in 0..9 range}
i+ {Add it to value}
loop] {To NEXTHEX}
6- 31& {Map remainder to uppercase}
{'A'} if>0 {Bail out if out of range}
7- {'F'} if<0 {Hex letter}
tmp= {Non-zero to mark hex digits found}
16+ {Map in 10..15 range}
i+ {Add it to value}
loop] {To NEXTHEX}
tmp [if<>0 {There is a value to process}
Buffer 2- Buffer= {We advanced too much}
Mode [if<0 {"Store"}
Value Store. {Store value through store pointer}
Store 1+ Store= {Advance store pointer}
loop] {To NEXTITEM}
[if=0 {"Examine"}
CNewline! {Forces printing of new address}
Value Store= {Also set store pointer}
1- Examine=] {Will print one value}
[do {"Block Examine"}
Examine Value- if<0 {Walk with Examine until past Value}
Examine 1+ Examine= {Advance examine pointer}
7& [if=0 CNewline!] {If address mod 8 == 0 continue on next line}
Pos<, [if=0 {If at start of line print address}
2 Pos<. {Tiny 2 pixel indent to be nice}
Examine>, PrintByte! {Print high-byte of address}
Examine<, PrintByte! {Print low-byte of address}
$3a PrintChar!] {Print colon}
Pos 4+ Pos= {Small 4 pixel space to fit on Gigatron screen}
Examine, PrintByte! {Print data byte at address}
loop]
0 Mode= {Back to Examine mode}
loop] {To NEXTITEM}
$5c PrintChar!] {Error prompt '\' and break loop}
pop ret
] ProcessBuffer=
Pos<++ {Force a non-zero low byte}
$0f20 \sysArgs6: {Pen color yellow, background color blue}
\sysArgs0. CNewline! {Now forced to scroll and clear last line}
{ Display '*' and welcome message }
$2a [do PrintChar! tmp, tmp<++ if<>0loop]
$0400 call
{-----------------------------------------------------------------------+
| RAM page 4 |
+-----------------------------------------------------------------------}
$0400:
{ Input loop, assume some kind of ASCII keyboard is hooked up }
[do {GETLINE}
$81 Buffer= {Prepare for next input line}
CNewline!
[do {NEXTCHAR}
127 \sysArgs7. {Pen color white for user input}
PrintChar! Pos= {Draw cursor}
\serialRaw, [do {Wait for key change}
tmp= \serialRaw, Buffer.
tmp^ if=0 Buffer, loop]
Buffer, 10^ if<>0 {Enter/return breaks NEXTCHAR loop}
117^ [if=0 {Delete pressed (10^127 == 117)}
$20 PrintChar! Pos= {Remove cursor}
Pos<, 6- [if>=0 {If not on first position}
Pos<. {Step back}
Buffer 1- Buffer=] {Also remove character from buffer}
loop] {To NEXTCHAR}
96- if>=0loop {Ignore apparent unprintable garbage}
Buffer, PrintChar! {Print accepted characters}
Buffer<++ {Advance pointer, keeping the character}
Pos<, 150^ [if=0 {Arrived at position 25 (25*6 == 150)}
$81 Buffer= {Discard of too long input}
$5c PrintChar! CNewline!] {Error indicator '\'}
loop] {To NEXTCHAR}
Buffer. {Terminate input with zero}
Mode= {Start in examine mode}
$20 PrintChar! {Remove and advance cursor}
$0f \sysArgs7. {Pen color yellow for output}
ProcessBuffer!
loop] {To GETLINE}