250 lines
10 KiB
Plaintext
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}
|