!M 0000 ; 0001 .. MicroVIP operating system 0000 ; 0002 .. modified from the VIP hex listing 0000 ; 0003 .. and using information from VIPER Vol 1, Issue 3 0000 ; 0004 .. by J.W. Wentworth's Interpretation of VIP 0000 ; 0005 .. D. Hunter 09/03/17 0000 ; 0006 .. 0000 ; 0007 .. NOTE: the subroutines on page #8100 are not moved from the original VIP so that 0000 ; 0008 .. the OS is still compatible with Chip-8. 0000 ; 0009 .. 0000 ; 0010 .. Enter the VIP operating system by holding down the 'C' key when entering RUN 0000 ; 0011 .. A 4 digit hex address / file number is entered followed by a command key 0000 ; 0012 .. e.g. 0123 0000 ; 0013 .. There are four commands possible: 0000 ; 0014 .. Memory Read = A 0000 ; 0015 .. Memory Write = 0 (enter the byte to write) 0000 ; 0016 .. Flash Read = B (address = file number [0000-01FF]) 0000 ; 0017 .. Flash Write = F (address = file number [0000-01FF]) 0000 ; 0018 .. 0000 ; 0019 .. The registers R3-RF are stored in a table on start up 0000 ; 0020 .. #0FB3-#0FBF <- R3.0-RF.0 0000 ; 0021 .. #0FC3-#0FCF <- R3.1-RF.1 0000 ; 0022 .. 0000 ; 0023 .. Execute a RESET (RUN OFF, RUN ON) to exit a command and start again 0000 ; 0024 .. 0000 ; 0025 .. Memory Map 0000 ; 0026 .. 0000 - 0FFF RAM (4K) 0000 ; 0027 .. 8000 - 81FF ROM1 (512)[MicroVIP ROM] 0000 ; 0028 .. 8200 - 83FF ROM2 (512) [UT4 Monitor] 0000 ; 0029 .. 8400 - 9FFF ROM3 (7K) [Tiny BASIC] 0000 ; 0030 .. A000 - BFFF 0000 ; 0031 .. C000 - C3FF Auxiliary RAM (1K) 0000 ; 0032 .. D000 - FFFF 0000 ; 0033 .. 0000 ; 0034 .. I/O Port Map [] = future option 0000 ; 0035 .. # OUT IN 0000 ; 0036 .. 1 video offvideo on 0000 ; 0037 .. 2 keypad [ASCII Keyboard] 0000 ; 0038 .. 3 output portinput port 0000 ; 0039 .. 4 [I2C out][I2C in] 0000 ; 0040 .. 5 control reg[UART status] 0000 ; 0041 .. 6 [UART txd][UART rxd] 0000 ; 0042 .. 7 SPI out SPI in 0000 ; 0043 .. 0000 ; 0044 .. 0000 ; 0045 .. control register (PORT 5) 0000 ; 0046 .. bit 0,1:Q mux 00 = tone (VIP) 0000 ; 0047 .. 01 = serial (UT4) 0000 ; 0048 .. 10 = GPIO out strobe 0000 ; 0049 .. 11 = Flash SPI CS 0000 ; 0050 .. bit 2:Tone Disable0 = tone enabled 1 = tone disabled 0000 ; 0051 .. bit 3:UART pins0 = Q/EF2 1 = UART (future) 0000 ; 0052 .. bit 4:Flash WP0 = WP off 1 = WP on 0000 ; 0053 .. bit 5: 0000 ; 0054 .. bit 6: 0000 ; 0055 .. bit 7: 0000 ; 0056 .. 0000 ; 0057 .. Q 0000 ; 0058 .. FLASH CS (inverted) 0000 ; 0059 .. LED / SPEAKER TONE ON 0000 ; 0060 0000 ; 0061 .. EF PINS 0000 ; 0062 .. VIDEO FRAME EF1 0000 ; 0063 .. UT4 SERIAL EF2 0000 ; 0064 .. KEYPAD EF3 0000 ; 0065 .. (OPEN) EF4 0000 ; 0066 0000 ; 0067 STKTOP: EQU #AF .. top of stack is below register memory 0000 ; 0068 LINE27: EQU 216 .. display starts at line 27, position 0 0000 ; 0069 .. for 5 rows (27,28,29,30,31) 0000 ; 0070 .. so the characters are at the bottom 0000 ; 0071 .. of the screen 0000 ; 0072 .. 27 * 8 = 216 = #D8 0000 ; 0073 NXTCHR: EQU 217 .. line 27, position 1 0000 ; 0074 0000 ; 0075 .. Serial Flash commands 0000 ; 0076 CMDWR: EQU #02 0000 ; 0077 CMDRD: EQU #03 0000 ; 0078 CMDSTA: EQU #05 0000 ; 0079 CMDWEN: EQU #06 0000 ; 0080 CMDERA: EQU #20 0000 ; 0081 0000 ; 0082 .. REGISTER USAGE 0000 ; 0083 .. R0 = DMA (video memory) 0000 ; 0084 .. R1 = INTERRUPT 0000 ; 0085 .. R2 = STACK POINTER 0000 ; 0086 .. R3 = PC 0000 ; 0087 .. R4 = DISPLAY CONTROL SUBROUTINE (#81DD) 0000 ; 0088 .. R5 = 5 ROW DISPLAY SUBROUTINE (#81C6) 0000 ; 0089 .. R6 = POINTER TO ADDRESSED BYTE ENTERED BY OPERATOR 0000 ; 0090 .. R7 = GET BYTE FROM KEYPAD SUBROUTINE (#81BA) 0000 ; 0091 .. FLASH READ/WRITE: SERIAL FLASH PAGE ADDRESS (upper 16 bits of address) 0000 ; 0092 .. R8 = R8.1 IS A TIMER FOR CHIP 8 PROGRAMS, TESTED EVERY TV SCREEN 0000 ; 0093 .. R8.0 TIMER TESTED AND DECREMENTED EVERY TV SCREEN (60 HZ) 0000 ; 0094 .. A TONE IS ON (Q SET) WHEN TIMER > 0 0000 ; 0095 .. R8.0 TIMER ALSO CONTROLS DEBOUNCE FOR THE KEYBOARD 0000 ; 0096 .. R9 = SPECIAL VALUE USED BY THE RANDOM NUMBER GENERATOR IN CHIP 8, 0000 ; 0097 .. INCREMENTED ONCE PER TV SCREEN 0000 ; 0098 .. RA = DATA POINTER USED IN 5 ROW HEX DIGIT DISPLAY -POINTS TO CHARACTER DATA 0000 ; 0099 .. RB = RB.1 STORES DISPLAY PAGE UPPER ADDRESS FOR USE DURING THE INTERRUPT ROUTINE 0000 ; 0100 .. RB.0 USED DURING THE INTERRUPT ROUTINE TO DECREMENT R8.1 W/O CHANGING DF 0000 ; 0101 .. RC = KEYBOARD SCAN SUBROUTINE (#8195) 0000 ; 0102 .. RD = DESTINATION POINTER TO BE DISPLAYED ON DISPLAY PAGE 0000 ; 0103 .. RE = RE.1 STORES CONTROL DIGIT (A, 0, B OR F) FROM USER 0000 ; 0104 .. RE.0 STORES THE MOST SIGNIFICANT DIGIT FOR THE KEYBOARD INPUT 0000 ; 0105 .. RF = RF.1 0000 ; 0106 .. RF.0 IS USED FOR KEYBOARD SCANNING AND A COUNTER FOR THE 5 ROW DISPLAY 0000 ; 0107 0000 ; 0108 ORG #8000 8000 ; 0109 8000 F880; 0110 COLD: LDI A.1(MON) .. jump to MON from boot vector 8002 B2; 0111 PHI R2 8003 F808; 0112 LDI A.0(MON) 8005 A2; 0113 PLO R2 8006 E2; 0114 SEX R2 .. 2 -> X 8007 D2; 0115 SEP R2 .. 2 -> P 8008 65; 0116 MON: OUT 5 .. reset control register for VIP mode 8009 00; 0117 ,#00 800A 62; 0118 OUT 2 .. set keyboard scan for switch 'C' 800B 0C; 0119 ,#0C 800C ; 0120 800C ; 0121 .. Set the top of RAM at the 4K boundary (max size for a VIP) 800C ; 0122 .. a memory test is not needed since the memory size is fixed by the FPGA 800C F8FF; 0123 MEMCK: LDI #FF .. set for top of memory, #0FFF 800E A1; 0124 PLO R1 800F F80F; 0125 LDI #0F 8011 B1; 0126 PHI R1 8012 ; 0127 8012 3618; 0128 DONE: B3 CLRDSP .. start if KEY 'C' pressed 8014 90; 0129 GHI R0 .. else, start user program at #0000 8015 A0; 0130 PLO R0 8016 E0; 0131 SEX R0 8017 D0; 0132 SEP R0 8018 ; 0133 8018 ; 0134 .. Erase the display page from 0FFF to 0FB0 8018 E1; 0135 CLRDSP: SEX R1 8019 F800; 0136 CLEAR: LDI #00 801B 73; 0137 STXD 801C 81; 0138 GLO R1 801D FBAF; 0139 XRI STKTOP .. clear register table to memory top 801F 3A19; 0140 BNZ CLEAR .. (#0FB0 to #0FFF) 8021 ; 0141 8021 ; 0142 .. copy registers to a register table 8021 ; 0143 .. by creating op codes on the fly 8021 ; 0144 .. #0FB3-#0FBF <- R3.0-RF.0 8021 ; 0145 .. #0FC3-#0FCF <- R3.1-RF.1 8021 F8D2; 0146 REGDMP: LDI #D2 .. SEP R2 op code 8023 73; 0147 STXD 8024 F89F; 0148 LDI #9F .. GHI RF op code 8026 51; 0149 STR R1 8027 81; 0150 GLO R1 8028 A0; 0151 PLO R0 8029 91; 0152 GHI R1 802A B0; 0153 PHI R0 .. R0 <- R1 802B F8CF; 0154 LDI #CF 802D A1; 0155 PLO R1 .. R1 <- #0FCF (top of register table) 802E D0; 0156 REGRD: SEP R0 802F 73; 0157 STXD 8030 20; 0158 DEC R0 8031 20; 0159 DEC R0 8032 40; 0160 LDA R0 8033 FF01; 0161 SMI #01 8035 20; 0162 DEC R0 8036 50; 0163 STR R0 8037 FB82; 0164 XRI #82 .. stop after R3.0 is stored (GLO R2 opcode) 8039 3A2E; 0165 BNZ REGRD 803B ; 0166 803B ; 0167 .. Initialize the registers to start the operating system 803B 92; 0168 GHI R2 803C B3; 0169 PHI R3 803D F841; 0170 LDI A.0(MAIN) 803F A3; 0171 PLO R3 8040 D3; 0172 SEP R3 .. go to MAIN 8041 90; 0173 MAIN: GHI R0 8042 B2; 0174 PHI R2 .. R2.1 = top of memory(stack) 8043 BB; 0175 PHI RB .. RB.1 = top of memory (video) 8044 BD; 0176 PHI RD .. RD.1 = top of memory (display mem) 8045 F881; 0177 LDI #81 .. point subroutines to page 2 of ROM 8047 B1; 0178 PHI R1 .. #81 -> R1.1 8048 B4; 0179 PHI R4 .. #81 -> R4.1 8049 B5; 0180 PHI R5 .. #81 -> R5.1 804A B7; 0181 PHI R7 .. #81 -> R7.1 804B BA; 0182 PHI RA .. #81 -> RA.1 804C BC; 0183 PHI RC .. #81 -> RC.1 804D ; 0184 804D F846; 0185 LDI A.0(INT) 804F A1; 0186 PLO R1 .. set interrupt pointer 8050 ; 0187 8050 F8AF; 0188 LDI STKTOP 8052 A2; 0189 PLO R2 .. set stack pointer 8053 ; 0190 8053 F8DD; 0191 LDI A.0(DISPD) 8055 A4; 0192 PLO R4 .. R4 = display data 8056 ; 0193 8056 F8C6; 0194 LDI A.0(DISPW) 8058 A5; 0195 PLO R5 .. R5 = write character to display memory 8059 ; 0196 8059 F8BA; 0197 LDI A.0(GETB).. RA = get 2 hex digits into a byte 805B A7; 0198 PLO R7 805C ; 0199 805C F8A1; 0200 LDI A.0(DBNCE).. RC = keyboard debounce initially 805E ; 0201 .. = keyboard scan after first call 805E AC; 0202 PLO RC 805F ; 0203 805F E2; 0204 SEX R2 .. set R2 as stack pointer 8060 69; 0205 INP 1 .. turn display on 8061 ; 0206 8061 ; 0207 .. Enter address 8061 DC; 0208 SEP RC .. call keypad debounce for the 'C' key 8062 D7; 0209 SEP R7 .. get address upper byte 8063 D7; 0210 SEP R7 .. routine must be called 3 times 8064 D7; 0211 SEP R7 .. because R7 returns to main 8065 B6; 0212 PHI R6 .. put high byte in R6 8066 ; 0213 8066 D7; 0214 SEP R7 .. get address lower byte 8067 D7; 0215 SEP R7 8068 D7; 0216 SEP R7 8069 A6; 0217 PLO R6 .. R6 = address / file number entered by user 806A ; 0218 806A D4; 0219 SEP R4 .. display address 806B ; 0220 806B ; 0221 .. get user command 806B DC; 0222 SEP RC .. keyboard scan 806C BE; 0223 PHI RE .. store control value (key) in RE.1 806D 32F2; 0224 BZ MWR .. Memory write? 806F ; 0225 806F FB0A; 0226 XRI #0A 8071 32ED; 0227 BZ MRD .. Memory read? 8073 ; 0228 8073 ; 0229 .. Flash Read/Write command? 8073 22; 0230 DEC R2 8074 61; 0231 OUT 1 .. turn off the display so Q can be used for chip select 8075 ; 0232 8075 96; 0233 GHI R6 8076 B7; 0234 PHI R7 .. copy file number into R7 8077 86; 0235 GLO R6 8078 A7; 0236 PLO R7 .. copy file number into R7 8079 ; 0237 8079 ; 0238 .. shift R7 left by 4 to create a flash page address 8079 F804; 0239 LDI #04 807B AE; 0240 PLO RE 807C 87; 0241 SETPG: GLO R7 807D FE; 0242 SHL 807E A7; 0243 PLO R7 807F 97; 0244 GHI R7 8080 7E; 0245 SHLC 8081 B7; 0246 PHI R7 .. R7 = R7 << 1 8082 2E; 0247 DEC RE 8083 8E; 0248 GLO RE 8084 3A7C; 0249 BNZ SETPG 8086 ; 0250 8086 E3; 0251 SEX R3 8087 65; 0252 OUT 5 .. connect Q to Flash CS 8088 03; 0253 ,#03 8089 E2; 0254 SEX R2 808A ; 0255 808A F800; 0256 LDI #00 .. set address pointer (R6) to start of RAM 808C A6; 0257 PLO R6 808D B6; 0258 PHI R6 808E ; 0259 808E ; 0260 .. put 24 bit flash address on stack 808E 22; 0261 DEC R2 808F 73; 0262 STXD .. page address (7-0) = #00 8090 87; 0263 GLO R7 8091 73; 0264 STXD .. page address (15-8) 8092 97; 0265 GHI R7 8093 73; 0266 STXD .. page address (23-16) 8094 ; 0267 8094 9E; 0268 GHI RE .. get control value 8095 FB0B; 0269 XRI #0B .. FLASH READ? 8097 32D5; 0270 BZ FRD 8099 ; 0271 8099 9E; 0272 GHI RE 809A FB0F; 0273 XRI #0F 809C 32A0; 0274 BZ FWR .. FLASH WRITE? 809E ; 0275 809E ; 0276 .. can put other commands here 809E 309E; 0277 BR $ .. no, invalid command, go into endless loop 80A0 ; 0278 80A0 ; 0279 .. SERIAL FLASH ROUTINES 80A0 ; 0280 .. for Winbond W25Q128 Serial Flash (16MB) 80A0 ; 0281 .. the serial flash replaces the cassette tape interface 80A0 ; 0282 .. the first 2MB of the serial flash is reserved for the VIP OS (000000-1FFFFF) 80A0 ; 0283 .. up to 512 memory (4K) images can be saved in the serial flash (0000-01FF) 80A0 ; 0284 80A0 ; 0285 .. Flash Write Routine 80A0 ; 0286 .. erase a 4K sector, then write entire 4K memory image to it 80A0 ; 0287 .. R2 = stack pointer 80A0 ; 0288 .. R6 = memory address 80A0 ; 0289 .. R9 = sector page address (0000-1FF0) 80A0 ; 0290 .. The serial flash can only write one page (256 bytes) at a time 80A0 ; 0291 .. So, 16 page writes are needed to write a complete 4K sector 80A0 ; 0292 80A0 F820; 0293 FWR: LDI CMDERA 80A2 52; 0294 STR R2 .. save erase sector command on stack 80A3 ; 0295 80A3 F87E; 0296 LDI A.0(WRENA) 80A5 AC; 0297 PLO RC 80A6 DC; 0298 SEP RC .. send write enable for erase sector 80A7 ; 0299 80A7 F887; 0300 LDI A.0(SNDCMD) 80A9 AC; 0301 PLO RC 80AA DC; 0302 SEP RC .. send command 80AB 7A; 0303 REQ .. deassert chip select 80AC ; 0304 80AC 22; 0305 WRTPG: DEC R2 .. back up stack pointer 80AD F800; 0306 LDI #00 80AF 73; 0307 STXD .. page address (7-0) is always 0 80B0 87; 0308 GLO R7 .. page address (15-8) 80B1 73; 0309 STXD 80B2 97; 0310 GHI R7 .. page address (23-16) 80B3 73; 0311 STXD 80B4 F802; 0312 LDI CMDWR 80B6 52; 0313 STR R2 .. write page command 80B7 ; 0314 80B7 F86F; 0315 LDI A.0(FWAIT) 80B9 AC; 0316 PLO RC 80BA DC; 0317 SEP RC .. wait for flash to be ready 80BB ; 0318 80BB F87E; 0319 LDI A.0(WRENA) 80BD AC; 0320 PLO RC 80BE DC; 0321 SEP RC .. send write enable for page write 80BF ; 0322 80BF F887; 0323 LDI A.0(SNDCMD) 80C1 AC; 0324 PLO RC 80C2 DC; 0325 SEP RC .. send write page command 80C3 ; 0326 80C3 ; 0327 .. send page (256 bytes) of data 80C3 E6; 0328 SEX R6 .. point X to memory 80C4 67; 0329 WRLOOP: OUT 7 .. send it out, inc R6 80C5 86; 0330 GLO R6 .. on next page? 80C6 3AC4; 0331 BNZ WRLOOP .. no, keep going 80C8 7A; 0332 REQ .. yes, deassert chip select 80C9 E2; 0333 SEX R2 .. restore X 80CA ; 0334 80CA 17; 0335 INC R7 .. go to next page of flash 80CB 87; 0336 GLO R7 80CC FA0F; 0337 ANI #0F .. was last page of sector sent (R7 == #xxx0)? 80CE 3AAC; 0338 BNZ WRTPG .. no, continue 80D0 ; 0339 80D0 69; 0340 FDONE: INP 1 .. turn video back on 80D1 26; 0341 DEC R6 .. get last byte 80D2 D4; 0342 SEP R4 .. and display it 80D3 30D3; 0343 BR $ .. endless loop 80D5 ; 0344 80D5 ; 0345 .. Flash Read Routine 80D5 ; 0346 .. read a 4K sector and store in memory 80D5 ; 0347 .. R2 = stack pointer 80D5 ; 0348 .. R6 = memory address 80D5 F803; 0349 FRD: LDI CMDRD 80D7 52; 0350 STR R2 .. read command 80D8 ; 0351 80D8 F887; 0352 LDI A.0(SNDCMD) 80DA AC; 0353 PLO RC 80DB DC; 0354 SEP RC .. send read page command 80DC ; 0355 80DC 22; 0356 DEC R2 80DD F800; 0357 LDI #00 80DF 52; 0358 STR R2 80E0 ; 0359 80E0 67; 0360 RDLOOP: OUT 7 .. send zero byte to read in data 80E1 6F; 0361 INP 7 .. get SPI byte read and put in memory 80E2 56; 0362 STR R6 80E3 16; 0363 INC R6 80E4 22; 0364 DEC R2 .. restore pointer 80E5 ; 0365 80E5 96; 0366 GHI R6 80E6 FB10; 0367 XRI #10 .. at top of memory (#1000)? 80E8 3AE0; 0368 BNZ RDLOOP .. no, continue 80EA 7A; 0369 REQ .. yes, deassert chip select 80EB ; 0370 80EB 30D0; 0371 BR FDONE .. display last byte and spin 80ED ; 0372 80ED ; 0373 .. MEMORY ROUTINES 80ED ; 0374 80ED ; 0375 .. Memory read 80ED ; 0376 .. displays the next byte with a press of any key 80ED DC; 0377 MRD: SEP RC .. get any key from keyboard 80EE 16; 0378 INC R6 .. go to next address 80EF D4; 0379 SEP R4 .. display byte 80F0 30ED; 0380 BR MRD 80F2 ; 0381 80F2 ; 0382 .. Memory Write 80F2 D7; 0383 MWR: SEP R7 .. get byte to write 80F3 D7; 0384 SEP R7 80F4 D7; 0385 SEP R7 80F5 56; 0386 STR R6 .. store in the address 80F6 D4; 0387 SEP R4 .. display byte 80F7 16; 0388 INC R6 .. next address 80F8 30F2; 0389 BR MWR 80FA ; 0390 80FA ; 0391 .. end of main routine 80FA ; 0392 80FA ; 0393 .. filler 80FA 00; 0394 ,#00 80FB 00; 0395 ,#00 80FC 00; 0396 ,#00 80FD 00; 0397 ,#00 80FE 00; 0398 ,#00 80FF 00; 0399 ,#00 8100 ; 0400 8100 ; 0401 8100 ; 0402 ORG #8100 8100 ; 0403 8100 ; 0404 .. CHARACTER MAP LOOK UP TABLE 8100 ; 0405 .. offsets to the character data 8100 ; 0406 8100 30; 0407 CH0: ,A.0(DIG0) 8101 39; 0408 CH1: ,A.0(DIG1) 8102 22; 0409 CH2: ,A.0(DIG2) 8103 2A; 0410 CH3: ,A.0(DIG3) 8104 3E; 0411 CH4: ,A.0(DIG4) 8105 20; 0412 CH5: ,A.0(DIG5) 8106 24; 0413 CH6: ,A.0(DIG6) 8107 34; 0414 CH7: ,A.0(DIG7) 8108 26; 0415 CH8: ,A.0(DIG8) 8109 28; 0416 CH9: ,A.0(DIG9) 810A 2E; 0417 CHA: ,A.0(DIGA) 810B 18; 0418 CHB: ,A.0(DIGB) 810C 14; 0419 CHC: ,A.0(DIGC) 810D 1C; 0420 CHD: ,A.0(DIGD) 810E 10; 0421 CHE: ,A.0(DIGE) 810F 12; 0422 CHF: ,A.0(DIGF) 8110 ; 0423 8110 ; 0424 .. CHARACTER MAP 8110 ; 0425 .. each character is 5 bytes 8110 ; 0426 .. in a 8w x 5h matrix 8110 ; 0427 .. the characters are 4w by 5h, left justified 8110 ; 0428 8110 F0; 0429 DIGE: ,#F0 .. ****.... 8111 80; 0430 ,#80 .. *....... 8112 F0; 0431 DIGF: ,#F0 .. ****.... 8113 80; 0432 ,#80 .. *....... 8114 F0; 0433 DIGC: ,#F0 .. ****.... 8115 80; 0434 ,#80 .. *....... 8116 80; 0435 ,#80 .. *....... 8117 80; 0436 ,#80 .. *....... 8118 F0; 0437 DIGB: ,#F0 .. ****.... 8119 50; 0438 ,#50 .. .*.*.... 811A 70; 0439 ,#70 .. .***.... 811B 50; 0440 ,#50 .. .*.*.... 811C F0; 0441 DIGD: ,#F0 .. ****.... 811D 50; 0442 ,#50 .. .*.*.... 811E 50; 0443 ,#50 .. .*.*.... 811F 50; 0444 ,#50 .. .*.*.... 8120 F0; 0445 DIG5: ,#F0 .. ****.... 8121 80; 0446 ,#80 .. *....... 8122 F0; 0447 DIG2: ,#F0 .. ****.... 8123 10; 0448 ,#10 .. ...*.... 8124 F0; 0449 DIG6: ,#F0 .. ****.... 8125 80; 0450 ,#80 .. *....... 8126 F0; 0451 DIG8: ,#F0 .. ****.... 8127 90; 0452 ,#90 .. *..*.... 8128 F0; 0453 DIG9: ,#F0 .. ****.... 8129 90; 0454 ,#90 .. * *.... 812A F0; 0455 DIG3: ,#F0 .. ****.... 812B 10; 0456 ,#10 .. ...*.... 812C F0; 0457 ,#F0 .. ****.... 812D 10; 0458 ,#10 .. ...*.... 812E F0; 0459 DIGA: ,#F0 .. ****.... 812F 90; 0460 ,#90 .. *..*.... 8130 F0; 0461 DIG0: ,#F0 .. ****.... 8131 90; 0462 ,#90 .. *..*.... 8132 90; 0463 ,#90 .. *..*.... 8133 90; 0464 ,#90 .. *..*.... 8134 F0; 0465 DIG7: ,#F0 .. ****.... 8135 10; 0466 ,#10 .. ...*.... 8136 10; 0467 ,#10 .. ...*.... 8137 10; 0468 ,#10 .. ...*.... 8138 10; 0469 ,#10 .. ...*.... 8139 60; 0470 DIG1: ,#60 .. .**..... 813A 20; 0471 ,#20 .. ..*..... 813B 20; 0472 ,#20 .. ..*..... 813C 20; 0473 ,#20 .. ..*..... 813D 70; 0474 ,#70 .. .***.... 813E A0; 0475 DIG4: ,#A0 .. *.*..... 813F A0; 0476 ,#A0 .. *.*..... 8140 F0; 0477 ,#F0 .. ****.... 8141 20; 0478 ,#20 .. ..*..... 8142 20; 0479 ,#20 .. ..*..... 8143 ; 0480 8143 ; 0481 .. END OF CHARACTER MAP 8143 ; 0482 8143 ; 0483 .. video interrupt (64 x 32 format) 8143 7A; 0484 INTX: REQ .. tone off 8144 42; 0485 LDA R2 .. get D from stack 8145 70; 0486 RET .. exit and re-enable interrupt 8146 22; 0487 INT: DEC R2 8147 78; 0488 SAV .. T-> STACK 8148 22; 0489 DEC R2 8149 52; 0490 STR R2 .. D-> STACK 814A ; 0491 .. note DF is not changed by this routine 814A ; 0492 814A C4; 0493 NOP .. 3 cycle instruction to synchronize 814B 19; 0494 INC R9 .. increment random number value 814C F800; 0495 LDI #00 814E A0; 0496 PLO R0 814F 9B; 0497 GHI RB 8150 B0; 0498 PHI R0 .. reset R0 (DMA pointer) to video memory 8151 ; 0499 8151 E2; 0500 SEX R2 .. NOP 8152 E2; 0501 SEX R2 .. NOP 8153 80; 0502 DISP: GLO R0 .. LINE START ADDR -> D 8154 E2; 0503 SEX R2 8155 E2; 0504 SEX R2 8156 20; 0505 DEC R0 .. reset R0.1 if pass page 8157 A0; 0506 PLO R0 .. line start addr -> R0.0 8158 E2; 0507 SEX R2 .. nop 8159 20; 0508 DEC R0 .. reset R0.1 if pass page 815A A0; 0509 PLO R0 .. line start addr -> R0.0 815B E2; 0510 SEX R2 .. nop 815C 20; 0511 DEC R0 .. reset R0.1 if pass page 815D A0; 0512 PLO R0 .. line start addr -> R0.0 815E 3C53; 0513 BN1 DISP .. loops 32 times 8160 ; 0514 8160 ; 0515 .. decrement timers every video frame (~16ms) 8160 ; 0516 .. R8.1 is a regular timer 8160 ; 0517 .. R8.0 is the tone timer 8160 ; 0518 8160 98; 0519 TIMER: GHI R8 8161 3267; 0520 BZ TIMX 8163 AB; 0521 PLO RB 8164 2B; 0522 DEC RB 8165 8B; 0523 GLO RB 8166 B8; 0524 PHI R8 .. dec timer.1 without changing DF 8167 88; 0525 TIMX: GLO R8 8168 3243; 0526 BZ INTX .. exit with tone off if timer = 0 816A 7B; 0527 SEQ .. turn tone on if timer > 0 816B 28; 0528 DEC R8 .. decrement tone timer 816C 3044; 0529 BR INTX+1 .. exit with tone on 816E ; 0530 816E ; 0531 .. wait for serial flash to be ready by continuous reads of the status register 816E D3; 0532 SEP R3 816F EC; 0533 FWAIT: SEX RC .. point to ROM 8170 7B; 0534 SEQ .. assert chip select 8171 67; 0535 OUT 7 .. send read status command 8172 05; 0536 ,CMDSTA 8173 67; 0537 FWLOOP: OUT 7 .. write dummy value 8174 00; 0538 ,#00 8175 6F; 0539 INP 7 .. get status byte, write to ROM (RX) ignored 8176 F6; 0540 SHR 8177 3373; 0541 BDF FWLOOP .. wait for busy bit to clear 8179 7A; 0542 REQ .. deassert chip select 817A E2; 0543 SEX R2 .. restore X register 817B 306E; 0544 BR FWAIT-1 817D ; 0545 817D ; 0546 .. send write enable command 817D D3; 0547 SEP R3 817E EC; 0548 WRENA: SEX RC .. point to ROM 817F 7B; 0549 SEQ .. assert chip select 8180 67; 0550 OUT 7 .. send write enable command 8181 06; 0551 ,CMDWEN 8182 7A; 0552 REQ .. deassert chip select 8183 E2; 0553 SEX R2 .. restore X register 8184 307D; 0554 BR WRENA-1 8186 ; 0555 8186 ; 0556 .. assert chip select, then send command and address 8186 D3; 0557 SEP R3 8187 7B; 0558 SNDCMD: SEQ .. assert chip select 8188 67; 0559 OUT 7 .. send command byte 8189 67; 0560 OUT 7 .. send address 23-16 818A 67; 0561 OUT 7 .. send address 15-8 818B 67; 0562 OUT 7 .. send address 7-0 818C 3086; 0563 BR SNDCMD-1 818E ; 0564 818E ; 0565 .. filler 818E 00; 0566 ,#00 818F 00; 0567 ,#00 8190 00; 0568 ,#00 8191 00; 0569 ,#00 8192 00; 0570 ,#00 8193 00; 0571 ,#00 8194 ; 0572 8194 ; 0573 8194 ; 0574 .. keyboard scan 8194 D3; 0575 SEP R3 8195 E2; 0576 KSCN: SEX R2 .. this subroutine uses the stack 8196 9C; 0577 GHI RC 8197 AF; 0578 PLO RF .. #81 -> RF.0 8198 ; 0579 8198 2F; 0580 KSCN1: DEC RF .. next key value 8199 22; 0581 DEC R2 .. move stack down because OUT increments it 819A 8F; 0582 GLO RF 819B 52; 0583 STR R2 .. store RF.0 on stack 819C ; 0584 819C 62; 0585 OUT 2 .. set keypad latch value, INC R2 819D E2; 0586 SEX R2 819E E2; 0587 SEX R2 .. pause 819F 3E98; 0588 BN3 KSCN1 81A1 ; 0589 81A1 ; 0590 .. alternative entry point to just debounce 81A1 F804; 0591 DBNCE: LDI #04 81A3 A8; 0592 PLO R8 .. set R8.0 to debounce timer (~66ms) 81A4 88; 0593 GLO R8 81A5 3AA4; 0594 BNZ $-1 .. wait for timeout 81A7 ; 0595 81A7 F804; 0596 DBNCE1: LDI #04 81A9 A8; 0597 PLO R8 .. additional timing operation 81AA ; 0598 81AA 36A7; 0599 B3 DBNCE1 .. wait for key 81AC 88; 0600 GLO R8 .. pause 81AD 31AA; 0601 BQ $-3 .. if Q = 1, R8.0 timer is still running 81AF ; 0602 81AF 8F; 0603 GLO RF .. get scan value 81B0 FA0F; 0604 ANI #0F .. mask off lower byte 81B2 52; 0605 STR R2 .. store on the stack 81B3 3094; 0606 BR KSCN-1 .. exit 81B5 ; 0607 81B5 ; 0608 .. filler 81B5 00; 0609 ,#00 81B6 00; 0610 ,#00 81B7 00; 0611 ,#00 81B8 00; 0612 ,#00 81B9 ; 0613 81B9 ; 0614 .. assemble two keyboard entries into a byte 81B9 ; 0615 .. note: this needs to be called 3 times to get through it completely 81B9 ; 0616 .. because the keyboard scan keeps returning to main 81B9 ; 0617 .. 81B9 D3; 0618 SEP R3 81BA DC; 0619 GETB: SEP RC .. get first digit (end 3rd SEP R7) 81BB FE; 0620 SHL .. (end 1st SEP R7) 81BC FE; 0621 SHL 81BD FE; 0622 SHL 81BE FE; 0623 SHL 81BF AE; 0624 PLO RE .. put it in the high nibble 81C0 ; 0625 81C0 DC; 0626 SEP RC .. get second digit 81C1 8E; 0627 GLO RE .. (end 2nd SEP R7) 81C2 F1; 0628 OR .. combine the digits 81C3 30B9; 0629 BR GETB-1 .. and return with digits in D 81C5 ; 0630 81C5 ; 0631 .. write digit character to the display memory 81C5 D4; 0632 SEP R4 81C6 AA; 0633 DISPW: PLO RA .. put digit to display in RA.0 81C7 0A; 0634 LDN RA .. offset into character map 81C8 AA; 0635 PLO RA .. get first byte of character data 81C9 ; 0636 81C9 F805; 0637 LDI #05 81CB AF; 0638 PLO RF .. set row counter for character data 81CC ; 0639 81CC 4A; 0640 STRDM: LDA RA .. get byte 81CD 5D; 0641 STR RD .. save in display memory 81CE 8D; 0642 GLO RD 81CF FC08; 0643 ADI #08 81D1 AD; 0644 PLO RD .. offset to next display line (64 bits = 8 bytes) 81D2 2F; 0645 DEC RF 81D3 8F; 0646 GLO RF 81D4 3ACC; 0647 BNZ STRDM .. all 5 rows? 81D6 ; 0648 81D6 8D; 0649 GLO RD 81D7 FCD9; 0650 ADI NXTCHR .. sets RD to 1 byte to the right 81D9 AD; 0651 PLO RD .. so characters do not overlap 81DA 30C5; 0652 BR DISPW-1 81DC ; 0653 81DC ; 0654 .. subroutine to display data address and contents on screen 81DC D3; 0655 SEP R3 81DD 22; 0656 DISPD: DEC R2 .. dec stack pointer 81DE 06; 0657 LDN R6 81DF 73; 0658 STXD .. store byte on stack addressed by R6 81E0 86; 0659 GLO R6 81E1 73; 0660 STXD .. store lower byte of address 81E2 96; 0661 GHI R6 81E3 52; 0662 STR R2 .. store upper byte of address 81E4 ; 0663 81E4 F806; 0664 LDI #06 81E6 AE; 0665 PLO RE .. set special control byte 81E7 ; 0666 81E7 F8D8; 0667 LDI LINE27 .. point to location for address display 81E9 AD; 0668 PLO RD .. in RD 81EA ; 0669 81EA 02; 0670 DSPBY: LDN R2 .. get upper byte 81EB F6; 0671 SHR 81EC F6; 0672 SHR 81ED F6; 0673 SHR 81EE F6; 0674 SHR .. get upper nibble 81EF D5; 0675 SEP R5 .. display the digit 81F0 ; 0676 81F0 42; 0677 LDA R2 81F1 FA0F; 0678 ANI #0F .. get lower nibble 81F3 D5; 0679 SEP R5 .. display the digit 81F4 ; 0680 81F4 8E; 0681 GLO RE 81F5 F6; 0682 SHR 81F6 AE; 0683 PLO RE .. shift over control byte 81F7 ; 0684 81F7 32DC; 0685 BZ DISPD-1 .. exit if all digits written 81F9 ; 0686 81F9 3BEA; 0687 BNF DSPBY .. DF=0 after writing high address byte 81FB ; 0688 .. else, provide space between the address and data 81FB 1D; 0689 INC RD 81FC 1D; 0690 INC RD 81FD 30EA; 0691 BR DSPBY .. next byte 81FF ; 0692 81FF 01; 0693 ,#01 .. filler and check byte 8200 ; 0694 END 0000