00001 ; 00002 ; ROBOT3.AS 00003 ; 00004 ; RAM is 0000-0800 00005 ; 6522 I/O is at "VIA" (2000-200F) 00006 ; CA1 is for falling-edge priority interrupts 00007 ; CA2 is for falling-edge Motion interrupt (it uses a separate 00008 ; pin so that we can disable it separately). 00009 ; CB2 (pin 19) is SR out 00010 ; CB1 (pin 18) is SR clock out 00011 ; PA0-7 are inputs 00012 ; PA0 (pin 2) is battery 00013 ; PA1 (pin 3) is dark 00014 ; PA2 (pin 4) 00015 ; PA3 (pin 5) 00016 ; PA4-6 (pins 6-8) is interrupt priority 00017 ; PA7 (pin 9) 00018 ; PB0-7 are outputs 00019 ; PB0 (pin 10) is lobeep 00020 ; PB1 (pin 11) is hibeep 00021 ; PB2 (pin 12) is right LED 00022 ; PB3 (pin 13) is left LED 00023 ; PB4 (pin 14) is right-side motor direction 00024 ; PB5 (pin 15) is left-side motor direction 00025 ; PB5 (pin 16) 00026 ; PB5 (pin 17) 00027 00028 0000 DATA EQU $0000 ; base of variable table 00029 0040 OUTBUF EQU $0040 ; transmit buffer 00030 0080 INBUFF EQU $0080 ; receiver buffer 00031 0200 LCODE EQU $0200 ; start of Loaded-code 00032 0500 ICODE EQU $0500 ; start of run-time Int. proc. 00033 0640 BCODE EQU $0640 ; start of Boot-code 00034 2000 VIA EQU $2000 ; address of 6522 VIA 00035 4000 ACIA EQU $4000 ; address of 6551 ACIA 00036 00037 ;DELAY EQU $8000 00038 ;MCOPY EQU $801C 00039 ;LDELAY EQU $803E 00040 ;LOBEEP EQU $804A 00041 ;HIBEEP EQU $8060 00042 ;HILO EQU $8076 00043 ;REVDIR EQU $8081 00044 ;FORDIR EQU $808A 00045 ;LTDIR EQU $8093 00046 ;RTDIR EQU $809E 00047 ;MOTOFF EQU $80A9 00048 ;IRQRET EQU $80B4 00049 ;FCOPY EQU $80BD 00050 ;FLASHBF EQU $80E2 00051 ;ERASE EQU $810A 00052 ;RAMTST EQU $8165 00053 ;PARSE EQU $818B 00054 ;BINHEX EQU $8234 00055 ;XMITWT EQU $825D 00056 ;HEXBIN EQU $8266 00057 ;BINBYT EQU $8281 00058 ;BOOT EQU $8292 00059 ;NMI EQU $82D6 00060 ;IRQ EQU $82DF 00061 00062 8339 FFREE EQU $8339 00063 00064 ; 00065 ; 6522 VIA definitions 00066 ; 00067 2000 ORG VIA 00068 2000 ORB .DS 1 ;Output Register B 00069 2000 IRB EQU ORB ;Input Register B 00070 2001 ORA .DS 1 ;Output Register A 00071 2001 IRA EQU ORA ;Input Register A 00072 2002 DDRB .DS 1 ;Data Direction Register B 00073 2003 DDRA .DS 1 ;Data Direction Register A 00074 2004 T1CL .DS 1 ;read: T1 counter, low-order 00075 ;write: T1 latches, low-order 00076 2005 T1CH .DS 1 ;T1 counter, high-order 00077 2006 T1LL .DS 1 ;T1 latches, low-order 00078 2007 T1LH .DS 1 ;T1 latches, high-order 00079 2008 T2CL .DS 1 ;read: T2 counter, low-order 00080 ;write: T2 latches, low-order 00081 2009 T2CH .DS 1 ;T2 counter, high-order 00082 200A SR .DS 1 ;Shift Register 00083 200B ACR .DS 1 ;Auxiliary Control Register 00084 200C PCR .DS 1 ;Peripheral Control Register 00085 200D IFR .DS 1 ;Interrupt Flag Register 00086 200E IER .DS 1 ;Interrupt Enable Register 00087 00088 ; 00089 ; 6551 ACIA definitions 00090 ; 00091 4000 ORG ACIA 00092 4000 ATXM .DS 1 ;Transmitter Register (write only) 00093 4000 ARCX EQU ATXM ;Receiver Register (read only) 00094 4001 ASTS .DS 1 ;Status Register (read only) 00095 4001 ARES EQU ASTS ;Soft Reset (write only) 00096 4002 ACMD .DS 1 ;Command Register 00097 4003 ACTL .DS 1 ;Control Register 00098 00099 ; 00100 ; page zero variable declarations 00101 ; 00102 0000 ORG DATA 00103 0000 MODE .DS 1 ; operation mode 00104 0001 RESTMSK .DS 1 ; max resting time 00105 0002 MOVEMSK .DS 1 ; max moving time 00106 0003 ORACOP .DS 1 ; copy of 6522 ORA 00107 0004 IFRCOP .DS 1 ; copy of 6522 IFR 00108 0005 DLYCNT .DS 1 ; delay counter 00109 0006 OUTNDX .DS 1 ; output char index 00110 0007 UASTAT .DS 1 ; UART status 00111 00112 0008 FDA .DS 1 00113 0009 XX .DS 1 00114 000A YY .DS 1 00115 000B FRADLO .DS 1 00116 000C FRADHI .DS 1 00117 000D FCNT .DS 1 00118 000E FFDA .DS 1 00119 000F FRENLO .DS 1 00120 0010 FRENHI .DS 1 00121 0011 ECNTLO .DS 1 00122 0012 ECNTHI .DS 1 00123 0013 TOADLO .DS 1 00124 0014 TOADHI .DS 1 00125 00126 0080 ORG INBUFF 00127 0080 INNDX .DS 1 ; input buffer index 00128 00129 00130 0200 ORG LCODE 00131 00132 ; 00133 ; Jump table for 3 "personalities", IRQ, and NMI. 00134 ; 00135 VEC1: 00136 0200 4C 10 02 JMP MAIN1 ; NMI button "personality" 00137 VEC2: 00138 0203 4C 38 02 JMP MAIN2 ; left button "personality" 00139 VEC3: 00140 0206 4C FD 02 JMP MAIN3 ; right button "personality" 00141 IRQVEC: 00142 0209 4C 97 03 JMP IRQ2 ; continue IRQ processing 00143 NMIVEC: 00144 020C 4C 0F 02 JMP NMI2 ; continue NMI processing 00145 00146 NMI2: 00147 020F 40 RTI ; no further NMI stuff to do... 00148 00149 ; 00150 ; "NMI personality" 00151 ; 00152 MAIN1: 00153 0210 78 SEI ; no interrupts 00154 0211 EA NOP ; space for a JMP 00155 0212 EA NOP 00156 0213 EA NOP 00157 0214 20 76 80 JSR HILO 00158 0217 4C 35 02 JMP X1 00159 ; Put the FROM start addr in FRADLO/HI. 00160 ; Put the FROM ending addr in FRENLO/HI. 00161 ; Put the TO start addr in TOADLO/HI. 00162 021A A9 80 LDA #$80 00163 021C 85 0B STA FRADLO 00164 021E A9 07 LDA #$07 00165 0220 85 0C STA FRADHI 00166 0222 A9 85 LDA #$85 00167 0224 85 0F STA FRENLO 00168 0226 A9 07 LDA #$07 00169 0228 85 10 STA FRENHI 00170 022A A9 FA LDA #$FA 00171 022C 85 13 STA TOADLO 00172 022E A9 7F LDA #$7F 00173 0230 85 14 STA TOADHI 00174 0232 20 86 07 JSR FCOPY 00175 X1: 00176 0235 4C 35 02 JMP X1 00177 00178 ; 00179 ; "Button 1 personality" 00180 ; 00181 MAIN2: 00182 0238 A9 88 LDA #$88 ; disable ACIA xmtr/rcvr 00183 023A 8D 02 40 STA ACMD 00184 00185 023D A9 22 LDA #$22 ; PCR modes: neg edge ints on CA1, CA2 00186 023F 8D 0C 20 STA PCR 00187 ; 00188 ; Setup T1 as a random-number generator. 00189 ; 00190 0242 A9 FF LDA #$FF 00191 0244 8D 06 20 STA T1LL ; init T1 latches 00192 0247 A9 FF LDA #$FF ; separate this, for easy changes 00193 0249 8D 07 20 STA T1LH 00194 024C 8D 05 20 STA T1CH ; and counters 00195 ; 00196 ; Setup the SR to be a PWM source, output through CB2. 00197 ; 00198 024F A9 51 LDA #$51 ; ACR modes: SR free-run 00199 0251 8D 0B 20 STA ACR 00200 0254 A9 00 LDA #$00 ; load duty cycle (initially 0 - no output) 00201 0256 8D 0A 20 STA SR 00202 0259 A9 FF LDA #$FF ; load period (FF = ms) 00203 025B 8D 08 20 STA T2CL 00204 025E 8D 09 20 STA T2CH ; start counter 00205 ; 00206 ; Init some system parameters. 00207 ; 00208 0261 A9 0F LDA #$0F ; init the moving delay mask 00209 0263 85 02 STA MOVEMSK 00210 0265 A9 0F LDA #$0F ; init the resting delay mask 00211 0267 85 01 STA RESTMSK 00212 ; 00213 ; Beep/Blink that we're ready to go. 00214 ; 00215 0269 A9 FF LDA #$FF ; delay about 1 second 00216 026B 20 00 80 JSR DELAY 00217 026E A9 00 LDA #$00 ; everything off 00218 0270 8D 00 20 STA ORB 00219 0273 20 76 80 JSR HILO ; beep/blink 00220 ; 00221 ; Enable interrupts for Proximity and Motion. 00222 ; 00223 ; LDA #$82 ; enable ints for CA1 (not CA2) 00224 ; STA IER 00225 ; CLI ; enable processor IRQ's 00226 00227 ; 00228 ; This is the main program loop. 00229 ; 00230 MAIN2L: 00231 ; 00232 ; Choose a random direction that we will travel. 00233 ; Spin left or right. 00234 ; 00235 0276 AD 04 20 LDA T1CL ; choose a RND spin direction 00236 0279 10 05 BPL L21 ; - based on the N flag 00237 027B 20 9E 80 JSR RTDIR ; N true, spin right 00238 027E D0 03 BNE L22 ; jump over 00239 0280 20 93 80 L21: JSR LTDIR ; N false, spin left 00240 ; 00241 ; Spin in the chosen direction for a random length of time. 00242 ; 00243 0283 A9 FF L22: LDA #$FF ; motors on 00244 0285 8D 0A 20 STA SR 00245 0288 AD 04 20 LDA T1CL ; do a RND short delay 00246 028B 20 00 80 JSR DELAY 00247 028E AD 05 20 LDA T1CH ; do a RND long delay 00248 0291 29 03 AND #$03 ; limit the delay time 00249 0293 20 3E 80 JSR LDELAY 00250 0296 20 A9 80 JSR MOTOFF ; motors off 00251 ; 00252 ; Go forward a random distance. 00253 ; 00254 0299 20 8A 80 JSR FORDIR ; forward direction 00255 029C A9 FF LDA #$FF ; motors on 00256 029E 8D 0A 20 STA SR 00257 02A1 AD 04 20 LDA T1CL ; do a RND short delay 00258 02A4 20 00 80 JSR DELAY 00259 02A7 AD 05 20 LDA T1CH ; do a RND long delay 00260 02AA 25 02 AND MOVEMSK ; limit the delay time 00261 02AC 20 3E 80 JSR LDELAY 00262 02AF 20 A9 80 JSR MOTOFF ; motors off 00263 ; 00264 ; We are stopped, so now we can watch for movement thru our 00265 ; IR motion detector. 00266 ; 00267 ; LDA #$01 00268 ; JSR LDELAY 00269 ; LDA MODE 00270 ; ORA #$40 00271 ; STA MODE 00272 ; 00273 ; Sit and do nothing for a random time interval. 00274 ; 00275 02B2 AD 05 20 LDA T1CH ; do a RND long delay 00276 02B5 25 01 AND RESTMSK ; limit the delay time 00277 02B7 20 3E 80 JSR LDELAY ; do nothing for awhile 00278 ; 00279 ; We're finished doing nothing - turn off the IR motion detector. 00280 ; 00281 ; LDA MODE 00282 ; AND #$BF 00283 ; STA MODE 00284 ; 00285 ; Update the Mode byte by reading the system state from ORA. 00286 ; 00287 ; First, clear out the lower nibble. 00288 ; 00289 02BA A9 F0 LDA #$F0 ; update modes 00290 02BC 25 00 AND MODE 00291 02BE 85 00 STA MODE 00292 ; 00293 ; Next, read the ORA state, and mask the lower nibble into the 00294 ; mode byte. 00295 ; 00296 02C0 A9 50 LDA #$50 ; enable ORA w/o handshake 00297 02C2 8D 0B 20 STA ACR 00298 02C5 AD 01 20 LDA ORA ; read ORA state 00299 02C8 29 0F AND #$0F ; mask off high nibble 00300 02CA 05 00 ORA MODE ; combine the nibbles 00301 02CC 85 00 STA MODE ; and write it back out 00302 02CE A9 51 LDA #$51 ; back to ORA with handshake 00303 02D0 8D 0B 20 STA ACR 00304 ; 00305 ; Check the system state which was just updated into the Mode byte. 00306 ; 00307 ; Is the battery low? 00308 ; 00309 02D3 A9 01 LDA #$01 ; battery low? 00310 02D5 25 00 AND MODE 00311 02D7 F0 03 BEQ L23 00312 02D9 EA NOP ; placeholder for charger-seek routine 00313 02DA EA NOP 00314 02DB EA NOP 00315 ; 00316 ; Is it light or dark? 00317 ; 00318 02DC A9 02 L23: LDA #$02 ; light or dark? 00319 02DE 25 00 AND MODE 00320 ; BEQ L24 00321 02E0 10 0A BPL L24 ; never dark, for now (no sensor yet) 00322 ; 00323 ; It's dark: increase our resting interval, and shorten the 00324 ; distance that we travel. 00325 ; 00326 02E2 A9 FF LDA #$FF ; it's dark 00327 02E4 85 01 STA RESTMSK ; long sleep time 00328 02E6 A9 03 LDA #$03 ; short movement distance 00329 02E8 85 02 STA MOVEMSK 00330 02EA D0 08 BNE L25 00331 ; 00332 ; It's light: use normal resting interval and distance. 00333 ; 00334 02EC A9 0F L24: LDA #$0F ; it's light 00335 02EE 85 01 STA RESTMSK ; shorter sleep time 00336 02F0 A9 0F LDA #$0F ; longer movement distance 00337 02F2 85 02 STA MOVEMSK 00338 ; 00339 ; Do everything again. 00340 ; 00341 02F4 20 76 80 L25: JSR HILO ; beep 00342 02F7 20 76 80 JSR HILO 00343 02FA 4C 76 02 JMP MAIN2L ; loop again 00344 00345 00346 00347 ; 00348 ; "Button 2 personality" 00349 ; 00350 MAIN3: 00351 02FD A9 88 LDA #$88 ; disable ACIA xmtr/rcvr 00352 02FF 8D 02 40 STA ACMD 00353 00354 0302 A9 22 LDA #$22 ; PCR modes: neg edge ints on CA1, CA2 00355 0304 8D 0C 20 STA PCR 00356 ; 00357 ; Setup T1 as a random-number generator. 00358 ; 00359 0307 A9 FF LDA #$FF 00360 0309 8D 06 20 STA T1LL ; init T1 latches 00361 030C A9 FF LDA #$FF ; separate this, for easy changes 00362 030E 8D 07 20 STA T1LH 00363 0311 8D 05 20 STA T1CH ; and counters 00364 ; 00365 ; Setup the SR to be a PWM source, output through CB2. 00366 ; 00367 0314 A9 51 LDA #$51 ; ACR modes: SR free-run 00368 0316 8D 0B 20 STA ACR 00369 0319 A9 00 LDA #$00 ; load duty cycle (initially 0 - no output) 00370 031B 8D 0A 20 STA SR 00371 031E A9 FF LDA #$FF ; load period (FF = ms) 00372 0320 8D 08 20 STA T2CL 00373 0323 8D 09 20 STA T2CH ; start counter 00374 ; 00375 ; Init some system parameters. 00376 ; 00377 0326 A9 3F LDA #$3F ; init the moving delay mask 00378 0328 85 02 STA MOVEMSK 00379 032A A9 03 LDA #$03 ; init the resting delay mask 00380 032C 85 01 STA RESTMSK 00381 ; 00382 ; Beep/Blink that we're ready to go. 00383 ; 00384 032E A9 FF LDA #$FF ; delay about 1 second 00385 0330 20 00 80 JSR DELAY 00386 0333 A9 00 LDA #$00 ; everything off 00387 0335 8D 00 20 STA ORB 00388 0338 20 76 80 JSR HILO ; beep/blink 00389 ; 00390 ; This is the main program loop. 00391 ; 00392 MAIN3L: 00393 ; 00394 ; Choose a random direction that we will travel. 00395 ; Spin left or right. 00396 ; 00397 033B AD 04 20 LDA T1CL ; choose a RND spin direction 00398 033E 10 05 BPL L31 ; - based on the N flag 00399 0340 20 9E 80 JSR RTDIR ; N true, spin right 00400 0343 D0 03 BNE L32 ; jump over 00401 0345 20 93 80 L31: JSR LTDIR ; N false, spin left 00402 ; 00403 ; Spin in the chosen direction for a random length of time. 00404 ; 00405 0348 A9 FF L32: LDA #$FF ; motors on 00406 034A 8D 0A 20 STA SR 00407 034D AD 04 20 LDA T1CL ; do a RND short delay 00408 0350 20 00 80 JSR DELAY 00409 0353 AD 05 20 LDA T1CH ; do a RND long delay 00410 0356 29 03 AND #$03 ; limit the delay time 00411 0358 20 3E 80 JSR LDELAY 00412 035B 20 A9 80 JSR MOTOFF ; motors off 00413 ; 00414 ; Go forward a random distance. 00415 ; 00416 035E 20 8A 80 JSR FORDIR ; forward direction 00417 0361 A9 FF LDA #$FF ; motors on 00418 0363 8D 0A 20 STA SR 00419 0366 AD 04 20 LDA T1CL ; do a RND short delay 00420 0369 20 00 80 JSR DELAY 00421 036C AD 05 20 LDA T1CH ; do a RND long delay 00422 036F 25 02 AND MOVEMSK ; limit the delay time 00423 0371 20 3E 80 JSR LDELAY 00424 0374 20 A9 80 JSR MOTOFF ; motors off 00425 ; 00426 ; Sit and do nothing for a random time interval. 00427 ; 00428 0377 AD 05 20 LDA T1CH ; do a RND long delay 00429 037A 25 01 AND RESTMSK ; limit the delay time 00430 037C 20 3E 80 JSR LDELAY ; do nothing for awhile 00431 ; 00432 ; We're finished doing nothing. 00433 ; Update the Mode byte by reading the system state from ORA. 00434 ; 00435 037F A9 50 LDA #$50 ; enable ORA w/o handshake 00436 0381 8D 0B 20 STA ACR 00437 0384 AD 01 20 LDA ORA ; read ORA state 00438 0387 85 00 STA MODE ; and write it back out 00439 0389 A9 51 LDA #$51 ; back to ORA with handshake 00440 038B 8D 0B 20 STA ACR 00441 ; 00442 ; Do everything again. 00443 ; 00444 038E 20 76 80 JSR HILO ; beep 00445 0391 20 76 80 JSR HILO 00446 0394 4C 3B 03 JMP MAIN3L ; loop again 00447 00448 00449 00450 IRQ2: 00451 ; 00452 ; We are in Run mode, so look for other sources of the interrupt 00453 ; (we've already checked the ACIA). 00454 ; 00455 0397 AD 0D 20 LDA IFR 00456 039A 85 04 STA IFRCOP ; check source of int 00457 039C 6A ROR A ; 00458 039D 6A ROR A ; check for CA1 int. first 00459 039E B0 03 BCS PRIOR ; a priority int.? 00460 03A0 4C B4 80 JMP IRQRET ; unknown int. 00461 ; 00462 ; The interrupt came from the priority encoder chip. 00463 ; 00464 PRIOR: 00465 03A3 AD 01 20 LDA ORA ; get the Priority value 00466 03A6 85 03 STA ORACOP 00467 03A8 29 70 AND #$70 ; mask off other bits 00468 03AA C9 00 CMP #$00 ; Cliff - highest priority 00469 03AC F0 13 BEQ CLIFF 00470 03AE C9 10 CMP #$10 ; Proximity (one side) 00471 03B0 F0 0F BEQ PROX 00472 03B2 C9 20 CMP #$20 ; Proximity (other side) 00473 03B4 F0 0B BEQ PROX 00474 ; CMP #$50 ; Motion 00475 ; BEQ MOTION 00476 03B6 C9 60 CMP #$60 ; Button 1 00477 03B8 F0 46 BEQ BUTT1 00478 03BA C9 70 CMP #$70 ; Button 2 00479 03BC F0 54 BEQ BUTT2 00480 03BE 4C B4 80 JMP IRQRET ; un-handled int. 00481 00482 CLIFF: 00483 ; 00484 ; We're about to fall off a cliff! 00485 ; 00486 00487 00488 ; 00489 ; We just bumped into something! 00490 ; Stop moving, and back up a few inches. 00491 ; 00492 PROX: 00493 03C1 AD 0A 20 LDA SR ; save the motor on/off state 00494 03C4 48 PHA 00495 03C5 20 A9 80 JSR MOTOFF ; motors off 00496 03C8 20 76 80 JSR HILO ; beep 00497 03CB 20 81 80 JSR REVDIR ; reverse direction 00498 03CE A9 FF LDA #$FF ; motors on 00499 03D0 8D 0A 20 STA SR 00500 03D3 A9 C0 LDA #$C0 ; backup a little 00501 03D5 20 00 80 JSR DELAY 00502 03D8 20 A9 80 JSR MOTOFF ; motors off 00503 ; 00504 ; Did we hit the right or left bumper? 00505 ; 00506 03DB A9 10 LDA #$10 ; left or right? 00507 03DD 24 03 BIT ORACOP 00508 03DF D0 05 BNE IRQ3 00509 03E1 20 93 80 JSR LTDIR ; left: short spin rt 00510 03E4 D0 03 BNE IRQ4 00511 IRQ3: 00512 03E6 20 9E 80 JSR RTDIR ; right: short spin lt 00513 ; 00514 ; Spin away from the obstacle. 00515 ; 00516 IRQ4: 00517 03E9 A9 FF LDA #$FF ; motors on 00518 03EB 8D 0A 20 STA SR 00519 03EE A9 A0 LDA #$A0 ; spin for awhile 00520 03F0 20 00 80 JSR DELAY 00521 03F3 20 A9 80 JSR MOTOFF ; motors off 00522 ; 00523 ; Continue as before, as if nothing had happened. 00524 ; 00525 03F6 20 8A 80 JSR FORDIR ; continue in forward direction 00526 03F9 68 PLA ; restore the motor on/off state 00527 03FA 8D 0A 20 STA SR 00528 03FD 4C B4 80 JMP IRQRET 00529 00530 BUTT1: 00531 0400 A9 05 LDA #$05 ; turn on hibeep and right LED 00532 0402 8D 00 20 STA ORB 00533 0405 A9 10 LDA #$10 ; delay a little 00534 0407 20 00 80 JSR DELAY 00535 040A A9 00 LDA #$00 ; everything off 00536 040C 8D 00 20 STA ORB 00537 040F 4C B4 80 JMP IRQRET 00538 00539 BUTT2: 00540 0412 A9 0A LDA #$0A ; turn on lobeep and left LED 00541 0414 8D 00 20 STA ORB 00542 0417 A9 10 LDA #$10 ; delay a little 00543 0419 20 00 80 JSR DELAY 00544 041C A9 00 LDA #$00 ; everything off 00545 041E 8D 00 20 STA ORB 00546 0421 4C B4 80 JMP IRQRET 00547 00548 ; 00549 ; Our IR motion detector saw something. 00550 ; Move toward it. 00551 ; 00552 MOTION: 00553 0424 A9 03 LDA #$03 00554 0426 20 60 80 JSR HIBEEP 00555 00556 0429 A5 00 LDA MODE ; Motion int. enabled ? 00557 042B 29 40 AND #$40 00558 042D D0 03 BNE M1 00559 042F 4C B4 80 JMP IRQRET ; Motion int. not enabled 00560 M1: 00561 0432 A9 80 LDA #$80 00562 0434 20 60 80 JSR HIBEEP 00563 0437 A5 00 LDA MODE ; set Motion flag 00564 0439 09 20 ORA #$20 00565 043B 85 00 STA MODE 00566 043D 4C B4 80 JMP IRQRET 00567 00568 00569 00570 0780 ORG $0780 00571 00572 0780 D6 82 .WORD NMI 00573 0782 92 82 .WORD BOOT 00574 0784 DF 82 .WORD IRQ 00575 00576 ; Copy a block of memory to flash. 00577 ; Put the FROM start addr in FRADLO/HI. 00578 ; Put the FROM ending addr in FRENLO/HI. 00579 ; Put the TO start addr in TOADLO/HI. 00580 FCOPY: 00581 0786 A2 00 LDX #$0 ; init X 00582 FCOPY3: 00583 0788 A1 0B LDA (FRADLO,X) ; get a byte 00584 078A 85 08 STA FDA 00585 078C 20 AB 07 JSR FLASHB 00586 078F A5 0B LDA FRADLO ; are we done? 00587 0791 C5 0F CMP FRENLO ; check lo byte 00588 0793 D0 07 BNE FCNEXT ; no, go INC addresses 00589 0795 A5 0C LDA FRADHI ; check hi byte 00590 0797 C5 10 CMP FRENHI ; 00591 0799 D0 01 BNE FCNEXT ; no, go INC addresses 00592 079B 60 RTS 00593 FCNEXT: 00594 079C E6 0B INC FRADLO ; not done, INC addresses 00595 079E D0 02 BNE FCOPY1 ; did lo byte wrap? 00596 07A0 E6 0C INC FRADHI ; yes, INC hi byte 00597 FCOPY1: 00598 07A2 E6 13 INC TOADLO ; now INC the destination, also 00599 07A4 D0 E2 BNE FCOPY3 ; go back to loop 00600 07A6 E6 14 INC TOADHI ; wrapped - INC hi byte 00601 07A8 18 CLC 00602 07A9 90 DD BCC FCOPY3 00603 00604 00605 ; Flash a single byte, using the data in FDA, and the addr in 00606 ; FRADLO/HI. FCNT will contain how many more times we would 00607 ; have tried it. If it fails, FFDA contains the data that was 00608 ; read back. Nothing is preserved. 00609 FLASHB: 00610 07AB A0 19 LDY #$19 ; Max of 25 retries 00611 07AD A2 00 LDX #$0 ; init X 00612 FLOOP: 00613 07AF A9 40 LDA #$40 ; send Program Byte command 00614 07B1 81 13 STA (TOADLO,X) 00615 07B3 A5 08 LDA FDA ; send the data to be programmed 00616 07B5 81 13 STA (TOADLO,X) 00617 07B7 66 00 ROR 0 ; 5 00618 07B9 26 00 ROL 0 ; 5 00619 07BB EA NOP ; wait a total of 10 us 2 00620 07BC EA NOP ; 2 00621 07BD A9 C0 LDA #$C0 ; send the Verify command 2 00622 07BF 81 13 STA (TOADLO,X) ; 6 00623 07C1 A1 13 LDA (TOADLO,X) ; read the programmed byte 00624 07C3 C5 08 CMP FDA ; is it the same? 00625 07C5 F0 03 BEQ FDONE ; yes, we're done 00626 07C7 88 DEY ; no, try again 00627 07C8 D0 E5 BNE FLOOP 00628 FDONE: 00629 07CA 84 0D STY FCNT ; save the number of loops 00630 07CC 85 0E STA FFDA ; save the last data we read 00631 07CE A9 00 LDA #$0 ; send the Read Mode command 00632 07D0 81 13 STA (TOADLO,X) 00633 07D2 60 RTS 00634 00635 00636 00637 8000 ORG $8000 00638 ; Time delay. 00639 ; Put the delay value in A. A value of 00 is 256 loops (max delay). 00640 ; With 256 loops, the number of machine cycles is: 329479+131072N, 00641 ; where N is the number of NOP instructions. If N is 5, and the 00642 ; clock is 1 Mhz, then the max delay is 0.985 seconds, or 3.85 ms 00643 ; per loop. If N is 12, and the clock is 1.8432 Mhz, then the max 00644 ; delay is 1.032 seconds, or 4.03 ms per loop. 00645 ; X and Y are preserved, Status is not. 00646 ; Location 07 is used for temp storage. 00647 DELAY: 00648 8000 85 05 STA DLYCNT 00649 8002 8A TXA ; save X 00650 8003 48 PHA 00651 8004 A2 00 LDX #$0 ; init X 00652 DLOOP: 00653 8006 E8 INX ; waste time 00654 8007 EA NOP 00655 8008 EA NOP 00656 8009 EA NOP 00657 800A EA NOP 00658 800B EA NOP 00659 800C EA NOP 00660 800D EA NOP 00661 800E EA NOP 00662 800F EA NOP 00663 8010 EA NOP 00664 8011 EA NOP 00665 8012 EA NOP 00666 8013 D0 F1 BNE DLOOP ; did X wrap? 00667 8015 C6 05 DEC DLYCNT ; yes, decrement counter 00668 8017 D0 ED BNE DLOOP ; are we done? No - loop again. 00669 8019 68 PLA ; we're done - restore X 00670 801A AA TAX 00671 801B 60 RTS ; return 00672 00673 00674 ; Copy a block of memory. 00675 ; Put the FROM start addr in FRADLO/HI. 00676 ; Put the FROM ending addr in FRENLO/HI. 00677 ; Put the TO start addr in TOADLO/HI. 00678 MCOPY: 00679 801C A2 00 LDX #$0 ; init X 00680 MCOPY3: 00681 801E A1 0B LDA (FRADLO,X) ; get a byte 00682 8020 81 13 STA (TOADLO,X) ; put the byte 00683 8022 A5 0B LDA FRADLO ; are we done? 00684 8024 C5 0F CMP FRENLO ; check lo byte 00685 8026 D0 07 BNE MCNEXT ; no, go INC addresses 00686 8028 A5 0C LDA FRADHI ; check hi byte 00687 802A C5 10 CMP FRENHI ; 00688 802C D0 01 BNE MCNEXT ; no, go INC addresses 00689 802E 60 RTS 00690 MCNEXT: 00691 802F E6 0B INC FRADLO ; not done, INC addresses 00692 8031 D0 02 BNE MCOPY1 ; did lo byte wrap? 00693 8033 E6 0C INC FRADHI ; yes, INC hi byte 00694 MCOPY1: 00695 8035 E6 13 INC TOADLO ; now INC the destination, also 00696 8037 D0 E5 BNE MCOPY3 ; go back to loop 00697 8039 E6 14 INC TOADHI ; wrapped - INC hi byte 00698 803B 4C 1E 80 JMP MCOPY3 ; go back to loop 00699 00700 00701 ; Do longer delays, in multiples of about 1 second. 00702 ; Put the desired delay in A. 00703 ; A value of 00 will return immediately. 00704 LDELAY: 00705 803E F0 09 BEQ LDELAY2 ; if 00, return right away 00706 8040 AA TAX ; save the counter in X 00707 LDELAY1: 00708 8041 A9 00 LDA #$00 ; do a 1-second delay 00709 8043 20 00 80 JSR DELAY 00710 8046 CA DEX ; DEC the counter 00711 8047 D0 F8 BNE LDELAY1 ; done? 00712 LDELAY2: 00713 8049 60 RTS ; yes - return 00714 00715 00716 ; Sound the low-tone beeper and blink one of the LEDs, using the 00717 ; time stored in A. X and Y are preserved. 00718 LOBEEP: 00719 804A 48 PHA ; save A 00720 804B AD 00 20 LDA ORB ; get the Output Reg. 00721 804E 09 05 ORA #$05 ; set the bits 00722 8050 8D 00 20 STA ORB ; write the Output Reg. 00723 8053 68 PLA ; get the delay value 00724 8054 20 00 80 JSR DELAY ; delay 00725 8057 AD 00 20 LDA ORB 00726 805A 29 FA AND #$FA ; clear the bits 00727 805C 8D 00 20 STA ORB 00728 805F 60 RTS 00729 00730 HIBEEP: 00731 8060 48 PHA ; save A 00732 8061 AD 00 20 LDA ORB ; get the Output Reg. 00733 8064 09 0A ORA #$0A ; set the bits 00734 8066 8D 00 20 STA ORB ; write the Output Reg. 00735 8069 68 PLA ; get the delay value 00736 806A 20 00 80 JSR DELAY ; delay 00737 806D AD 00 20 LDA ORB 00738 8070 29 F5 AND #$F5 ; clear the bits 00739 8072 8D 00 20 STA ORB 00740 8075 60 RTS 00741 00742 00743 HILO: 00744 8076 A9 20 LDA #$20 00745 8078 20 60 80 JSR HIBEEP 00746 807B A9 20 LDA #$20 00747 807D 20 4A 80 JSR LOBEEP 00748 8080 60 RTS 00749 00750 REVDIR: 00751 8081 AD 00 20 LDA ORB 00752 8084 09 30 ORA #$30 00753 8086 8D 00 20 STA ORB 00754 8089 60 RTS 00755 00756 FORDIR: 00757 808A AD 00 20 LDA ORB 00758 808D 29 CF AND #$CF 00759 808F 8D 00 20 STA ORB 00760 8092 60 RTS 00761 00762 LTDIR: 00763 8093 AD 00 20 LDA ORB 00764 8096 29 CF AND #$CF 00765 8098 09 20 ORA #$20 00766 809A 8D 00 20 STA ORB 00767 809D 60 RTS 00768 00769 RTDIR: 00770 809E AD 00 20 LDA ORB 00771 80A1 29 CF AND #$CF 00772 80A3 09 10 ORA #$10 00773 80A5 8D 00 20 STA ORB 00774 80A8 60 RTS 00775 00776 MOTOFF: 00777 80A9 A9 00 LDA #$00 ; turn off the motors 00778 80AB 8D 0A 20 STA SR 00779 80AE A9 10 LDA #$10 ; give them a chance to stop 00780 80B0 20 00 80 JSR DELAY 00781 80B3 60 RTS 00782 00783 00784 IRQRET: 00785 ; common return point for IRQ's 00786 80B4 AD 01 20 LDA ORA ; for debounce - clear the IFR 00787 80B7 68 PLA ; restore the Y, X, and A 00788 80B8 A8 TAY 00789 80B9 68 PLA 00790 80BA AA TAX 00791 80BB 68 PLA 00792 80BC 40 RTI ; return from interrupt 00793 00794 00795 00796 ; Copy a block of memory to flash. 00797 ; Put the FROM start addr in FRADLO/HI. 00798 ; Put the FROM ending addr in FRENLO/HI. 00799 ; Put the TO start addr in TOADLO/HI. 00800 FCOPYF: 00801 80BD A2 00 LDX #$0 ; init X 00802 FCOPY3F: 00803 80BF A1 0B LDA (FRADLO,X) ; get a byte 00804 80C1 85 08 STA FDA 00805 80C3 20 E2 80 JSR FLASHBF 00806 80C6 A5 0B LDA FRADLO ; are we done? 00807 80C8 C5 0F CMP FRENLO ; check lo byte 00808 80CA D0 07 BNE FCNEXTF ; no, go INC addresses 00809 80CC A5 0C LDA FRADHI ; check hi byte 00810 80CE C5 10 CMP FRENHI ; 00811 80D0 D0 01 BNE FCNEXTF ; no, go INC addresses 00812 80D2 60 RTS 00813 FCNEXTF: 00814 80D3 E6 0B INC FRADLO ; not done, INC addresses 00815 80D5 D0 02 BNE FCOPY1F ; did lo byte wrap? 00816 80D7 E6 0C INC FRADHI ; yes, INC hi byte 00817 FCOPY1F: 00818 80D9 E6 13 INC TOADLO ; now INC the destination, also 00819 80DB D0 E2 BNE FCOPY3F ; go back to loop 00820 80DD E6 14 INC TOADHI ; wrapped - INC hi byte 00821 80DF 18 CLC 00822 80E0 90 DD BCC FCOPY3F 00823 00824 00825 ; Flash a single byte, using the data in FDA, and the addr in 00826 ; FRADLO/HI. FCNT will contain how many more times we would 00827 ; have tried it. If it fails, FFDA contains the data that was 00828 ; read back. Nothing is preserved. 00829 FLASHBF: 00830 80E2 A0 19 LDY #$19 ; Max of 25 retries 00831 80E4 A2 00 LDX #$0 ; init X 00832 FLOOPF: 00833 80E6 A9 40 LDA #$40 ; send Program Byte command 00834 80E8 81 13 STA (TOADLO,X) 00835 80EA A5 08 LDA FDA ; send the data to be programmed 00836 80EC 81 13 STA (TOADLO,X) 00837 80EE 66 00 ROR 0 ; 5 00838 80F0 26 00 ROL 0 ; 5 00839 80F2 EA NOP ; wait a total of 10 us 2 00840 80F3 EA NOP ; 2 00841 80F4 A9 C0 LDA #$C0 ; send the Verify command 2 00842 80F6 81 13 STA (TOADLO,X) ; 6 00843 80F8 A1 13 LDA (TOADLO,X) ; read the programmed byte 00844 80FA C5 08 CMP FDA ; is it the same? 00845 80FC F0 03 BEQ FDONEF ; yes, we're done 00846 80FE 88 DEY ; no, try again 00847 80FF D0 E5 BNE FLOOPF 00848 FDONEF: 00849 8101 84 0D STY FCNT ; save the number of loops 00850 8103 85 0E STA FFDA ; save the last data we read 00851 8105 A9 00 LDA #$0 ; send the Read Mode command 00852 8107 81 13 STA (TOADLO,X) 00853 8109 60 RTS 00854 00855 ; Erase the flash. The flash may be 128K or bigger, but all we 00856 ; can address is 32K, so just erase that. 00857 ; When RAM is using the high 8K, the 32K flash will be seen at 00858 ; 6000-DFFF, and 6000 is the 'high block'. Otherwise, the flash 00859 ; is at 8000-FFFF. Nothing is preserved. 00860 ; We will use 00 thru 07 for various things. 00861 ; 05 and 06 contain the #$ of times that we did the erase cycle. 00862 ERASE: 00863 810A A2 00 LDX #$00 00864 810C A9 00 LDA #$00 ; Init our temp storage 00865 810E 85 08 STA FDA ; We will program all bytes to #$00 first. 00866 8110 85 13 STA TOADLO ; Flash starts at address 6000. 00867 8112 A9 60 LDA #$60 00868 8114 85 14 STA TOADHI 00869 ERASE1: 00870 8116 20 E2 80 JSR FLASHBF ; Program a byte 00871 8119 E6 13 INC TOADLO ; INC to next address 00872 811B D0 F9 BNE ERASE1 ; No wrap - go do next address 00873 811D E6 14 INC TOADHI ; Wrapped - INC hi byte 00874 811F A9 E0 LDA #$E0 ; Did we go beyond 32K (DFFF) ? 00875 8121 C5 14 CMP TOADHI 00876 8123 D0 F1 BNE ERASE1 ; No, go do this address 00877 8125 A9 00 LDA #$0 ; Yes, get ready to erase 00878 8127 85 13 STA TOADLO 00879 8129 85 11 STA ECNTLO ; erase-cycle counter 00880 812B 85 12 STA ECNTHI 00881 812D A9 60 LDA #$60 ; back to the beginning 00882 812F 85 14 STA TOADHI 00883 ERASE2: 00884 8131 A9 20 LDA #$20 ; send the Erase command 00885 8133 81 13 STA (TOADLO,X) 00886 8135 81 13 STA (TOADLO,X) ; we must send it twice 00887 8137 A9 03 LDA #$3 ; Delay for about 12 ms (10 ms required) 00888 8139 20 00 80 JSR DELAY ; 00889 ERASE3: 00890 813C A9 A0 LDA #$A0 ; send the Erase Verify command 00891 813E 81 13 STA (TOADLO,X) 00892 8140 A1 13 LDA (TOADLO,X) ; is the data #$FF ? 00893 8142 C9 FF CMP #$FF 00894 8144 D0 11 BNE ERASE4 ; no, go INC counters and try again 00895 8146 E6 13 INC TOADLO ; yes, INC the address counter 00896 8148 D0 F2 BNE ERASE3 00897 814A E6 14 INC TOADHI 00898 814C A5 14 LDA TOADHI 00899 814E C9 E0 CMP #$E0 ; are we beyond 32K (DFFF) ? 00900 8150 D0 EA BNE ERASE3 ; no, do another erase cycle 00901 EDONE: 00902 8152 A9 00 LDA #$0 ; we're done - send the Read Mode command 00903 8154 81 13 STA (TOADLO,X) 00904 8156 60 RTS 00905 ERASE4: 00906 8157 E6 11 INC ECNTLO ; INC the erase-retry counter 00907 8159 D0 D6 BNE ERASE2 00908 815B E6 12 INC ECNTHI 00909 815D A5 12 LDA ECNTHI 00910 815F C9 04 CMP #$4 ; have we done more than 1000 cycles? 00911 8161 F0 EF BEQ EDONE ; yes - quit (failure) 00912 8163 D0 CC BNE ERASE2 ; no - do another erase cycle 00913 00914 00915 ; RAM memory test. 00916 ; Put the starting address in FRADLO/HI. 00917 ; Put the #$ of addresses to test in ECNTLO/HI. 00918 ; After the test, ECNTLO/HI contain the number of addresses 00919 ; that are not yet tested --> 0000 means no failures; and FRADLO/HI 00920 ; will contain the address of the first bad address. 00921 RAMTST: 00922 8165 D8 CLD ; set binary mode 00923 8166 A2 00 LDX #$0 ; init X 00924 RMLOOP: 00925 8168 A5 0B LDA FRADLO ; load low-byte start addr 00926 816A 81 0B STA (FRADLO,X) ; write the addr into the RAM 00927 816C A1 0B LDA (FRADLO,X) ; read back the RAM 00928 816E C5 0B CMP FRADLO ; is it the same? 00929 8170 D0 18 BNE RMDONE ; no - stop the test 00930 8172 E6 0B INC FRADLO ; yes - INC the low-byte addr 00931 8174 D0 02 BNE RM1 ; wrapped? 00932 8176 E6 0C INC FRADHI ; yes - INC the hi-byte addr 00933 8178 C6 11 RM1: DEC ECNTLO ; DEC the byte counter 00934 817A A5 11 LDA ECNTLO ; load the counter for comparison 00935 817C C9 FF CMP #$FF ; did we wrap (00 to FF)? 00936 817E D0 02 BNE RM2 ; no - go check the hi byte 00937 8180 C6 12 DEC ECNTHI ; yes - DEC the hi byte 00938 8182 A5 12 RM2: LDA ECNTHI ; are we done? 00939 8184 D0 E2 BNE RMLOOP ; no - do loop again 00940 8186 A5 11 LDA ECNTLO ; maybe - check the lo byte 00941 8188 D0 DE BNE RMLOOP ; no - do loop again 00942 RMDONE: 00943 818A 60 RTS 00944 00945 PARSE: 00946 ; 00947 ; parse a line of serial input 00948 ; 00949 818B A5 80 LDA INNDX 00950 818D F0 21 BEQ PDONE ; anything in the buffer? 00951 818F A9 0D LDA #$0D ; send a CR/LF 00952 8191 20 5D 82 JSR XMITWT 00953 8194 A9 0A LDA #$0A 00954 8196 20 5D 82 JSR XMITWT 00955 8199 A5 81 LDA INBUFF+1 ; check the first char 00956 819B C9 3A CMP #':' ; code load ? 00957 819D F0 16 BEQ CLOAD 00958 819F C9 3F CMP #'?' ; examine memory ? 00959 81A1 F0 50 BEQ EXAMINE 00960 81A3 C9 3D CMP #'=' ; deposit memory ? 00961 81A5 F0 26 BEQ DEPOSIT 00962 81A7 C9 47 CMP #'G' ; GOTO ? 00963 81A9 F0 6A BEQ SUBR 00964 00965 PROMPT: 00966 81AB A9 3E LDA #'>' 00967 81AD 20 5D 82 JSR XMITWT 00968 PDONE: 00969 81B0 A9 00 LDA #$00 ; zero inbuffer count 00970 81B2 85 80 STA INNDX 00971 81B4 60 RTS 00972 00973 CLOAD: 00974 81B5 20 66 82 JSR HEXBIN ; convert buffer to binary 00975 81B8 A5 86 LDA INBUFF+6 ; make an indirect out of first addr 00976 81BA 85 83 STA INBUFF+3 ; INBUFF+3, INBUFF+4 is the vector 00977 ; now copy the bytes to the indicated memory locations 00978 81BC A0 00 LDY #$00 ; init the indexes 00979 81BE A2 0A LDX #$0A 00980 CL1: 00981 81C0 B5 80 LDA INBUFF,X ; get a byte 00982 81C2 91 83 STA (INBUFF+3),Y ; store it 00983 81C4 E8 INX ; inc the indexes 00984 81C5 E8 INX 00985 81C6 C8 INY 00986 81C7 C4 82 CPY INBUFF+2 ; done? 00987 81C9 D0 F5 BNE CL1 00988 81CB F0 E3 BEQ PDONE 00989 00990 00991 DEPOSIT: 00992 ; syntax: =aaaadd ; where aaaa is start address, dd is the 00993 ; data (up to 63 bytes). 00994 81CD 20 66 82 JSR HEXBIN 00995 81D0 A5 84 LDA INBUFF+4 ; make an indirect out of first addr 00996 81D2 85 81 STA INBUFF+1 ; INBUFF+1, INBUFF+2 is the vector 00997 81D4 A5 80 LDA INBUFF ; set the count to match the # of bytes 00998 81D6 38 SEC 00999 81D7 E9 05 SBC #$05 01000 81D9 30 D0 BMI PROMPT 01001 81DB F0 CE BEQ PROMPT 01002 81DD 4A LSR A 01003 81DE 29 3F AND #$3F ; never more than 63 bytes 01004 81E0 85 80 STA INBUFF 01005 81E2 A0 00 LDY #$00 ; init the indexes 01006 81E4 A2 06 LDX #$06 01007 DEP1: 01008 81E6 B5 80 LDA INBUFF,X ; get a byte 01009 81E8 91 81 STA (INBUFF+1),Y ; store it 01010 81EA E8 INX ; inc the indexes 01011 81EB E8 INX 01012 81EC C8 INY 01013 81ED C4 80 CPY INBUFF ; done? 01014 81EF D0 F5 BNE DEP1 01015 81F1 F0 B8 BEQ PROMPT 01016 01017 01018 EXAMINE: 01019 ; syntax: ?aaaa ; where aaaa is the start address. 01020 81F3 20 66 82 JSR HEXBIN 01021 81F6 A5 84 LDA INBUFF+4 ; make an indirect out of first addr 01022 81F8 85 81 STA INBUFF+1 ; INBUFF+1, INBUFF+2 is the vector 01023 81FA A0 00 LDY #$00 ; init the indexes 01024 81FC A2 00 LDX #$00 ; count the # of out-chars we produce 01025 EXAM1: 01026 81FE B1 81 LDA (INBUFF+1),Y ; get a byte 01027 8200 20 34 82 JSR BINHEX 01028 8203 C8 INY 01029 8204 C0 10 CPY #$10 ; done? 01030 8206 D0 F6 BNE EXAM1 01031 8208 A9 0D LDA #$0D ; send CRLF 01032 820A 20 5D 82 JSR XMITWT 01033 820D A9 0A LDA #$0A 01034 820F 20 5D 82 JSR XMITWT 01035 EX1: 01036 8212 18 CLC 01037 8213 90 96 BCC PROMPT 01038 01039 01040 ; GOTO a routine. 01041 ; syntax: Gaaaaddxxyy ; where aaaa is address, dd is A data, 01042 ; xx is X data, and yy is Y data. 01043 ; An RTS will bring us back here (then prompt). 01044 SUBR: 01045 8215 20 66 82 JSR HEXBIN 01046 8218 A5 82 LDA INBUFF+2 01047 821A 85 83 STA INBUFF+3 01048 821C A5 84 LDA INBUFF+4 ; make an indirect out of first addr 01049 821E 85 82 STA INBUFF+2 ; INBUFF+2, INBUFF+3 is the vector 01050 8220 A9 4C LDA #$4C ; make a JMP instruction 01051 8222 85 81 STA INBUFF+1 01052 8224 A9 00 LDA #$00 ; zero inbuffer count 01053 8226 85 80 STA INNDX 01054 8228 A5 86 LDA INBUFF+6 ; init the registers 01055 822A A6 88 LDX INBUFF+8 01056 822C A4 8A LDY INBUFF+10 01057 822E 20 81 00 JSR INBUFF+1 ; make the call 01058 8231 18 CLC 01059 8232 90 DE BCC EX1 01060 01061 01062 ; Convert the value in A into two hex-ascii bytes, and store 01063 ; the two bytes in OUTBUF,X. Increment X as we go. 01064 BINHEX: 01065 8234 48 PHA ; save the byte 01066 8235 4A LSR A ; do the high nibble first 01067 8236 4A LSR A 01068 8237 4A LSR A 01069 8238 4A LSR A 01070 8239 18 CLC ; make it ascii 01071 823A 69 30 ADC #$30 01072 823C C9 3A CMP #$3A ; if it's a letter, add a little more 01073 823E 30 03 BMI BH1 01074 8240 18 CLC 01075 8241 69 07 ADC #$07 01076 BH1: 01077 8243 95 40 STA OUTBUF,X ; store the ascii byte 01078 8245 20 5D 82 JSR XMITWT 01079 8248 E8 INX ; INC the pointer 01080 8249 68 PLA ; get the original byte 01081 824A 29 0F AND #$0F ; do the low nibble 01082 824C 18 CLC ; make it ascii 01083 824D 69 30 ADC #$30 01084 824F C9 3A CMP #$3A 01085 8251 30 03 BMI BH2 01086 8253 18 CLC 01087 8254 69 07 ADC #$07 01088 BH2: 01089 8256 95 40 STA OUTBUF,X ; store the 2nd ascii byte 01090 8258 20 5D 82 JSR XMITWT 01091 825B E8 INX ; INC the pointer again 01092 825C 60 RTS 01093 01094 01095 XMITWT: 01096 825D 8D 00 40 STA ATXM 01097 8260 A9 10 LDA #$10 01098 8262 20 00 80 JSR DELAY 01099 8265 60 RTS 01100 01101 ; Convert the whole buffer from hex-ascii to binary, from 01102 ; top to bottom, ending with INBUFF+2. 01103 ; The binary byte will replace the first of the two 01104 ; ascii bytes. 01105 HEXBIN: 01106 8266 A2 7E LDX #$7E 01107 HB1: 01108 8268 B5 80 LDA INBUFF,X ; get the hi ascii byte 01109 826A 20 81 82 JSR BINBYT ; convert to BCD 01110 826D 0A ASL A ; move it to the hi nibble 01111 826E 0A ASL A 01112 826F 0A ASL A 01113 8270 0A ASL A 01114 8271 95 80 STA INBUFF,X ; save it 01115 8273 B5 81 LDA INBUFF+1,X ; get the lo ascii byte 01116 8275 20 81 82 JSR BINBYT ; convert to BCD 01117 8278 15 80 ORA INBUFF,X ; add the nibbles 01118 827A 95 80 STA INBUFF,X ; save the binary result 01119 827C CA DEX ; dec the counter 01120 827D CA DEX 01121 827E D0 E8 BNE HB1 ; done? 01122 8280 60 RTS 01123 01124 01125 BINBYT: 01126 ; convert a hex-ascii byte to binary 01127 8281 C9 60 CMP #$60 01128 8283 30 02 BMI BB2 01129 8285 29 DF AND #$DF 01130 BB2: 01131 8287 38 SEC 01132 8288 E9 30 SBC #$30 01133 828A C9 11 CMP #$11 01134 828C 30 03 BMI BB1 01135 828E 38 SEC 01136 828F E9 07 SBC #$07 01137 BB1: 01138 8291 60 RTS 01139 01140 01141 BOOT: 01142 ; 01143 ; The Reset vector (FFFC) points here. 01144 ; Set up the minimal stuff to support code-load. 01145 ; 01146 8292 78 SEI ; no IRQ interrupts 01147 8293 D8 CLD ; no Decimal mode 01148 8294 A9 82 LDA #$82 ; enable CA1 ints from 6522 01149 8296 8D 0E 20 STA IER 01150 8299 A9 00 LDA #$00 01151 829B 8D 03 20 STA DDRA ; port A is input 01152 829E 8D 00 20 STA ORB ; all 0's on output port 01153 82A1 85 80 STA INNDX ; init inbuff index 01154 82A3 85 00 STA MODE ; hi bits off = Monitor mode 01155 82A5 A9 FF LDA #$FF 01156 82A7 8D 02 20 STA DDRB ; port B is output 01157 82AA A9 C0 LDA #$C0 ; CB2 always low (motors off) 01158 82AC 8D 0C 20 STA PCR 01159 82AF 8D 01 40 STA ARES ; ACIA soft reset 01160 82B2 A9 1A LDA #$1A ; 8-N-1, 2400 baud 01161 82B4 8D 03 40 STA ACTL 01162 82B7 58 CLI 01163 82B8 A9 89 LDA #$89 ; enable ACIA xmtr/rcvr 01164 82BA 8D 02 40 STA ACMD 01165 BOOT2: 01166 82BD A5 00 LDA MODE 01167 82BF 29 20 AND #$20 01168 82C1 C9 20 CMP #$20 ; NMI button ? 01169 82C3 D0 03 BNE B3 01170 82C5 4C 00 02 JMP VEC1 01171 82C8 C9 80 B3: CMP #$80 ; button 1 ? 01172 82CA D0 03 BNE B4 01173 82CC 4C 03 02 JMP VEC2 01174 82CF C9 40 B4: CMP #$40 ; button 2 ? 01175 82D1 D0 EA BNE BOOT2 ; if monitor, just sit here 01176 82D3 4C 06 02 JMP VEC3 01177 01178 01179 ; 01180 ; NMI entry point. Use it to change from Code Load to Run mode. 01181 ; 01182 NMI: 01183 82D6 A5 00 LDA MODE 01184 82D8 09 20 ORA #$20 01185 82DA 85 00 STA MODE 01186 82DC 4C 0C 02 JMP NMIVEC 01187 01188 ; 01189 ; IRQ entry point. 01190 ; 01191 IRQ: 01192 82DF 48 PHA ; save A, X, and Y (in that order) 01193 82E0 8A TXA 01194 82E1 48 PHA 01195 82E2 98 TYA 01196 82E3 48 PHA 01197 ; 01198 ; First, do the minimal stuff needed to service the ACIA. 01199 ; 01200 82E4 AD 01 40 LDA ASTS ; check ACIA interrupt reg. 01201 82E7 29 08 AND #$08 ; check recv reg full 01202 82E9 F0 18 BEQ IRQ1 ; no recv char? 01203 82EB AD 00 40 LDA ARCX ; get the char 01204 82EE C9 20 CMP #$20 ; is it less than a Space? 01205 82F0 10 06 BPL IRQ5 ; no - go process the char 01206 82F2 20 8B 81 JSR PARSE ; yes - go parse the line 01207 82F5 4C B4 80 JMP IRQRET 01208 IRQ5: 01209 ; 01210 ; We received a char from the ACIA. 01211 ; 01212 82F8 A6 80 LDX INNDX 01213 82FA E0 7D CPX #$7D ; stay within the buffer 01214 82FC 10 01 BPL IRQ6 01215 82FE E8 INX 01216 82FF 86 80 IRQ6: STX INNDX 01217 8301 95 80 STA INBUFF,X ; store the char in the buffer 01218 IRQ1: 01219 ; 01220 ; Check the mode - either return or do more int. processing. 01221 ; 01222 8303 A5 00 LDA MODE ; if any upper 3 bits are on, we're in Run mode 01223 8305 29 E0 AND #$E0 01224 8307 F0 03 BEQ IRQ7 01225 8309 4C 09 02 JMP IRQVEC ; Run mode - do other IRQ checking 01226 ; Monitor mode - see if a button was pressed 01227 830C AD 0D 20 IRQ7: LDA IFR ; check source of int 01228 830F 85 04 STA IFRCOP ; save a copy of the IFR 01229 8311 29 02 AND #$02 ; check for CA1 int. first 01230 8313 F0 21 BEQ IRQ8 ; nope - don't know what it was 01231 ; The interrupt came from the priority encoder chip. 01232 8315 AD 01 20 LDA ORA ; get the Priority value 01233 8318 85 03 STA ORACOP ; save a copy 01234 831A 29 70 AND #$70 ; mask off other bits 01235 831C C9 60 CMP #$60 ; Button 1 ? 01236 831E D0 08 BNE IRQ9 01237 8320 A5 00 LDA MODE 01238 8322 09 80 ORA #$80 01239 8324 85 00 STA MODE 01240 8326 D0 0E BNE IRQ8 01241 IRQ9: 01242 8328 A5 03 LDA ORACOP 01243 832A 29 70 AND #$70 01244 832C C9 70 CMP #$70 ; Button 2 ? 01245 832E D0 06 BNE IRQ8 01246 8330 A5 00 LDA MODE 01247 8332 09 40 ORA #$40 01248 8334 85 00 STA MODE 01249 8336 4C B4 80 IRQ8: JMP IRQRET 01250 01251 01252 ;********************************************* 01253 ;**** INTERRUPT AND RESTART VECTORS 01254 ;********************************************* 01255 01256 FFFA ORG $FFFA 01257 FFFA D6 82 .WORD NMI ; NMI vector 01258 RESET: 01259 FFFC 92 82 .WORD BOOT ; Cold start & reset vector 01260 FFFE DF 82 .WORD IRQ ; IRQ vector (and BRK vector) 01261 01262 8292 .END BOOT