; RECEIVE ; ; Nick Kennedy ; ; 11/15/86 ; ; This program is intended to receive ; and run binary files via the serial ; input port. ; ; This part of the program creates ; the cassette boot file. ; IF [RECORD-START+1] MOD 128 NORECS: EQU [RECORD-START+1]/128 + 1 ELSE NORECS: EQU [RECORD-START+1]/128 ENDIF ; ORG $4000 ; PROC CASFN: DB 'C:', $9B RUNCS: LDX #$40 ; IOCB #4 LDA #3 ; Open STA ICCOM,X LDA #HIGH CASFN STA ICBAH,X LDA #LOW CASFN STA ICBAL,X LDA #8 STA ICAX1,X LDA #%10000000; Short IR gaps STA ICAX2,X JSR CIOV BPL :OK1 STY $600 RTS ; ; Now, put the entire file: ; :OK1: LDX #$40 LDA #$B STA ICCOM,X LDA #HIGH STRT STA ICBAH,X LDA #LOW STRT STA ICBAL,X LDA #HIGH [RECORD-START+1] STA ICBLH,X LDA #LOW [RECORD-START+1] STA ICBLL,X JSR CIOV BPL :OK2 STY $600 RTS ; :OK2: LDA #$C ; Close IOCB STA ICCOM,X JSR CIOV BPL :OK3 STY $601 ; :OK3: RTS ; Back to DOS ; EPROC ; ; System Equates: IRQST: EQU $D20E B600LO EQU $CC ; for 600 baud B600HI EQU $05 B192LO EQU $28 ; for 19.2K baud B192HI EQU $0 SERIN: EQU $D20D ; Data in register. SEROUT: EQU $D20D ; Outgoing data here IRQEN EQU $D20E ; IRQ enable. 0=disable, 1=enable. Bit 5 is serial input. ; POKMSK EQU $10 ; Shadow for above. SKCTL: EQU $D20F SSKCTL: EQU $232 ; Shadow for above SKSTAT: EQU $D20F ; Serial port stat. SKRES: EQU $D20A; Write resets above AUDCTL EQU $D208 VSERIN EQU $20A; Serial input vector VSEROR: EQU $20C ; Serial out ready. VSEROC: EQU $20E ; Transmission cpt. AUDF1: EQU $D200 AUDF2: EQU $D202 AUDF3: EQU $D204 AUDF4: EQU $D206 AUDC1: EQU $D201 AUDC2: EQU $D203 AUDC3: EQU $D205 AUDC4: EQU $D207 CH: EQU $2FC ; Keyboard code here CIOV: EQU $E456 ICCOM: EQU $342 ICBAL: EQU $344 ICBAH: EQU $345 ICBLL: EQU $348 ICBLH: EQU $349 ICAX1: EQU $34A ICAX2: EQU $34B RTCLOK: EQU $14 BEEP: EQU $FD CONSOL: EQU $D01F ZLOAD: EQU $CB ; Z-page pointer L=2 ; STRT: LOC $700 ; Cassette start ; ; Put Cassette header bytes: ; LDADR: DB $FF, LOW NORECS, LOW LDADR, HIGH LDADR, LOW INIT1, HIGH INIT1 ; ; Refer. to OS manual pg 166 and ; De Re Atari pg c-7/8: ; START: LDA #$3C ; Off motor STA $D302 ; (PACTL) LDA #LOW [RECORD+1] STA $237 ; (MEMLO) STA $E ; (APPMHI) LDA #HIGH [RECORD+1] STA $238 STA $F LDA #LOW INIT STA $A ; (DOSVEC) LDA #HIGH INIT STA $B ; (DOSVEC) CLC ; indicate boot success RTS ; End of init. INIT1: RTS ; No boot continuation. ENDL: DS 1 ENDH: DS 1 PLACE: DS 1 TIMER: DS 1 ; My timeout timer FLAG: DS 1 ; TVECT: DS 2 ; Place for VSEROR SIRF: DS 1 ; Serial input rdy flag SORF: DS 1 ; Output ready flag TCF: DS 1 ; Transmission cpt flag ; ; STRINGS: IMHR: DB 'I VE MADE IT THIS FAR!', $9B KYBD: DB 'K:' PMPT1: DB 'Input Filespec. Example: D2:FILE',$9B BSTMSG: DB 'Bad status on opening file.', $9B NTLF: DB 'Header error - not a load file.', $9B MSFRE: DB 'Data input frame error', $9B SBOR: DB 'Serial input over-run', $9B ; ; ; INITIALIZE ; INIT: LDA #0 ; Clear Run/Init adr. STA $2E0 STA $2E1 STA $2E2 STA $2E3 JSR OPENK LDA #$9B JSR PUTBYT LDA #$9B JSR PUTBYT PRINTS PMPT1 LDA #$9B JSR PUTBYT ; ; Stash cursor position: ; LDA $54 PHA LDA $55 PHA LDA $56 PHA GETRK: JSR GETK CMP #$9B BEQ GREC JSR PUTBYT JMP GETRK GREC: PLA STA $56 PLA STA $55 PLA STA $54 LDA #$1F ; CURSOR right JSR PUTBYT LDA #$1E ; left JSR PUTBYT LDA #13 STA ICAX1 ; Forced read LDA #HIGH RECORD STA ICBAH LDA #LOW RECORD STA ICBAL JSR GETREC ; Get filename. PRINTS RECORD ; Echo it. LDA #12 STA ICAX1 JSR CLOSK ; Close #1. ; ; Set AUDCTL for 1.79 Mhz. into ch 3 ; and ch 3 into ch 4: ; LDA #%00101000 STA AUDCTL ; ; Set baud rate ; LDA #B192LO STA AUDF3 LDA #B192HI STA AUDF4 ; ; LDA #$A0 ; Off Sound 1,2,3 STA AUDC1 STA AUDC2 STA AUDC3 LDA #$A8 ; On, channel 4 STA AUDC4 ; ; Set the interrupt vectors: ; SEI LDA #HIGH TINT STA VSEROR+1 LDA #LOW TINT STA VSEROR LDA #HIGH RINT STA VSERIN+1 LDA #LOW RINT STA VSERIN LDA #HIGH TCINT STA VSEROC+1 LDA #LOW TCINT STA VSEROC CLI ; ; Initialize transmission done ; flag & input ready flag. ; LDA #0 STA TCF LDA #$FF STA SIRF ; ; Send the filespec to the other 800: ; PROC JSR TINIT LDY #0 :LOOP: LDA RECORD,Y ; Get byte JSR TLOOP ; Send it LDA RECORD,Y ; again to check CMP #$9B ; For EOL BEQ :DUN INY ; Next byte BNE :LOOP ; Forced branch ; ; Get ready to receive acknowledge: ; :DUN: JSR RINIT JSR RLOOP ; Get status BNE :GOOD PRINTS BSTMSG JMP INIT :GOOD: JSR RLOOP ; check header byts CMP #$FF BNE :BADHD JSR RLOOP CMP #$FF BEQ :GDHD :BADHD: PRINTS NTLF ; Not load file JMP INIT :GDHD: JSR RLOOP ; Get load address STA LOAD+1 STA $605 ;********** STA $607 JSR RLOOP STA LOAD+2 STA $606 ;*********** STA $608 JSR RLOOP ; Get end address STA ENDL JSR RLOOP STA ENDH :RBYTE: LDY #0 ; Dummy index. JSR RLOOP ; Get file byte. LOAD: STA RECORD ; (Dummy address) LDA LOAD+2 CMP ENDH BNE :NOTEQ LDA LOAD+1 CMP ENDL BNE :NOTEQ JMP :SEGDUN ; Segment done :NOTEQ: INC LOAD+1 ; Increment load INC $607;************** BNE :RBYTE ; address. INC LOAD+2 INC $608 ;************** JMP :RBYTE :SEGDUN LDA $2E2 ; Check init adr. BNE :INIT ; No init if = 0. LDA $2E3 BEQ :RDY :INIT: LDA $2E2 ; (:INIT, not INIT) STA :GO+1 ; Set up JSR adr LDA $2E3 STA :GO+2 :GO: JSR HELL ; HELL is dummy ADR. :RDY: JSR JIF2 ; Stall 2 jiffies JSR TINIT JSR TLOOP ; Send any byte. JSR RINIT JSR RLOOP ; EOF? BEQ :RUN ; Yes JMP :GDHD ; :RUN: LDA #%11000111 AND POKMSK ; Disable serial STA POKMSK ; bus IRQ's. STA IRQEN LDA $2E0 BNE :DORUN LDA $2E1 BNE :DORUN :RUNN: JSR HECK ; HECK is a dummy :DORUN: LDA $2E0 ; if there's a run STA :RUNN+1 ; address, else LDA $2E1 ; we restart. STA :RUNN+2 JMP :RUNN RTS ; In case it comes back EPROC ; RINIT: JSR JIF2 ; in case TCF fails. LDA TCF ; output complete? BNE RINIT ; No, wait. LDA #0 STA SKCTL ; Init. POKEY LDA #$13 STA SSKCTL STA SKCTL ; ; Set the serial input IRQ vector to ; my service routine: ; SEI LDA #%00100000 ORA POKMSK ; Enable input AND #%11100111;Disable output STA POKMSK ; and trans. cpt STA IRQEN CLI STA SKRES ; Reset status flgs RTS ; ; The program idles here while waiting for a SERIN interrupt: ; RLOOP: BIT SKSTAT ; Frame error? BMI GDSTM PRINTS MSFRE ; Yes PLA PLA JMP INIT GDSTM: BIT SKSTAT ; Over-run? BVS GDSTAT PRINTS SBOR ; Yes PLA PLA JMP INIT GDSTAT: BIT SIRF ; Serial in ready? BMI RLOOP ; No LDA #$FF STA SIRF LDA SERIN ; Yes, read byte. RTS ; ; JIF2: Stall 2 jiffies waiting to ; be sure the other guy gets into ; receive mode. ; JIF2: LDA RTCLOK STA PLACE INC PLACE INC PLACE JIF2A: LDA RTCLOK CMP PLACE BNE JIF2A RTS ; JIF10: LDA RTCLOK ; waste 10/60 sec. ADC #$A STA PLACE JIF10A: LDA RTCLOK CMP PLACE BNE JIF10A RTS ; ; Subroutine to put record to E: ; (Have ICBAH/L loaded before entry) ; (Use MACRO PRINTS) ; PUTREC: LDA #$80 STA ICBLL LDX #0 STX ICBLH LDA #9 ; Put record. STA ICCOM JSR CIOV RTS ; ; Subroutine to get a record from #0 ; User set ICBAL/H. ; GETREC: LDX #0 LDA #5 STA ICCOM LDA #$80 STA ICBLL STX ICBLH JSR CIOV STY $600 RTS ; ; ; Subroutine to put byte to E: ; (Have byte in accumulator on entry) ; PUTBYT: LDX #$B ; Put byte STX ICCOM LDX #0 STX ICBLH STX ICBLL JSR CIOV RTS ; ; TRANSMIT section follows: ; TINIT: JSR JIF10 LDA #0 STA SKCTL ; init POKEY STA SORF ; Output ready flag LDA #$23 ; KYBD scan and STA SSKCTL ; debounce on and STA SKCTL; bit 5 mode. ; ; Enable interrupts: ; SEI LDA #%00010000 ;Send ready on ORA POKMSK AND #%11011111 ; Receive off. STA POKMSK STA IRQEN CLI RTS ; ; Transmit loop follows: ; TLOOP: PHA ; Save data LDA RTCLOK ; set up time out SBC #$A ; 10 jiffies limit STA PLACE TLOOP1: LDA RTCLOK CMP PLACE ; Timed out? BNE TLOOP2 ; No. PRINTS TLPTO ; Yes PLA ; Clean off return adr PLA PLA ; And data JMP INIT ; Start over TLOOP2: LDA SORF ; Ser. out ready? BMI TLOOP1 ; No. PLA ; Get data back STA SEROUT; Yes, send byte. LDA #$FF ; Not rdy flag. STA SORF STA TCF ; Trans. not cpt. SEI LDA #%00001000; Enable IRQ ORA POKMSK ; for trans. cpt. STA POKMSK STA IRQEN CLI RTS ; ; A routine to get one byte from ; IOCB #0 (assumed to be E:): ; GETBYT: LDX #0 STX ICBLL STX ICBLH LDA #7 STA ICCOM ; Get bytes. JSR CIOV RTS ; ; Transmit interrupt routine: ; TINT: CLI LDA #0 STA SORF ; Output rdy flag STA CONSOL ;**************** PLA RTI ; ; Receive interrupt routine: ; RINT: CLI LDA #0 STA SIRF PLA RTI ; ; Output transmission cpt routine: ; TCINT: SEI ; in case not already LDA #0 ; Output is complete. STA TCF LDA #%11110111 ; Off with IRQ AND POKMSK ; for trans. cpt. STA POKMSK STA IRQEN PLA CLI RTI ; ; ; OPEN KEYBOARD, IOCB #1 ; OPENK: LDX #$10 LDA #3 STA ICCOM,X LDA #4 ; Read STA ICAX1,X LDA #HIGH KYBD STA ICBAH,X LDA #LOW KYBD STA ICBAL,X JSR CIOV RTS CLOSK: LDX #$10 ; Close it. LDA #$C STA ICCOM,X JSR CIOV RTS ; GETK: LDX #$10 ; Get one byte from LDA #$7 ; keyboard. STA ICCOM,X LDA #0 STA ICBLL,X STA ICBLH,X JSR CIOV RTS HELL: PRINTS NOINI ; INIT =0 PLA ; We shouldn't be here. PLA JMP INIT HECK: PRINTS RUNZRO ; RUN = 0 PLA ; We shouldn't be here PLA JMP INIT NOINI: DB 'Went to INIT with INIT=0; ERROR!', $9B RUNZRO DB 'Went to RUN but RUN = 0; ERROR!', $9B TLPTO: DB 'TIMED OUT IN TLOOP!', $9B ; ; RECORD is where I input my filename ; It takes no file space cause it's ; at the end ; OEND: EQU *O RECORD: END RUNCS ;