0001 0000 ; **************************************************************************** 0002 0000 ; 0003 0000 ; The SC/MP I/O Monitor. 0004 0000 ; 0005 0000 ; Developed from the SCMPKB monitor by D.J.D. 0006 0000 ; Tape routines by N.J.T. 0007 0000 ; Converted to TASM and annotated by Paul Robson (autismuk@aol.com) 0008 0000 ; 0009 0000 ; **************************************************************************** 0010 0000 0011 0000 #define High(x) (((x) >> 8) & 15) 0012 0000 #define Low(x) ((x) & 255) 0013 0000 #define DatPtr(a) ((a)+1) 0014 0000 0015 0000 Ram .equ 0F00h ; this is where the standard RAM is 0016 0000 Disp .equ 0D00h ; this is where the display is 0017 0000 0018 0000 ; **************************************************************************** 0019 0000 ; Offsets into the data structure , from P2 0020 0000 ; **************************************************************************** 0021 0000 dl .equ 0 ; Segment for Digit 1 0022 0000 dh .equ 1 ; Segment for Digit 2 0023 0000 d3 .equ 2 ; Segment for Digit 3 0024 0000 d4 .equ 3 ; Segment for Digit 4 0025 0000 adll .equ 4 ; Segment for Digit 5 0026 0000 adlh .equ 5 ; Segment for Digit 6 0027 0000 adhl .equ 6 ; Segment for Digit 7 0028 0000 adhh .equ 7 ; Segment for Digit 8 0029 0000 d9 .equ 8 ; Segment for Digit 9 0030 0000 cnt .equ 9 ; Counter 0031 0000 pushed .equ 10 ; Key pushed 0032 0000 char .equ 11 ; Char Read 0033 0000 adl .equ 12 ; Memory Address (low) 0034 0000 word .equ 13 ; Memory Word 0035 0000 adh .equ 14 ; Memory Address (High) 0036 0000 ddta .equ 15 ; first flag 0037 0000 row .equ 16 ; row counter 0038 0000 next .equ 17 ; flag for now data 0039 0000 ; **************************************************************************** 0040 0000 ; Ram areas used by SCIOS. P3 is saved elsewhere 0041 0000 ; The Data macro is used because of the pre-increment of the PC 0042 0000 ; in the processor isn't supported by TASM. 0043 0000 ; **************************************************************************** 0044 0000 p1h .equ DatPtr(0FF9h) 0045 0000 p1l .equ DatPtr(0FFAh) 0046 0000 p2h .equ DatPtr(0FFBh) 0047 0000 p2l .equ DatPtr(0FFCh) 0048 0000 a .equ DatPtr(0FFDh) 0049 0000 e .equ DatPtr(0FFEh) 0050 0000 s .equ DatPtr(0FFFh) 0051 0000 ; **************************************************************************** 0052 0000 ; Start of monitor listing 0053 0000 ; **************************************************************************** 0054 1000 .org 1000h ; stops TASM complaining... 0055 1000 00 halt ; pulse the H flag 0056 1001 CF FF st @-1(3) ; save A at P3-1,dec it 0057 1003 90 1E jmp Start ; Go to the monitor start 0058 1005 ; **************************************************************************** 0059 1005 ; Debug exit : restore environment 0060 1005 ; **************************************************************************** 0061 1005 37 GoOut: xpah 3 ; Save A in P3 (A is Go address High) 0062 1006 C2 0C ld adl(2) 0063 1008 33 xpal 3 0064 1009 C7 FF ld @-1(3) ; fix go address 0065 100B C0 F2 ld e ; restore registers 0066 100D 01 xae 0067 100E C0 EB ld p1l 0068 1010 31 xpal 1 0069 1011 C0 E7 ld p1h 0070 1013 35 xpah 1 0071 1014 C0 E7 ld p2l 0072 1016 32 xpal 2 0073 1017 C0 E3 ld p2h 0074 1019 36 xpah 2 0075 101A C0 E4 ld s 0076 101C 00 halt ; reset single step 0077 101D 07 cas 0078 101E C0 DE ld a 0079 1020 08 nop 0080 1021 05 ien 0081 1022 3F xppc 3 0082 1023 ; **************************************************************************** 0083 1023 ; Debug Entry Point 0084 1023 ; **************************************************************************** 0085 1023 C8 D9 Start: st a ; Copy all registers to memory 0086 1025 40 lde 0087 1026 C8 D7 st e 0088 1028 06 csa 0089 1029 C8 D5 st s 0090 102B 35 xpah 1 0091 102C C8 CC st p1h 0092 102E 31 xpal 1 0093 102F C8 CA st p1l 0094 1031 C4 0F ldi High(Ram) ; Copy P2, make it point to RAM 0095 1033 36 xpah 2 ; at the same time 0096 1034 C8 C6 st p2h 0097 1036 C4 00 ldi Low(Ram) 0098 1038 32 xpal 2 0099 1039 C8 C2 st p2l 0100 103B C7 01 ld @1(3) ; Bump P3 for return 0101 103D 33 xpal 3 ; save it in ADL,ADH so on 0102 103E CA 0C st adl(2) ; exit we are at (end+1) 0103 1040 37 xpah 3 0104 1041 CA 0E st adh(2) 0105 1043 C4 00 ldi 0 ; Clear D3 and D4 0106 1045 CA 02 st d3(2) 0107 1047 CA 03 st d4(2) 0108 1049 C4 01 ldi 1 ; P3H = 1 0109 104B 37 xpah 3 0110 104C 90 6D Abort: jmp Mem ; Go to 'Mem' mode handler 0111 104E ; **************************************************************************** 0112 104E ; Run program from currently displayed address 0113 104E ; **************************************************************************** 0114 104E C2 0E GoNow: ld adh(2) ; A = High Byte of Address 0115 1050 90 B3 jmp GoOut 0116 1052 ; **************************************************************************** 0117 1052 ; Tape Interface Routines. 0118 1052 ; **************************************************************************** 0119 1052 Count .equ 0D5h 0120 1052 Len .equ 0D6h 0121 1052 ; **************************************************************************** 0122 1052 ; Store to Tape. P1^Data,@Count is the bytes 0123 1052 ; **************************************************************************** 0124 1052 C5 01 ToTape: ld @1(1) ; E := (P1), increment P1 0125 1054 01 xae 0126 1055 C4 01 ldi 1 ; A := 1 (the bit pattern) 0127 1057 CB D5 Next: st Count(3) ; Save in Count (P3) 0128 1059 C4 01 ldi 1 ; set F0 to 1 0129 105B 07 cas 0130 105C 8F 08 dly 8 ; Delay 8 Cycles 0131 105E C3 D5 ld Count(3) ; A = Count & E 0132 1060 50 ane ; test if bit is set... 0133 1061 98 07 jz Zero 0134 1063 8F 18 dly 018h ; (bit is 1) Delay $18 cycles 0135 1065 C4 00 ldi 0 ; set F0 to 0 again 0136 1067 07 cas 0137 1068 90 05 jmp CDone 0138 106A C4 00 Zero: ldi 0 ; bit is zero (set F0 to 0) 0139 106C 07 cas 0140 106D 8F 18 dly 018h ; Delay $18 Cycles 0141 106F 8F 20 CDone: dly 020h ; Delay $20 more Cycles 0142 1071 C3 D5 ld Count(3) ; shift the bit pattern left 0143 1073 F3 D5 add Count(3) ; (CYL cleared by CAS !) 0144 1075 9C E0 jnz Next ; if non zero we haven't finished 0145 1077 BB D6 dld Len(3) ; decrement the length counter 0146 1079 9C D7 jnz ToTape ; if non-zero do the next byte 0147 107B 3F xppc 3 ; return from caller 0148 107C ; **************************************************************************** 0149 107C ; Load from Tape to ^P1. Is broken out via Reset 0150 107C ; **************************************************************************** 0151 107C C4 08 FrTape: ldi 8 ; Count is a bit count here 0152 107E CB D5 st Count(3) 0153 1080 06 Loop: csa ; look at the status 0154 1081 D4 20 ani 20h ; wait for the 'start' bit 0155 1083 98 FB jz Loop 0156 1085 8F 1C dly 01Ch ; wait $1C cycles 0157 1087 19 sio ; shift a bit in 0158 1088 8F 1C dly 01Ch ; wait a few more cycles 0159 108A BB D5 dld Count(3) ; do this 8 times 0160 108C 9C F2 jnz Loop 0161 108E 40 lde ; get the byte we got 0162 108F CD 01 st @1(1) ; save it, increment the pointer 0163 1091 90 E9 jmp FrTape ; and get the next one. 0164 1093 ; **************************************************************************** 0165 1093 ; Offset calculator 0166 1093 ; **************************************************************************** 0167 1093 C6 FE Offset: ld @-2(2) ; Subtract 2 from destination address 0168 1095 32 xpal 2 ; put low byte in AC 0169 1096 03 scl 0170 1097 FB D8 cad 0D8h(3) ; subtract low byte of jump inst addr 0171 1099 C9 01 st 1(1) ; put in jump operand 0172 109B 3F xppc 3 ; return 0173 109C 08 nop ; padding 0174 109D ; **************************************************************************** 0175 109D ; Bump MSB of address 0176 109D ; **************************************************************************** 0177 109D AA 0E DTack: ild adh(2) ; increment and load ADH 0178 109F 90 36 jmp Data 0179 10A1 ; **************************************************************************** 0180 10A1 ; Put Word in Memory 0181 10A1 ; **************************************************************************** 0182 10A1 C2 0E MemDn: ld adh(2) ; P1 = ADH/ADL 0183 10A3 35 xpah 1 0184 10A4 C2 0C ld adl(2) 0185 10A6 31 xpal 1 0186 10A7 C2 0D ld word(2) ; get and store word 0187 10A9 C9 00 st (1) 0188 10AB 90 34 jmp DataCK 0189 10AD ; **************************************************************************** 0190 10AD ; Key Check 0191 10AD ; **************************************************************************** 0192 10AD E4 06 MemCK: xri 06 ; Check for 'go' 0193 10AF 98 9D jz GoNow 0194 10B1 E4 05 xri 05 ; Check for 'term' 0195 10B3 98 22 jz Data 0196 10B5 AA 0C ild adl(2) ; bump address low 0197 10B7 9C 1E jnz Data ; no carry-through required 0198 10B9 90 E2 jmp DTack ; goto bump MSB code 0199 10BB ; **************************************************************************** 0200 10BB ; Mem mode 0201 10BB ; **************************************************************************** 0202 10BB C4 FF Mem: ldi -1 ; Set "First" flag 0203 10BD CA 11 st next(2) ; and flag for "address now" 0204 10BF CA 0F st ddta(2) 0205 10C1 C2 0E MemL: ld adh(2) ; P1 = ADH/L 0206 10C3 35 xpah 1 0207 10C4 C2 0C ld adl(2) 0208 10C6 31 xpal 1 0209 10C7 C1 00 ld 0(1) ; Get the byte at ADHL 0210 10C9 CA 0D st word(2) ; save it away in 'work' 0211 10CB C4 3F ldi Low(DispD)-1 ; Fix Data Segment... 0212 10CD 33 xpal 3 ; P3 now points to DispD routine 0213 10CE 3F xppc 3 ; call it 0214 10CF 90 DC jmp MemCK ; command return... 0215 10D1 C4 1A ldi Low(Adr)-1 ; call the 'adr' subroutine 0216 10D3 33 xpal 3 0217 10D4 3F xppc 3 0218 10D5 90 EA jmp MemL ; get next character 0219 10D7 ; **************************************************************************** 0220 10D7 ; Data Mode 0221 10D7 ; **************************************************************************** 0222 10D7 C4 FF Data: ldi -1 ; set first flag 0223 10D9 CA 0F st ddta(2) 0224 10DB C2 0E ld adh(2) ; P1 = ADHL 0225 10DD 35 xpah 1 0226 10DE C2 0C ld adl(2) 0227 10E0 31 xpal 1 0228 10E1 C1 00 DataCK: ld 0(1) ; get word & save it for display 0229 10E3 CA 0D st word(2) 0230 10E5 C4 3F DataL: ldi Low(DispD)-1 ; call the display routine 0231 10E7 33 xpal 3 0232 10E8 3F xppc 3 0233 10E9 90 C2 jmp MemCK ; go to the memory routine 0234 10EB C4 04 ldi 4 ; shift it in 0235 10ED CA 09 st cnt(2) 0236 10EF AA 0F ild ddta(2) ; if first 0237 10F1 9C 06 jnz Dnfst 0238 10F3 C4 00 ldi 0 ; zero word if first 0239 10F5 CA 0D st word(2) 0240 10F7 CA 11 st next(2) ; set flag for address done 0241 10F9 02 Dnfst: ccl ; shift left 0242 10FA C2 0D ld word(2) 0243 10FC F2 0D add word(2) 0244 10FE CA 0D st word(2) 0245 1100 BA 09 dld cnt(2) ; do it 8 times 0246 1102 9C F5 jnz Dnfst 0247 1104 C2 0D ld word(2) ; get the word 0248 1106 58 ore ; or with the hex pattern 0249 1107 CA 0D st word(2) 0250 1109 90 96 jmp MemDn ; store it and try again 0251 110B ; **************************************************************************** 0252 110B ; Segment Data 0253 110B ; **************************************************************************** 0254 110B SA .equ 1 ; Segment bit patterns 0255 110B SB .equ 2 0256 110B SC .equ 4 0257 110B SD .equ 8 0258 110B SE .equ 16 0259 110B SF .equ 32 0260 110B SG .equ 64 0261 110B ; **************************************************************************** 0262 110B ; Hex number to seven segment table 0263 110B ; **************************************************************************** 0264 110B 3F CRom: .db SA+SB+SC+SD+SE+SF 0265 110C 06 .db SB+SC 0266 110D 5B .db SA+SB+SD+SE+SG 0267 110E 4F .db SA+SB+SC+SD+SG 0268 110F 66 .db SB+SC+SF+SG 0269 1110 6D .db SA+SC+SD+SF+SG 0270 1111 7D .db SA+SC+SD+SE+SF+SG 0271 1112 07 .db SA+SB+SC 0272 1113 7F .db SA+SB+SC+SD+SE+SF+SG 0273 1114 67 .db SA+SB+SC+SF+SG 0274 1115 77 .db SA+SB+SC+SE+SF+SG 0275 1116 7C .db SC+SD+SE+SF+SG 0276 1117 39 .db SA+SD+SE+SF 0277 1118 5E .db SB+SC+SD+SE+SG 0278 1119 79 .db SA+SD+SE+SF+SG 0279 111A 71 .db SA+SE+SF+SG 0280 111B ; **************************************************************************** 0281 111B ; Make 4 digit address. Shift left one then add new low hex 0282 111B ; digit. On entry,digit in E,P2 points to RAM 0283 111B ; **************************************************************************** 0284 111B C4 04 Adr: ldi 4 ; set number of shifts 0285 111D CA 09 st cnt(2) 0286 111F AA 0F ild ddta(2) ; check if first 0287 1121 9C 06 jnz notfst ; if not skip 0288 1123 C4 00 ldi 0 ; zero address 0289 1125 CA 0E st adh(2) 0290 1127 CA 0C st adl(2) 0291 1129 02 notfst: ccl ; shift ADHL left 0292 112A C2 0C ld adl(2) 0293 112C F2 0C add adl(2) 0294 112E CA 0C st adl(2) 0295 1130 C2 0E ld adh(2) 0296 1132 F2 0E add adh(2) 0297 1134 CA 0E st adh(2) 0298 1136 BA 09 dld cnt(2) ; do it 4 times 0299 1138 9C EF jnz notfst 0300 113A C2 0C ld adl(2) ; or in the digit 0301 113C 58 ore 0302 113D CA 0C st adl(2) 0303 113F 3F xppc 3 ; and return 0304 1140 ; **************************************************************************** 0305 1140 ; Convert Hex Data to Segments. P2 Points to RAM. Drops through 0306 1140 ; to hex address conversion 0307 1140 ; **************************************************************************** 0308 1140 C4 01 DispD: ldi High(CRom) ; P1 = Segment conversion Table 0309 1142 35 xpah 1 0310 1143 C4 0B ldi Low(CRom) 0311 1145 31 xpal 1 0312 1146 C2 0D ld word(2) ; get low nibble 0313 1148 D4 0F ani 0Fh 0314 114A 01 xae 0315 114B C1 80 ld -128(1) ; get CROM+E (low) 0316 114D CA 00 st dl(2) 0317 114F C2 0D ld word(2) ; get high nibble 0318 1151 1C sr 0319 1152 1C sr 0320 1153 1C sr 0321 1154 1C sr 0322 1155 01 xae 0323 1156 C1 80 ld -128(1) ; get CROM+E 0324 1158 CA 01 st dh(2) ; update the display 0325 115A ; **************************************************************************** 0326 115A ; Convert Hex Address to segment, P2 points to RAM. Drops through 0327 115A ; to keyboard and display 0328 115A ; **************************************************************************** 0329 115A 03 DispA: scl 0330 115B C4 01 ldi High(CRom) ; P1 = Segment conversion Table 0331 115D 35 xpah 1 0332 115E C4 0B ldi Low(CRom) 0333 1160 31 xpal 1 0334 1161 C2 0C LoopD: ld adl(2) 0335 1163 D4 0F ani 0F 0336 1165 01 xae 0337 1166 C1 80 ld -128(1) ; get CROM+E (low) 0338 1168 CA 04 st adll(2) 0339 116A C2 0C ld adl(2) ; get high nibble 0340 116C 1C sr 0341 116D 1C sr 0342 116E 1C sr 0343 116F 1C sr 0344 1170 01 xae 0345 1171 C1 80 ld -128(1) ; get CROM+E 0346 1173 CA 05 st adlh(2) ; update the display 0347 1175 06 csa ; check if done 0348 1176 D4 80 ani 080h 0349 1178 98 09 jz Done 0350 117A 02 ccl ; clear carry,done next time ! 0351 117B C4 00 ldi 0 0352 117D CA 03 st d4(2) ; zero digit 4 0353 117F C6 02 ld @2(2) ; fix P2 for next time around 0354 1181 90 DE jmp LoopD 0355 1183 Done: 0356 1183 C6 FE ld @-2(2) ; refix P2 on exit 0357 1185 ; **************************************************************************** 0358 1185 ; Keyboard and Display Input. 0359 1185 ; JMP Command in A (GO=6,MEM=7,TERM=3,in E +16) 0360 1185 ; Number return, hex number in E reg 0361 1185 ; ABORT key goes to abort 0362 1185 ; all registers used 0363 1185 ; P2 points to RAM,address MUST be xxx0 0364 1185 ; to re-execute do XPPC3 0365 1185 ; **************************************************************************** 0366 1185 C4 00 Kybd: ldi 0 ; zero char 0367 1187 CA 0B st char(2) 0368 1189 C4 0D ldi High(Disp) ; P1 points to the display 0369 118B 35 xpah 1 0370 118C C4 FF Off: ldi -1 ; Set Row/Digit Address 0371 118E CA 10 st row(2) 0372 1190 C4 0A ldi 10 ; Set Row Count 0373 1192 CA 09 st cnt(2) 0374 1194 C4 00 ldi 0 ; Zero keyboard input 0375 1196 CA 0A st pushed(2) 0376 1198 31 xpal 1 ; Set display address (low) 0377 1199 KDLoop: 0378 1199 AA 10 ild row(2) ; next row ? 0379 119B 01 xae ; put it in E 0380 119C C2 80 ld -128(2) ; get the segment into A 0381 119E C9 80 st -128(1) ; send it to the display 0382 11A0 8F 00 dly 0 ; delay for display,let keys settle 0383 11A2 C1 80 ld -128(1) ; get keyboard input 0384 11A4 E4 FF xri 0FFh ; invert the input so 1 = pressed 0385 11A6 9C 4C jnz Key ; jump if a key pushed (save in Pushed) 0386 11A8 Back: 0387 11A8 BA 09 dld cnt(2) ; check if done 0388 11AA 9C ED jnz KDLoop ; no if jump 0389 11AC C2 0A ld pushed(2) ; check if key pressed 0390 11AE 98 0A jz CkMore ; if no, then go to try again 0391 11B0 C2 0B ld char(2) 0392 11B2 9C D8 jnz Off ; if yes, wait for release 0393 11B4 C2 0A ld pushed(2) ; released ? set char 0394 11B6 CA 0B st char(2) 0395 11B8 90 D2 jmp Off 0396 11BA C2 0B CkMore: ld char(2) ; check if there was a character 0397 11BC 98 CE jz Off ; no, keep looking 0398 11BE 0399 11BE 01 Command:xae ; copy into E 0400 11BF 40 lde 0401 11C0 D4 20 ani 020h ; check for command 0402 11C2 9C 28 jnz Cmnd ; jump if command 0403 11C4 C4 80 ldi 080h ; find number (its a digit 0..F) 0404 11C6 50 ane 0405 11C7 9C 1B jnz Lt7 ; 0 to 7 0406 11C9 C4 40 ldi 040h 0407 11CB 50 ane 0408 11CC 9C 19 jnz N89 ; 8, 9 0409 11CE C4 0F ldi 0fh ; B to F 0410 11D0 50 ane 0411 11D1 F4 07 adi 7 0412 11D3 01 xae 0413 11D4 C0 80 ld -128(0) ; get number 0414 11D6 01 KeyRtn: xae ; save in E 0415 11D7 C7 02 ld @2(3) ; fix return,add 2 0416 11D9 3F xppc 3 0417 11DA 90 A9 jmp Kybd ; allows us to go round again 0418 11DC 0A 0B 0C 0D .db 0Ah,0Bh,0Ch,0Dh,0,0,0Eh,0Fh 0418 11E0 00 00 0E 0F 0419 11E4 60 Lt7: xre ; keep low digit (handler for 0..7) 0420 11E5 90 EF jmp KeyRtn 0421 11E7 60 N89: xre ; get low (handler for 8 & 9) 0422 11E8 F4 08 adi 8 ; make it 8 or 9 0423 11EA 90 EA jmp KeyRtn 0424 11EC 0425 11EC 60 Cmnd: xre 0426 11ED E4 04 xri 4 ; check if abort 0427 11EF 98 08 jz Abrt ; if so,goto abort 0428 11F1 3F xppc 3 ; return 0429 11F2 90 91 jmp Kybd ; and allow reentry 0430 11F4 0431 11F4 58 Key: ore ; make character 0432 11F5 CA 0A st pushed(2) ; save it 0433 11F7 90 AF jmp Back 0434 11F9 0435 11F9 C4 00 Abrt: ldi High(Abort) ; goto abort 0436 11FB 37 xpah 3 0437 11FC C4 4B ldi Low(Abort)-1 0438 11FE 33 xpal 3 0439 11FF 3F xppc 3 0440 1200 0441 1200 0442 1200 0443 1200 .end 0444 1200 0445 1200 tasm: Number of errors = 0