The Vicmon machine language cartridge is an excellent tool for exploring the Vic-20. This article and its associated video will show you how to use it to create a simple program that will change the normal output of a Vic so that it feels a bit like a teletype terminal. This will be done by taking over some of the functionality of the KERNEL's CHROUT subroutine at $FFD2
. For those without an easy way of entering an assembly language program, there is a BASIC listing at the end.
Assuming you have the Vicmon cartridge attached to your machine or emulator, you can now enter the monitor. If you are not too familiar with the Vicmon cartridge, have a look at: Beginning Assembly Programming on the Vic-20.
SYS 24576
Each KERNAL subroutine is actually just a jump table to somewhere else. To see where the CHROUT subroutine jumps to, we'll disassemble the code at $FFD2
:
.D FFD2
Which shows that it contains:
FFD2 JMP ($0326)
This is an indirect jump to the address stored at $0326
.
If we now look at $0326
:
.M 0326
We see that the first two bytes are 7A F2
. The 6502 is little-endian, so it stores the least significant byte first and hence this is address $F27A
. Because $0326
is in RAM, we can change the address there to point to our code. Once our routine has been run, we'll jump to $F27A
to output the character to screen.
It would be better if our program doesn't interfere with BASIC, so as it is quite small, we can store it in the cassette buffer. This is located at $033C
and is 191 bytes long. If you load or save with the cassette, the program will naturally be lost.
The program is essentially in two parts. The first part changes the output vector to point to the second part and sets the volume to maximum. The second part is the routine which will be called when the CHROUT ($FFD2
) subroutine jumps to the output vector stored at $0326
. This part will output a noise, pause and then jump to the original output vector at $F27A
.
The video below shows how to use the Vicmon machine language cartridge to enter the program and demonstrates the TTY effect.
Disassembly of Program
Here is the full program as entered in the video, so that you can play with it yourself.
; Initialize the routine
033C LDA #$03 ; Point output vector used by $FFD2 to our routine
033E STA $0327 ; |
0341 LDA #$4C ; |
0343 STA $0326 ; \
0346 LDA #$0F ; Set the volume to maximum
0348 STA $900E ; \
034B RTS
; The main routine pointed to by the output vector
034C PHA ; Save the character to be printed
034D CMP #$20 ; Skip making a noise if a space character
034F BEQ $035A ; \
0351 CMP #$0D ; Skip making a noise if a return character
0353 BEQ $035A ; \
0355 LDA #$80 ; Make the lowest note possible with speaker 2
0357 STA $900B ; \
035A TXA ; Save the registers because $FFD2 doesn't alter them
035B PHA ; |
035C TYA ; |
035D PHA ; \
035E LDY #$00 ; Delay to hold note if making a noise or give equal gap
0360 LDX #$15 ; |
0362 DEY ; |
0363 BNE $0362 ; |
0365 DEX ; |
0366 BNE $0362 ; \
0368 LDA #$00 ; Turn off speaker 2
036A STA $900B ; \
036D LDY #$00 ; Delay between letters
036F LDX #$10 ; |
0371 DEY ; |
0372 BNE $0371 ; |
0374 DEX ; |
0375 BNE $0371 ; \
0377 PLA ; Restore the registers
0378 TAY ; |
0379 PLA ; |
037A TAX ; |
037B PLA ; \
037C JMP $F27A ; Jump to the normal output vector stored in $0326
Memory Dump
Below is a memory dump of the program. Some find it quicker to enter the hex codes directly and this is also useful to create a BASIC program that will load the machine language.
033C A9 03 8D 27 03
0341 A9 4C 8D 26 03
0346 A9 0F 8D 0E 90
034B 60 48 C9 20 F0
0350 09 C9 0D F0 05
0355 A9 80 8D 0B 90
035A 8A 48 98 48 A0
035F 00 A2 15 88 D0
0364 FD CA D0 FA A9
0369 00 8D 0B 90 A0
036E 00 A2 10 88 D0
0373 FD CA D0 FA 68
0378 A8 68 AA 68 4C
037D 7A F2
I find it quite nice to work with the hex as well as assembly language, particularly when you are debugging as it can be quicker to navigate and find what you are looking for. Here you can see the repeated LDA
commands used at the start of the program as A9
. You can also see the 20
used to detect a space at $034E
. If you wanted to change this character, you could just alter that memory location, instead of reassembling the line.
BASIC Alternative
The following is the program converted to BASIC so that anyone with a Vic can enter it.
10 FOR ADR=828 TO 894:READ OCT:POKE ADR,OCT:NEXT ADR
20 DATA 169,3,141,39,3,169,76,141,38,3
30 DATA 169,15,141,14,144,96,72,201,32,240
40 DATA 9,201,13,240,5,169,128,141,11,144
50 DATA 138,72,152,72,160,0,162,21,136,208
60 DATA 253,202,208,250,169,0,141,11,144,160
70 DATA 0,162,16,136,208,253,202,208,250,104
80 DATA 168,104,170,104,76,122,242
90 SYS 828
All you have to do is RUN
the program and from that point on your Vic will feel a bit like a TTY.
Where now?
For more information on Vicmon or for those just starting to program the Vic-20 in assembly language, take a look at: Beginning Assembly Programming on the Vic-20. I have also created an extended version of the TTY simulator and hosted it on GitHub: vic20_simtty.