PAGE 01 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 002 ORG :D3F4 003 * 004 * 005 * 006 ******************** 007 * READ FILE HEADER * 008 ******************** 009 * 010 * Locates a file on tape and reads leader. 011 * Exit: Interrupts are disabled. BCDEHL preserved. 012 * 013 D3F4 CD8FD9 RHDR CALL :D98F Disable sound interrupt 014 D3F7 CD80D4 CALL :D480 Find sync pattern 015 D3FA CDD4D4 CALL :D4D4 Read flag type byte 016 D3FD DAF4D3 JC :D3F4 Again if reading error 017 D400 FE55 CPI :55 018 D402 C2F4D3 JNZ :D3F4 Again if not flag byte 019 D405 CDD4D4 CALL :D4D4 Read file type byte 020 D408 DAF4D3 JC :D3F4 Again if reading error 021 D40B C9 RET 022 * 023 ********************* 024 * WRITE FILE LEADER * 025 ********************* 026 * 027 * Writes a leader for program or data block on tape. 028 * Disables interrupts which could cause problems. 029 * 030 * Entry: at WHDR: Entry if not during run program. 031 * at WHD20: If during run of program. 032 * Exit: BCDEHL preserved. 033 * 034 D40C CDFFDA WHDR CALL :DAFF Print 'SET RECORD, START 035 D40F 9CDB DBL :DB9C TAPE, TYPE SPACE' 036 D411 CDCBD7 CALL :D7CB Wait for spacebar pressed 037 D414 CD2ED4 WHD20 CALL :D42E Switch on cassette motors 038 D417 F3 DI Disable interrupts 039 D418 00 NOP 040 D419 00 NOP 041 D41A CDEDD4 CALL :D4ED Write leader 042 D41D 3E55 MVI A,:55 Get flag byte 043 D41F C309D5 JMP :D509 Write flag byte 044 * 045 ************** 046 * (Not used) * 047 ************** 048 * 049 D422 CDF1D2 MPT27 CALL :D2F1 Write block on tape 050 D425 00 NOP 051 D426 00 NOP 052 * 053 ********************** 054 * WRITE FILE TRAILER * 055 ********************** 056 * 057 * Write a trailer for program or datablock. 058 * 059 * Entry: Length of trailer in C. 060 * Exit: A=0, BCDEHL preserved. 061 * 062 *WTRL 063 D427 CD50D5 CWCLOS CALL :D550 Write trailer bytes PAGE 02 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 064 D42A FB EI Enable interrupts 065 D42B C345D4 JMP :D445 Stop cassette motors 066 * 067 ************************* 068 * START CASSETTE MOTORS * 069 ************************* 070 * 071 * Turns on motor of selected cassettedeck and 072 * waits 665 msec. 073 * 074 * Exit: All registers preserved. 075 * 076 D42E F5 CASST PUSH PSW 077 D42F 3A4000 LDA :0040 Load POROM 078 D432 F630 ORI :30 Disable cassette motors 079 D434 E5 PUSH H 080 D435 213D01 LXI H,:013D Addr CASSL 081 D438 AE XRA M Get selected cassette 082 D439 E1 POP H 083 D43A 324000 STA :0040 Remember POROM 084 D43D 3206FD STA :FD06 Switch cassette motor on 085 D440 CD41DE CALL :DE41 Delay 086 D443 F1 POP PSW 087 D444 C9 RET 088 * 089 ************************ 090 * STOP CASSETTE MOTORS * 091 ************************ 092 * 093 * Switches off cassettemotors. 094 * 095 * Exit: All registers preserved. 096 * 097 *CRCLOS 098 D445 F5 CASSP PUSH PSW 099 D446 3A4000 LDA :0040 Load POROM 100 D449 F630 ORI :30 Disable cassette motors 101 D44B 324000 STA :0040 Remember POROM 102 D44E 3206FD STA :FD06 Switch cassette motors off 103 D451 F1 POP PSW 104 D452 C9 RET 105 * 106 ************ 107 * READ BIT * 108 ************ 109 * 110 * Reads one bit from tape. 111 * 112 * Entry: Address input port in HL. Input low state. 113 * Exit: CY=0: sign bit of A is bit read. 114 * CY=1: reading error. 115 * BHL preserved. 116 * 117 D453 AF RBIT XRA A 118 D454 57 MOV D,A 119 D455 47 MOV B,A 120 D456 4F MOV C,A 121 122 * 1st impulse: 123 124 D457 05 RBT10 DCR B 125 D458 CA7ED4 JZ :D47E Too long low PAGE 03 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 126 D45B B6 ORA M 127 D45C F257D4 JP :D457 Wait for high 128 D45F 0D RBT30 DCR C 129 D460 CA7ED4 JZ :D47E Too long high 130 D463 15 DCR D 131 D464 A6 ANA M 132 D465 FA5FD4 JM :D45F Wait low 133 D468 010000 LXI B,:0000 134 135 * 2nd impulse: 136 137 D46B 05 RBT40 DCR B 138 D46C CA7ED4 JZ :D47E Too long low 139 D46F B6 ORA M 140 D470 F26BD4 JP :D46B Wait high again 141 D473 0D RBT50 DCR C 142 D474 CA7ED4 JZ :D47E Too long high 143 D477 14 INR D 144 D478 A6 ANA M 145 D479 FA73D4 JM :D473 Wait low 146 D47C 7A MOV A,D 147 D47D C9 RET 148 149 * If error: 150 151 D47E 37 RBT90 STC Set CY if error 152 D47F C9 RET 153 * 154 *************** 155 * READ LEADER * 156 *************** 157 * 158 * Finds a section of leader on the tape. 159 * 160 * Entry: No conditions. 161 * Exit: BCDEHL preserved, interrupts disabled. 162 * 163 D480 C5 RLEAD PUSH B 164 D481 D5 PUSH D 165 D482 E5 PUSH H 166 D483 0628 MVI B,:28 Estimate of impulse length 167 D485 2100FD LXI H,:FD00 Address input port 168 D488 3EFF RDL05 MVI A,:FF 169 D48A FB RDL10 EI Enable interrupts 170 D48B 00 NOP (here cursor flashes) 171 D48C F3 DI Disable interrupts 172 D48D A6 ANA M 173 D48E FA8AD4 JM :D48A Wait low 174 D491 48 MOV C,B Estimated length in C 175 D492 1614 MVI D,:14 Needs this many cycles for 176 synchronisation. Must be 177 more than trailer length. 178 D494 1E00 RDL30 MVI E,:00 179 D496 AF XRA A 180 D497 1D RDL40 DCR E 181 D498 CA88D4 JZ :D488 Too long low; start again 182 D49B B6 ORA M 183 D49C F297D4 JP :D497 Wait high 184 D49F 0600 MVI B,:00 185 D4A1 04 RDL50 INR B 186 D4A2 CA88D4 JZ :D488 Too long high; start again 187 D4A5 A6 ANA M PAGE 04 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 188 D4A6 FAA1D4 JM :D4A1 Wait low 189 D4A9 78 MOV A,B 190 D4AA 91 SUB C Compare impulse length 191 with estimate 192 D4AB F2B0D4 JP :D4B0 193 D4AE 2F CMA ) 194 D4AF 3C INR A ) 2-complement if <0 195 D4B0 5F RDL60 MOV E,A Store difference in E 196 D4B1 79 MOV A,C Calculate margin 197 D4B2 E6F0 ANI :F0 198 D4B4 1F RAR 199 D4B5 1F RAR 200 D4B6 1F RAR Margin: 1/8th of estimate 201 D4B7 BB CMP E Compare with difference 202 D4B8 DAC3D4 JC :D4C3 Not within margin 203 204 * If sync archieved: 205 206 D4BB 15 DCR D 207 D4BC C294D4 JNZ :D494 Next impulse until D=0 208 D4BF 14 INR D 209 D4C0 C394D4 JMP :D494 Next impulse until out 210 of margin 211 212 * If out of margin: 213 214 D4C3 15 RDL70 DCR D 215 D4C4 C288D4 JNZ :D488 Not synchronised; again 216 D4C7 AF XRA A 217 D4C8 B6 RDL80 ORA M 218 D4C9 F2C8D4 JP :D4C8 Wait high 219 D4CC A6 RDL90 ANA M 220 D4CD FACCD4 JM :D4CC Wait low 221 D4D0 E1 POP H 222 D4D1 D1 POP D 223 D4D2 C1 POP B 224 D4D3 C9 RET 225 * 226 ************* 227 * READ BYTE * 228 ************* 229 * 230 * Reads one byte from tape. 231 * 232 * Entry: No conditions. 233 * Exit: CY=0: Byte read in A. 234 * CY=1: Some error. 235 * BCDEHL preserved. 236 * 237 D4D4 C5 RBYTE PUSH B 238 D4D5 D5 PUSH D 239 D4D6 E5 PUSH H 240 D4D7 2100FD LXI H,:FD00 Address input port 241 D4DA 1EFE MVI E,:FE 242 D4DC CD53D4 RBY10 CALL :D453 Read bit 243 D4DF DAE9D4 JC :D4E9 If reading error; CY=1 244 D4E2 17 RAL 245 D4E3 7B MOV A,E 246 D4E4 17 RAL 247 D4E5 5F MOV E,A Shift bit into E 248 D4E6 DADCD4 JC :D4DC Next bit 249 D4E9 E1 RBY20 POP H 8 bits read, no error PAGE 05 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 250 D4EA D1 POP D 251 D4EB C1 POP B 252 D4EC C9 RET 253 * 254 **************** 255 * WRITE LEADER * 256 **************** 257 * 258 * Writes a leader on the tape. From WLD10 also used 259 * to write a trailer. 260 * 261 * Entry: No conditions. 262 * Exit: A=0, BCDEHL preserved. 263 * 264 D4ED 00 WLEAD NOP 265 D4EE C5 PUSH B 266 D4EF E5 PUSH H 267 D4F0 2AE602 LHLD :02E6 Get leader impulse length 268 D4F3 01E807 LXI B,:07E8 Period for synchr. 269 D4F6 CD24D5 WLD10 CALL :D524 Write bit 270 D4F9 0B DCX B 271 D4FA 78 MOV A,B 272 D4FB B1 ORA C 273 D4FC C2F6D4 JNZ :D4F6 Write many bits 274 D4FF 2AE802 LHLD :02E8 Get impulse length data bit 275 D502 CD24D5 CALL :D524 Write a data '1' bit to end 276 D505 E1 POP H 277 D506 C1 POP B 278 D507 00 NOP 279 D508 C9 RET 280 * 281 ************** 282 * WRITE BYTE * 283 ************** 284 * 285 * Write a byte to tape. 286 * 287 * Entry: Byte to be written in A. 288 * Exit: All registers preserved. 289 * 290 D509 F5 WBYTE PUSH PSW 291 D50A C5 PUSH B 292 D50B D5 PUSH D 293 D50C E5 PUSH H 294 D50D 2AE802 LHLD :02E8 Get impulse length bit '1' 295 D510 5C MOV E,H 296 D511 55 MOV D,L DE: inpulse length bit '0' 297 D512 0608 MVI B,:08 8 bits to write 298 D514 17 WBY10 RAL Set/reset CY for kind of bit 299 D515 DC24D5 CC :D524 Write data '1' bit 300 D518 EB XCHG 301 D519 D424D5 CNC :D524 Write data '0' bit 302 D51C EB XCHG 303 D51D 05 DCR B 304 D51E C214D5 JNZ :D514 Next bit 305 D521 C356CB JMP :CB56 Pop all, ret 306 * 307 ************* 308 * WRITE BIT * 309 ************* 310 * 311 * Write 2 impulses on tape, one long, one short. PAGE 06 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 312 * 313 * Entry: H: Half count first cycle. 314 * L: Half count second cycle. 315 * Exit: All registers preserved. 316 * 317 D524 F5 WBIT PUSH PSW 318 D525 D5 PUSH D 319 D526 E5 PUSH H 320 D527 6C MOV L,H 321 D528 1106FD LXI D,:FD06 Address output port 322 D52B CD3CD5 CALL :D53C Write 1st impulse 323 D52E E1 POP H 324 D52F E5 PUSH H 325 D530 65 MOV H,L 326 D531 7D MOV A,L 327 D532 D608 SUI :08 Allow for return to WBYTE 328 D534 6F MOV L,A 329 D535 CD3CD5 CALL :D53C Write 2nd impulse 330 D538 E1 POP H 331 D539 D1 POP D 332 D53A F1 POP PSW 333 D53B C9 RET 334 * 335 *************** 336 * WRITE CYCLE * 337 *************** 338 * 339 * Writes one impulse (hi/lo) on tape. Two cycles 340 * are required for one bit. 341 * 342 * Entry: DE: Address output port. 343 * HL: Impulse length constants. 344 * Exit: HL = 0. BCDE preserved. 345 * 346 D53C 3A4000 WCYC LDA :0040 POROM in A 347 D53F F601 ORI :01 lsb = 1 348 D541 12 STAX D Output port is made '1' 349 D542 25 WCY10 DCR H 350 D543 C242D5 JNZ :D542 Write '1' until H=0 351 D546 2D DCR L 352 D547 2D DCR L 353 D548 2D DCR L Allow for return to WBIT 354 D549 3D DCR A 355 D54A 12 STAX D Output port is made '0' 356 D54B 2D WCY20 DCR L 357 D54C C24BD5 JNZ :D54B Write '0' until L=0 358 D54F C9 RET 359 * 360 ********************** 361 * WRITE TRAILER BITS * 362 ********************** 363 * 364 * Writes trailer bits after a block on tape. 365 * 366 * Entry: Number of trailer bits in C. 367 * Exit: A=0, other registers preserved. 368 * F corrupted. 369 * 370 D550 C5 WTRLX PUSH B 371 D551 E5 PUSH H 372 D552 2AEA02 LHLD :02EA Trailer impulse length 373 D555 0600 MVI B,:00 PAGE 07 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 374 D557 C3F6D4 JMP :D4F6 Write trailer bits 375 * 376 D55A FF DATA :FF 377 D55B FF DATA :FF 378 D55C FF DATA :FF 379 D55D FF DATA :FF 380 D55E FF DATA :FF 381 D55F FF DATA :FF 382 * 383 ******************************** 384 * INITIALISE KEYBOARD POINTERS * 385 ******************************** 386 * 387 * Set all keyboard pointers to default values. 388 * 389 * Entry: Address ASCII-table in HL (3E8C5). 390 * Exit: BCDE preserved. 391 * 392 *KLIRS 393 D560 22A702 KBINIT SHLD :02A7 Load pointer ASCII-table 394 D563 AF KLIRP XRA A 395 D564 32B902 STA :02B9 Allow complete scan routine 396 D567 32C302 STA :02C3 CTRL not pressed 397 D56A 21BA02 LXI H,:02BA 398 D56D 22BE02 SHLD :02BE Set KLIIN ) Ignore 399 D570 22C002 SHLD :02C0 Set KLIOU ) previous inputs 400 D573 2F CMA 401 D574 32C402 STA :02C4 BREAK pointer = FF 402 D577 C9 RET 403 * 404 ************************************** 405 * KEYBOARD INTERRUPT SERVICE (RST 6) * 406 ************************************** 407 * 408 * Current interrupt mask is saved. Only stack and 409 * clock interrupts are allowed. Keyboard timer 4 410 * is re-loaded. 411 * KBXCT is counted down: abort if not 0. 412 * Else: scan keyboard and store result. 413 * 414 * Entry: None. 415 * Exit: All registers + int. mask preserved. 416 * 417 D578 F5 KBINT PUSH PSW 418 D579 C5 PUSH B 419 D57A D5 PUSH D 420 D57B 3A5F00 LDA :005F 421 D57E F5 PUSH PSW Preserve current int. mask 422 D57F 3E84 MVI A,:84 ) 423 D581 32F8FF STA :FFF8 ) Allow stack and clock 424 D584 325F00 STA :005F ) interrupts only 425 D587 FB EI 426 D588 CD9DD9 CALL :D99D Reload keyboard timer 427 D58B 21C101 LXI H,:01C1 428 D58E 35 DCR M Decr. keyb.scan time count 429 D58F C2CDD9 JNZ :D9CD No scanning if <>0 430 431 * if KBXCT = 0: 432 433 D592 3602 MVI M,:02 Set keyb. scan time counter 434 D594 CD9AD5 CALL :D59A Scan keyboard, store result 435 D597 C3CDD9 JMP :D9CD Restore int.mask; ret. PAGE 08 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 436 * 437 ******************************* 438 * SCAN KEYBOARD, STORE RESULT * 439 ******************************* 440 * 441 * Exit: All registers corrupted. 442 * 443 D59A 11F1FF KBSCAN LXI D,:FFF1 Input port from keyboard 444 D59D 21F7FF LXI H,:FFF7 Output port to keyboard 445 D5A0 01C402 LXI B,:02C4 BREAK pointer 446 D5A3 F3 DI 447 D5A4 3640 MVI M,:40 Scan row 6 448 D5A6 1A LDAX D and get result 449 D5A7 FB EI 450 D5A8 87 ADD A Check for BREAK pressed 451 D5A9 FA06D6 JM :D606 If BREAK pressed 452 D5AC CD50D7 CALL :D750 Update BREAK pointer 453 D5AF 3AB902 LDA :02B9 Get BREAK pointer 454 D5B2 B7 ORA A Scan for BREAK only? 455 D5B3 C205D6 JNZ :D605 Then abort 456 457 * Scan all rows and store result in MAP1: 458 459 D5B6 01A902 LXI B,:02A9 MAP1 for currently 460 pressed key 461 D5B9 C5 PUSH B Preserve MAP1 addr 462 D5BA 3C INR A Determine row 463 D5BB F5 KEB10 PUSH PSW 464 D5BC F3 DI 465 D5BD 77 MOV M,A Scan row 466 D5BE 1A LDAX D Get result 467 D5BF FB EI 468 D5C0 02 STAX B Store result in MAP1 469 D5C1 03 INX B 470 D5C2 F1 POP PSW 471 D5C3 87 ADD A Determine next row 472 D5C4 D2BBD5 JNC :D5BB Scan next row if not ready 473 474 * REPT handling: 475 476 D5C7 3AAF02 LDA :02AF 477 D5CA E620 ANI :20 Check if REPT pressed 478 D5CC 47 MOV B,A Store result 479 D5CD 21C202 LXI H,:02C2 Addr. REPT counter 480 D5D0 7E MOV A,M Get contents 481 D5D1 3601 MVI M,:01 Update it for immediate scan 482 D5D3 CADFD5 JZ :D5DF If REPT not pressed 483 D5D6 3D DCR A Else 484 D5D7 77 MOV M,A Decr. REPT counter 485 D5D8 C204D6 JNZ :D604 If <>0, abort scan 486 D5DB 3602 MVI M,:02 Else RPCNT=2 487 D5DD 06FF MVI B,:FF Set B=FF for REPT pressed 488 489 * ASCII-value of key pressed into KLIND: 490 491 D5DF E1 KEB40 POP H Get addr MAP1 492 D5E0 E5 PUSH H Save addr. MAP1 493 D5E1 11B102 LXI D,:02B1 Get addr. MAP2 494 D5E4 0E00 MVI C,:00 495 D5E6 7E KEB50 MOV A,M Get result scan current 496 row in A 497 D5E7 05 DCR B PAGE 09 DAI FIRMWARE D3F4-D61F V1.0 Rev.1 498 D5E8 04 INR B REPT pressed ? 499 D5E9 C2F0D5 JNZ :D5F0 If REPT pressed 500 D5EC EB XCHG 501 D5ED AE XRA M ) Check if new input 502 D5EE EB XCHG ) 503 D5EF A6 ANA M ) 504 D5F0 B7 KEB60 ORA A ) 505 D5F1 C432D6 CNZ :D632 If new: Get ASCII-code 506 and store it in KLIND 507 D5F4 13 INX D 508 D5F5 23 INX H Next row 509 D5F6 0C INR C 510 D5F7 79 MOV A,C 511 D5F8 FE08 CPI :08 All rows checked? 512 D5FA C2E6D5 JNZ :D5E6 Next row if not 513 D5FD D1 KEB70 POP D Get MAP1 addr in DE 514 D5FE D5 PUSH D 515 D5FF 44 MOV B,H ) Get MAP2 addr in HL 516 D600 4D MOV C,L ) 517 D601 CD4FDE CALL :DE4F Transfer (MAP1) into MAP2 518 D604 D1 KEB80 POP D Scrap 519 D605 C9 KEB81 RET 520 521 * if BREAK pressed: 522 523 D606 C5 KEB90 PUSH B Save Breakpntr 524 D607 CDA6D8 CALL :D8A6 All sound off 525 D60A C1 POP B 526 D60B 00 NOP 527 D60C CD45D4 CALL :D445 Stop cassette motors 528 D60F 0A LDAX B Get KBRFL 529 D610 3C INR A 530 D611 CA05D6 JZ :D605 If KBRFL=FF: break acknow- 531 ledged already 532 D614 02 STAX B Else: store new KBRFL 533 D615 FE20 CPI :20 534 D617 C205D6 JNZ :D605 If new KBRFL<>20: wait for 535 soft-break to be accepted 536 D61A CD63D5 CALL :D563 Else: init keyb. pointers 537 D61D C30CC8 JMP :C80C Print 'BREAK', return to 538 monitor 539 * 540 * 546 D620 END *************************** * S Y M B O L T A B L E * *************************** CASSP D445 CASST D42E CRCLOS D445 CWCLOS D427 KBINIT D560 KBINT D578 KBSCAN D59A KEB10 D5BB KEB40 D5DF KEB50 D5E6 KEB60 D5F0 KEB70 D5FD KEB80 D604 KEB81 D605 KEB90 D606 KLIRP D563 KLIRS D560 MPT27 D422 RBIT D453 RBT10 D457 RBT30 D45F RBT40 D46B RBT50 D473 RBT90 D47E RBY10 D4DC RBY20 D4E9 RBYTE D4D4 RDL05 D488 RDL10 D48A RDL30 D494 RDL40 D497 RDL50 D4A1 RDL60 D4B0 RDL70 D4C3 RDL80 D4C8 RDL90 D4CC RHDR D3F4 RLEAD D480 WBIT D524 WBY10 D514 WBYTE D509 WCY10 D542 WCY20 D54B WCYC D53C WHD20 D414 WHDR D40C WLD10 D4F6 WLEAD D4ED WTRL D427 WTRLX D550