The story so-far ...
I have written a simple machine code monitor based on my previous efforts - it's a bit "woz mon II" like because - well - that's what I first started with. I put some vectors into RAM so that other ROMs (ie. my TinyBasic) can use the monitor ROM serial code and save some space - this has freed up some 250 bytes in the TinyBasic ROM (hurrah!)
And I've managed to do this without compromising the space left over for the TinyBasic too - so it still has from $0300 through $0FFF for program (and 'dynamic') storage. (Variables @-Z are all in zero page)
At power-on time, the monitor looks for the on-board button being pressed and if it's not pressed then it boots directly into Basic. This takes a millisecond or so with most of the time spent printing out the welcome banner at 34800 bauds.
Basic, when starting, looks at the first save slot in the EEPROM and if the first line has
REM! at the very start of the line then it loads that program and runs it.
So this gives the system a way to power-up and auto-start a basic program.
But if you push the button at power-on, or reset time then the monitor is started and the jump to Basic is skipped, then if you subsequently push the button and start Basic (with the
@ command) then the auto-run feature is skipped. This would let you start the system into Basic without the auto-run - e.g. in some sort of embedded situation when you wanted to change the program.
(And yes, I think this is unlikely, but I'm retro-thinking here)
I think this gives you the best of both worlds.
Incidentally, the auto-start feature is borrowed from NIBL (National Industrial Basic Language) which is a TinyBasic that runs on the INS8060 CPUs (SC/MP). I understand that many of these systems were used in "industrial" scenarios during their lifetime - e.g. early computerised lift (elevator) controllers...
So power on into Basic:
Code: Select all
Ruby 6507 Computer 4K
GIBL v6
>DIR
0:
1: Bagels
2:
3:
4: Nightmare #6
5: Larson 4
>
Power on with the button pushed:
Code: Select all
Ruby 6507 Computer 4K
GMon v2
0000:
and that's the monitor.
Monitor commands are like woz-mon:
{address} .address action It supports memory dumping, disassembly, entering new data, going to Basic, setting he on-board LEDs and reading the button. Also moving memory and bulk zeroing or setting memory to a value.
Code: Select all
; Commands:
; Hex Enter number into current address (CA), carry on...
; # Comment
; @ Go to Basic
; ? Read button
; [ssss] ! Set LEDs to low nibble of ssss
; [ssss] G Run machine code from CA or ssss
; [ssss] P Prints (Dump) 16 bytes from CA or ssss
; [ssss] .eeee [P] Print (Dump) from start to end. (P optional)
; [ssss] L List (Disassemble) from CA or ssss
; [ssss] : vv [vv ...] Store into memory from CA or ssss
; [ssss] .eeee Z Zero memory from CA or ssss through eeee
; [ssss] .eeee > tttt Move memory from CA or ssss through eeee to tttt
; [ssss] .eeee / vv Fill memory from CA or ssss through eeee with value
; [ssss] +vvvv Add CA or ssss to vvvv, display result.
; [ssss] -vvvv Sub vvvv from CA or ssss, display result.
there is still 1¼ Kbytes free - could be more as I've not really tried to golf the code size down for now. I may add in a breakpoint handler and maybe mini-assembler but I feel thee may be little need for it all.
There is now a set of vectors and a small amount of code in RAM starting at $0180 - middle of the 6502 stack. There is exactly 32 bytes of stack free for programs to use. Possibly sub-optimal, but the Monitor uses little and Basic just as little. (Basic resets the stack pointer to $EF at startup and uses 17 bytes at most)
Code: Select all
0000: 100.1ff
0100: 31 30 30 2E 31 46 46 0D AA AA AA AA AA AA AA AA | 100.1FF |
0110: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0120: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0130: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0140: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0150: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0160: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0170: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
0180: 4C CA 01 4C BD 01 4C 9C 01 4C AB 01 4C B4 01 48 | L L L L L H |
0190: A5 E5 85 20 29 8F 85 E5 85 F8 68 60 20 8F 01 20 | ) h` |
01A0: BA 10 48 A5 20 85 E5 85 F8 68 60 20 8F 01 20 F9 | H h` |
01B0: 10 4C A2 01 20 8F 01 20 6C 11 4C A2 01 A5 E5 29 | L l L ) |
01C0: 8F 09 90 85 E5 85 F8 6C FC FF 20 8F 01 4C DE 11 | l L |
01D0: AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA | |
01E0: AA AA AA AA AA 10 00 06 09 D0 09 06 6B 15 7B 13 | { |
01F0: 00 00 00 00 0B 52 BA FB DE B0 FF 00 00 00 80 00 | b |
I initialise page 1 to
AA so I can keep an eye on it. Note $1Fx is the VIA, so usable stack is from $1EF down through $1D0. $100 through $17F is the keyboard input buffer. There is some wiggle room here - even by reducing the size of the input buffer down to (say) 96 bytes (just to make it an easy number for the start of the vectors, so $160 rather than $180) would be more than acceptable.
For the curious the code there is: (Using the disassembler)
Code: Select all
0200: 180L
0180: 4C CA 01 <L..L..> JMP $01CA
0183: 4C BD 01 <L..L..> JMP $01BD
0186: 4C 9C 01 <L..L..> JMP $019C
0189: 4C AB 01 <L..L..> JMP $01AB
018C: 4C B4 01 <L..H..> JMP $01B4
018F: 48 <H... )> PHA
0190: A5 E5 <... ).> LDA $E5
0192: 85 20 <. )...> STA $20
0194: 29 8F <).....> AND #$8F
0196: 85 E5 <....h`> STA $E5
0198: 85 F8 <..h` .> STA $F8
019A: 68 <h` .. > PLA
019B: 60 <` .. .> RTS
019C: 20 8F 01 < .. ..> JSR $018F
019F: 20 BA 10 < ..H. > JSR $10BA
01A2: 48 <H. ...> PHA
01A3: A5 20 <. ....> LDA $20
01A5: 85 E5 <....h`> STA $E5
01A7: 85 F8 <..h` .> STA $F8
01A9: 68 <h` .. > PLA
01AA: l
01AA: 60 <` .. .> RTS
01AB: 20 8F 01 < .. ..> JSR $018F
01AE: 20 F9 10 < ..L..> JSR $10F9
01B1: 4C A2 01 <L.. ..> JMP $01A2
01B4: 20 8F 01 < .. l.> JSR $018F
01B7: 20 6C 11 < l.L..> JSR $116C
01BA: 4C A2 01 <L....)> JMP $01A2
01BD: A5 E5 <..)...> LDA $E5
01BF: 29 8F <).....> AND #$8F
01C1: 09 90 <......> ORA #$90
01C3: 85 E5 <....l.> STA $E5
01C5: 85 F8 <..l.. > STA $F8
01C7: 6C FC FF <l.. ..> JMP ($FFFC)
01CA: 20 8F 01 < ..L..> JSR $018F
01CD: 4C DE 11 <L.....> JMP $11DE
01D0: AA <......> TAX
But really the only thing of interest is the first few JMP instructions which programs can use to call/goto various things. Also, the reason there appears to be so-much code there is the need to fiddle with the EEPROM bank-select register, keep a soft-copy (or 2) so we can correctly return to the ROM that called the routine. This code needs to be outside the ROM area...
Code: Select all
; Vectored routines:
goMonV: jmp goMon2 ; $0180
goBasicV: jmp goBasic2 ; $0183
putCharV: jmp putChar2 ; $0186
getCharV: jmp getChar2 ; $0189
getLineV: jmp getLine2 ; $018C
You could drop into the monitor, do "stuff" and come back again:
Code: Select all
>NEW
>10PRINT "Hello, world!"
>20END
>RUN
Hello, world!
>CALL &180
GMon v2
0000: 300.3ff
0300: 00 0A 19 50 52 49 4E 54 20 22 48 65 6C 6C 6F 2C | PRINT "Hello, |
0310: 20 77 6F 72 6C 64 21 22 0D 00 14 07 45 4E 44 0D | world!" END |
0320: FF FF 00 40 80 08 FF FF FF FF 00 08 00 00 00 00 | @ |
0330: 00 E0 FF FF FF FF 34 C8 00 B1 FF FF 6B C9 48 F6 | 4 k H |
0340: FF FF A4 10 00 C0 FF FF FF FF 08 15 01 B4 FF FF | |
0350: 00 20 FF FF FF FF 00 08 80 02 FF FF FF FF 00 84 | |
0360: FF FF 00 08 00 00 FF FF FF FF 00 00 00 00 FF FF | |
0370: 00 02 FF FF FF FF 00 24 00 70 FF FF FF FF 10 00 | $ p |
0380: FF FF 48 45 40 80 FF FF FF FF 20 0E 02 88 FF FF | HE@ |
0390: 00 10 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 | |
03A0: FF FF 00 40 14 00 FF FF FF FF 00 00 00 08 FF FF | @ |
03B0: 00 04 FF FF FF FF 00 19 60 65 FF FF 37 6C EB B5 | `e 7l |
03C0: FF FF 00 00 05 A0 FF FF FF FF 48 88 02 88 FF FF | H |
03D0: 80 00 FF FF FF FF 00 00 00 40 FF FF FF FF 10 10 | @ |
03E0: FF FF 00 21 40 88 FF FF FF FF 02 00 00 00 FF FF | !@ |
03F0: 00 25 FF FF 4E 1B A7 B3 00 91 FF FF 26 FE B1 95 | % N & |
0400: 183G
GIBL v6
>OLD
>LIST
10 PRINT "Hello, world!"
20 END
>
So that's about that for now. Comments/Suggestions welcome and I'll make a little video of it soon...
Cheers,
-Gordon