; PORTS.S is part of SIO2PC. It contains the routines which ; set up and use the serial port. ; ; The following subroutines are found in this file: ; CON_COM GET_MSR GET1 PUT1 ; PUT1A REG_INIT MAN_PORT ENABLE ; DISABLE CK_LINES COM_SET; LOCK_IT ; TOG_SPEED RE_BAUD INT_COM COMMENT\ HERE ARE SOME FACTS STRAIGHT OFF THE CHIP DATA SHEET: LCR: b7: DLAB - 0 access receiver buffer, 1 access divisior latches b0,1 11 means 8 data bits LSR: b0 1 means data ready b1 1 means over-run: data not read before new data entered b2 1 parity error, when parity being used b3 1 means framing error b4 1 means BREAK occurred b5 1 means transmitter holding register empty (THRE) b6 1 means transmitter empty (TEMT) b7 always 0 in char mode, in FIFO mode, 1 means an error exists in FIFO MCR: b1 1 makes RTS output low b3 1 enables the INT output *** SEE NOTE BELOW *** b4 1 enables the loopback mode ; I found that setting bit 3 = 1 for COM3 locks up the MOUSE on COM1 ; so don't do that. It must have something to do with the interrupt. ; I assume setting b3 on COM4 would lock up the MOUSE on COM2, and ; vice versa for both COM1/3 & COM2/4. MSR: b2 TERI trailing edge of RI detected b6 -RI line status; 1 -> RI is low; 0 -> RI is high ENDOFCOMMENT\ COMMENT\ REV 4.11 removes this routine ; This routine allows setting the lower 4 bits of the MCR by inputting a ; single hex digit 0 - F. "Experiment with MCR". Note - bit 1 won't ; stay clear because main loop calls DISABLE EXP_MCR: MOV DX, MCR IN AL, DX CALL BYTE2HEX ; convert AL to ascii digits in BH (low) and BL (high) MOV W[MCR_HERE], BX ; insert current into GIVE_MCR string PSTATUS GIVE_MCR, ATTR9 ; print current and request new ... CALL GET_TORK CALL TO_UPPER CMP AL, 27 ; escape cancels JE > L1 CALL HEXDIGIT ; converts ASCII digit to number in AL JC EXP_MCR ; if bad input MOV DX, MCR OUT DX, AL MOV LAST_MCR, AL CALL ACC_DLY L1: RET ENDOFCOMMENT\ ; COM_SET ; COM_SET gets the desired com # from tail or kybd ; input, then sets registers and initializes PORT. ; COM_SET: CALL GET_TORK CMP AL,' ' JE COM_SET PUSH AX CALL PRINT1 SUB AL,'1'; Convert ASCII to binary number, 0 - 3. CMP AL,04 JB ABO; OK if <4 PSTATUS VOR, ATTR9 TICKS 36 CALL FLUSH POP AX STC; FLAG ERROR RET; Error exit ABO: MOV COM_NO,AL CALL REG_INIT CALL CON_COM MOV CONFIGD,0FFh; FLAG THAT PORT HAS BEEN CONFIGD. POP AX ; Now, fill in the port # on the menu MOV [ACOMN], AL ; line. CURSET 0604h PRINTL TX7 CLC; GOOD STATUS RET ; GET1 is a sub that gets one byte from the defined PORT. It gets ; directly from the hardware, not using BIOS or DOS. ; USES AL. DATA IS RETURNED IN AL. GET1: PUSH ES, DX, AX ; MOV AL, 'B' ; CALL PUT_LOC ; ; 4.10 takes out the setting of DLAB for each byte. DLAB is ; expected to already be in the right state. ; MOV DX, LCR ; Set DLAB to 0 for access to receive buffer ; IN AL, DX ; CALL ACC_DLY ; AND AL, 01111111xB ; OUT DX, AL ; CALL ACC_DLY ; 4.10 ADDED MOV VARBL, 2; Time out timer - 4.07 went 3 to 2 CHECK: CMP VARBL, 0 JNE >L1 MOV AL, 'a' MOV ERR_CHAR, AL CALL PUT_ERCH; Put report of the timeout to ERROR field STC ; error exit - carry means timed out POP AX, DX, ES RET L1: MOV DX,LSR ; bit 0 of LSR set means data ready IN AL,DX CALL ACC_DLY AND AL, 00000001xB JE CHECK ; Loop if bit is 0... ; Else, read a byte from receive buffer... POP AX ; preserve AH MOV DX,BAUD IN AL, DX CALL ACC_DLY ; 3.01 TOOK OUT - 4.10 put back POP DX, ES CLC ; 'good' status RET ; GETSLO (3.20) is like GET1, except it allows several seconds before ; timing out ... GETSLO: PUSH ES,DX,AX ; 4.10 takes out PUT_LOC call and DLAB setting ... ; MOV AL,'B' ; CALL PUT_LOC ; MOV DX, LCR ; Set DLAB to 0 for access to receive buffer ; IN AL, DX ; CALL ACC_DLY ; AND AL, 01111111xB ; OUT DX, AL ; CALL ACC_DLY ; added by 4.10 MOV VARBL, 72; Time out timer CHKSLO: CMP VARBL, 0 JNE >L1 MOV AL, 'a' MOV ERR_CHAR, AL CALL PUT_ERCH; Put report of the timeout to ERROR field STC ; error exit - carry means timed out POP AX, DX, ES RET L1: MOV DX, LSR ; bit 0 of LSR set means data ready IN AL, DX CALL ACC_DLY AND AL,00000001xB JE CHKSLO ; Loop if bit is 0... ; Else, read a byte from receive buffer... POP AX ; preserve AH MOV DX, BAUD IN AL, DX CALL ACC_DLY ; 3.01 TOOK OUT - 4.10 PUT BACK POP DX, ES CLC ; 'good' status RET ; PUT1: ; This subroutine puts one byte from AL out to the defined PORT. It ; waits for the transmitter to be empty before returning. ; AL IS USED. AL IS CHANGED BY THIS SUBROUTINE. PUT1: PUSH DX PUSH AX MOV ERR_CHAR,'b'; Error reporting code for timeout ; MOV W[COUNT_TIME],0; set-up time-out timer MOV VARBL, 2; - 4.06; 4.07 changed 5 to 2 ; MOV AL,'C'; loop reporting code ; CALL PUT_LOC MOV DX,LSR L5: CMP VARBL, 0 ;CALL DO_TIME; time-out timer 4.06 JZ >L1; break out of this part of loop IN AL,DX ; Check if holding buffer is empty CALL ACC_DLY AND AL,00100000xB ; bit 5 is hold reg. status JE L5 ; bit set means empty L1: MOV DX,BAUD ; *** rev 2.4 L1: was on next line *** POP AX OUT DX,AL CALL ACC_DLY MOV DX,LSR ; Get status of transmitter L6: CMP VARBL, 0 ;CALL DO_TIME 4.06 JZ >L1 IN AL,DX CALL ACC_DLY AND AL,01000000xB ; bit 6 = 1 means empty JE L6 L1: POP DX MOV ERR_CHAR, ' '; don't blame me! RET ; PUT1A ; ; This subroutine also puts one byte out. However, it loads when the ; holding buffer is empty. Also, it returns immediately, unless CX = 1 ; then it waits till the transmitter is empty. It is used to send a ; number of bytes using CX as a counter in external loop. ; USES & CHANGES AL ; If T6 <> 0, this routine will wait until transmitter is empty, ; plus the delay of T6 * 850 nSec PUT1A: PUSH DX PUSH AX ; PUSH AX ; DEBUG INFO ; MOV AL,'D' ; " ; CALL PUT_LOC ; " ; POP AX ; " ; MOV W[COUNT_TIME], 0 ; " MOV VARBL, 2; 4.07 changed 5 to 2 MOV ERR_CHAR,'c' MOV DX,LSR L7: CMP VARBL, 0 ; CALL DO_TIME 4.06 JZ >L1 IN AL,DX CALL ACC_DLY AND AL,00100000xB ; bit 5 means xmtr holding reg empty JE L7 L1: MOV DX,BAUD POP AX OUT DX,AL ; send the byte CALL ACC_DLY ; rev 4.12 added CMP T6,0 ; If T6 <> 0 wait for TX empty JNE >L1 CMP CX,1 ; If CX = 1, then wait for transmitter empty... JNE AAF L1: MOV DX,LSR L1: CMP VARBL, 0 ;CALL DO_TIME 4.06 JZ AAF IN AL,DX CALL ACC_DLY AND AL,01000000xB ; Tx buf empty when b6 = 1. JE L1 CMP T6,0 ; Do between bytes time delay if T6 <> 0 JE AAF PUSH BX MOV BX,T6 CALL TIMER_0 POP BX AAF: POP DX RET ; SET NEW BAUD RATE, AS IN SPARTA'S ULTRASPEED I/O: ; Note: Desired baud divisor must have been previously ; stored @ T9 RE_BAUD: MOV SPEED, 'N' ; Assumption is for Normal MOV DX,LCR ; First change DLAB to 1 so can address divisor MOV AL,10000011XB; OUT DX,AL CALL ACC_DLY ; 4.10 ; MOV AX,T9 ; 6: 19.2; 4: 28.8; 3: 38.4 MOV DX,BAUD ; OUT DX,AX ; 16 bit transfer 4.10 changes to two 8's OUT DX, AL XCHG AH, AL CALL ACC_DLY INC DX ; high bit to next register @ BAUD + 1 OUT DX, AL CALL ACC_DLY XCHG AH, AL ; for compare below ; CMP AX, 6 ; If T9 <> 6, then High speed JE >L1 MOV SPEED, 'H' L1: CALL PUT_SPEED MOV AL,00000011Xb MOV DX,LCR OUT DX,AL CALL ACC_DLY RET ; Following toggles speed between ultra and 19.2: TOG_SPEED: CMP SPEED, 'H' JNE >L1 MOV SPEED, 'N' MOV T9, 6 JE > L2 ; 4.10 - L2 was ADY L1: MOV SPEED, 'H' MOV AX, PCDIV MOV T9, AX L2: CALL RE_BAUD RET ; Subroutine CON_COM configures the chosen COM port and changes its ; BAUD to 19,200. Set those registers up first! CON_COM: ; Now, change the baud to 19,200: MOV DX,LCR ; First change DLAB to 1 so can address divisor MOV AL,10000011xB; ***PROGRAM MODE INDEPENDENT OF BIOS: 1.05 *** OUT DX,AL CALL ACC_DLY ; REV 4.12 ; MOV AX,06 ; 6 is divisor for 19.2 KB MOV T9, AX ; Keep a record MOV SPEED, 'N' ; Normal CALL PUT_SPEED MOV DX,BAUD ; OUT DX,AX ; 16 bit transfer ; ; 4.10 changes speed programing from a 16 bit transfer to two 8 bit ; transfers ... OUT DX, AL ; low byte of rate word XCHG AH, AL CALL ACC_DLY INC DX OUT DX, AL ; high byte CALL ACC_DLY ; 4.10 added ; MOV AL,00000011xB MOV DX,LCR OUT DX,AL CALL ACC_DLY ; CALL TIME_LAG 4.10 took out IN AL,DX; See if port reads back as written. CALL ACC_DLY ; 4.10 ADDED CMP AL,00000011xB JE >L1 ; This is just a warning, doesn't stop program PSTATUS BADLCR, ATTR10 TICKS 54 ; check - why is below only done if there's an error? 4.10 fixed ... ; moved L1 up here ... L1: MOV DX,MCR ; Initialize MCR ; warnings for MCR: make sure loopback is explicitly turned off (b4 = 0) ; and make sure b3 isn't set. b3 will mess up the mouse on the ; corresponding odd or even port. MOV AL,00000111xB; RTS,DTR OUT1,OUT2 all low, no loopback mode OUT DX,AL CALL ACC_DLY MOV LAST_MCR, AL CALL DISABLE; PUT RTS into disable data out state. CALL ACC_DLY ; 4.10 - was TIME_LAG - location was L1 MOV DX,INT_EN ; *** DISABLE ALL INTERRUPTS FROM UART*** MOV AL,0 ; *** A REVISION 1.03 CHANGE *** OUT DX,AL ; Do loopback test on UART: ; Give the UART time to settle... TICKS 2 MOV DX,BAUD; First clear the input register to reset IN AL,DX CALL ACC_DLY ; 4.10 changed from TIME_LAG MOV DX,MCR IN AL,DX PUSH AX; Save old MCR mode OR AL,10h; Enable loopback mode CALL ACC_DLY ; 4.10 - was TIME_LAG OUT DX,AL ; MOV LAST_MCR,AL ; 4.10 took out - MCR already saved TICKS 2 MOV CX,0FFh; So PUT1A will return immediately MOV AL,11001101xB; a random char CALL PUT1A CALL GET1 JC > L1 CMP AL,11001101xB JE > L2 ; 4.10 - L2 was ABJ L1: PSTATUS NOLOOP, ATTR10 TICKS 54 L2: POP AX ; was ABJ MOV DX,MCR OUT DX,AL CALL ACC_DLY ; 4.10 MOV LAST_MCR,AL MOV AL, 0 ; turn off 16550 FIFO mode 4.07 MOV DX, INT_IDENT ; this is FIFO control as write register OUT DX, AL CALL ACC_DLY ; 4.10 CALL MT_550 ; now clear any data from 16550 buffer - 4.07 RET ; a routine to clear the 16550 buffer; 40.7 MT_550: PUSH AX, CX, DX MOV CX, 16 L2: MOV DX, LSR IN AL, DX CALL ACC_DLY ; 4.10 ADDED TEST AL, 1 ; b0 set means data ready JZ > L1 ; 0 means no byte waiting MOV DX, BAUD ; else read and throw away data IN AL, DX CALL ACC_DLY ; 4.10 ADDED LOOP L2 ; up to 16 times L1: POP DX, CX, AX RET ; GET_MSR ; This routine reads the Modem Status Register and returns ; it in the AL register. Uses AL only. GET_MSR: PUSH DX MOV DX, MSR; MSR must be defined previously. IN AL, DX CALL ACC_DLY POP DX RET ; REGISTER INITIALIZE ... ; This routine loads the register names with the values ; appropriate based on the base value found in the variable ; COM_NO REG_INIT: PUSH AX,DS MOV DI,WORD PTR COM_NO; contains 0 to 3; ****QUICKA CHANGE**** AND DI,0Fh; screen off high byte SHL DI,1; times 2 to address word MOV DX,0040h; point to BIOS data area MOV DS,DX MOV DX,[DI]; get UART base address for chosen port #IF CARLM PUSH DX, DI MOV DI, 08 ; LPT1 address MOV DX, [DI] CMP DX, 0 JZ >L1; if BIOS AREA DOESN'T LIST ONE ... PUSH CS POP ES MOV ES:[PP_OUT1], DX INC DX MOV ES:[PP_IN], DX INC DX MOV ES:[PP_OUT2], DX L1: POP DI, DX #ENDIF POP DS ; Now, if bios data area said port address = 0, CMP DX,0 JNE ENTRY2 MOV DX, PORTS[DI]; Get default port address ; ENTRY2 is the entry point for MAN_PORT, which already has DX = ADDR ENTRY2: MOV BAUD,DX; and store it in my data area INC DX MOV INT_EN, DX; +1 INC DX MOV INT_IDENT,DX; +2 INC DX MOV LCR,DX; +3 INC DX MOV MCR,DX; +4 INC DX MOV LSR,DX; +5 INC DX MOV MSR,DX; +6 ; Now use macro to print hex value of base address on COM status line MOV AX,BAUD HEXTEX CMTXT CURSET 092Ch PRINTL OPT2 POP AX RET ; 3.20 subroutines to raise and lower RTS (command line) ; for the 1050-2-PC hardware ... RTS_DN: PUSH AX, DX MOV AL, LAST_MCR OR AL, 2; setting bit makes RTS low MOV LAST_MCR, AL MOV DX, MCR OUT DX, AL CALL ACC_DLY; 4.15 added POP DX, AX RET RTS_UP: PUSH AX, DX MOV AL, LAST_MCR AND AL, 11111101xb; clearing bit makes RTS high MOV LAST_MCR, AL MOV DX, MCR OUT DX, AL CALL ACC_DLY ; 4.15 POP DX, AX RET ; A Subroutine to set the RTS line to level required to enable ; the data out line: ENABLE: PUSH AX PUSH DX CMP LOCK_RTS,0 JNE ABL; Skip if locked on MOV AL, LAST_MCR; See if already enabled **** 1.07 **** AND AL, 2 JE ABL; skip if already enabled MOV DX, MCR IN AL, DX CALL ACC_DLY AND AL,0FFh-2 ; Set bit 1 (RTS) off OUT DX, AL CALL ACC_DLY MOV LAST_MCR, AL ABL: POP DX POP AX RET ; A subroutine to disable the data out line to the Atari bus: DISABLE: PUSH AX PUSH DX CMP LOCK_RTS,0; <>0 means RTS locked in enabled state JNE ABM MOV AL,LAST_MCR AND AL,2 JNE ABM MOV DX,MCR IN AL, DX CALL ACC_DLY OR AL, 2 ; Set bit 1 (RTS) on JMP > L1 L1: OUT DX, AL CALL ACC_DLY MOV LAST_MCR, AL ABM: POP DX POP AX RET ; MAN_PORT is called when menu choice Option - "E" is made. It gets ; a 4 digit port address from the user and re-configures the 8250 ; based on the new port address. MAN_PORT: PSTATUS QADRS, ATTR9 CALL GET4H; Get 16 bit # in BX JC >L1 ; Abort because ESC pressed MOV DX,BX; REG_INIT expects port base in DX CALL ENTRY3; New entry point into REG_INIT is ENTRY2 CALL CON_COM; Configure port CURSET 0602h PRINTL TX7 L1: RET ENTRY3: PUSH AX; This is just to get something on the stack because JMP ENTRY2; REG_INIT POP's AX before returning. ; This subroutine checks the MSR and puts status info into the ; debug info line as to whether the command line is high or low ; EXPECTS MSR INFO IN AX. REGISTERS AREN'T DISTURBED. ; The result will be that, regardless of one chip or two chip, ; ZF true means command line is low CK_LINES: PUSH AX TEST AL,01000000xB; RI is command line LAHF ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS CMP B[REV_FLAG], 'i' JNE >L1 XOR AH, 01000000Xb; complement ZF L1: SAHF; FLAGS <- AH JE >L2; branch if command is 0 (low) ; 4.10 L2 was L1 MOV AL,'H' JMP > L3 ; 4.10 L3 was XAAD L2: MOV AL,'L'; Command is low L3: CALL PUT_CLINE POP AX RET ; LOCK_IT LOCKS the RTS line in the ENABLED position LOCK_IT: CMP LOCK_RTS,0 JNE >L1 CALL ENABLE; First, enable it MOV LOCK_RTS,0FFh; Then, lock it on SMOVE STLOCKD, LOCKSTAT, 6 JMP ABQ L1: MOV LOCK_RTS,0 CALL DISABLE SMOVE STNORM, LOCKSTAT, 6 ABQ: NOP CURSET 0804h PRINTL TX14 RET ; ************ DIAGNOSTICS SUB-MENU ************************************* ; DIAGS: CALL CLR_SCRN PRINTL M_DIAG L4: CALL GET_TORK CALL TO_UPPER CMP AL, '1' JNE > L1 CALL INT_COM JMP DIAGS L1: CMP AL, '2' ; line status troubleshooting JNE > L3 CALL LINES JMP DIAGS L3: CMP AL, '3' ; put sectors to Atari JNE > L5 CALL DGETSEX JMP SHORT DIAGS L5: CMP AL, '5' JNE L4 L2: RET ; ************* An Intercom Program to test the serial ports ************ ; This routine monitors for keyboard input, sends out all bytes recieved ; over the serial port. (Escape terminates this mode, and 0 not allowed.) ; bytes are also echoed to the screen ; The incoming port is also monitored, and all bytes received are put to ; the screen (Escape cancels this mode) INT_COM: CALL CLR_SCRN L1: CALL IS_A_KEY ; carry clear means no key JNC > L2 CMP AL, 0 ; 0 not allowed, it's a flag on the atari end JE > L2 PUSH AX MOV CX, 0FFFFh ; 0 makes PUT1A hold till empty CMP AL, 13 ; if CR JNE > L3 ; translate to EOL MOV AL, 09Bh L3: CALL PUT1A ; send byte and return immediately POP AX CMP AL, 27 ; escape? JE > O1 ; exit function CMP AL, 13 ; CR ?? JNE > A1 CALL LINEFEED JMP > L2 A1: CALL PRINT1 ; put char in AL to screen ; CMP AL, 09Bh ; if carriage return ; JNE > L2 ; CALL LINEFEED ; Now, see if any incoming byte in serial port L2: MOV DX, LSR IN AL, DX ; get line status - NOTE - CHECK FRAMING AND OVERRUN CALL ACC_DLY ; 4.10 ADDED AND AL, 1 ; bit 0 set means input ready JZ L1 ; no input, restart loop CALL GET1 ; input the byte CMP AL, 09Bh ; translate EOL to CR/LF JNE > L4 CALL LINEFEED JMP L1 L4: CALL PRINT1 CMP AL, 27 JNE L1 O1: RET ; O means OUT of here ; ************ LINE STATUS DIAGNOSTICS **************************** LINES: CALL CLR_SCRN CURSET 0 PRINTL M_LINES CALL OUT_STAT CALL HI L2: CALL CMD_STAT CALL CK_BRK CALL IS_A_KEY JNC L2 ; carry clear means no key CALL TO_UPPER CMP AL, 'O'; toggle data out status? JNE > L1 CALL OUT_TOG CALL OUT_STAT JMP SHORT L2 L1: CMP AL, 'I' JNE > L3 CALL HI L3: CMP AL, 27 ; escape JNE L2 MOV CMD_LAS, ' ' ; force H or L next time MOV OUTNOW, ' ' CALL OUT_HIGH ; clear BREAK bit in LCR RET ; A routine to toggle the status of the Data Out line ... OUT_TOG: MOV DX, LCR IN AL, DX XOR AL, 040h ; bit 6 = 1 to set break mode ( data out low ) CALL ACC_DLY OUT DX, AL CALL ACC_DLY ; 4.10 ADDED RET OUT_HIGH: MOV DX, LCR IN AL, DX AND AL, 10111111xB CALL ACC_DLY OUT DX, AL RET ; Update the status of the Data Out Line ... OUT_STAT: MOV DX, LCR IN AL, DX AND AL, 01000000xB JZ > L1 ; 0 means bit 6 not set which means line is HIGH MOV AL, 'L' JMP > L2 L1: MOV AL, 'H' L2: CMP AL, OUTNOW JZ > O1 ; Out of here if no change MOV OUTNOW, AL CURSET 050Ah ; row 5, col 10 CALL PRINT1 O1: RET ; Toggle the status of Data In line to H HI: CURSET 060Ah ; row 6, col 10 MOV AL, 'H' CALL PRINT1 RET ; check for BREAK ( data in line low) ; NOTE: you can only read this bit once per BREAK, then it ; clears, and the data in line must go high again and another ; BREAK occur before the bit is set again. CK_BRK: MOV DX, LSR IN AL, DX CALL ACC_DLY ; 4.10 ADDED AND AL, 00010000xB ; bit 4 set means break occurred JZ > O1 CURSET 060Ah MOV AL, 'L' CALL PRINT1 RET ; Update the status of the COMMAND line CMD_STAT: MOV DX, MSR IN AL, DX CALL ACC_DLY ; 4.12 TEST AL,01000000xB; RI is command line LAHF ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS CMP B[REV_FLAG], 'i' JNE >L1 XOR AH, 01000000Xb; complement ZF L1: SAHF; FLAGS <- AH JE >L1; branch if command is 0 (low) MOV AL,'H' JMP >L2 L1: MOV AL,'L'; Command is low L2: CMP AL, CMD_LAS JZ > O1 MOV CMD_LAS, AL CURSET 040Ah CALL PRINT1 O1: RET ; Put/Get sectors to/from the Atari: DGETSEX: PRINTL NUMSECS TICKS 40 L2: CALL CLR_SCRN MOV DS_SCRN, 0 ; initialize screen pointer L4: CALL CL_ORKEY ; command line low or keypress JNZ > O1 ; 0 flag means cmnd line went low; else - keypressed ; here, command line went low and no keypress ... L3: CALL GET_CF ; read in a command frame JNC > L5 ; if no error, don't print status CALL DO_SS; put status on screen JMP L4 ; and try again for command frame L5: CALL DS_SECNO ; good CF, then put sector number to field ; now, see if command was write or read MOV AL, CMND CMP AL, 'W' JNE > L6 L7: CALL DPUTSEC CALL DO_SS ; put status to screen JMP L4 ; keep looping till user hits a key L6: CMP AL, 'P' ; works with Get or Put JE L7 CMP AL, 'R' ; read sector? JNE L4 ; not W, P, or R shouldn't be possible CALL DGETSEC ; Doesn't return an error status CALL DO_SS JMP L4 O1: RET ; Wait for CMND LINE to go low or key to be pressed .. ; Note: when bit 6 of MSR = 0, this means that the RI input is ; logic 1; or command line is HIGH (TTL 1) or, RS-232 line is at ; -10 volts: all mean the same thing. With the ONECHIP design ; the line status is same at PC as at Atari. With the old design ; the RI line is inverse on PC due to inversion on board. ; Returns with 0 flag set if CMND LOW, else 0 flag clear and char ; in AL if key was pressed. CL_ORKEY: CALL IS_A_KEY ; carry clear, no key; else char in AL JNC > L2 LAHF ; put flags in AH AND AH, 10111111xB ; clear zero flag i.e. - force not zero condition SAHF ; restore flags JC > L3 ; forced branch - carry will still be set here L2: MOV DX, MSR IN AL,DX CALL ACC_DLY ; 4.12 AND AL,01000000xB ; checking RI bit... LAHF ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS CMP [REV_FLAG], 'i' JNE >L1 XOR AH, 01000000Xb; complement ZF L1: SAHF; FLAGS <- AH - For cmnd line LOW, Zero (equal) results JNE CL_ORKEY L3: RET ; GET_CF reads in a command frame. Cmnd line already verified low GET_CF: MOV DX, BAUD ; Read the register IN AL,DX; Throw away this byte... CALL ACC_DLY ; First, clear any error bits from LSR: (REV 3.01) MOV DX, LSR IN AL, DX CALL ACC_DLY ; ; Now read characters from the port. Command frame is 5 bytes long. ; First, get 4 bytes, computing checksum... ; First, a routine to time out if no data forthcoming in 1/6 sec MOV VARBL,10; 3.06 L2: MOV DX, LSR IN AL,DX ; First see if a byte is ready CALL ACC_DLY N1: AND AL,1 JNZ > L1 ; branch if byte waiting... CMP VARBL,0 JNE L2 ; loop until timed out... REV 3.06 U1: MOV AL, 'T' U3: MOV [DS_FLD+4], AL ; flag that timeout did occur JMP EO1 ; go home MOV DX, MSR ; 3.05 IN AL, DX CALL ACC_DLY ; 4.12 ; CALL CK_LINES AND AL, 01000000XB LAHF CMP [REV_FLAG], 'i' JNE >L3 XOR AH, 01000000xB L3: SAHF JE L2 ; JE MEANS CMND LINE IS LOW MOV AL, 'H' ; flag cmnd line didn't stay low MOV [DS_FLD+4], AL JMP EO1 ; else abort attempt to get cmnd frame L1: CALL GET1; Get DEVID JC U1 ; means timed out MOV DEVID,AL ; get 3 more bytes MOV CX,3 MOV BL,DEVID L1: CALL GET1 JC U1 ; carry set means timed out in GET1 MOV SI,CX MOV [CFCKSM+SI],AL ; Store the command frame bytes CLC ; do checksum math ADC BL,AL ADC BL,0 LOOP L1 ; Now get checksum and store it... CALL GET1 JC U1 MOV CFCKSM, AL CMP BL, CFCKSM JE U2 ; Abort the whole thing if bad CKSUM MOV AL, 'K' ; flag bad checksum JNE U3 ; forced branch ; 3.05 moved block below. was after checking cmnd line raised: ; At this point, we have successfully read a command frame. Now, wait ; for the computer to raise the command line: U2: MOV VARBL, 2; 4.08 - did use BX in a crude counter for timeout B1: CMP VARBL, 0 JNE >L1 ; timed out, cmnd line didn't go high MOV AL, 'L'; flag cmnd line didn't go back high JE U3 ; forced branch L1: MOV DX, MSR IN AL,DX CALL ACC_DLY ; 4.12 AND AL,01000000xB LAHF ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS CMP [REV_FLAG], 'i' JNE >L4 XOR AH, 01000000xb; complement ZF L4: SAHF; FLAGS <- AH JE B1 CLC ; flag good result JNC > O3 EO1: STC ; flag error O3: RET ; This routine puts the SECTOR I/O status chars to the screen and ; advances the screen location pointer. Direct screen writes are used. ; it also fills the source field back with the default chars after each ; write. DO_SS: PUSH ES,SI,DI,AX,CX MOV ES, SCR_SEG MOV SI, DS_FLD MOV DI, DS_SCRN ; current screen ram pointer to field MOV CX, 16 ; # of chars to put S0: MOV AL, [SI] MOV ES:[DI],AL INC SI INC DI INC DI ; skip attribute byte LOOP S0 CMP DI, (25*160 -1) JB > S1 XOR DI, DI ; overflow to top of page S1: MOV DS_SCRN, DI ; store pointer to next field MOV AX, 'n'*0100H + 'n' ; get nn in AX MOV [DS_FLD], AX MOV AH, ' ' MOV [DS_FLD+2], AX MOV CX, 5 MOV DI, DS_FLD+4 MOV AX, '*'*0100h + '*' ; load ** into AX S3: MOV [DI], AX INC DI INC DI LOOP S3 MOV [DI],AL ; last odd one! POP CX, AX, DI, SI, ES RET ; Put the sector number in DFAUX1/2 to the DS_FLD field DS_SECNO: MOV DI, OFFSET DS_FLD + 2 ; Point to 1's digit ... MOV AL, CFAUX1 MOV AH, CFAUX2 CALL INT2DEC RET ; ****************** Interrupt driven serial I/O ***************** ; A subroutine to set up and enable the interrupt: S_U_INT: