******************************************************************************** * Apple II SSC Firmware * * * * By Larry Kenyon * * -January 1981- * * * * (C) Copyright 1981 by Apple Computer, Inc. * ******************************************************************************** * This is a disassembly of the Super Serial Card (SSC) ROM, based on the * * listing in _Super Serial Card Installation and Operating Manual_ (starting * * on page 58). The ROM binary is from AppleWin's "SSC.rom", which puts the * * $C200 code at the end rather than the start. * ******************************************************************************** * Project created by Andy McFadden, using 6502bench SourceGen v1.7.4. * * Last updated 2021/06/11 * ******************************************************************************** * Notes on declarations... * * * * *** SSC Card Addresses *** * * * * Bit-> B7 B6 B5 B4 B3 B2 B1 B0 * * +----------------------------+ * * DIPSW1 S1 S2 S3 S4 Z Z S5 S6 (left dipswitch) * * * * (S1-S4 used for baud rate, S5-S6 for firmware mode) * * * * DIPSW2 S1 Z S2 Z S3 S4 S5 CTS (right dipswitch) * * * * STREG INT DSR DCD TDR RDR OVR FE PE * * * * CTLREG STB << WL >> CK << BAUD RATE >> * * * * CMDREG <<PARITY >> ECH <<XMIT>> RE DTR * * * * * * *** Screen Variables: PPC and SIC modes *** * * STATEFLG ($578-$C0): * * B7=CR gen enb flag B6=after LC input flg * * B2-B0=command interpreter states * * 0 0 0 idle * * 0 0 1 cmd char received * * 0 1 0 collect <N> until char then do command * * 0 1 1 skip until space, then goto state 4 * * 1 0 0 E/D commands * * 1 0 1 unused * * 1 1 0 wait until CR then set state to zero * * 1 1 1 wait until CR then do proc indicated by parm * * * * (B4-B0 determine enquire char for P8A mode) * * * * CIC mode: * * B7=terminal mode flag * * B3-B5=chain slot * * * * DELAYFLG ($478-$C0): * * B7-B6=screen translation options * * 0 0 LC->UC * * 0 1 no translation * * 1 0 LC->UC inverse * * 1 1 LC->UC, UC->UC inverse * * (1-3 will allow LC chars to pass thru monitor) * * * * B5-B4=CR delay 0 0 = no delay * * B3-B2=LF delay 0 1 = 32 millisec * * B1-B0=FF delay 1 0 = 1/4 sec * * 1 1 = 2 sec * * * * MISCFLG ($7f8-$C0): * * B7=echo bit B6=tabbing option enable * * B5=linefeed eat B4=Pascal/BASIC flag * * B3=XOFF enb flag B2=keyboard enb * * B1=PPC/CIC mode B0=LF generate enb * * * * CIC mode: B6=term mode shift enb * ******************************************************************************** PARAMETER .eq $0438 {const} ;accumulator for cmd parameter CHNBYTE .eq $0638 {const} ;current output screen ($CN00 entry) BUFBYTE .eq $06b8 {const} ;buffer for one input byte MON_CH .eq $24 ;cursor horizontal displacement SLOT16 .eq $26 ;save $NO to free up Y-reg CHARACTER .eq $27 ;output, screen and input chars MON_BASL .eq $28 ;base address for text output (lo) ZPTMP1 .eq $2a ;when ZPTEMP isn't enough ZPTMP2 .eq $2b ;temporaries, temporaries! ZPTEMP .eq $35 ;workhorse temporary MON_CSWL .eq $36 ;character output hook (lo) MON_CSWH .eq $37 ;character output hook (hi) MON_KSWL .eq $38 ;character input hook (lo) MON_KSWH .eq $39 ;character input hook (hi) MON_A1L .eq $3c ;general purpose MON_RNDL .eq $4e ;low byte of KEYIN "random" value MON_RNDH .eq $4f ;high byte of KEYIN "random" value STACK .eq $0100 {addr/256} ;system stack block INBUFF .eq $0200 {addr/256} ;system input buffer DELAYFLG .eq $03b8 ;(see notes) HANDSHKE .eq $0438 ;SIC P8A char counter for ETX/ACK STATEFLG .eq $04b8 ;(see notes) CMDBYTE .eq $0538 ;holds command character (PPC & CIC) STSBYTE .eq $05b8 ;status/ioresult/input byte PWDBYTE .eq $0638 ;printer (format) width COLBYTE .eq $06b8 ;column position counter MISCFLG .eq $0738 ;(see notes) MSLOT .eq $07f8 ;buffer for hi slot addr ($CN) KBD .eq $c000 ;R last key pressed + 128 KBDSTRB .eq $c010 ;RW keyboard strobe DIPSW1 .eq $c081 ;(+$NO) dipswitch block 1 DIPSW2 .eq $c082 ;(+$NO) dipswitch block 2 RDREG .eq $c088 ;(+$NO) read data reg (read) RESET .eq $c089 ;(+$NO) software reset (write) STREG .eq $c089 ;(+$NO) status register (read) CMDREG .eq $c08a ;(+$NO) command register (R/W) CTLREG .eq $c08b ;(+$NO) control register (R/W) CLRROM .eq $cfff ;disable slot C8 ROM MON_NXTA1 .eq $fcba ;increment A1; set carry if A1 >= A2 before inc MON_COUT .eq $fded ;print Acc to output device via $36-37 MON_COUTZ .eq $fdf6 MON_SETKBD .eq $fe89 ;reset char input handler to ROM MON_SETVID .eq $fe93 ;reset char output handler to ROM MON_IORTS .eq $ff58 ;JSR here to find out where one is .org $c800 ******************************************************************************** * * * C800 space: high level stuff. * * * ******************************************************************************** c800: 20 9b c9 PASCALINIT jsr PENTRY ;Pascal 1.0 initialization entry c803: a9 16 lda #$16 ;no XOFF, echo, LF eat, or LF gen c805: 48 INIT1 pha ;goes to MISCFLG after modification c806: a9 00 lda #$00 c808: 9d b8 04 sta STATEFLG,x c80b: 9d b8 03 sta DELAYFLG,x c80e: 9d 38 04 sta HANDSHKE,x c811: 9d b8 05 sta STSBYTE,x c814: 9d 38 06 sta PWDBYTE,x c817: 9d b8 06 sta COLBYTE,x c81a: b9 82 c0 lda DIPSW2,y ;set LF gen option from D2-S5 c81d: 85 2b sta ZPTMP2 ;save for later c81f: 4a lsr A ;S5-> carry c820: 4a lsr A ;if S5=on=0 then leave MISCFLG alone c821: 90 04 bcc INIT1A c823: 68 pla ;otherwise, make sure LF gen c824: 29 fe and #$fe ; enable is reset c826: 48 pha c827: b8 INIT1A clv ;V will be clear for CIC mode c828: b9 81 c0 lda DIPSW1,y c82b: 4a lsr A ;SIC modes set carry c82c: b0 07 bcs INIT2 ;branch for SIC modes c82e: 4a lsr A c82f: b0 0e bcs INIT2B ;PPC mode branch c831: a9 01 lda #$01 ;Ctl-A c833: d0 3d bne INIT5 ;<always> CIC mode branch c835: 4a INIT2 lsr A ;set carry for P8A c836: a9 03 lda #$03 ;set ETX as default inquiry char c838: b0 02 bcs INIT2A ;branch for P8A c83a: a9 80 lda #$80 ;for P8 set auto CR gen c83c: 9d b8 04 INIT2A sta STATEFLG,x c83f: 2c 58 ff INIT2B bit MON_IORTS ;set V-flag for PPC, SIC modes c842: a5 2b lda ZPTMP2 c844: 29 20 and #$20 ;set CR delay c846: 49 20 eor #$20 ;SO 1=ENB, 0=DISABLE c848: 9d b8 03 sta DELAYFLG,x ; from D2-S2 ; c84b: 70 0a bvs INIT3 ;<always> branch around Pascal ; ; Pascal 1.0 read entry (must be at $C84D). ; c84d: 20 9b c8 jsr PASCALREAD ;do Pascal 1.1 read c850: ae f8 07 ldx MSLOT ;modify for 1.0 c853: 9d b8 05 sta STSBYTE,x ;character read c856: 60 rts ; ; Now where were we? ; c857: a5 2b INIT3 lda ZPTMP2 ;PPC, SIC modes use switches c859: 4a lsr A ; to set pwidth, CR delay c85a: 4a lsr A c85b: 29 03 and #$03 c85d: a8 tay c85e: f0 04 beq INIT4 ; c860: 68 pla ;reset video enable for pwidth#40 c861: 29 7f and #$7f c863: 48 pha ; c864: b9 a6 c9 INIT4 lda PWDTBL,y c867: 9d 38 06 sta PWDBYTE,x c86a: a4 26 ldy SLOT16 ; c86c: 68 pla ;clear CIC bit in future MISCFLG c86d: 29 95 and #$95 ; (and tabbing, XOFF and LF eat bits) c86f: 48 pha c870: a9 09 lda #$09 ;Ctl-I ; c872: 9d 38 05 INIT5 sta CMDBYTE,x ;cmd ESC char (ignored for SIC modes) c875: 68 pla c876: 9d 38 07 sta MISCFLG,x ;set MISCFLG flags ; ; Now for the ACIA initialization routine. ; c879: a5 2b INITACIA lda ZPTMP2 ;DIPSW2 c87b: 48 pha c87c: 29 a0 and #$a0 ;data bit options for CIC mode c87e: 50 02 bvc INITACIA1 ;branch for CIC mode c880: 29 80 and #$80 ;8 data, 1 or 2 stop for SIC, PPC c882: 20 a1 cd INITACIA1 jsr DATACMD1 ;set control reg c885: 20 81 cd jsr BAUDCMD1 ;set dipswitch baud rate c888: 68 pla c889: 29 0c and #$0c ;parity options for CIC mode c88b: 50 02 bvc INITACIA2 ;branch for CIC mode c88d: a9 00 lda #$00 ;disable parity for SIC, PPC modes c88f: 0a INITACIA2 asl A c890: 0a asl A c891: 0a asl A c892: 09 0b ora #$0b c894: 99 8a c0 sta CMDREG,y c897: b9 88 c0 lda RDREG,y ;throw out the strange stuff c89a: 60 rts ; ; Pascal read routine. ; c89b: 20 9b c9 PASCALREAD jsr PENTRY ;shared by both Pascal versions c89e: 20 aa c8 jsr GETCHAR ;get ACIA/KBD data c8a1: 29 7f and #$7f ;clear high bit for Pascal c8a3: ac f8 07 PASEXIT ldy MSLOT c8a6: be b8 05 ldx STSBYTE,y ;error status-> X-reg c8a9: 60 rts ; ; GETCHAR routine waits for the next char from either the ACIA or keyboard (if ; enabled). Used by Pascal read routine, XON wait, and ACK wait. Data is ; returned in the A-register. ; c8aa: 20 ff ca GETCHAR jsr INPUT ;ACIA data? c8ad: b0 05 bcs GETCHAR1 c8af: 20 2c cc jsr CKKBD ;keyboard input? c8b2: 90 f6 bcc GETCHAR c8b4: 60 GETCHAR1 rts ;exit when we have something ; ; CIC exit routine. ; c8b5: 20 1e ca CICEXIT jsr CHECKTERM ;see if we've entered terminal mode ; ; BASIC exit routine. ; c8b8: 68 BASICEXIT pla c8b9: a8 tay c8ba: 68 pla c8bb: aa tax c8bc: a5 27 lda CHARACTER c8be: 60 rts ; ; BASIC input routine. ; c8bf: f0 29 BINPUT beq BINACIA ;branch if not CIC mode c8c1: bd b8 06 lda COLBYTE,x ;input buffer full? c8c4: 10 05 bpl BINKBD c8c6: 5e b8 06 lsr COLBYTE,x ;reset buffer full c8c9: d0 24 bne BINACIA1 ;<always> c8cb: 20 3e cc BINKBD jsr GETKBD ;keyboard data? c8ce: 90 1a bcc BINACIA ; ; c8d0: bd b8 03 BINEND lda DELAYFLG,x c8d3: 29 c0 and #$c0 ;translate lowercase to uppercase? c8d5: f0 0e beq BINEND1 ;if so, let the monitor do it c8d7: a5 27 lda CHARACTER ;if not, set flag if c8d9: c9 e0 cmp #$e0 ; this is a lowercase char c8db: 90 08 bcc BINEND1 ; for input buffer correction c8dd: bd b8 04 lda STATEFLG,x ; (circumvent Apple monitor) c8e0: 09 40 ora #$40 c8e2: 9d b8 04 sta STATEFLG,x ; c8e5: 28 BINEND1 plp c8e6: f0 d0 beq BASICEXIT ;branch if not CIC mode c8e8: d0 cb bne CICEXIT ;<always> check to see if we entered term mode (via kybd escape) c8ea: 20 ff ca BINACIA jsr INPUT ;ACIA data? c8ed: 90 dc bcc BINKBD c8ef: 20 11 cc BINACIA1 jsr RESTORE ;do BASIC cursed duty c8f2: 28 plp c8f3: 08 php ;get CIC mode indicator c8f4: f0 da beq BINEND ;skip if not CIC mode c8f6: 20 d1 c9 jsr CKINPUT ;look for input stream special chars c8f9: 4c d0 c8 LC8F9 jmp BINEND ; ; SIC, PPC BASIC output routine. ; c8fc: 20 1a cb SEROUT jsr CMDSEQCK ;check for a command sequence c8ff: b0 b7 bcs BASICEXIT ;branch if we were in command mode c901: a5 27 lda CHARACTER ;save char on stack c903: 48 pha c904: bd 38 07 lda MISCFLG,x ;if video or tabbing enabled, c907: 29 c0 and #$c0 ; don't mess with the cursor c909: d0 16 bne TABCHECK ; c90b: a5 24 lda MON_CH ;check for comma tabbing c90d: f0 42 beq NOTAB ;if CH=0, there was no tab or comma c90f: c9 08 cmp #8 ;Integer BASIC comma? c911: f0 04 beq COMMA c913: c9 10 cmp #16 ;Applesoft comma? c915: d0 0a bne TABCHECK c917: 09 f0 COMMA ora #$f0 c919: 3d b8 06 and COLBYTE,x ;set col to previous tab c91c: 18 clc c91d: 65 24 adc MON_CH ;then increment to next tab c91f: 85 24 sta MON_CH ; c921: bd b8 06 TABCHECK lda COLBYTE,x c924: c5 24 cmp MON_CH ;is tabbing needed? c926: f0 29 beq NOTAB ;if equal then no tab needed c928: a9 a0 lda #$a0 ;space for forward tab c92a: 90 08 bcc TAB1 c92c: bd 38 07 lda MISCFLG,x ;don't backspace unless tabbing c92f: 0a asl A ; option is enabled c930: 10 1f bpl NOTAB c932: a9 88 lda #$88 ;backspace for backtab c934: 85 27 TAB1 sta CHARACTER c936: 2c 58 ff bit MON_IORTS ;set V=1 to indicate tabbing c939: 08 php ;save tabbing indicator c93a: 70 0c bvs TAB2 ;<always> around batch move entry c93c: ea nop ; ; Short batch move: locate at $C93D for compatibility with SIC P8 block move. ; c93d: 2c 58 ff BATCHIN bit MON_IORTS ;[known $60; always sets V-flag] c940: 50 bvc ▼ LC8F9+1 ;dummy BVC c941: b8 BATCHOUT clv ;V=0 for output entry c942: ae f8 07 ldx MSLOT c945: 4c ef c9 jmp BATCHIO ; ; Burp . . . ; c948: 20 b5 c9 TAB2 jsr ADJUST ;adjust column count c94b: 20 6b cb jsr OUTPUT2 ;don't go to screen when tabbing c94e: 4c 68 c9 jmp FORCECR ;share some code. . . c951: 68 NOTAB pla c952: b8 clv c953: 08 php ;save 'no tab' indication c954: 85 27 NOTAB1 sta CHARACTER ;(force CR reentry) c956: 48 pha c957: 20 68 cb jsr OUTPUT1 ;enter after cmd seq check c95a: 20 b5 c9 jsr ADJUST c95d: 68 pla c95e: 49 8d eor #$8d ;was it a CR? c960: 0a asl A c961: d0 05 bne FORCECR c963: 9d b8 06 sta COLBYTE,x ;if so, reset column to 0 c966: 85 24 sta MON_CH ; c968: bd b8 04 FORCECR lda STATEFLG,x ;force CR disabled? c96b: 10 0d bpl SEREND c96d: bd 38 06 lda PWDBYTE,x ;force CR if limit reached c970: f0 08 beq SEREND ;(for P8 poke compatibility) c972: 18 clc c973: fd b8 06 sbc COLBYTE,x c976: a9 8d lda #$8d c978: 90 da bcc NOTAB1 ;branch to force CR ; c97a: 28 SEREND plp c97b: 70 a4 bvs TABCHECK ;branch if tabbing ; c97d: bd 38 07 lda MISCFLG,x ;don't mess with cursor c980: 30 16 bmi SEREND2 ; when video is on c982: bc b8 06 ldy COLBYTE,x c985: 0a asl A c986: 30 0e bmi SETCH ;set CH to value of col for tabbing c988: 98 tya c989: a0 00 ldy #0 c98b: 38 sec c98c: fd 38 06 sbc PWDBYTE,x c98f: c9 f8 cmp #$f8 ;within 8 chars of pwidth? c991: 90 03 bcc SETCH c993: 69 27 adc #$27 ;if so, adjust to within 8 of 40 c995: a8 tay c996: 84 24 SETCH sty MON_CH ; c998: 4c b8 c8 SEREND2 jmp BASICEXIT ;that's all ; ; Pascal entry routine. ; c99b: 8e f8 07 PENTRY stx MSLOT c99e: 84 26 sty SLOT16 c9a0: a9 00 lda #0 c9a2: 9d b8 05 sta STSBYTE,x c9a5: 60 rts ; ; SIC mode printer width table. ; c9a6: 29 PWDTBL .dd1 $29 ;40 columns c9a7: 48 .dd1 $48 ;72 columns c9a8: 50 .dd1 $50 ;80 columns c9a9: 84 .dd1 $84 ;132 columns ; ; Pascal write routine (doubles as Pascal 1.0 entry point) ; - must be at $C9AA - ; c9aa: 85 27 PASCALWRITE sta CHARACTER c9ac: 20 9b c9 jsr PENTRY c9af: 20 63 cb jsr OUTPUT c9b2: 4c a3 c8 jmp PASEXIT ;load X-reg with error byte & RTS ; ; Column adjust routine (PPC, SIC modes only). ; c9b5: a5 27 ADJUST lda CHARACTER c9b7: 49 08 eor #$08 ;backspace? c9b9: 0a asl A c9ba: f0 04 beq DECRCOL ;if so, decrement column c9bc: 49 ee eor #$ee ;delete? ($ff, rub) c9be: d0 09 bne CTRLTST c9c0: de b8 06 DECRCOL dec COLBYTE,x ;decrement column count c9c3: 10 03 bpl ADJRTS c9c5: 9d b8 06 sta COLBYTE,x ;don't allow to go below 0 c9c8: 60 ADJRTS rts c9c9: c9 c0 CTRLTST cmp #$c0 ;don't increment column count for c9cb: b0 fb bcs ADJRTS ; control characters c9cd: fe b8 06 inc COLBYTE,x c9d0: 60 rts ; ; Routine to process special input chars. ; c9d1: bd 38 07 CKINPUT lda MISCFLG,x c9d4: 29 08 and #$08 ;input ctl chars enabled? c9d6: f0 16 beq CIEND ; c9d8: bd b8 04 lda STATEFLG,x c9db: a4 27 ldy CHARACTER c9dd: c0 94 cpy #$94 ;Ctl-T? c9df: d0 04 bne CKINPUT1 c9e1: 09 80 ora #$80 ;set terminal mode c9e3: d0 06 bne CKINPUT2 ;<always> c9e5: c0 92 CKINPUT1 cpy #$92 ;Control-R? c9e7: d0 05 bne CIEND c9e9: 29 7f and #$7f ;reset terminal mode c9eb: 9d b8 04 CKINPUT2 sta STATEFLG,x c9ee: 60 CIEND rts ; ; Short block move. ; c9ef: 8a BATCHIO txa c9f0: 0a asl A c9f1: 0a asl A c9f2: 0a asl A c9f3: 0a asl A c9f4: 85 26 sta SLOT16 c9f6: a9 00 lda #0 c9f8: 9d b8 05 sta STSBYTE,x ;zero error indication c9fb: 70 0f bvs MOVIN ; c9fd: a0 00 MOVOUT ldy #$00 c9ff: b1 3c lda (MON_A1L),y ;get buffer data ca01: 85 27 sta CHARACTER ca03: 20 02 cc jsr ACIAOUT ;send it out the ACIA ca06: 20 ba fc jsr MON_NXTA1 ca09: 90 f2 bcc MOVOUT ca0b: 60 rts ca0c: 20 d2 ca MOVIN jsr SRIN ca0f: 90 fb bcc MOVIN ca11: b9 88 c0 lda RDREG,y ca14: a0 00 ldy #0 ca16: 91 3c sta (MON_A1L),y ;put ACIA data into buffer ca18: 20 ba fc jsr MON_NXTA1 ca1b: 90 ef bcc MOVIN ca1d: 60 rts ******************************************************************************** * * * Terminal mode routines. * * * ******************************************************************************** ca1e: bd b8 04 CHECKTERM lda STATEFLG,x ;have we entered terminal mode? ca21: 10 31 bpl TERMRTS ;if not, a simple RTS will do. . . ; ; We enter the world of terminal mode. ; ca23: a9 02 lda #$02 ;start in shift-lock state ca25: 48 pha ;shift state is saved on stack ca26: a9 7f lda #$7f ca28: 20 e2 cd jsr KCMD1 ;reset echo (default to full dup) ; ca2b: a4 24 TERMNEXT ldy MON_CH ca2d: b1 28 lda (MON_BASL),y ca2f: 85 27 sta CHARACTER ;save screen character ca31: a9 07 TERMNEXT1 lda #$07 ;implement a flashing underline ca33: 25 4f and MON_RNDH ; for a cursor ca35: d0 10 bne TERMNEXT3 ca37: a4 24 ldy MON_CH ca39: a9 df lda #$df ca3b: d1 28 cmp (MON_BASL),y ;is underline on the screen? ca3d: d0 02 bne TERMNEXT2 ;if not, put it there ca3f: a5 27 lda CHARACTER ;otherwise use true screen char ca41: 91 28 TERMNEXT2 sta (MON_BASL),y ca43: e6 4f inc MON_RNDH ;make it flash, but ca45: e6 4f inc MON_RNDH ;not too slow and not too fast ; ca47: bd b8 04 TERMNEXT3 lda STATEFLG,x ;are we still in term mode? ca4a: 30 09 bmi TERMACIAIN ;if so, go check ACIA ; ca4c: 20 11 cc jsr RESTORE ;always replace our cursor ca4f: 68 pla ;clean up the stack ca50: a9 8d lda #$8d ;return a <CR> to cover up ca52: 85 27 sta CHARACTER ca54: 60 TERMRTS rts ca55: 20 ff ca TERMACIAIN jsr INPUT ;ACIA input? ca58: 90 0c bcc TERMKBDIN ;if not, go check keyboard ca5a: 20 11 cc jsr RESTORE ;restore cursor, input->character ca5d: 20 d1 c9 jsr CKINPUT ;check for Ctl-T, Ctl-R ca60: 20 a3 cc jsr SCREENOUT1 ;input->screen always ca63: 4c 2b ca jmp TERMNEXT ca66: 20 3e cc TERMKBDIN jsr GETKBD ;keypress? ca69: 90 c6 bcc TERMNEXT1 ;skip if not ca6b: 70 be bvs TERMNEXT ;branch if we did a kbd escape seq. ca6d: bd 38 07 lda MISCFLG,x ;shifting enabled? ca70: 0a asl A ca71: 10 22 bpl TERMSEND1 ca73: 68 pla ;recover termstate ca74: a8 tay ca75: a5 27 lda CHARACTER ca77: c0 01 cpy #1 ;1 = shift letters, xlate numbers ca79: f0 20 beq TERMCAP ca7b: b0 34 bcs TERMLOCK ;2 means caps lock mode ; ca7d: c9 9b TERMNORM cmp #$9b ;ESC? ca7f: d0 06 bne TERMLETTER ; ca81: c8 TERMINC iny ;increment status ca82: 98 TERMINC1 tya ca83: 48 pha ;put back on stack ca84: 4c 2b ca jmp TERMNEXT ca87: c9 c1 TERMLETTER cmp #$c1 ;<A? ca89: 90 08 bcc TERMSEND ca8b: c9 db cmp #$db ;>Z? ca8d: b0 04 bcs TERMSEND ca8f: 09 20 ora #$20 ;it's a letter so translate to LC ca91: 85 27 sta CHARACTER ; ca93: 98 TERMSEND tya ca94: 48 pha ;put state back on stack ca95: 20 68 cb TERMSEND1 jsr OUTPUT1 ;go output ca98: 4c 2b ca jmp TERMNEXT ca9b: c9 9b TERMCAP cmp #$9b ;two escapes? ca9d: f0 e2 beq TERMINC ca9f: c9 b0 cmp #$b0 ;<0? caa1: 90 0a bcc TERMCAP1 caa3: c9 bb cmp #$bb ;>colon? caa5: b0 06 bcs TERMCAP1 ; ; ESC <number> so translate into missing ASCII char. ; caa7: a8 tay caa8: b9 09 ca lda TRANSLATE-176,y caab: 85 27 sta CHARACTER caad: a0 00 TERMCAP1 ldy #0 ;back to state 0 caaf: f0 e2 beq TERMSEND ;<always> cab1: c9 9b TERMLOCK cmp #$9b ;ESC? cab3: d0 de bne TERMSEND cab5: a0 00 ldy #0 cab7: f0 c9 beq TERMINC1 ;<always> ; ; Translate table. ; cab9: 9b TRANSLATE .dd1 $9b ;ESC caba: 9c .dd1 $9c ;FS cabb: 9f .dd1 $9f ;US cabc: db .dd1 $db ;left bracket cabd: dc .dd1 $dc ;left slash cabe: df .dd1 $df ;underscore cabf: fb .dd1 $fb ;left enclose cac0: fc .dd1 $fc ;vertical bar cac1: fd .dd1 $fd ;right enclose cac2: fe .dd1 $fe ;tilde cac3: ff .dd1 $ff ;rub ; ; General purpose wait routine. ; ; WAITMS wait for [A-reg] milliseconds (256 if A-reg=0). ; cac4: a2 ca WAITMS ldx #202 cac6: ca WAITMS1 dex ;<don't let this loop cross a page> cac7: d0 fd bne WAITMS1 ;5 microsecond loop cac9: 38 sec caca: e9 01 sbc #$01 cacc: d0 f6 bne WAITMS cace: ae f8 07 ldx MSLOT cad1: 60 rts ; ; ACIA status register read routines. ; cad2: a4 26 SRIN ldy SLOT16 ;SLOT16=$NO cad4: b9 89 c0 lda STREG,y cad7: 48 pha cad8: 29 20 and #$20 ;DCD? cada: 4a lsr A ;an error if not cadb: 4a lsr A cadc: 85 35 sta ZPTEMP cade: 68 pla cadf: 29 0f and #$0f cae1: c9 08 cmp #$08 ;set carry if RDR full, else clear cae3: 90 04 bcc SRIN1 cae5: 29 07 and #$07 ;PE, FE, OVR valid only when RDR=1 cae7: b0 02 bcs SRIN2 ;<always> cae9: a5 35 SRIN1 lda ZPTEMP caeb: 05 35 SRIN2 ora ZPTEMP ;get CDC error bit caed: f0 05 beq SRIN3 ;branch if no errors found caef: 09 20 ora #$20 ;else set bit 5 to offset for Pascal caf1: 9d b8 05 sta STSBYTE,x ;and save in status temp caf4: 60 SRIN3 rts ;CY=1 means data is available ; ; SROUT checks if TDR is empty + hardware handshake is OK. ; caf5: a4 26 SROUT ldy SLOT16 caf7: b9 89 c0 lda STREG,y cafa: 29 70 and #$70 cafc: c9 10 cmp #$10 ;equ if TDR empty, DCD, DSR, & CTS cafe: 60 rts ; ; General input routine. ; caff: 20 d2 ca INPUT jsr SRIN cb02: 90 15 bcc NOINPUT1 ; cb04: b9 88 c0 lda RDREG,y ;get the ACIA input cb07: 09 80 ora #$80 ;set hi bit for BASIC cb09: c9 8a cmp #$8a ;linefeed? cb0b: d0 09 bne INPUT2 ; cb0d: a8 tay cb0e: bd 38 07 lda MISCFLG,x ;see if we should eat it cb11: 29 20 and #$20 cb13: d0 03 bne NOINPUT ;if so, just keep it a secret cb15: 98 tya ; cb16: 38 INPUT2 sec ;indicate data cb17: 60 rts cb18: 18 NOINPUT clc ;carry clear for no input cb19: 60 NOINPUT1 rts ; ; General output routine. ; ; Start of command check routine. ; cb1a: a4 26 CMDSEQCK ldy SLOT16 cb1c: b9 81 c0 lda DIPSW1,y cb1f: 4a lsr A cb20: b0 36 bcs NOCMD ;don't worry about cmd seq for SIC cb22: bd b8 04 lda STATEFLG,x cb25: 29 07 and #$07 ;are we in a command sequence? cb27: f0 05 beq ESCCHECK cb29: 20 fc cd jsr CMDPROC ;if so, goto command central cb2c: 38 sec ;indicate command cb2d: 60 rts cb2e: a5 27 ESCCHECK lda CHARACTER cb30: 29 7f and #$7f ;ignore high bit cb32: dd 38 05 cmp CMDBYTE,x ;is this beginning of a cmd seq? cb35: d0 05 bne XOFFCK cb37: fe b8 04 inc STATEFLG,x ;start up command modes cb3a: 38 sec ;indicate command cb3b: 60 rts cb3c: bd 38 07 XOFFCK lda MISCFLG,x ;is XON enabled? cb3f: 29 08 and #$08 cb41: f0 15 beq NOCMD ;skip this if not ; cb43: 20 ff ca jsr INPUT ;any input? cb46: 90 10 bcc NOCMD ;if not, go output cb48: c9 93 cmp #$93 ;is it an XOFF? cb4a: f0 0e beq XONWAIT ;if so, go wait for another input cb4c: 48 pha cb4d: bd 38 07 lda MISCFLG,x ;CIC mode? cb50: 4a lsr A cb51: 4a lsr A cb52: 68 pla cb53: 90 04 bcc ANRTS cb55: 9d b8 06 sta BUFBYTE,x ;if so, we have a buffer cb58: 18 NOCMD clc ;indicate not a cmd seq cb59: 60 ANRTS rts cb5a: 20 aa c8 XONWAIT jsr GETCHAR ;get ACIA/kbd data cb5d: c9 91 cmp #$91 ;is it an XON? cb5f: d0 f9 bne XONWAIT ;if not, wait cb61: 18 clc ;otherwise, indicate not a cmd seq cb62: 60 rts ; and return ; ; Now the output routine you've been waiting for. ; cb63: 20 1a cb OUTPUT jsr CMDSEQCK cb66: b0 f1 bcs ANRTS ;don't output command sequences ; cb68: 20 9e cc OUTPUT1 jsr SCREENOUT ; cb6b: a4 26 OUTPUT2 ldy SLOT16 cb6d: b9 81 c0 lda DIPSW1,y cb70: 4a lsr A cb71: 90 4e bcc OUTPUT3 ;skip ETX/ACK for native modes cb73: 4a lsr A cb74: 90 4b bcc OUTPUT3 ;branch if not P8A emulation ; ; P8A ETX/ACK stuff. ; ; After 148 characters but not within an escape sequence of up to 5 characters, ; the handshake is performed (will delay until 'not ESC' and then 4 more chars ; or until an 'ESC'). ; cb76: a5 27 P8AOUT1 lda CHARACTER ;save char on stack cb78: 48 pha cb79: bd 38 04 lda HANDSHKE,x ;char count for buffer full cb7c: c9 67 cmp #103 ;if <103 then 153 chars in buffer cb7e: 90 10 bcc ETX cb80: c9 6c cmp #108 ;if >=108 then less than 149 chars cb82: b0 22 bcs P8AOUT2 ; so no handshake is needed yet cb84: c9 6b cmp #107 ;sets carry if 107 (149 sent) cb86: 68 pla cb87: 48 pha cb88: 49 9b eor #$9b ;ESC? cb8a: 29 7f and #$7f ;ignore hi-bit cb8c: d0 18 bne P8AOUT2 ;count as 1 of 5 if not 'ESC' cb8e: b0 19 bcs P8AOUT3 ;don't count if 149th char is 'ESC' ; cb90: bd b8 04 ETX lda STATEFLG,x ;send query char to printer cb93: 29 1f and #$1f ;(default is ETX) cb95: 09 80 ora #$80 cb97: 85 27 sta CHARACTER cb99: 20 02 cc jsr ACIAOUT cb9c: 20 aa c8 ACK jsr GETCHAR ;get ACIA/kbd data cb9f: 49 86 eor #$86 ;ACK? cba1: d0 ed bne ETX ;if not ACK, repeat handshake cba3: 9d 38 04 sta HANDSHKE,x ;init char count to 255 ; cba6: de 38 04 P8AOUT2 dec HANDSHKE,x cba9: 68 P8AOUT3 pla ;get real char to output cbaa: 85 27 sta CHARACTER cbac: 49 8d eor #$8d ;if CR and CR delay mode cbae: 0a asl A cbaf: d0 0a bne P8AOUT4 ; then fake char count to less than cbb1: bd b8 03 lda DELAYFLG,x ; 48 to force handshake on next cbb4: 29 30 and #$30 ; character out cbb6: f0 03 beq P8AOUT4 cbb8: 9d 38 04 sta HANDSHKE,x ; cbbb: 20 02 cc P8AOUT4 jsr ACIAOUT cbbe: 4c ea cb jmp LFGEN ;(skip delays) ; ; And back to normal output. ; cbc1: 20 02 cc OUTPUT3 jsr ACIAOUT ; ; Now check for CR, LF, and FF delays. ; cbc4: 0a asl A cbc5: a8 tay cbc6: bd b8 03 lda DELAYFLG,x ;get delay flags cbc9: c0 18 cpy #$18 ;form feed? cbcb: f0 0c beq OUTDLY1 cbcd: 4a lsr A cbce: 4a lsr A ;right justify LF delay cbcf: c0 14 cpy #$14 ;line feed? cbd1: f0 06 beq OUTDLY1 cbd3: 4a lsr A cbd4: 4a lsr A ;right justify CR delay cbd5: c0 1a cpy #$1a ;carriage return? cbd7: d0 25 bne OUTPUTEND cbd9: 29 03 OUTDLY1 and #$03 ;just want lowest 2 bits cbdb: f0 0d beq LFGEN ;no delay indicated cbdd: a8 tay cbde: b9 fe cb lda DLYTBL-1,y cbe1: a8 tay ;delay in 32 msec increments cbe2: a9 20 OUTDLYLP lda #32 cbe4: 20 c4 ca jsr WAITMS cbe7: 88 dey cbe8: d0 f8 bne OUTDLYLP ; ; Check on LF generation option. ; cbea: a5 27 LFGEN lda CHARACTER cbec: 0a asl A cbed: c9 1a cmp #$1a ;carriage return? cbef: d0 0d bne OUTPUTEND cbf1: bd 38 07 lda MISCFLG,x ;is LF generate enabled? cbf4: 6a ror A cbf5: 90 07 bcc OUTPUTEND cbf7: a9 8a lda #$8a cbf9: 85 27 sta CHARACTER ;line feed cbfb: 4c 6b cb jmp OUTPUT2 ;(don't echo it) cbfe: 60 OUTPUTEND rts cbff: 01 DLYTBL .dd1 $01 ;32 msec cc00: 08 .dd1 $08 ;1/4 sec cc01: 40 .dd1 $40 ; 2 sec ; ; ACIA output routine. ; cc02: 20 f5 ca ACIAOUT jsr SROUT ;ready for output? cc05: d0 fb bne ACIAOUT cc07: 98 tya cc08: 09 89 ora #$89 ;prepare to address ACIA, cc0a: a8 tay ; causing 6502 false read to occur cc0b: a5 27 lda CHARACTER ; on page $BF (avoiding RDR read) cc0d: 99 ff bf sta $bfff,y ;here you are ACIA cc10: 60 rts ; ; Restore cursor (not for Pascal) ; (A-reg should contain new char) ; cc11: 48 RESTORE pha ;save new character cc12: a4 24 ldy MON_CH cc14: a5 27 lda CHARACTER ;old character cc16: 91 28 sta (MON_BASL),y cc18: 68 pla ; cc19: c9 95 cmp #$95 ;screen pick? cc1b: d0 0c bne RESTOREND cc1d: a5 27 lda CHARACTER ;if so, use screen char cc1f: c9 20 cmp #$20 ;inverse? cc21: b0 06 bcs RESTOREND cc23: 20 df cc jsr GETXLATE ;reverse the translation cc26: 59 db cc eor REVMASK,y cc29: 85 27 RESTOREND sta CHARACTER cc2b: 60 rts ; ; Pascal-BASIC keyboard fetch. ; cc2c: 18 CKKBD clc ;return carry clear for no data cc2d: bd 38 07 lda MISCFLG,x cc30: 29 04 and #$04 ;answer no if keyboard is disabled cc32: f0 09 beq CKKBDXIT ; cc34: ad 00 c0 CKKBD1 lda KBD cc37: 10 04 bpl CKKBDXIT cc39: 8d 10 c0 sta KBDSTRB cc3c: 38 sec ;indicate data cc3d: 60 CKKBDXIT rts ; ; Get a char from keyboard for BASIC only. ; cc3e: e6 4e GETKBD inc MON_RNDL ;mix up random # seed cc40: d0 02 bne GETKBD1 ; for BASIC cc42: e6 4f inc MON_RNDH cc44: 20 2c cc GETKBD1 jsr CKKBD ;keyboard fetch routine cc47: b8 clv ;indicate no escape sequence cc48: 90 f3 bcc CKKBDXIT ;exit if no key press cc4a: 20 11 cc jsr RESTORE ;do BASIC cursed duty cc4d: 29 7f and #$7f cc4f: dd 38 05 cmp CMDBYTE,x ;is is the start of a command? cc52: d0 3d bne GETKBDONE ;if not, exit indicating data cc54: a4 26 ldy SLOT16 cc56: b9 81 c0 lda DIPSW1,y ;only do cmd esc for PPC, SIC modes cc59: 4a lsr A cc5a: b0 35 bcs GETKBDONE ; ; Keyboard escape handler. ; cc5c: a0 0a KBDESC ldy #$0a ;first print a prompt cc5e: b9 93 cc PROMPTLOOP lda PROMPTBL,y cc61: 85 27 sta CHARACTER cc63: 98 tya cc64: 48 pha cc65: 20 a3 cc jsr SCREENOUT1 ;always send to screen cc68: 68 pla cc69: a8 tay cc6a: 88 dey cc6b: 10 f1 bpl PROMPTLOOP ; cc6d: a9 01 lda #1 ;start out in command state 1 cc6f: 20 7b ce jsr SETOSTATE ; cc72: 20 34 cc GETCMD jsr CKKBD1 ;wait for keyboard character cc75: 10 fb bpl GETCMD cc77: c9 88 cmp #$88 ;backspace? cc79: f0 e1 beq KBDESC ;if so, then start over cc7b: 85 27 sta CHARACTER ; cc7d: 20 a3 cc jsr SCREENOUT1 cc80: 20 1a cb jsr CMDSEQCK ;pump thru cmd interpreter ; cc83: bd b8 04 lda STATEFLG,x ;are we done? cc86: 29 07 and #$07 cc88: d0 e8 bne GETCMD ;if not, go again ; cc8a: a9 8d lda #$8d ;force back a carriage return cc8c: 85 27 sta CHARACTER cc8e: 2c 58 ff bit MON_IORTS ;indicate that a cmd seq has occurred cc91: 38 GETKBDONE sec ;indicate success cc92: 60 rts cc93: ba c3 d3 d3+ PROMPTBL .str “:CSS ELPPA”,$8d ; ; Routine to print a character on the current display. ; cc9e: bd 38 07 SCREENOUT lda MISCFLG,x cca1: 10 13 bpl NOOUT ;if screen disabled ; cca3: bd 38 07 SCREENOUT1 lda MISCFLG,x ;entry after echo check cca6: 29 02 and #$02 ;if it isn't CIC mode, cca8: f0 0d beq ASCREEN ;always use the Apple screen ccaa: bd b8 04 lda STATEFLG,x ;current screen = Apple screen? ccad: 29 38 and #$38 ccaf: f0 06 beq ASCREEN ;slot 0= Apple screen ; ccb1: 8a txa ;jump to CN00 space ccb2: 48 pha ccb3: a9 af lda #<SENDCD-1 ; to vector to the peripheral ccb5: 48 pha ; in the chain slot ccb6: 60 NOOUT rts ; ; Apple 40-col screen driver. ; ccb7: 20 df cc ASCREEN jsr GETXLATE ;get the translate options ccba: 09 80 ora #$80 ;set high bit of char ccbc: c9 e0 cmp #$e0 ;lowercase? ccbe: 90 06 bcc TESTLETTER ccc0: 59 d3 cc eor LCMASK,y ;do lowercase trip ccc3: 4c f6 fd TOSCREEN jmp MON_COUTZ ;all regs are preserved ; ; If uppercase, we only map letters. ; ccc6: c9 c1 TESTLETTER cmp #$c1 ;<A? ccc8: 90 f9 bcc TOSCREEN ccca: c9 db cmp #$db ;>Z? cccc: b0 f5 bcs TOSCREEN ccce: 59 d7 cc eor UCMASK,y ccd1: 90 f0 bcc TOSCREEN ;<always> ; ; Masks for case translation. ; ccd3: 20 00 e0 20 LCMASK .bulk $20,$00,$e0,$20 ccd7: 00 00 00 c0 UCMASK .bulk $00,$00,$00,$c0 ccdb: 00 00 e0 c0 REVMASK .bulk $00,$00,$e0,$c0 ccdf: bd b8 03 GETXLATE lda DELAYFLG,x ;translate options in B6-B7 cce2: 2a rol A cce3: 2a rol A cce4: 2a rol A cce5: 29 03 and #$03 cce7: a8 tay cce8: a5 27 lda CHARACTER ccea: 60 rts ; ; SSC command processor. ; ; Command table (used by command processer[sic] routine). ; cceb: 42 CMDTBL .dd1 $42 ;B(reak) ccec: 67 .dd1 $67 ;CIC PAS NS=7 cced: c0 .dd1 <BREAKCMD-1 ccee: 54 .dd1 $54 ;T(erminal) ccef: 47 .dd1 $47 ;CIC NS=7 ccf0: a6 .dd1 <TERMCMD-1 ccf1: 43 .dd1 $43 ;C(R generate) ccf2: 87 .dd1 $87 ; PPC NS=7 ccf3: a6 .dd1 <TERMCMD-1 ccf4: 51 .dd1 $51 ;Q(uit) ccf5: 47 .dd1 $47 ;CIC NS=7 ccf6: b8 .dd1 <QUITCMD-1 ccf7: 52 .dd1 $52 ;R(eset) ccf8: c7 .dd1 $c7 ;CIC PPC NS=7 ccf9: ac .dd1 <RESETCMD-1 ccfa: 5a .dd1 $5a ;Z command ccfb: e7 .dd1 $e7 ;CIC PPC PAS NS=7 ccfc: f3 .dd1 <ZCMD-1 ccfd: 49 .dd1 $49 ;I command ccfe: 90 .dd1 $90 ; PPC NS=0 ccff: d3 .dd1 <ICMD-1 cd00: 4b .dd1 $4b ;K command cd01: 90 .dd1 $90 ; PPC NS=0 cd02: df .dd1 <KCMD-1 ; cd03: 45 .dd1 $45 ;E(cho) cd04: 43 .dd1 $43 ;CIC NS=3 cd05: 80 .dd1 $80 cd06: 46 .dd1 $46 ;F(romkybd) cd07: e3 .dd1 $e3 ;CIC PPC PAS NS=3 cd08: 04 .dd1 $04 cd09: 4c .dd1 $4c ;L(F generate) cd0a: e3 .dd1 $e3 ;CIC PPC PAS NS=3 cd0b: 01 .dd1 $01 cd0c: 58 .dd1 $58 ;X(off) cd0d: e3 .dd1 $e3 ;CIC PPC PAS NS=3 cd0e: 08 .dd1 $08 cd0f: 54 .dd1 $54 ;T(abbing) cd10: 83 .dd1 $83 ; PPC NS=3 cd11: 40 .dd1 $40 cd12: 53 .dd1 $53 ;S(hifting) cd13: 43 .dd1 $43 ;CIC NS=3 cd14: 40 .dd1 $40 cd15: 4d .dd1 $4d ;M(unch LF) cd16: e3 .dd1 $e3 ;CIC PPC PAS NS=3 cd17: 20 .dd1 $20 ; cd18: 00 .dd1 $00 ;end of first part marker ; cd19: 42 CMDTBL1 .dd1 $42 ;B(aud) cd1a: f6 .dd1 $f6 ;CIC PPC PAS NS=6 cd1b: 7c .dd1 <BAUDCMD-1 cd1c: 50 .dd1 $50 ;P(arity) cd1d: f6 .dd1 $f6 ;CIC PPC PAS NS=6 cd1e: 9a .dd1 <PARITYCMD-1 cd1f: 44 .dd1 $44 ;D(ata) cd20: f6 .dd1 $f6 ;CIC PPC PAS NS=6 cd21: 9b .dd1 <DATACMD-1 cd22: 46 .dd1 $46 ;F(f delay) cd23: f6 .dd1 $f6 ;CIC PPC PAS NS=6 cd24: 46 .dd1 <FFCMD-1 cd25: 4c .dd1 $4c ;L(F delay) cd26: f6 .dd1 $f6 ;CIC PPC PAS NS=6 cd27: 40 .dd1 <LFCMD-1 cd28: 43 .dd1 $43 ;C(R delay) cd29: f6 .dd1 $f6 ;CIC PPC PAS NS=6 cd2a: 3a .dd1 <CRCMD-1 cd2b: 54 .dd1 $54 ;T(ranslate) cd2c: d6 .dd1 $d6 ;CIC PPC NS=6 cd2d: 34 .dd1 <TRANCMD-1 cd2e: 4e .dd1 $4e ;N command cd2f: 90 .dd1 $90 ; PPC NS=0 cd30: e8 .dd1 <NCMD-1 cd31: 53 .dd1 $53 ;S(creenslot) cd32: 56 .dd1 $56 ;CIC NS=6 cd33: 60 .dd1 <SSLOTCMD-1 ; cd34: 00 .dd1 $00 ;end of table marker ; ; Command routines (called by parser). (Must start in page $CD . . .) ; cd35: a9 3f TRANCMD lda #$3f ;set screen translate options cd37: a0 07 ldy #$07 cd39: d0 10 bne DELAYSET ;<always> cd3b: a9 cf CRCMD lda #$cf ;set CR delay cd3d: a0 05 ldy #$05 cd3f: d0 0a bne DELAYSET ;<always> cd41: a9 f3 LFCMD lda #$f3 ;set LF delay cd43: a0 03 ldy #$03 cd45: d0 04 bne DELAYSET ;<always> cd47: a9 fc FFCMD lda #$fc ;set FF delay cd49: a0 01 ldy #$01 cd4b: 3d b8 03 DELAYSET and DELAYFLG,x ;don't disturb the other flags cd4e: 85 2a sta ZPTMP1 cd50: bd 38 04 lda PARAMETER,x cd53: 29 03 and #$03 ;just use two bits cd55: 18 clc cd56: 6a ror A ;once for fun cd57: 2a ROTATE rol A ;change directions cd58: 88 dey cd59: d0 fc bne ROTATE ;prepare it to OR into the flags ; cd5b: 05 2a ora ZPTMP1 cd5d: 9d b8 03 sta DELAYFLG,x cd60: 60 rts cd61: 29 07 SSLOTCMD and #$07 ;set slot command cd63: 0a asl A cd64: 0a asl A cd65: 0a asl A cd66: 85 2a sta ZPTMP1 cd68: 0a asl A cd69: c5 26 cmp SLOT16 ;make sure we don't set it cd6b: f0 0f beq SSLOTCMD1 ; to our own slot cd6d: bd b8 04 lda STATEFLG,x cd70: 29 c7 and #$c7 ;put new slot number in bits 3-5 cd72: 05 2a ora ZPTMP1 ; of CMDBYTE,X cd74: 9d b8 04 sta STATEFLG,x cd77: a9 00 lda #0 ;store zero into cd79: 9d 38 06 sta CHNBYTE,x ;slot offset (set to CN00 entry) cd7c: 60 SSLOTCMD1 rts cd7d: 29 0f BAUDCMD and #$0f ;set new baud rate cd7f: d0 07 bne BAUDCMD2 cd81: b9 81 c0 BAUDCMD1 lda DIPSW1,y ;zero parm = reload from switches cd84: 4a lsr A cd85: 4a lsr A cd86: 4a lsr A cd87: 4a lsr A cd88: 09 10 BAUDCMD2 ora #$10 ;set int. baud rate generator cd8a: 85 2a sta ZPTMP1 cd8c: a9 e0 lda #$e0 cd8e: 85 2b CTLREGSET sta ZPTMP2 cd90: b9 8b c0 lda CTLREG,y cd93: 25 2b and ZPTMP2 cd95: 05 2a ora ZPTMP1 cd97: 99 8b c0 sta CTLREG,y cd9a: 60 rts cd9b: 88 PARITYCMD dey ;trick: so CTLREG,Y actually addresses the command reg ; cd9c: 0a DATACMD asl A ;set new # of data bits cd9d: 0a asl A cd9e: 0a asl A cd9f: 0a asl A cda0: 0a asl A cda1: 85 2a DATACMD1 sta ZPTMP1 cda3: a9 1f lda #$1f cda5: d0 e7 bne CTLREGSET ;<always> cda7: 1e b8 04 TERMCMD asl STATEFLG,x ;set terminal mode cdaa: 38 sec cdab: b0 10 bcs QCMD1 ;<always> cdad: 99 89 c0 RESETCMD sta RESET,y ;drop RTS, DTR cdb0: 20 93 fe jsr MON_SETVID ;PR#0 cdb3: 20 89 fe jsr MON_SETKBD ;IN#0 cdb6: ae f8 07 ldx MSLOT cdb9: 1e b8 04 QUITCMD asl STATEFLG,x ;clear terminal mode cdbc: 18 clc cdbd: 7e b8 04 QCMD1 ror STATEFLG,x cdc0: 60 rts cdc1: b9 8a c0 BREAKCMD lda CMDREG,y ;send break signal cdc4: 48 pha ; for 233 milliseconds cdc5: 09 0c ora #$0c cdc7: 99 8a c0 sta CMDREG,y cdca: a9 e9 lda #233 ;delay for 233 microsec.[sic] cdcc: 20 c4 ca jsr WAITMS cdcf: 68 pla ;restore old command reg contents cdd0: 99 8a c0 sta CMDREG,y cdd3: 60 rts cdd4: a9 28 ICMD lda #$28 cdd6: 9d 38 06 sta PWDBYTE,x ;set printer width to 40 cdd9: a9 80 lda #$80 cddb: 1d 38 07 ora MISCFLG,x ;set screen echo cdde: d0 05 bne KCMD2 ;<always> ; cde0: a9 fe KCMD lda #$fe ;reset the LF generate flag cde2: 3d 38 07 KCMD1 and MISCFLG,x cde5: 9d 38 07 KCMD2 sta MISCFLG,x cde8: 60 rts cde9: c9 28 NCMD cmp #40 ;>=40? cdeb: 90 0e bcc ZCMDRTS ;if not, just exit cded: 9d 38 06 sta PWDBYTE,x ;set new printer width cdf0: a9 3f lda #$3f ;disable screen, set listing mode cdf2: d0 ee bne KCMD1 ;<always> cdf4: 1e 38 05 ZCMD asl CMDBYTE,x ;disable command recognition cdf7: 38 sec cdf8: 7e 38 05 ror CMDBYTE,x cdfb: 60 ZCMDRTS rts ; ; Vector according to command state. ; cdfc: a8 CMDPROC tay ;A-reg=command state cdfd: a5 27 lda CHARACTER cdff: 29 7f and #$7f ; ce01: c9 20 cmp #$20 ;skip spaces for all modes ce03: d0 09 bne CMDPROC2 ce05: c0 03 cpy #$03 ;except mode 3 ce07: f0 01 beq CMDPROC1 ce09: 60 rts ce0a: a9 04 CMDPROC1 lda #$04 ce0c: d0 6d bne SETOSTATE ;<always> ce0e: c9 0d CMDPROC2 cmp #$0d ;carriage return? ce10: d0 12 bne CMDPROC4 ce12: 20 79 ce jsr ZEROSTATE ;abort for states 0-5, exit for 6,7 ce15: c0 07 cpy #$07 ;in state 7 we vector to the proc ce17: f0 01 beq CMDPROC3 ce19: 60 rts ;otherwise, just exit ce1a: a9 cd CMDPROC3 lda #$cd ;all procs must start in page $CD ce1c: 48 pha ce1d: bd 38 04 lda PARAMETER,x ce20: 48 pha ce21: a4 26 ldy SLOT16 ;needed by break cmd ce23: 60 rts ce24: 85 35 CMDPROC4 sta ZPTEMP ce26: a9 ce lda #$ce ;all routines must start ce28: 48 pha ; in page $CE ce29: b9 30 ce lda STATETBL,y ce2c: 48 pha ce2d: a5 35 lda ZPTEMP ce2f: 60 rts ;RTS to command procedure ; ; Now the state routines. ; ; State branch table. ; ce30: a7 STATETBL .dd1 <STATERR-1 ;bad state ce31: 37 .dd1 <CSTATE1-1 ;<cmd< seen ce32: 61 .dd1 <CSTATE2-1 ;accumulate parameter ce33: 89 .dd1 <CDONE-1 ;skip until space ce34: 8a .dd1 <CSTATE4-1 ;E/D something ce35: a7 .dd1 <STATERR-1 ;illegal state ce36: 89 .dd1 <CDONE-1 ;skip until CR ce37: 89 .dd1 <CDONE-1 ;skip until CR then do cmd ; ; Command state 1. ; ce38: dd 38 05 CSTATE1 cmp CMDBYTE,x ;is it <cmd>? ce3b: d0 06 bne CSTATE1A ce3d: de b8 04 dec STATEFLG,x ;set state back to zero ce40: 4c 02 cc jmp ACIAOUT ;output <cmd> if so ce43: c9 30 CSTATE1A cmp #$30 ;>=0? ce45: 90 0d bcc CSTATE1B ce47: c9 3a cmp #$3a ;<=9? ce49: b0 09 bcs CSTATE1B ce4b: 29 0f and #$0f ;it's a number ce4d: 9d 38 04 sta PARAMETER,x ce50: a9 02 lda #2 ce52: d0 27 bne SETOSTATE ;<always> set mode 2 and return ce54: c9 20 CSTATE1B cmp #$20 ;is it a control char? ce56: b0 06 bcs CSTATE1C ce58: 9d 38 05 sta CMDBYTE,x ;set new command character ce5b: 4c 79 ce jmp ZEROSTATE ;reset state to zero ce5e: a0 00 CSTATE1C ldy #$00 ;use command table ce60: f0 4d beq CMDSEARCH ;<always> ; ; Command state 2: accumulate parameter. ; ce62: 49 30 CSTATE2 eor #$30 ;convert $30-$39 to 0-9 ce64: c9 0a cmp #$0a ;0-9? ce66: b0 0d bcs CSTATE2A ce68: a0 0a ldy #$0a ;it's a number, so add ce6a: 7d 38 04 ACCLOOP adc PARAMETER,x ; it to 10*parameter ce6d: 88 dey ce6e: d0 fa bne ACCLOOP ce70: 9d 38 04 sta PARAMETER,x ce73: f0 15 beq CDONE ;<always> ce75: a0 2e CSTATE2A ldy #$2e ;use command table [LDY #CMDTBL1-CMDTBL] ce77: d0 36 bne CMDSEARCH ;<always> ; ; Set command state. ; ce79: a9 00 ZEROSTATE lda #0 ce7b: 85 2a SETOSTATE sta ZPTMP1 ce7d: ae f8 07 ldx MSLOT ce80: bd b8 04 lda STATEFLG,x ce83: 29 f8 and #$f8 ce85: 05 2a ora ZPTMP1 ce87: 9d b8 04 sta STATEFLG,x ce8a: 60 CDONE rts ; ; Command state 4 (E/D). ; ce8b: a8 CSTATE4 tay ;E/D -> Y-reg ce8c: bd 38 04 lda PARAMETER,x ce8f: c0 44 cpy #$44 ;D(isable)? ce91: f0 09 beq CSTATE4A ce93: c0 45 cpy #$45 ;E(nable)? ce95: d0 11 bne STATERR ;if not, ignore this command ce97: 1d 38 07 ora MISCFLG,x ;set flag ce9a: d0 05 bne CSTATE4B ;<always> ce9c: 49 ff CSTATE4A eor #$ff ;invert for disable ce9e: 3d 38 07 and MISCFLG,x ;reset flag cea1: 9d 38 07 CSTATE4B sta MISCFLG,x ; ; Escape to state 6. ; cea4: a9 06 SETSTATE6 lda #6 cea6: d0 d3 bne SETOSTATE ;<always> cea8: a9 20 STATERR lda #32 ;code for bad command ceaa: 9d b8 05 sta STSBYTE,x cead: d0 f5 bne SETSTATE6 ;<always> ; ; Table driven command processor. ; ceaf: b9 eb cc CMDSEARCH lda CMDTBL,y ;get candidate character ceb2: f0 f4 beq STATERR ;a zero marks the end of a subtable ceb4: c5 35 cmp ZPTEMP ;match? ceb6: f0 05 beq CMDMATCH ceb8: c8 iny ceb9: c8 CMDSEARCH1 iny ;reentry for wrong modes ceba: c8 iny ;entry length = 3 cebb: d0 f2 bne CMDSEARCH ;<always> cebd: c8 CMDMATCH iny cebe: b9 eb cc lda CMDTBL,y cec1: 85 2a sta ZPTMP1 cec3: 29 20 and #$20 ;check Pascal enable cec5: d0 07 bne CMDMATCH1 ;it's on so don't check P-bit cec7: bd 38 07 lda MISCFLG,x ;off so make sure ceca: 29 10 and #$10 ; that we aren't in Pascal cecc: d0 eb bne CMDSEARCH1 ;branch if we are ; cece: bd 38 07 CMDMATCH1 lda MISCFLG,x ;get CIC/PPC bit ced1: 4a lsr A ;shift CIC/PPC mode bit to carry ced2: 4a lsr A ced3: 24 2a bit ZPTMP1 ;PPC->N CIC->V ced5: b0 04 bcs CMDMATCH2 ;branch if CIC mode ced7: 10 e0 bpl CMDSEARCH1 ;not OK for PPC ced9: 30 02 bmi CMDEXEC ;and OK cedb: 50 dc CMDMATCH2 bvc CMDSEARCH1 ;not OK for CIC ; cedd: a5 2a CMDEXEC lda ZPTMP1 ;retrieve table mode byte cedf: 48 pha cee0: 29 07 and #$07 cee2: 20 7b ce jsr SETOSTATE ;set next state cee5: c8 iny cee6: 68 pla cee7: 29 10 and #$10 cee9: d0 07 bne CMDEXEC1 ;if bit 4 is set, vector to routine ceeb: b9 eb cc lda CMDTBL,y ceee: 9d 38 04 sta PARAMETER,x cef1: 60 rts cef2: a9 cd CMDEXEC1 lda #$cd ;routines must be in page $CD cef4: 48 pha cef5: b9 eb cc lda CMDTBL,y cef8: 48 pha cef9: a4 26 ldy SLOT16 cefb: bd 38 04 lda PARAMETER,x ;lot of routines need this cefe: 60 rts ceff: c2 .dd1 $c2 ;[DFB $00 in original; checksum byte?] .org $c200 ******************************************************************************** * * * CN00 space code * * * * [Serial cards are installed in slot 2 by convention, so this is disassembled * * at $C200. The original listing showed this at $C700.] * * * ******************************************************************************** c200: 2c 58 ff BINIT bit MON_IORTS ;set the V-flag c203: 70 0c bvs BENTRY ;<always> c205: 38 IENTRY sec ;BASIC input entry c206: 90 bcc ▼ LC21E+2 ;opcode for BCC c207: 18 OENTRY clc ;BASIC output entry c208: b8 clv c209: 50 06 bvc BENTRY ;<always> skip around Pascal 1.1 entry c20b: 01 .dd1 $01 ;generic signature byte c20c: 31 .dd1 $31 ;device signature byte c20d: 8e .dd1 <PINIT c20e: 94 .dd1 <PREAD c20f: 97 .dd1 <PWRITE c210: 9a .dd1 <PSTATUS c211: 85 27 BENTRY sta CHARACTER c213: 86 35 stx ZPTEMP ;input buffer index c215: 8a txa ;save X and Y regs on stack c216: 48 pha c217: 98 tya c218: 48 pha c219: 08 php ;save entry flags c21a: 78 sei ;no rupts during slot determination c21b: 8d ff cf sta CLRROM ;switch out other $C800 ROMs c21e: 20 58 ff LC21E jsr MON_IORTS c221: ba tsx c222: bd 00 01 lda STACK,x ;recover $CN c225: 8d f8 07 sta MSLOT c228: aa tax ;X-reg will generally be $CN c229: 0a asl A c22a: 0a asl A ;determine $NO c22b: 0a asl A c22c: 0a asl A c22d: 85 26 sta SLOT16 c22f: a8 tay ;Y-reg will generally be $NO c230: 28 plp ;restore rupts c231: 50 29 bvc NORMIO ; ; BASIC initialization. ; c233: 1e 38 05 asl CMDBYTE,x ;always enable commands c236: 5e 38 05 lsr CMDBYTE,x c239: b9 8a c0 lda CMDREG,y ;just had a power-on or program reset? c23c: 29 1f and #$1f c23e: d0 05 bne BINIT1 c240: a9 ef lda #$ef ;if so, go join init in progress c242: 20 05 c8 jsr INIT1 ; c245: e4 37 BINIT1 cpx MON_CSWH c247: d0 0b bne FROMIN c249: a9 07 lda #<OENTRY c24b: c5 36 cmp MON_CSWL ;if CSW is already pointing to OENTRY, c24d: f0 05 beq FROMIN ; then we must have come from KSW c24f: 85 36 sta MON_CSWL ;otherwise, set CSW to OENTRY c251: 18 FROMOUT clc ;indicate we are called for output c252: 90 08 bcc NORMIO ;<always> c254: e4 39 FROMIN cpx MON_KSWH ;make sure KSW points here c256: d0 f9 bne FROMOUT c258: a9 05 lda #$05 c25a: 85 38 sta MON_KSWL ;set up KSW (note carry set from CPX) ; ; Branch to appropriate BASIC I/O routine. ; c25c: bd 38 07 NORMIO lda MISCFLG,x ;separate CIC mode from others c25f: 29 02 and #$02 ;not zero for CIC mode c261: 08 php ;save CIC mode indication c262: 90 03 bcc BOUTPUT c264: 4c bf c8 jmp BINPUT c267: bd b8 04 BOUTPUT lda STATEFLG,x ;check for after lowercase input c26a: 48 pha c26b: 0a asl A c26c: 10 0e bpl BOUTPUT1 ;skip if not c26e: a6 35 ldx ZPTEMP c270: a5 27 lda CHARACTER c272: 09 20 ora #$20 c274: 9d 00 02 sta INBUFF,x ;restore lowercase in buffer c277: 85 27 sta CHARACTER ;and for output echo c279: ae f8 07 ldx MSLOT c27c: 68 BOUTPUT1 pla c27d: 29 bf and #$bf ;zero the flag c27f: 9d b8 04 sta STATEFLG,x c282: 28 plp ;retrieve CIC mode indication c283: f0 06 beq BOUTPUT2 ;branch for PPC, SIC modes c285: 20 63 cb jsr OUTPUT ;CIC mode output c288: 4c b5 c8 jmp CICEXIT ;finish by checking for term mode c28b: 4c fc c8 BOUTPUT2 jmp SEROUT ******************************************************************************** * * * New Pascal interface entries. * * * ******************************************************************************** c28e: 20 00 c8 PINIT jsr PASCALINIT c291: a2 00 ldx #0 ;no error possible c293: 60 rts c294: 4c 9b c8 PREAD jmp PASCALREAD c297: 4c aa c9 PWRITE jmp PASCALWRITE ; ; New Pascal status request. ; ; A-reg=0 -> ready for output? ; A-reg=1 -> has input been received? ; c29a: 4a PSTATUS lsr A ;save request type in carry c29b: 20 9b c9 jsr PENTRY ;(preserves carry) c29e: b0 08 bcs PSTATIN c2a0: 20 f5 ca jsr SROUT ;ready for output? c2a3: f0 06 beq PSTATUS2 c2a5: 18 clc c2a6: 90 03 bcc PSTATUS2 ;carry clear for not ready c2a8: 20 d2 ca PSTATIN jsr SRIN ;sets carry correctly c2ab: bd b8 05 PSTATUS2 lda STSBYTE,x ;get error flags c2ae: aa tax c2af: 60 rts ; ; Routine to send a character to another card. ; c2b0: a2 03 SENDCD ldx #3 c2b2: b5 36 SAVEHOOK lda MON_CSWL,x c2b4: 48 pha c2b5: ca dex c2b6: 10 fa bpl SAVEHOOK ; ; Now put card address in hook. ; c2b8: ae f8 07 ldx MSLOT c2bb: bd 38 06 lda PWDBYTE,x c2be: 85 36 sta MON_CSWL c2c0: bd b8 04 lda STATEFLG,x ;get slot # c2c3: 29 38 and #$38 c2c5: 4a lsr A c2c6: 4a lsr A c2c7: 4a lsr A c2c8: 09 c0 ora #$c0 ;form $CN c2ca: 85 37 sta MON_CSWH ; ; Output to the peripheral. ; c2cc: 8a txa ;save $CN c2cd: 48 pha c2ce: a5 27 lda CHARACTER c2d0: 48 pha c2d1: 09 80 ora #$80 ;80 col boards want hi-bit on c2d3: 20 ed fd jsr MON_COUT ; ; Now restore everything the other card may have clobbered. ; c2d6: 68 pla c2d7: 85 27 sta CHARACTER c2d9: 68 pla c2da: 8d f8 07 sta MSLOT c2dd: aa tax c2de: 0a asl A c2df: 0a asl A c2e0: 0a asl A c2e1: 0a asl A c2e2: 85 26 sta SLOT16 c2e4: 8d ff cf sta CLRROM ; ; Put back CSWL into CHNBYTE. ; c2e7: a5 36 lda MON_CSWL c2e9: 9d 38 06 sta PWDBYTE,x ; c2ec: a2 00 ldx #0 c2ee: 68 RESTORHOOK pla c2ef: 95 36 sta MON_CSWL,x c2f1: e8 inx c2f2: e0 04 cpx #4 c2f4: 90 f8 bcc RESTORHOOK c2f6: ae f8 07 ldx MSLOT c2f9: 60 rts ; c2fa: c1 d0 d0 cc+ .str “APPLE” c2ff: 08 .dd1 $08