Getting screen output using Assembly was plenty hard enough. Getting a printing subroutine was even tougher. I don’t want to litter my programs with the same code over and over every time I want to print. So I looked for a way to set the printing commands into a useful re-usable routine. If your program prints more than one time to the screen, it becomes beneficial to have a printing subroutine. It saves memory, both source and assembled. And, with these old 48K to 128K (8 bit) machines, every byte counts.
In BASIC and many other languages printing is very simple and there generally isn’t a need to make it into a subroutine unless you are doing something else along with the printing.
Instructions
To accomplish this milestone I had to read, a lot! I had to learn about using JSR and RTS, the assembly equivalents of GOSUB and RETURN, and how the 6502 manages the stack. Ultimately the most valuable resource were the Boot Camp articles by Tom Hudson published in A.N.A.L.O.G magazine, specially the late 1985 and early 1986 issues.
The JSR and RTS instructions are defined below:
- JSR : Jump to SubRoutine. Causes program execution to continue at the address specified as the operand of the JSR instruction. The routine pointed to should be terminated with an RTS so the instruction following the JSR will be executed when the subroutine is complete.
- RTS : ReTurn from Subroutine. Causes program execution to resume at the first instruction that follows the calling JSR.
Sample Code
This is the small program I wrote that uses a subroutine to accomplish the printing. Following the code, I detail what it does. Again, I am using the OSS Mac/65 assembler.
05 .OPT OBJ 10 *= $3600 39 ; Defines 70 CIOV = $E456 71 ICHID = $0340 ;IOCB 0 S: 72 ICCOM = $0342 ;IOCB Command 73 ICBAL = $0344 ;Xfer Buffer Adr 74 ICBAH = $0345 75 ICBLL = $0348 ;Buffer Len 76 ICBLH = $0349 77 PRTREC = $09 ; Print Record Cmd 78 MAXLEN = $FF ; Max String Len 80 EOL = $9B 82 CLS = $7D 0300 ; Test printing 0305 ; Print clear screen followed by "Hello World!" 0310 LDA #SHI/256 0320 LDY #SHI&255 0330 JSR PRINT 0335 ; Print "Goodbye World!" 0340 LDA #SBYE/256 0350 LDY #SBYE&255 0360 JSR PRINT 0370 RTS 5000 ; Print Subroutine 5005 PRINT 5010 ; Store Starting String Address 5015 LDX #$00 5020 STA ICBAH,X 5030 TYA 5040 STA ICBAL,X 5050 ; Set IOCB Command 5055 LDA #PRTREC 5060 STA ICCOM,X 5070 ; Set Max Buffer Length 5075 LDA #MAXLEN 5080 STA ICBLH,X 5090 STA ICBLL,X 5100 ; Call CIO to Print 5105 JSR CIOV 5110 RTS 10000 ; String Data 10005 SHI .BYTE CLS,"Hello World!",EOL 10010 SBYE .BYTE "Goodbye World!",EOL
Breakdown
Lines 5 and 10: Tell Mac/65 to generate code, and define the location in memory to assemble to ($3600).
Lines 70 to 76: Definitions for the CIO and IOCB addresses used by the print routine.
Lines 77, 78: IOCB value definitions.
Lines 80 to 82: Definitions used in the strings to be printed.
Lines 310, 320: Load the Accumulator with the high byte of the string (to be printed) address. Load the Y register with the low byte of the string address.
Line 330: Call the print subroutine.
Lines 340, 350: Load the Accumulator with the high byte of the string (to be printed) address. Load the Y register with the low byte of the string address.
Line 360: Call the print subroutine.
Line 370: Leave the program
Line 5005: Label the starting address of the print subroutine.
Line 5015: Load X register with 0.
Line 5020: Store the Accumulator value (which holds the strings address high byte) into the IOCB string buffer address high byte.
Line 5030: Transfer the Y register (which holds the strings address low byte) to the Accumulator.
Line 5040: Store the Accumulator value into the IOCB string buffer address low byte.
Line 5055: Load the Accumulator with 9, the IOCB print record command value.
Line 5060: Store the Accumulator value into the IOCB command address.
Line 5075: Load the Accumulator with value $FF (255). This will be the max size for the string to be printed.
Line 5080,5090: Store the Accumulator value into the IOCB buffer length address high and low bytes.
Line 5105: Call the CIO routine. It will use the IOCB information that was just setup, causing the string the be printed until either 255 characters are reached or EOL ($9B) (155) is encountered.
Line 5110: Return from the print subroutine.
Lines 10005, 10010: The strings to be printed, with labels, both terminated with EOL ($9B) (155).
Assembling and Running
After the code has been entered and ready to assemble:
I assembled the code using “ASM ,,#D2:PRINTSUB.COM” to generate the compiled version. Look ma, no errors!
Now, I’ve exited to DOS (SpartaDOS) and about to run the assembled program:
And the results. Notice the screen was cleared as well due to the inclusion of the CLS ($7D) (125) character in the first string:
Accomplishing the Same Thing in BASIC
With BASIC, the same outcome can be accomplished with this. It’s a lot simpler, but not nearly as efficient in machine cycles.
10 PRINT CHR$(125);"Hello World!" 20 PRINT "Goodbye World!"
Next
Now to incorporate the subroutine into my preferences program!