.macro CLI ANDCC #$EF .endm .macro SEI ORCC #$10 .endm OIE EQU $0000 ; missing from source code below ; ; Title: Simple interrupt input and output using a ; 6850 ACIA and single character buffers. ; ; Name: SINTIO ; ; Purpose: ; ; This program consists of 5 subroutines that ; perform interrupt driven input and output using ; a 6850 ACIA. ; ; INCH ; Read a character. ; INST ; Determine input status ; (whether input buffer is empty). ; OUTCH ; Write a character. ; OUTST ; Determine output status ; (whether output buffer is full). ; INIT ; Initialize. ; Entry: ; ; INCH ; No parameters. ; INST ; No parameters. ; OUTCH ; Register A = character to transmit ; OUTST ; No parameters. ; INIT ; No parameters. ; Exit: ; INCH ; Register A = character. ; INST ; Registers used: ; Carry = 0 if input buffer is empty, ; 1 if character is available. ; OUTCH ; No parameters ; OUTST ; Carry = 0 if output buffer is empty, ; 1 if it is full. ; INIT ; No parameters. ; INCH ; A,CC ; INST ; A,CC ; OUTCH ; A,CC OUTST ; A,CC ; INIT ; A ; ; Time: ; ; INCH ; 40 cycles if a character is available ; INST ; 12 cycles ; OUTCH ; 87 cycles if output buffer is empty and ; the ACIA is ready to transmit ; OUTST ; 12 cycles ; INIT ; 76 cycles ; IOSRVC ; 42 cycles minimum if the interrupt is not ours ; 63 cycles to service an input interrupt ; 99 cycles to service an output interrupt ; These include the time required for the ; processor to respond to an interrupt ; (21 cycles). ; ; Size: ; ; Program 144 bytes ; Data 6 bytes ; ; ARBITRARY 6850 ACIA MEMORY ADDRESSES ; ACIADR EQU $A000 ; ACIA DATA REGISTER ACIACR EQU $A001 ; ACIA CONTROL REGISTER ACIASR EQU $A001 ; ACIA STATUS REGISTER ; ; TRS-80 COLOR COMPUTER INTERRUPT VECTOR ; INTVEC EQU $0100 ; VECTOR TO INTERRUPT ; SERVICE ROUTINE ; ; READ A CHARACTER FROM INPUT BUFFER ; INCH: JSR INST ; GET INPUT STATUS BCC INCH ; HALT IF NO CHARACTER AVAILABLE CLR RECDF ; INDICATE INPUT BUFFER EMPTY LDA RECDAT ; GET CHARACTER FROM INPUT BUFFER RTS ; DETERMINE INPUT STATUS ; (CARRY = 1 IF DATA AVAILABLE) ; INST: LDA RECDF ; GET DATA READY FLAG LSRA ; SET CARRY FROM DATA READY FLAG ; CARRY = 1 IF CHARACTER AVAILABLE RTS ; ; WRITE A CHARACTER INTO OUTPUT BUFFER AND THEN ON TO ACIA ; ; OUTCH: PSHS A ; SAVE CHARACTER TO WRITE ; WAIT FOR OUTPUT BUFFER TO EMPTY, STORE NEXT CHARACTER WAITOC: JSR OUTST ; GET OUTPUT STATUS BCS WAITOC ; WAIT IF OUTPUT BUFFER FULL PULS A ; GET CHARACTER STA TRNDAT ; STORE CHARACTER IN BUFFER LDA #$FF ; INDICATE BUFFER FULL STA TRNDF JSR OUTDAT ; SEND CHARACTER TO PORT RTS ; ; DETERMINE OUTPUT STATUS (CARRY = 1 IF OUTPUT BUFFER FULL) ; OUTST: LDA TRNDF ; GET TRANSMIT FLAG LSRA SET CARRY FROM TRANSMIT FLAG RTS ; CARRY = 1 IF BUFFER FULL ; ; INITIALIZE INTERRUPT SYSTEM AND 6850 ACIA ; INIT: ; ; DISABLE INTERRUPTS DURING INITIALIZATION BUT SAVE ; PREVIOUS STATE OF INTERRUPT FLAG ; PSHS CC ; SAVE CURRENT FLAGS (PARTICULARLY I FLAG) SEI ; DISABLE INTERRUPTS DURING ; INITIALIZATION ; ; INITIALIZE COLOR COMPUTER INTERRUPT VECTOR ; LDX INTVEC ; GET CURRENT INTERRUPT VECTOR STX NEXTSR ; SAVE IT AS ADDRESS OF NEXT SERVICE ; ROUTINE LDX #IOSRVC ; GET ADDRESS OF OUR SERVICE ROUTINE STX INTVEC ; SAVE IT AS INTERRUPT VECTOR ; ; INITIALIZE SOFTWARE FLAGS ; CLR RECDF ; NO INPUT DATA AVAILABLE CLR TRNDF ; OUTPUT BUFFER EMPTY CLR OIE ; INDICATE NO OUTPUT INTERRUPT NEEDED ; ; 6850 READY TO TRANSMIT INITIALLY ; ; INITIALIZE 6850 ACIA (UART) ; LDA #00000011b ; MASTER RESET ACIA (IT HAS NO RESET INPUT). STA ACIACR LDA #10010001b ; INITIALIZE ACIA MODE ; BIT 7 = 1 T0 ENABLE INPUT INTERRUPTS ; BITS 6,5 = 0 TO DISABLE OUTPUT INTERRUPTS ; BITS 4,3,2 = 100 FOR 8 DATA BITS, 2 STOP ; BITS ; BITS 1,0 = O1 FOR DIVIDE BY 16 CLOCK STA ACIACR PULS CC ; RESTORE FLAGS (THIS REENABLES INTERRUPTS ; IF THEY HERE ENABLED WHEN INIT WAS ; CALLED) RTS ; GENERAL INTERRUPT HANDLER ; IOSRVC: ; ; GET ACIA STATUS: BIT 0 = 1 IF AN INPUT INTERRUPT, ; BIT 1 = 1 IF AN OUTPUT INTERRUPT ; LDA ACIASR ; GET ACIA STATUS LSRA ; EXAMINE BIT 0 BCS RDHDLR ; BRANCH IF AN INPUT INTERRUPT LSRA ; EXAMINE BIT 1 BCS WRHDLR ; BRANCH IF AN OUTPUT INTERRUPT JMP [NEXTSR] ; NOT THIS ACIA, EXAMINE NEXT INTERRUPT ; ; INPUT (READ) INTERRUPT HANDLER ; RDHDLR: LDA ACIADR ; LOAD DATA FROM 6850 ACIA STA RECDAT ; SAVE DATA IN INPUT BUFFER LDA #$FF STA RECDF ; INDICATE INPUT DATA AVAILABLE RTI ; ; OUTPUT (WRITE) INTERRUPT HANDLER ; WRHDLR: LDA TRNDF ; TEST DATA AVAILABLE FLAG BEQ NODATA ; JUMP IF N0 DATA TO TRANSMIT JSR OUTDT1 ; ELSE SEND DATA T0 6850 ACIA BRA WRDONE ; (NO NEED TO TEST STATUS) ; ; IF AN OUTPUT INTERRUPT OCCURS HHEN NO DATA IS AVAILABLE, ; WE MUST DISABLE IT (IN THE 6850) TO AVOID AN ENDLESS LOOP. ; LATER, WHEN A CHARACTER BECOMES AVAILABLE, WE CALL THE OUTPUT ; ROUTINE OUTDAT WHICH MUST TEST ACIA STATUS BEFORE SENDING THE DATA. ; THE OUTPUT ROUTINE MUST ALSO REENABLE THE OUTPUT INTERRUPT AFTER ; SENDING THE DATA. THIS PROCEDURE OVERCOMES THE PROBLEM OF AN ; UNSERVICED OUTPUT INTERRUPT ASSERTING ITSELF REPEATEDLY, WHILE ; STILL ENSURING THAT OUTPUT INTERRUPTS ARE RECOGNIZED AND THAT ; DATA IS NEVER SENT TO AN ACIA THAT IS NOT READY FOR IT. ; THE PROBLEM IS THAT AN OUTPUT DEVICE MAY REQUEST SERVICE BEFORE ; THE COMPUTER HAS ANYTHING T0 SEND (UNLIKE AN INPUT DEVICE THAT ; HAS DATA WHEN IT REQUESTS SERVICE). ; NODATA: LDA #10010001b ; ESTABLISH ACIA OPERATING MODE ; WITH OUTPUT INTERRUPTS DISABLED STA ACIACR WRDONE: RTI ; ;*************************************** ; ROUTINE: OUTDAT, OUTDT1 (OUTDAT IS NON-INTERRUPT DRIVEN ENTRY POINT) ; PURPOSE: SEND A CHARACTER TO THE ACIA ; ENTRY: TRNDAT = CHARACTER T0 SEND ; EXIT: NONE ; REGISTERS USED: A,CC ;**************************************** ; OUTDAT: LDA ACIASR ; CAME HERE WITH INTERRUPTS DISABLED ANDA #00000010b ; TEST WHETHER ACIA OUTPUT REGISTER EMPTY BEQ OUTDAT ; BRANCH (WAIT) IF IT IS NOT EMPTY OUTDT1: LDA TRNDAT ; GET THE CHARACTER STA ACIADR ; SEND CHARACTER TO ACIA CLR TRNDF ; INDICATE OUTPUT BUFFER EMPTY LDA #10110001b ; ESTABLISH ACIA OPERATING MODE WITH STA ACIACR ; OUTPUT INTERRUPTS ENABLED RTS ; ; DATA SECTION 1 ; RECDAT RMB 1 ; RECEIVE DATA RECDF RMB 1 ; RECEIVE DATA FLAG ; ; (0 = N0 DATA, FF = DATA AVAILABLE) ; TRNDAT RMB 1 ; TRANSMIT DATA TRNDF RMB 1 ; TRANSMIT DATA FLAG ; (0 = BUFFER EMPTY, FF = BUFFER FULL) NEXTSR RMB 2 ; ADDRESS OF NEXT INTERRUPT SERVICE ; ROUTINE ; ; SAMPLE EXECUTION: ; CHARACTER EQUATES ; ESCAPE EQU $1B ; ASCII ESCAPE CHARACTER TESTCH EQU 'A' ; TEST CHARACTER = A SC9A: JSR INIT ; INITIALIZE 6850 ACIA, INTERRUPT SYSTEM CLI ; ENABLE INTERRUPTS ; ; SIMPLE EXAMPLE, READ AND ECHO CHARACTERS ; UNTIL AN ESC IS RECEIVED ; LOOP: JSR INCH ; READ CHARACTER PSHS A JSR OUTCH ; ECHO CHARACTER PULS A CMPA #ESCAPE ; IS CHARACTER AN ESCAPE? BNE LOOP ; STAY IN LOOP IF NOT ; ; AN ASYNCHRONOUS EXAMPLE ; OUTPUT "A" TO CONSOLE CONTINUOUSLY BUT ALSO LOOK AT ; INPUT SIDE, READING AND ECHOING ANY INPUT CHARACTERS. ; ASYNLP: ; ; OUTPUT AN "A" IF OUTPUT IS NOT BUSY ; JSR OUTST ; IS OUTPUT BUSY? BCS ASYNLP ; JUMP IF IT IS LDA #TESTCH JSR OUTCH ; OUTPUT TEST CHARACTER ; ; CHECK INPUT PORT ; ECHO CHARACTER IF ONE IS AVAILABLE ; EXIT ON ESCAPE CHARACTER ; JSR INST ; IS INPUT DATA AVAILABLE? BCS ASYNLP ; JUMP IF NOT (SEND ANOTHER "A") JSR INCH ; GET CHARACTER CMPA #ESCAPE ; IS IT AN ESCAPE? BEQ DONE ; BRANCH IF IT IS JSR OUTCH ; ELSE ECHO CHARACTER BRA ASYNLP ; AND CONTINUE DONE: BRA SC9A ; REPEAT TEST END