home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
sysutl
/
ykey21.lbr
/
YK-EXAMP.LBR
/
USER201.ZZZ
/
USER201.AZM
Wrap
Text File
|
1987-12-11
|
13KB
|
413 lines
; ***********************************************
; PART III - THE NEW BIOS CODE
; ***********************************************
; LOADUSER.AZM (loads USER20.AZM) 11-24-87
; A replacement USER.ASM for N* Adv by R. Gaspari
UCODE:
OU EQU USORG-UCODE ; offset
ROW EQU 0
COL EQU 50 ; location of pop-up clock display
CA1 EQU 1BH ; cursor addressing sequence
CA2 EQU '='
CA3 EQU ROW+20H
CA4 EQU COL+20H
CI1 EQU 19H ; make cursor invisible (byte 1)
CI2 EQU 01H ; byte 2
CV1 EQU 18H ; cursor visible code (byte 1)
CV2 EQU 02H ; byte 2
;
; JUMP VECTOR (SEMI-TRADITIONAL)
;
USERORG EQU $+OU ; ORIGIN FOR REFERENCE
JP INIT ; INITIALIZATION CODE
JP CONST ; CONSOLE READY TEST
JP CONIN ; CONSOLE INPUT
JP CONOUT ; CONSOLE OUTPUT
JP LIST ; LIST DEVICE
JP LIST ; PUNCH ## (deleted to make room)
JP TIME ; READER (deleted, used for time)
JP LISTST ; LIST DEVICE READINESS TEST
;
; CONCLUDE VECTOR WITH BAUD RATES
; THE PRINTER RATE (BAUDA) IS ALTERED BY CPMGEN
BAUDA EQU $+OU ; Start-up baud rate for Adv slot 1
DEFB 112 ; 112 = 1200 baud
BAUDB EQU $+OU ; Start-up baud rate for slot 2
DEFB 126 ; 126 = 9600 baud
BAUDC EQU $+OU ; Startup for slot 3
DEFB 120 ; 127=19200; 124=4800; 120=2400; 96=600
;
; ********** END OF VECTOR ***********************
ENDVECT EQU $ ; MARK FOR LATER ORIGIN
;
;
; ***** ENTRY POINTS INTO "UPPER" BIOS ***********************
;
; ORG USERORG+200H ; JUST BEYOND USER AREA
; ACTUAL CONSOLE ROUTINES ARE ENTERED ABOVE USER AREA
CONSLI EQU USERORG+200H ; ACTUAL KEYBOARD INPUT ROUTINE
CONSLO EQU USERORG+200H+3 ; ACTUAL KEYBOARD OUTPUT ROUTINE
;
; MACHINE REGISTERS MAP0,MAP1,MAP2,CONTROL,TOP-SCAN-LINE
; ARE MANAGED THROUGH THE ROUTINES BELOW:
; ENTER WITH REG C=REG# 0 TO 4 RESPECTIVELY
; VALUE RETURNED/SUPPLIED IN REG B
RDREG EQU USERORG+200H+6 ; READ MACHINE REGISTER
WRREG EQU USERORG+200H+9 ; WRITE MACHINE REGISTER
;
; MUST SERVICE OFTEN WHILE HUNG IN I/O WAIT LOOPS:
OFTENS EQU USERORG+200H+12 ; CALL TO SERVICE OFTEN
; ROUTINE TOGGLES SPEAKER CONE
SPTOG EQU USERORG+200H+15 ; TOGGLE SPEAKER
;
;
; ************ BOARDLET I/O PORT DEFINITIONS ***********
;
; THE CP/M LIST DEVICE IS DEFINED AS PORT "A"
; IT IS HERE ASSIGNED TO BOARDLET 1
PORTAB EQU 1 ; BOARDLET 1
PORTA EQU (6-PORTAB)*16 ; BEGINNING OF BLOCK
PORTAT EQU 76H-PORTAB ; INTERROGATE FOR TYPE
;
; THIS INITIALIZES ADVANTAGE SLOT 2
PORTBB EQU 2 ; BOARDLET 2
PORTB EQU (6-PORTBB)*16 ; BEGINNING OF BLOCK
PORTBT EQU 76H-PORTBB ; SERIAL OR PARALLEL?
;
; THIS INITIALIZES ADVANTAGE SLOT 3
PORTCB EQU 3 ; BOARDLET 3
PORTC EQU (6-PORTCB)*16 ; FIRST PORT IN BOARDLET
PORTCT EQU 76H-PORTCB ; DETERMINES BOARLET TYPE
;
;
; WHEN THE PORT TYPE IS INTERROGATED, VALUES INPUT ARE:
BLTSER EQU 0F7H ; BOARDLET IS SERIAL
BLTPAR EQU 0DBH ; BOARDLET IS PARALLEL
; *******************************************************
;
ORG ENDVECT ; RESUME AT ABOVE MARKED LOCATION
;
;
;
; *** CONSOLE STATUS TEST FOR DATA READY
CONST EQU $+OU
CALL CLKPOP ; if pop-up clk in effect, display it
CALL 0F60Ch ; SERVICE OFTEN FOR SCROLL, ETC.
IN A,(0D0H) ; INTERROGATE KEYBOARD STATUS
AND 040H ; TEST KEYBOARD READY BIT
RET Z ; NO DATA, RETURN WITH A=0
CONS2: LD A,0FFH ; DATA WAITING, SEND FF
RET
CLKPOP EQU $+OU
LD A,(CLKFLG) ; see if pop-up flag is set
OR A
RET Z ; if no, return to call clkpop
LD HL,CLKCTR ; if yes, get the delay counter
INC (HL) ; display clk only every 256 iterations
RET NZ ; if NZ, go back to call clkpop
JP CDSP ; otherwise, display clock
CLKFLG EQU $+OU
DB 0 ; set 0FFh for continuous pop-up display
CLKCTR EQU $+OU
DB 0 ; temp storage for 256 state counter
; *** CONSOLE INPUT ## Complete overhaul of CONIN routine. ##
CONIN EQU $+OU ; relocated conin, coninl is local
CONINL: CALL CONST ; check status (again)
JR Z,CONINL ; loop until status says we're ready
CALL 0F600H ; get the byte using upper bios
; CP 9BH ; see if it's CMND-F1
; JR NZ,CN9B ; (single pop-up clock request)
; CALL CDSP ; if yes, display clock
; JR CONINL ; and go back for next input
CN9B: CP 9BH ; see if it's CMND-F1
JR NZ,CN9C ; (continuous pop-up clk display)
LD A,(CLKFLG) ; prepare to toggle the pop-up flag
CPL ; complement the accumulator
LD (CLKFLG),A ; store the toggled flag
JR CONINL ; go back for next input
CN9C: CP 7FH ; see if it's a "delete"
RET NZ ; if not, return with it the input byte
LD A,7FH ; if yes, get the 7F replacement
RET ; and return with it
; *** CONSOLE OUTPUT
CONOUT EQU $+OU
JP 0F603H ; SO SEND CHAR TO CONSOLE
;
;
; ***** BOARDLET I/O HANDLING **************************
; ***** CP/M'S "LIST" DEVICE - USES "PORTA" DEFINED ABOVE
;
LIST EQU $+OU
LISTX: CALL LISTST ; USE STATUS TEST BELOW
JR Z,LISTX ; LOOP UNTIL READY
IN A,(PORTAT) ; DETERMINE TYPE OF PORT
CP BLTSER ; SEE IF SERIAL
JR Z,LISTSER ; YES, SKIP INSTRUCTION BELOW
OUT (PORTA+4),A ; RESET PO-FLAG
LISTSER: LD A,C ; STAGE BYTE INTO A
OUT (PORTA),A ; SEND IT
RET ; AND EXIT
;
; *** LIST DEVICE STATUS TEST *** USES PORTA
LISTST EQU $+OU
CALL OFTENS ; SERVICE OFTEN FOR SCROLL
LD B,1 ; READY BIT FOR SERIAL PORT
IN A,(PORTAT) ; DETERMINE TYPE OF PORT A
CP BLTSER ; SEE IF SERIAL
JR Z,LTTSER ; YES SKIP NEXT INSTR
LD B,4 ; PARALLEL PORT READY MASK
LTTSER: IN A,(PORTA+1) ; INTERROGATE CONTROL PORT
AND B ; VS. READY MASK
RET Z ; DONE, Z=NOT READY
OR 0FFH ; READY, MAKE ALL ONES
RET
;
;***** CP/M'S "READER" DEVICE - Code deleted to make room
;READER
;
;***** CP/M "PUNCH" DEVICE - Code deleted to make room
;PUNCH
;
; ****** INITIALIZATION ROUTINE *******************
INIT EQU $+OU ; INITIALIZATION
XOR A ; INITIALIZE BYTE 3 & 4
LD (3),A ; SET THE "IOBYTE" TO "STANDARD"
LD (4),A ; SET CURRENT DISK TO A: & USER=0
; INITIALIZE "BOARDLET"S FOR SERIAL OR PARALLEL I/O
; START WITH PORT A - NORMALLY THE PRINTER
LD A,(BAUDA) ; STAGE BAUD RATE IN CASE SERIAL
LD D,A ; IN D REGISTER
IN A,(PORTAT) ; TEST PORT A TYPE
LD HL,INITAS ; SERIAL INIT STRING
LD BC,5*256+PORTA+1 ; B=5 COUNT, C=UART CMD PORT
CALL INITCOM ; USE COMMON ROUTINE
IN A,(PORTA) ; CLEAR ANY JUNK
JR NZ,INITB0 ; DONE IF NOT PARALLEL
OUT (PORTA+5),A ; SET PO-FLAG FOR PARALLEL PORT
;
; INITIALIZE ADV SLOT 2
INITB0: LD A,(BAUDB) ; STAGE BAUD RATE IN CASE SERIAL
LD D,A ; IN D REGISTER
IN A,(PORTBT) ; GET BOARD TYPE
LD HL,INITBS ; SERIAL INIT STRING
LD BC,5*256+PORTB+1 ; B=5 COUNT, C=UART CMD PORT
CALL INITCOM
IN A,(PORTB) ; CLEAR ANY JUNK
JR NZ,INITC0 ; DONE IF NOT PARALLEL
OUT (PORTB+6),A ; RESET PI-FLAG
; INITIALIZE ADV SLOT 3
INITC0: LD A,(BAUDC) ; STAGE BAUD RATE IN CASE SERIAL
LD D,A ; IN D REGISTER
IN A,(PORTCT) ; GET PORT C TYPE
LD HL,INITCS ; SERIAL INIT STRING
LD BC,5*256+PORTC+1 ; B=5 COUNT, C=UART CMD PORT
CALL INITCOM
IN A,(PORTC) ; CLEAR ANY JUNK
JR NZ,INITC9 ; DONE IF NOT PARALLEL
OUT (PORTC+5),A ; INIT PO-FLAG ON AS IF JUST ACK'ED
INITC9: RET ; END OF BOARDLET INITIALIZATION
; COMMON SUBROUTINE TO TEST BOARDLET TYPE ## Patch to known board type
; IF SERIAL, OUTPUT INITIALIZATION STRING
; REGS MUST BE: A=BOARDLET-TYPE, B=INITSTRING-LENGTH, C=COMMAND PORT
; D=BAUD-RATE-FACTOR, HL@INITSTRING
INITCOM EQU $+OU
CP BLTSER ; SEE IF SERIAL PORT
JR NZ,INITCP ; NOT SERIAL, GO TEST IF PARALLEL
DEFB 0EDH,0B3H ; Z80 OTIR INSTRUCTION, SENDS INIT STR
LD A,C ; NOW CHANGE I/O PORT
ADD A,7 ; FROM UART COMMAND TO BAUD RATE
LD C,A ; C=BAUD RATE PORT
DEFB 0EDH,51H ; Z80 OUT (C),D (BAUD RATE FROM D)
RET ; EXIT (NOTE Z FLAG IS OFF)
INITCP: CP BLTPAR ; SEE IF PARALLEL PORT
RET ; SO Z ON IFF PARALLEL PORT
; INITIALIZATION STRINGS FOR 8251 USARTS ON SERIAL BOARDLETS
INITAS EQU $+OU
INITBS EQU $+OU
INITCS EQU $+OU
DEFB 80H,80H ; FILLERS TO INSURE KNOWN STATE
DEFB 40H ; INTERNAL RESET COMMAND
DEFB 0CEH ; 2 STOPS, NO PARITY, 8 DATA BITS, 16X CLK
DEFB 37H ; RTS, ER, RXE, DTR, TXE COMMAND
;INITBS: DEFB 80H,80H,40H,0CEH,37H ; SAME AS FOR A
;INITCS: DEFB 80H,80H,40H,0CEH,37H ; SAME AS FOR A
CSTACK EQU $+OU ; stack grows into init area above
DW 0 ; storage for old stack pointer
; ****************************************
; PART IIIb - CLOCK READ ROUTINE
; ****************************************
TIME EQU $+OU ; routine returns with pointer in HL
DI
PUSH IX ; find addr of current fcb
POP HL ; put it in accum
LD A,H
CP 40H ; see if fcb located above 4000h
PUSH AF ; @2 save carry flag
LD A,84H
JR C,TSKIP ; if below 4000h, map high
OUT 0A0H,A ; otherwise, map PROM onto 0000 - 4000h
LD DE,0004H ; & read memory in the PROM space
JR TDONE
TSKIP: OUT 0A1H,A ; map PROM onto 4000h - 8000h
LD DE,4004H ; & read memory in the PROM space
TDONE: LD A,(DE) ; the first read is just for a reset
DEC DE ; enable done with 0003h & 0002h
LD HL,TIMREG ; 1. - CLOCK ENABLE routine
LD A,(HL) ; get first byte of recog sequence
TIEBYT: LD B,A ; b contains byte
LD C,8 ; do this for 8 bits
TIEBIT: SRL B ; 0->b7...b0->carry
JR NC,TIEX1
LD A,(DE) ; WRITE with bit A2 low & bit A0 high
JR TIEX2
TIEX1: DEC DE
LD A,(DE) ; WRITE with bit A2 low & bit A0 low
INC DE
TIEX2: DEC C
JR NZ,TIEBIT ; do all 8 bits
INC HL ; point to next byte
LD A,(HL) ; get next byte
OR A ; set zero flag
JR NZ,TIEBYT ; do next byte til code enable complete
TIREAD: INC DE ; 2. - CLOCK READ routine
LD HL,TIBUF+7 ; set up buffer
LD C,8 ; do 8 bytes
TIRBYT: LD B,8 ; do 8 bits
TIRBIT: LD A,(DE)
SRL A ; shift bit into carry
RR (HL) ; shift bit into (hl)
DEC B ; dec bit counter
JR NZ,TIRBIT ; read next bit
DEC HL ; point to next buf location
DEC C ; dec byte counter
JR NZ,TIRBYT ; read next byte
LD DE,TIBUF+3 ; point to weekday
INC HL ; point to year
LD A,(DE) ; get weekday
LD B,(HL) ; get year
LD (HL),A ; overwrite weekday onto year
LD A,B ; get year
LD (DE),A ; write year onto weekday
LD HL,TIBUF+1 ; point to "month" before RET
POP AF ; @2 get carry flag back again
LD A,0
JR C,TSKP2 ;
OUT 0A0H,A ; map normal RAM onto 0000h - 4000h
JR TDON2
TSKP2: INC A ; set A=1
OUT 0A1H,A ; map normal RAM onto 4000h - 8000h
TDON2: EI
RET ; and return from TIME
TIMREG EQU $+OU
DB 0c5h,3ah,0a3h,5ch ; comparison reg
DB 0c5h,3ah,0a3h,5ch,0 ; definition
TIBUF EQU $+OU ; (example) Tues 10/20/87 5:15pm
DB 0 ; year (87h)
DB 0 ; month (10h)
DB 0 ; day (20h)
DB 0 ; weekday (03h) [year]
DB 0 ; hour (17h)
DB 0 ; minutes (15h)
DB 0,0 ; seconds (0000)
; ****************************************
; PART IIIc - POP-UP CLOCK DISPLAY
; ****************************************
BIOSOUT EQU USORG+0203H ; bios conout for Northstar Adv
BIOSCUR EQU USORG+021EH ; current cursor location x & y
CDSP EQU $+OU ; clock display code
LD (CSTACK),SP ; save orig stack pointer
LD SP,CSTACK ; point to local stack
LD HL,(BIOSCUR) ; get current cursor location
PUSH HL ; save it (@1)
CALL TIME ; call TIME & retn with pointer
LD B,6 ; convert 6 bcd bytes to ascii
LD DE,CDABUF+7 ; point to start of ascii data buffer
CDS2: LD A,(HL) ; get the bcd data byte
CALL CDASC ; convert it & store at DE & DE+1
INC HL ; point to next bcd data
INC DE ; point to next ascii buffer loc
DEC B ; countdown 6 bcd bytes
JR NZ,CDS2 ;
LD HL,CDABUF ; point HL to start of cdabuf
LD B,25 ; count 25 bytes to send out
CDS4: LD C,(HL) ; get the byte to send to console
CALL BIOSOUT ; send out via bios conout
INC HL ; point to next loc
DEC B ; continue for all 25 bytes
JR NZ,CDS4
POP HL ; get orig cursor location
LD (BIOSCUR),HL ; put cursor back in bios
LD C,CV1 ; code to make cursor visible again
CALL BIOSOUT ; send it out via bios
LD C,CV2 ; byte 2 of "cursor visible"
CALL BIOSOUT ; send it out
LD SP,(CSTACK) ; restore orig stack
XOR A ; load 0 into A before ret
RET ; normal retn from CDSP
CDABUF EQU $+OU
DB CI1,CI2 ; make cursor invisible
DB CA1,CA2,CA3,CA4 ; move to location row & col
DB ' ' ;
DB 0,0,'/' ; month ascii
DB 0,0,'/' ; day ascii
DB 0,0,' ' ; year ascii
DB 0,0,':' ; hour ascii
DB 0,0,':' ; min ascii
DB 0,0,' ' ; sec ascii
CDASC EQU $+OU ; bcd to ascii conversion
LD C,A ; save incoming byte for later
RLCA ; shift right 4 times
RLCA ; (or left 4 times)
RLCA ;
RLCA ;
CALL CDAS2 ; convert and store
LD A,C ; get byte back
CDAS2 EQU $+OU
AND 0FH ; mask lower nibble
OR 30H ; convert to ascii
LD (DE),A ; store it
INC DE ; move to next loc for next nibble
RET ; retn CDAS2 & retn CDASC
UREF1 EQU $ ; location of end of code (local)
UREF2 EQU $+OU ; location of end (after it's moved)
USIZE EQU $-UCODE ; the size of code to be moved