{ 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