{ File: [Idun]<WDLion>LSEPTask.asm Last change by Chuck Fay 15-Nov-82 16:04:28: Always post status, whether it's different or not; moved test of PortBusyFlag to top so that it's tested whether or not there is a command to be sent. Jim Frandeen September 9, 1982 1:19 PM: Zero status after each command. Jim Frandeen August 5, 1982 12:20 PM: New IO Page format. Jim Frandeen May 3, 1982 7:41 AM: reorganize for new tasking Written by Roy Ogus} ; DEFINITION FILES: get "SysDefs" ; System defs get "CommonDefs" ; Common defs ; IMPORTS/EXPORTS: IMP DoNakedNotify ; From CPSubs IMP LSEPData ; From Common IMP LSEPStatus ; From Common IMP PortBusyFlag ; From CPSubs IMP ReadCPBuffer ; From CPSubs IMP WriteCPBuffer ; From CPSubs IMP Wait ; From Common IMP ZeroCommand ; From Common LSEPConsumerTask: {We can't send a command or read status unless the CP port is free.} LDA PortBusyFlag ORA A JNZ LSEPProducerTaskYield ; nz => CP port busy, skip to next task LDA LSEPData ; Check if data #0 ora a ; Set Flags JZ LSEPConsumerTaskYield DB opJMP LSEPConsumerTaskResumeAddress: DW InitializeLSEPConsumerTask ; JMP LSEPConsumerLoop ; Internal Definitions. LSEPCSB: {The LSEP CSB is read in the first time LSEPData is non zero. } LSEPCtlMask: {This mask is used to issue a NakedNotify when a control character has been sent to the LSEP. This mask is only read in once, the first time a control character is sent to the LSEP.} DS 2 ;1401F LSEPStatMask: {This mask is used to issue a NakedNotify when a status byte has been sent to the CP. This mask is only read in once, the first time a control character is sent to the LSEP.} DS 2 ;14020 PTDelay equ 13H ; Wait value of ~ 100 usec for UART settle ; Printer UART Baud rate generator programming SC0 equ 00H ; Counter 0 RL3 equ 30H ; Read/Load least significant, then most significant data Mode3 equ 6 ; Mode 3 - square generator BRGMode equ SC0+RL3+Mode3 ; Mode byte for 8253 BRG Clk Freq: db 3 ; Frequency: 0=110Hz, 1=300Hz, 2=1200Hz, 3=9600Hz ; Frequency: 4=19.2KHz Div110: dw 1047 ; Divisor for 110Hz (16X) Div300: dw 384 ; Divisor for 300Hz (16X) Div1200: dw 96 ; Divisor for 1200Hz (16X) Div9600: dw 12 ; Divisor for 9600Hz (16X) Div19200: dw 6 ; Divisor for 19200Hz (16X) Div28800: dw 4 ; Divisor for 28800Hz (16X) ; 8251A UART data. PTErrorMask equ 38H ; Framing, overrun, parity errors BreakDetMask equ 40H ; Break Detect bit PTCmdER equ 10H ; Command bit to clear errors Reset0 equ 80H ; First character of reset sequence (see notes) Reset1 equ 00H ; Second character of reset sequence Reset2 equ 40H ; Third character of reset sequence ;InvalidChar equ 4EH ; Invalid character as Raven data InvalidChar equ 7EH ; Invalid character for bad RxStatus PTMode: EQU 5AH ; 1 stop, odd parity, 7 bits, 16X PTCmdTx: db 23H ; Command, enable Tx only PTCmdTxRx: EQU 27H ; Command, enable Tx, Rx ; Port Control Block values to write zero into data word of CSB. LSEPZeroDataPCB: dw LSEPDataLoc ; CP buffer pointer (low): LSEP Ctl Data dw CPIOPageHi ; CP buffer pointer (high) dw 2 ; CP buffer count (bytes) dw ZeroCommand ; Pointer to IOP LSEP Ctl CSB status ; Port Control Block values to read LSEP CSB. LSEPReadCSBPCB: dw LSEPCSBLoc ; CP buffer pointer (low): LSEP Ctl Data dw CPIOPageHi ; CP buffer pointer (high) dw LSEPCSBSize ; CP buffer count (bytes) dw LSEPCSB ; Pointer to IOP LSEP Ctl CSB status ; Control Block values to transfer status to IOPage. LSEPStatusPCB: dw LSEPStatusLoc ; CP buffer pointer (low): LSEP Ctl CSB status dw CPIOPageHi ; CP buffer pointer (high) dw 2 ; CP buffer count (bytes) dw LSEPStatus ; Pointer to IOP LSEP Status CSB status ; InitializeLSEPConsumerTask: { Initialize the LSEPBaud rate generator and the LSEP UART. This sequence will guarantee correct initialization after both a hardware (expecting Mode), or a software (expecting Command) reset. The enable Rx,Tx command is sent to the UART. Set the 8253 printer UART clock according to value in Freq. Freq: 0=110Hz, 1=300Hz, 2=1200Hz, 3=9600Hz, 4=19.2 kHz, 5=28.8 kHz. } lda Freq rlc ; Multiply by 2 mov E,a mvi D,0 ; 2*index in B,C di ; No interrupts mvi a,BRGMode ; Get 8253 Mode word out LTimerMode ; Output to Timer lxi h,Div110 dad D ; Point to divisor mov a,m ; Least significant byte out LTimerCount0 ; Output to Timer inx h mov a,m ; Most significant byte out LTimerCount0 ; Output to Timer ei ; Enable interrupts LXI H,8000H+LPrinterCommand ;memory mapped IO MVI M,Reset0 ; MVI M,Reset1 ; MVI M,Reset2 ; nop ; Needed for B-step chips MVI M,PTMode ; Mode value (assumed asynchronous) MVI M,PTCmdTxRx ; Command to UART for Send/Receive LXI H,LSEPConsumerLoop SHLD LSEPConsumerTaskResumeAddress LXI H,BeginLSEPProducerTask SHLD LSEPProducerTaskResumeAddress {Read in the LSEP CSB. We read this only once at initialization time. It contains the Naked Notify masks.} LXI H,LSEPReadCSBPCB CALL ReadCPBuffer ; ; This is where the Task will start after the LSEP has been initialized. LSEPConsumerLoop: ; Send the byte to the Raven. ; The data to be sent is in LSEPData. ; Wait for transmitter to be ready. Yield if not. in IntReq ; Check for Tx Ready flag. ani LSEPTxReqMask JNZ LSEPConsumerTaskYield ; z => Tx is ready lda LSEPData ; Get next data item out LPrinterData ; and output it ; Transfer empty status to CP. ; Clear Full flag in Status lxi h,LSEPZeroDataPCB ; Point to the CPport control block call WriteCPBuffer ; Write CP main memory LHLD LSEPCtlMask CALL DoNakedNotify LSEPConsumerTaskYield: {Pass control to the LSEP Producer Task} ; DB opJMP LSEPProducerTaskResumeAddress: DW LSEPProducerTaskYield ; JMP BeginLSEPProducerTask BeginLSEPProducerTask: ; Read the data from the UART. ; Check if a character is ready. If we get here, we know the port is free. in IntReq ; Check for Tx Ready flag. ani LSEPRxReqMask JNZ LSEPProducerTaskYield ; Z => character ready in LPrinterData ; Read in character sta LStatus ; Save in local mvi E,3 ; Counter for bad status tries RxCharLoop: in LPrinterStatus ; Read in status sta UARTStatus ; Store away ani PTErrorMask jz GoodRxData ; Not good status, try again. dcr E jnz RxCharLoop ; Bad status received from the UART is in A. ; Reset the errors in the UART and pass InvalidChar as the status. BadPTRxStatus: MVI A,InvalidChar STA LStatus MVI A,PTCmdTxRx+PTCmdER ; Command to UART for Send/Receive ; Plus Set ClearErrors out LPrinterCommand lxi h,PTDelay call Wait ; Wait for UART to settle MVI A,PTCmdTxRx ; Send command again out LPrinterCommand lxi h,PTDelay call Wait ; Wait for UART to settle ; Check if BreakDetect was on. DB opMVIA ;A ← UARTStatus UARTStatus: DB 0 ani BreakDetMask jnz LSEPProducerTaskYield ; nz => a break, ignore character ; If no break detect, continue. ; The character was received with no Uart errors. GoodRxData: DB opMVIA ;A ← new status LStatus: DB 0 MOV E,A ;E ← new status lda LSEPStatus ;A ← previous status from IO Page ora a ;Test for zero MOV A,E ;A ← new status JZ SendLSEPStatus ;Send new status ;If the previous status has not been processed, set overflow. MVI A,7FH SendLSEPStatus: STA LSEPStatus lxi h,LSEPStatusPCB ; Point to CPport Control Block call WriteCPBuffer ; Write CP main memory LHLD LSEPStatMask CALL DoNakedNotify LSEPProducerTaskYield: {Pass control to the next task specified in Domino.cfg} DS 0 END LSEPTask