Tip 19: It’s been two or three years that I have been writing these Tips. Are they still helping anyone? If you would like to Have them continued please let me know through our Editor Paul Hill.
TS2068 TIPS
Tip 20: There have been requests for me to write some things for the TS2068. Therefore, here is something to help you to get more use out of Machine Language Utilities.
Unfortunately machine code routines are not always ‘relocatable ‘. This is because there are no relative calls or relative returns and some conditional branching are also not available in relative form.
To start you off I am including a small M.C. routine which is taken from the May/Jun 86 issue of Time Design Mag. The routine reads the Headers off the Tapes and comes in handy when running programs which accesses tapes for data. It uses only 193 bytes for the code and three short lines of BASIC for its support, however, it locates at 40000 which is not always the best place for it.
a) First CLEAR 39999. Then type in the following Loader:
10 PRINT "Address"; TAB 10; "Machine Code"; TAB 21; "Check-Sum" '
20 LET cs = 0: FOR f = 40000 TO 40175 STEP 5: PRINT f;
30 FOR n = 0 TO 5
40 INPUT "Enter Code"; a$: IF VAL a$<0 OR a$>256 THEN PRINT # 1; "Out of
range...Try again": GO TO 40
50 LET a = VAL a$: PRINT TAB (6 + 4*n-LEN a$); IF n = 5 AND a <> cs THEN PRINT'"
ERROR!!!...ReEnter Line": GO TO 30
60 IF n = 5 THEN GO TO 80
70 POKE f, a: LET cs = cs + a:
80 NEXT n: PRINT': NEXT f: PRINT "DONE": BEEP .1,20
b) Next load in the following decimal dump including the Check-sums:
CHECK CHECK
ADDRESS MACHINE CODE SUM ADDRESS MACHINE CODE SUM
40000 62 253 205 48 18 586 40090 192 192 62 32 215 693
40005 17 137 60 205 63 482 40095 17 13 1 205 215 451
40010 7 205 217 17 219 665 40100 156 201 205 183 156 901
40015 255 203 255 211 255 1179 40105 17 190 0 205 215 627
40020 219 244 50 195 92 800 40110 156 62 44 215 43 520
40025 62 1 211 244 221 739 40115 205 228 156 201 175 965
40030 38 8 157 221 229 648 40120 17 226 1 205 63 512
40035 17 17 0 175 55 264 40125 7 62 32 215 62 378
40040 205 252 0 211 225 903 40130 34 215 6 10 35 300
40045 48 242 58 195 92 635 40135 126 254 32 40 3 455
40050 211 244 219 255 203 1132 40140 215 16 247 62 34 574
40055 191 211 255 62 254 973 40145 215 38 157 46 22 478
40060 205 48 18 221 229 721 40150 201 175 229 205 63 873
40065 225 126 254 0 40 645 40155 7 225 62 32 215 541
40070 14 254 3 40 27 338 40160 205 228 156 201 70 860
40075 17 168 60 205 63 513 40165 43 78 229 205 233 788
40080 7 205 190 156 201 759 40170 48 205 161 49 225 688
40085 205 183 156 126 230 900 40175 201 0 0 0 0 201
c) When the Code has all been entered, get rid of all of the BASIC with: NEW
d) Next enter the following BASIC support:
100 CLS: PRINT " (Press BREAK when finished)"
110 RANDOMIZE USR 40000: PRINT
120 RANDOMIZE USR 40014: PRINT: GO TO 120
e) Then SAVE your Program with:
SAVE "HEADER" LINE 100: SAVE "header" CODE 40000, 176
f) The next thing to do is to shut down your computer for a minute. Then turn it back on, load your new program, rewind, press PLAY and read the Headers. Try some other tapes too.
g) Now that we all have the same program to work on, I will try to show you how to move it to any handy spot in memory. Take a good look at the disassembled version below. There is a total of ten instructions that needs to be changed if the machine code is moved to any other address. There is an index address and seven Calls that need to be changed. These instructions I have marked with asterisks. Two other instructions also need changing. They load the HL register pair with an address that depends on the location of the routine. These I have marked with Exclamation points!
The reason for marking these two differently is for the sake of demonstration. When I first wrote the BASIC program to change the necessary address in the instructions I overlooked these two. The result was interesting. Line 65 in the BASIC program, which I’ll call “MOVER”, adjusts these two lines. Line 60 adjusts the address put into the index register IX and Line 70 adjusts the seven CALLs that needs to be changed. The new location may be either a higher or a lower address than the original location. If the new address is lower than the orignal one, CLEAR (new address – 1).
The line numbers, of the supporting three lines of BASIC for the Program “HEADER “, doesn’t have to be 100, 110 & 120 they can be any three consecutive lines in BASIC.
h) Here is the dissassembled “header” routine:
HEADER: Address 4C40 TO 9D07
(40000) 9C40 3EFD LD A, FD
9C42 CD3012 CALL 1230, CHAN-OPEN
9C45 11893C LD DE, 3C89
9C48 CD3F07 CALL 073F, PO-MSG
9C4B CDD911 CALL 11D9, WAIT-KEY
(40014) 9C4E DBFF IN A, (FF)
9C50 CBFF SET 7, A
9C52 D3FF OUT (FF), A
9C54 DBF4 IN A, (F4)
9C56 32C35C LD (5CC3), A ; Store in
9C59 3E01 LD A, 01 spare byte.
9C5B D3F4 OUT (F4), A
9C5D DD21089D * LD IX, 9D08 ; Points to a
9C61 DDE5 PUSH IX copy of the
9C63 111100 LD DE, 0011 SAVE Command
9C66 AF XOR A
9C67 37 SCF
9C68 CDFC00 CALL 00FC, RD-TAPE
9C6B DDE1 POP IX
9C6D 30F2 JR NC, 9C61
9C6F 3AC35C LD A, (5CC3) ; Retrieve it.
9C72 D3F4 OUT (F4), A
9C74 DBFF IN A, (FF)
9C76 CBBF RES 7, A
9C78 D3FF OUT (FF), A
9C7A 3EFE LD A, FE
9C7C CD3012 CALL 1230, CHAN-OPEN
9C7F DDE5 PUSH IX
9C81 E1 POP HL
9C82 7E LD A, (HL)
9C83 FE00 CP 00
9C85 280E JR Z, 9C95
9C87 FE03 CP 03
9C89 281B JR Z, 9CA6
9C8B 11A83C LD DE, 3CA8
9C8E CD3F07 CALL 073F, PO-MSG
9C91 CDBE9C * CALL 9CBE
9C94 C9 RET
(40085) 9C95 NEXT BYTE 85 bytes
(40085) 9C95 CDB79C * CALL 9CB7
9C98 7E LD A, (HL)
9C99 E6C0 AND C0
9C9B C0 RET NZ
9C9C 3E20 LD A, 20
9C9E D7 RST 10 ; Print a space
9C9F 110D01 LD DE, 010D
9CA2 CDD79C * CALL 9CD7
9CA5 C9 RET
(40102) 9CA6 NEXT BYTE 17 bytes
(40102) 9CA6 CDB79C * CALL 9CB7
9CA9 11BE00 LD DE, 00BE
9CAC CDD79C * CALL 9CD7
9CAF 3E2C LD A, 2C
9CB1 D7 RST 10 ; Print a Comma
9CB2 2B DEC HL
9CB3 CDE49C * CALL 9CE4
9CB6 C9 RET
(40119) 9CB7 NEXT BYTE 17 bytes
(40119) 9CB7 AF XOR A
9CB8 11E201 LD DE, 01E2
9CBB CD3F07 CALL 073F, PO-MSG
9CBE 3E20 LD A, 20
9CC0 D7 RST 10 ; Print a Space
9CC1 3E22 LD A, 22
9CC3 D7 RST 10 ; Print a quote
9CC4 060A LD B, 0A
9CC6 23 INC HL
9CC7 7E LD A, (HL)
9CC8 FE20 CP 20
9CCA 2803 JR Z, 9CCF
9CCC D7 RST 10 ; PRINT-A
9CCD 10F7 DJNZ 9CC6
9CCF 3E22 LD A,22
9CD1 D7 RST 10 ; Print a quote
9CD2 269D ! LD H, 9D
9CD4 2E16 ! LD L, 16
9CD6 C9 RET
(40151) 9CD7 NEXT BYTE 32 bytes
(40151) 9CD7 AF XOR A
9CD8 E5 PUSH HL
9CD9 CD3F07 CALL 073F, PO-MSG
9CDC E1 POP HL
9CDD 3E20 LD A,20
9CDF D7 RST 10 ; Print a space
9CE0 CDE49C * CALL 9CE4
9CE3 C9 RET
(40164) 9CE4 NEXT BYTE 13 bytes
(40164) 9CE4 46 LD B, (HL)
9CE5 2B DEC HL
9CE6 4E LD C, (HL)
9CE7 E5 PUSH HL
9CE8 CDE930 CALL 30E9, STK-BC
9CEB CDA131 CALL 31A1, PRINT F.P. NUMBER
9CEE E1 POP HL
9CEF C9 RET
(40176) 9CF0 NEXT BYTE 12 bytes
24 BYTES OF WASTED MEMORY:
(40176) 9CF0 00 00 00 00 00 00 00 00
9CF8 00 00 00 00 00 00 00 00
9D00 00 00 00 00 00 00 00 00
(40200) 9D08 NEXT BYTE 24 bytes
17 BYTE COPY OF THE HEADER READ OFF THE TAPE:
(40200) 9D08 F8 22 48 45 41 44 45 52 ; SAVE "HEADER"
9D10 22 32 32 32 32 40 9C B0 40000,176
9D18 00
(40217) 9D19 NEXT BYTE 17 bytes
TOTAL M.C. BYTES USED by Original Routine = 217
i) Last but not least The Mover Program: Type it in and SAVE it.
1 REM ** MOVER **
5 PRINT # 1; AT 1,0; "Reset RAMTOP? (y/n)": PAUSE 0: IF INKEY$ = "Y" OR
INKEY$ = "y" THEN INPUT "CLEAR Address? ";f: CLEAR f
10 DEF FN a(x) = INT (X/256): DEF FN b(X) = X-256*FN a(X): DEFFN c(X) = PEEK X
+ 256*PEEK (X+1): GO TO 30
20 POKE f, FN b(a): POKE f+1, FN a(a): RETURN
30 INPUT "Old Address? ";old: INPUT "New Address? ";new: LET d = old-new
40 INPUT "FILE name? ";n$: INPUT "M.C. Length? ";len
50 BEEP .1,20: PRINT # 1; AT 1,0; "Prepare to load M.C.":PAUSE 100: PRINT AT
10,10; "START TAPE": LOAD n$CODE new
60 FOR f = new TO (new + len): IF PEEK f = 221 THEN LET f = f+1: IF PEEK f = 33
THEN LET f = f+1: LET a = FN c(f): LET a = a-d-24: GO SUB 20: LET f = f+2
65 IF PEEK f=38 THEN LET f = f+1: IF PEEK f = 157 THEN LET a = 256*PEEK f +
PEEK (f+2)-d-24: POKE f, FN a(a): POKE f+2, FN b(a): LET f = f+2
70 IF PEEK f = 205 THEN LET f = f+1: LET a = FN c(f): IF a>(old-1) THEN LET a
= a-d: GO SUB 20: LET f = f+1
80 NEXT f
90 BEEP .1,20: PRINT' "DONE": PAUSE 120: CLS: PRINT" To read tape headers GO TO
700": STOP
700 CLS: PRINT " (Press BREAK when finished)"
710 RANDOMIZE USR 49807: PRINT
720 RANDOMIZE USR 49821: PRINT: GO TO 720
j) Now lets make the change! If the new address is LOWER than the old address (40000) then reset RAMTOP with CLEAR (new address -1), otherwise leave it at 39999.
k) Next load the header reader routine to the new address as follows: LOAD “header” CODE (new address), 193 <ENTER>. In my example I used: LOAD “header” CODE 49807, 193 <ENTER>: RAMTOP was O.K. at 39999.
l) Here is where we make the changes. Type RUN <ENTER>
m) Try running this program without Line 65 and read some tapeheaders with it.
n) SAVE your new routine with: SAVE “header” CODE (new address), 193.
o) To use it: LOAD “header” CODE <ENTER>: Then add your three lines of BASIC support.
EXAMPLE: 700 CLS: PRINT " (Press BREAK when finished)"
710 RANDOMIZE USR 49807: PRINT
720 RANDOMIZE USR 49821: PRINT :GO TO 720
p) Note that the second entry point address is higher than the first entry point address by 14.
If you have any questions or comments feel free to write. Please enclose a SASE (in care of SINCUS)if you desire answers. Don is recuperating from a by-pass operation at home. We all hope Don gets well soon and back to the ole keyboards.