IMD 1.16: 13/08/2007 18:29:39 rom osborne source files *master* 10/9/81  OCCROM71HB =OCCROM61HB W OCCROM81HB OCCROM0AH OCCROM2AH #OCCROM7AH =OCCROM6AH dOCCROM8AH OCCROM3AH  !"#$OCCROM3AH %&'()*+,OCCROM3AH -.OCCROM1AH G/0123OCCROM5AH 4OCCROM4AH e56789:;OCCROM9AH <OCCROM12ASM'=>?OCCROM6BH W@ABCDEOCCROM8BH FOCCROM4BH eGHIJKLMOCCROM2BH #NOPOCCROM21HB #QRSOCCROM01HB TOCCROM11HB (UVWOCCROM42ASM_XYZ[\]OCCROM52ASM^OCCROM62ASMW_`abcdOCCROM32ASMefghijklOCCROM32ASM{mnopqrstOCCROM41HB _uvwxyzOCCROM91HB {OCCROM0BH |OCCROM3BH }~id. ; Entry None. ; Exit Back to diag main loop. proc CALL DSKDI ;initialize LDK A,100 :2: STO A,TEM CALL GNRN ;get next track STO A,SAVTRK LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if disk error CALL GNRN ;get random CALL DELAY ;delay LD A,TEM DEC A JRNZ :2 ;if not done JR DERC ;display error count space 4,8 ;DDAM: ;Test data address marks ;; Entry None ;; Exit After 1000 tries and displays ; proc ; CALL DSKDI ;initialize disk ; LDK BC,1000 ;:2: PUSH BC ; CALL DRDA ;read address mark ; LDK C,' ' ; JRZ :4 ;if good xfer ; LD HL,ERCNT ; INC HL ; STO HL,ERCNT ;update error count ; LDK C,80h ;pure white space ;:4: CALL COUT ;output indicator ; POP BC ; DEC BC ; MOV A,B ; OR C ; JRNZ :2 ;if not done ; JR DERC ;display error count space 4,8 DERC: ;Display error counter. ; Entry ERCNT = current error count LDK DE,DERCMG CALL ESTR ;output error prompt LD HL,ERCNT JMP ADRD ;output number DERCMG: DBE cr,lf DCE 'EROCCROM3BH OCCROM3BH OCCROM7BH =OCCROM5BH OCCROM9BH OCCROM02ASM OCCROM1BH AOCCROM51HB OCCROM31HB OCCROM31HB _OCCROM72ASM=OCCROM82ASM OCCROM92ASM OCCROM22ASM# TITLE 'Diagnostic section.' ; This section of code is entered either via the 1st prompt ; level by entering ^d, or by using the monitor command of ; 'T' if DEBUG is assembled on. ; ; This section of code contains all of the rom resident ; diagnostics to assist production and distributors. ; ; The diagnostic section uses a menu and contain test ; for major hardware pieces. These diagnostics are NOT ; considered to be all-encompassing...... DIAG: proc LK SP,ROMSTK LDK DE,DIAMSG DIAG1: CALL ASKU ;ask user for input LDK HL,DSKSWP ;disk swap cell LDK C,0 STO C,[HL] ;SET A=A,B=B CMP 'A' JZ CBOOT ;IF BOOT A DRIVE INC [HL] ;SWAP DRIVES A=B,B=A CMP 'B' JZ CBOOT ;IF BOOT B DRIVE DEC [HL] ;A=A, B=B CMP 'K' JZ KEYBT ;if Keyboard test CMP 'M' JZ TSTMEM ;if memory test CMP 'R' JZ TSERI ;if input test program CMP 'D' JRNZ DIAG ;if illegal DSKD: ;Here to run disk diagnostic LDK DE,DSKMSG CALL ASKU ;Ask user for input SUB 'A' JRZ :2 ;ifR cnt- ' page DSKDI: ;Disk diagnostic initialize ; Entry SDISK set to disk to test(0 or 1) proc LD A,SEC6 STO A,RNDV ;set random seed CALL DDRV ;deselect drive :2: LDK DE,0 STO DE,ERCNT ;clear error count MOV C,E CALL HOMED ;select drive 0, home. JRZ :3 ;if drive ready CALL RDSKC ;reset disk controller LDK DE,DNRMSG CALL ODER ;output disk error JR :2 :3: LDK BC,HSTBUF STO BC,DMADR ;set to default dma RET page ASKU: ;Ask user for input, first displaying prompt ; Entry DE= FWA of prompt message ; Exit A= normalized input from user CALL ESTR ;prompt user CALL GETCH ;get next char CMP ESC JZ DIAG ;if abort RET page KEYBT: ;Perform reading of keyboard and echoing to screen ; Keeps running till user types in ^Z. LDK DE,KEYTM CALL ESTR ;output prompt LDK HL,4000h JMP ACMDD ;enter A command KEYTM: DBE cr,lf DCE 'Enter keys (till ^Z) : ' page TSTMEM: ;performs a test of memory validating that the ; memory is working corre 'A' DEC A JRNZ DIAG ;if not A or B INC A :2: STO A,SDISK ;set drive CALL DRDT ;test reading entire disk CALL DSEKT ;test random seeks JMP DIAG1 ;next DIAMSG: DBE 'Z'-40h DBE ' ROM DIAGNOSTICs' DBE cr,lf,'Select Test:' DBE cr,lf,'A,B Boot Sys' DBE cr,lf,' D isk' DBE cr,lf,' K ey-vdt' DBE cr,lf,' M emory' DBE cr,lf,' R ead in test' DBE lf,cr,lf,' :' DCE ' ' DSKMSG: DBE cr,lf DCE 'Select (A,B): ' ; Disk diagnostic section. DRDT: ;Disk read test ; reads each sector on disk and reports any errors proc CALL DSKDI ;initialize disk LDK A,0 :2: STO A,SAVTRK LDK A,1 :3: STO A,SAVSEC LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if error LD A,SAVSEC INC A CMP MSEC+1 JRNZ :3 ;if not full track LD A,SAVTRK INC A CMP MTRK JRNZ :2 ;if not full disk JR DERC ;display error count space 4,10 DSEKT: ;Disk seek test ; Routine performs random seeks followed by reads validating ; drive is aligned and data path is valctly. ; Fixed limits on memory test are 4000h to EF00h ; (TEM = EF00h) ; Entry none. ; Exit To error if any errors occurred during ; the testing ; Calls GETNM proc LDK DE,TSMSG CALL ESTR ;prompt user about mem test LDK DE,TEM LDK HL,4000h LDK C,0A5h ;initial test pattern ; Loop thu testing memory within limits ; HL= FWA ; DE= LWA :2: DI PUSH DE ;save LWA PUSH HL ;save FWA :3: STO C,[hl] ;data to memory INC HL ;update address CALL CDEHL JRNZ :3 ;if not all done ; Now perform test on memory reading ; what was just written and comparing ; with pattern C. POP HL ;restore FWA PUSH H :5: DI LD A,[hl] CMP C ;validate good write JRZ :7 ;If GOOD compare EI MOV B,A ;save BAD data PUSH BC CALL OCRLF ;output new line CALL ADRD ;Output Location in error CALL OSP ;Output space char POP BC PUSH BC MOV A,C CALL NMOUT ;Output good data LDK C,'=' CALL COUT MOV A,B CALL NMOUT ;Output BAD data POP BC ;restore pattern CALL BREAK :7: Iaddress JR PBBH space 4,10 BREAK: ;Check for break key. ; Entry NONE ; Exit To DIAG if char entered is ESC, else ; return to caller A= char or 0 if none ; Calls SKEY, CI ; DESTROYS: A,F/F'S CALL SKEY ;get console status RZ ;If not ready CALL CI ;get char CMP ESC JZ DIAG ;if ESC, abort RET space 4,10 GETCH: ;returns the next character in the input stream ; TO the calling program. ; Entry NONE ; Exit C - next character normalized to UPPER case. ; Calls CI,CO,NORM ; DESTROYS: A,C,F/F'S CALL CI ;Get character from terminal CALL CO ;output it JMP NORM ; END OCCROM7?.??? l] INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of A AND 1100_0000b ;get drive bits only CMP C JZ RDSKD ;if drive already selected ; Check to see if this drive is the same as the last ; one selected. ; IF true, go to 3 ; else ; Save current trk register in LDSEL and ; set trk reg to last track used for newly selected ; drive ; end LD A,LDSEL ;last selected disk CMP C JRZ :3 ;if same drive MOV A,C STO A,LDSEL ;set to new drive PUSH BC LDK HL,LDTRK LD C,[hl] ;get last accessed track for new drive LD A,D.TRKR ;get current track STO A,[hl] ;save in table MOV A,C STO A,D.TRKR ;set trk register to last selected POP BC ; Set drive select perserving vio offset values :3: CALL RDSKD ;RESET CONTROLLER LDK B,5 ;NUMBER OF TRIES :5: LDK A,250 CALL DELAY LK A,250 ;2ND DELAY CALL DELAY LD A,D.STSR AND DS.INX RZ ;IF INDEX DJNZ :5 ;KEEP TRYING OR 80H OR DS.INX ;INDICATE NOT READY RET space 4,10 DDRV: ;Deselect drive ; Entry SDISK = current disk drive LD A,PIABD AND 1_1111b MNC HL CALL CDEHL JRNZ :5 ;If not all done EI ;allow key entry MOV A,C RRC ;shift one position MOV C,A LDK HL,FWAVM+40 INC [hl] ;indicate running POP HL POP DE CALL BREAK JRZ :2 ;if not data MOV C,A ;next test pattern JMP :2 ;keep on looping TSMSG: DBE cr,lf,'Memory tes' DCE 't' page TSERI: ;Input test routine through serial port ; Format of input: ; 8 bit binary data, no parity ; 1st two bytes are DW (length) ; (length) following bytes are placed ; at 4000h in memory; ; Exit: JMP 4000h Proc LK DE,:lmsg ;length msg CALL ESTR CALL READER ;get chr MOV L,C ;low byte of length CALL READER MOV H,C CALL PBWH ;print out length of test routine EX HL,DE ;DE = length LK HL,4000h ;FWA of test program :loop: MOV A,D OR E JRZ :xit ;if finished with input, run prgm CALL READER STO A,[hl] ;get & deposit next byte STO A,FWAVM+40 ;indicate recieved data INC HL DEC DE JR :loop :xit: LK DE,:xmsg ;exit message CALL ESTR TITLE 'Disk I/O routines.' ; Disk interface definitions and functions. ; 1792 functions. DML = 4 ;= 15 ms delay on function LTRKB = 3125 ;length of a track ; Note: Shugart says LTRKB = 3125... NRTRYS = 4 ;Number of retries MSECB = 10h ;Multi-sector r/w bit ; FUNCTION CODES D.RES = 00H ;RESTORE D.SEK = 14H ;SEEK D.STP = 20H ;STEP D.STPI = 40H ;STEP IN D.STPO = 60H ;STEP OUT D.RDS = 80H ;READ SECTOR D.WRTS = 0A0H ;WRITE SECTOR D.RDA = 0C0H ;READ ADDRESS D.RDT = 0E0H ;READ TRACK D.WRTT = 0F0H ;WRITE TRACK D.FINT = 0D0H ;FORCE INTERRUPT ; Disk status and command registers D.CMDR = H.FDC ;Disk command reg (write) D.STSR = H.FDC ;Status reg (read) D.TRKR = D.CMDR+1 ;track reg D.SECR = D.CMDR+2 ;Sector reg D.DATR = D.CMDR+3 ;Data reg (r/w) ; Status definitions BS.BSY = 0 ;Busy DS.BSY = 1 shl BS.BSY BS.DRQ = 1 DS.INX = 1 shl BS.DRQ ;Index mark detected DS.DRQ = DS.INX ;DR is full on read, empty on write BS.TK0 = 2 DS.TK0 = 1 shl BS.TK0 DS.LSD = DS.TK0 OV C,A JMP OPBD ;deselect last drive page PSEKC: ;Perform seek type command ; Entry A= command to perform without r1, and r0. ; PSEKC will or in the low two bits as defined ; by SEKDEL. ; Exit A= last value of D.STSr LDK HL,SEKDEL OR [hl] ;or in delay time for seek CALL FDSK ;function disk RNZ ;if Drive NOT ready JMP WBUSY space 4,10 SELDSK: ;Select disk in register C MOV A,C ;drive to home CALL SDRV1 ;C= drive JR HOMED1 HOMED: ;Home disk drive ; Entry SDISK= drive ; Exit A=0 if drive on home. proc CALL SDRV ;select drive HOMED1: LDK A,D.RES CALL PSEKC ;perform seek command CMP -1 JRZ SKEX1 ;if error BIT BS.SEK,A JRNZ SKEX1 ;if error BIT BS.TK0,A JRZ :4 ;if NOT home IF ODEBUG CALL LDSKS1 ;list status **** ENDIF XRA A ;clear A SKEX1: PUSH AF LDK A,-1 STO A,DACTVE ;start counter CALL STAT17 ;save disk controller regs POP AF RET ; Here if drive NOT homed, possible NOT ready :4: AND 80h JR SKEX1 space 4,10  JMP 4000h ;...to user program :lmsg: DBE cr,lf,'Start input: Len' ! DCE '=' :xmsg: DBE cr,lf,'Program begins' ! DCE ':' space 4,10 GNRN: ;Get next random number ; Exit A= new number to use (0 to MTRK-1) proc MOV A,R ;refresh register XOR [hl] AND 3Fh ;cannot exceed 28h=40d ADD A,16 CMP MTRK JC :4 ;if in range SUB MTRK :4: STO A,[hl] ;update RET space 4,10 ACMDD: ;Eotry here from Diagnostic loop HL = 4000h proc :3: CALL CI ;read char CPI EOFC JZ DIAG ;if request to quit STO A,[hl] ;into memory INC HL ;update pointer CPI CR JRNZ :5 ;If not carriage return STO LF,[hl] INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of  ;lost data DS.CRC = 08h ;CRC error in ID field BS.SEK = 4 DS.SEK = 1 shl BS.SEK ;Seek error DS.RNF = DS.SEK ;Record NOT found DS.HDL = 20h ;Head loaded DS.WTF = DS.HDL ;Write fault DS.WTP = 40h ;Write protected DS.NRY = 80h ;Drive NOT ready ; Disk timing counts D.DEL = 20 ;Delay after function page SDMA: ;Set DMA SETDMA: ; Entry BC = DMA address STO BC,DMADR RET space 4,10 SETTRK: ;Set track ; Entry BC = track STO BC,SAVTRK RET space 4,10 SETSEC: ;Set Sector ; Entry C= sector number (1 to MSEC) MOV A,C STO A,SAVSEC RET space 4,10 HOME: ;Home selected disk drive XRA A ;reset track to 0 STO A,SAVTRK RET PAGE SDRV: ;Select Drive ; Entry SDISK= drive ; Exit A= 0, if drive is ready ; Calls OPBD, DELAY ; Uses A,B proc LD A,SDISK SDRV1: LK HL,DSKSWP ;disk drive swap cell XOR [hl] ;swap A for B if DSKSWP=1 AND 1 ;Can only be 0 or 1 CMP 1 JRNZ :2 ;if not drive 1 LDK A,40h :2: ADI 40h MOV C,A LD A,PIABD MOV B, SEEK: ;Seek to track defined by SAVTRK ; Entry SAVTRK set to track ; SAVSEC set to sector number ; Exit A= 0, if no error, else status ; MUST NOT destroy DE, HL pair proc CALL SDRV ;select drive ; Here if drive already selected ; Check to see if SEEK is necessary by ; comparing SAVTRK to controller track ; register LD A,SAVTRK STO A,D.DATR ;set track wanted MOV C,A LD A,D.TRKR CMP C JRZ :8 ;if on track ; Disk seek required, function controller ; with SEEK command LDK A,5 SEEKA: STO A,RTRY ;update retry count LDK A,D.SEK CALL PSEKC ;perform seek command MOV C,A AND DS.CRC or DS.SEK JRNZ :10 ;if error ; Now read-address and verify on-track CALL DRDAS ;read address JRNZ :10 ;if error LDK HL,DSTSB LD A,SAVTRK CMP [hl] JRZ :8 ;if ON track LD A,RTRY DEC A JRNZ SEEKA ;if not max retrys ; here if seek error :10: MOV A,C ORI 80h ;indicate movement error JR SKEX1 ; Now set the sector register to requested ; Sector :8: ,D.WRTS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' bit :3: CALL FDSK POP BC ; Now xfer bytes to controller from DMA. DI LD HL,DMADR :5: PUSH BC LDK BC,LSECB ;length of std sector :6: CALL XDD ;xfer to disk JRNZ RWEX ;if error ; Now check if multi sector POP BC DJNZ :5 ;continue XRA A :8: JR RWEX1 page XDD: ;Xfer data from memory to disk ; Entry BC = length ; HL = FWA ; Exit HL = next address ; A=0 if no error, else status ; Uses A,BC,E, HL proc LD A,D.STSR BIT BS.BSY,A JRZ :5 ;if possible error BIT BS.DRQ,A JRZ XDD ;if no data LD A,[hl] STO A,D.DATR ;send to controller INC HL DEC BC MOV A,B OR C JRNZ XDD ;if not done XRA A ;indicate good xfer RET ; here if error :5: OR 80h ;indicate busy dropped RET page FDSK: ;Function disk routine ; All functions for DSK controller SHALL do so by using ; this routine. FDSK sets DACTVE to 0 indicating activity ; UPTIM uses this cell to turn off select if one CALL O2SP LD A,SAVTRK CALL PBBH ;output track LDK C,',' CALL COUT ;output comma LD A,D.TRKR CALL PBBH ;output controller track CALL O2SP LD A,SAVSEC CALL PBBH ;output sector LDK C,',' CALL COUT ;output comma LD A,D.SECR CALL PBBH ;output controller sector ; Update error counter LD HL,ERCNT INC HL STO HL,ERCNT ;update error count ; Clear controller CALL RDSKC ;reset disk controller ; Restore regs POP BC POP HL POP DE RET DERMSG: DBE cr,lf DCE 'Dsk ERR (sts trk sec)- ' space 4,10 STAT17: ;save 179x status ;called when disk error discovered: ;...saves 179x regs in high RAM. PUSH BC ! PUSH DE ! PUSH HL LK HL,D.STSR ;1st (lowest) 179x register LK DE,R179x ;register save area LK BC,4 ;move 4 bytes LDIR POP HL ! POP DE ! POP BC RET ; END OCCROM6?.???  PUSH HL PUSH BC PUSH AF LDK DE,DERMSG CALL ESTR ;output error POP AF ;get status value CALL PBBH ;output statusCALL WBUSY ;wait for FDC quiescence LD A,SAVSEC STO A,D.SECR ;set sector register XRA A ;indicate good RET space 4,10 DRDAS: ;Read Address info. ; Exit D.STSB = data bytes ; MUST NOT destroy DE pair proc LDK A,D.RDA CALL FDSK ;function disk ; Get status bytes LDK HL,DSTSB LDK B,6 DI PUSH DE ;save DE :2: LDK DE,4000 ;time out :3: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRNZ :4 ;if data ready DEC DE MOV A,D OR E JRNZ :3 ;if NOT time out LK C,SEKTMO ;seek time out JR RWEX ;error exit :4: LD A,D.DATR STO A,[hl] ;save byte INC HL DJNZ :2 ;if not done POP DE XRA A ;indicate good EI ! RET space 4,10 DREAD: ;Read disk sectors. ; Entry SDISK= drive ; B = number of sectors to read ; Number from 1 to MSEC ; DMADR= FWA for data. ; Exit DSTSB= A= 0, if no error ; HL = next DMA ; Uses All registers proc MOV D,B ;save sectors CALL SEEK ;seek to track, set sector JRNZ RWEX1 ;if se sec has ; occurred. ; Entry A= function code ; Exit A= 0, if chip accepted function ; else, A=-1, indicating time-out, See WBUSY ; Uses A, B, C proc MOV B,A ;save function code LD A,PIABD AND 1100_0000b JRNZ :1 ;if drive active PUSH BC CALL SDRV ;reselect drive POP BC :1: CALL WBUSY ;Wait for busy to clear RM ;if will NOT clear busy ; Controller NOT busy, issue command MOV A,B STO A,D.CMDR ;function drive ; Wait for busy to be set LDK C,0 :2: LD A,D.STSR RAR ;DS.BSY JRC :3 ;if chip went busy DEC C JRNZ :2 ;if not time-out JR WBUSYX ;exit, error ; Set DACTVE indicating activity on drive :3: LDK A,-1 STO A,DACTVE XRA A ;ZERO A RET space 4,10 WBUSY: ;Wait for Busy to clear ; Exit A= -1, if time out occurred, ; else ; A= last status and is positive. ; Uses A, C proc PUSH BC LDK BC,0 :1: LD A,D.STSR RAR ;DS.BSY JRNC :1A ;if NOT busy, proceed DEC BC MOV A,B OR C JRNZ :1 ;if not time-out WBUSYX: LDK Aek error MOV B,D LDK C,0 PUSH BC LDK A,D.RDS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' cit :3: CALL FDSK POP BC CMP -1 JRZ RWEX1 ;if drive NOT ready ; Now xfer bytes from controlles to DMA. DI LD HL,DMADR :5: PUSH BC LDK B,low LSECB :6: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRZ :6 ;if no data LD A,D.DATR STO A,[hl] INC HL ;FOR EDIT DJNZ :6 ;if not all data ; Now check if multi sector ;GOR THE EDITOR POP BC DJNZ :5 ;continue XRA A JR RWEX1 ; here on error RWEX: CALL STAT17 ;save disk controller regs POP DE ;restore stack OR 80h ;if busy cleared, indicate with 80h RWEX1: OR A ;set status PUSH AF LDK A,-1 STO A,DACTVE POP AF EI ! RET space 4,10 DWRT: ;Write to disk ; Entry SDISK= drive ; B= Number of sectors to xmit. ; DMADR= FWA of data ; Exit same as DREAD ; Uses All registers proc MOV D,B CALL SEEK JRNZ RWEX1 ;if seek error MOV B,D PUSH BC LDK A,-1 ;indicate error, drive NOT ready POP BC OR A ;set flags RET :1A: RAL ;restore A POP BC ;restore BC AND 7Fh ;make sure its positive RET space 4,8 RDSKD: ;Reset PIA and disk controller ; selecting drive specified by C ; Entry C= drive ; B= PIABD MOV A,B AND 0001_1111b ;get vio offset only OR C MOV C,A CALL OPBD ;function PIO-b ; JMP RDSKC RDSKC: ;reset disk controller ; Entry None ; Exit Busy cleared. ; A= 0. LDK A,D.FINT STO A,D.STSR ;clear controller XRA A ;clear A and flags RET ODER: ;Output disk error to console ; Entry DE= FWA of message ; SDISK = drive with error PUSH DE CALL OCRLF ;new line LD A,SDISK ADD A,'A' MOV C,A CALL CO ;output drive name CALL O2SP POP DE ;get message JMP ESTR DERR: ;Output disk system error ; Entry A= status from controller ; Exit error output PUSH DE PUSH HL PUSH BC PUSH AF LDK DE,DERMSG CALL ESTR ;output error POP AF ;get status value CALL PBBH ;output status TITLE 'FORMAT' FORMT: ;Format one track ; in IBM 3740 format consisting of 40 tracks, with each ; track containing 10 sectors. ; Drive already selected and ready ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK LDK HL,D.TRKR ;PRESENT TRACK OR [HL] JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RE ENDM PAGE LINK OCCROM1A.H ;ROM STANDARDS ;LOP,ROMD LINK OCCROM2A.H ;CPM BOOT ;BOOT LINK OCCROM3A.H ;CONSOL ROUTINES ;KEY LINK OCCROM4A.H ;PIA ROUTINES ;PIO,IEEE LINK OCCROM5A.H ;SIA ROUTINES ;SIO LINK OCCROM6A.H ;DISK ROUTINES ;DSK LINK OCCROM7A.H ;DIAGNOSIC ROUTINES ;DIA LINK OCCROM8A.H ;FORMAT ROUTINE ;XFMT LINK OCCROM9A.H ;UTILITES ;UTIL2 LINK OCCRAMA.ASM ;RAM LOCATIONS ; Endx FORMAT IS IN ROM INACMD = FALSE INBCMD = TRUE INDCMD = FALSE INFCMD = FALSE INGCMD = FALSE INHCMD = FALSE INMCMD = FALSE INRCMD = FALSE INSCMD = FALSE INTCMD = FALSE INXCMD = FALSE INZCMD = FALSE INDIA = TRUE ;INTERNAL DIAGNOSTICS INDMON = FALSE INUTIL = FALSE NULINT MACRO NUMB ORG %1*8 DI JMP ILINT NOP ! NOP ! NOP ! NOP ENDM PUSHAL MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM POPALL MACRO POP IY POP IX POP HL POP DE POP BC POP AF ow) seek to trk 12, sec 0 ; ;:fastr: LK HL,SAVTRK ; LK A,-4 ;seek 4 tracks out ; ADD [hl] ; STO A,[hl] ; LK HL,SEKDEL ; DEC [hl] ;speed up step rate ; CALL SEEK ;seek 4 track outwards, faster ; JRNZ :err ;if stepping too fast ; LD A,SEKDEL ; OR A ;stepping fastest possible? ; JRNZ :fastr ;try a faster seek ;; JR :end ;..else seeking fastest already ; ;:end: CALL BCPM1 ;read in cpm ; JMP BIOS ;cold start ; ;:err: LK HL,SEKDEL ; INC [hl] ;seek at previous (slower) speed ; LK A,0000_0011b ; AND [hl] ;limit seek to (slowest) 3 ; STO A,[hl] ; JR :end WBOOT: Proc LDK A,6-4 ;don't read CBIOS STO A,TEM ;save sectors LD A,CDISK ;Current logged in drive ; JR BCPM ;Boot CP/M space 4,10 BCPM: ;Boot CPM from disk ; Entry A = Drive to boot from. ; TEM = Number of sectors to read from ; track 3. ; A = Drive to boot or warm-boot from ; Exit A = 0, load sucessful. ; Z bit = 1, load successful. proc STO A,SDISK ;Set drive to boot from BCPM1: CALL HOMT ; END OCCROM8?.??? ors. ; Drive already selected and ready ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK LDK HL,D.TRKR ;PRESENT TRACK OR [HL] JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RE TITLE 'B o o t C P / M f r o m d i s k.' ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; ; Before any data is read in, the maximum drive step rate ; must be determined: ; 1. set slowest seek ; 2. home drive A: ; 3. seek track #12 ; 4. speed up step rate ; 5. seek 4 tracks outward (12=>8,8=>4,4=>0) ; 6. if error, slow down step rate by 1, ; load in CP/M, boot, exit, etc. ; 7. else try faster step rate ; (if not fastest, GOTO #4 above) ; 8. if stepping fastest rate, boot CP/M. ; The exit address is to the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDED ;home drive OR A JRNZ BCPME ;if drive NOT ready LDK BC,CCP ;Set buffer address CALL SETDMA LDK HL,0 STO HL,SAVTRK ;set track LDK A,1 STO A,SAVSEC ;set sector=1 ; Read in 1st two track LDK B,2 :4: PUSH BC LDK B,MSEC CALL DREAD ;read 1st track POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LD HL,SAVTRK INC HL STO HL,SAVTRK ;update track to read DJNZ :4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCP;OCCROM0A.H TITLE 'Osborne-One Monitor for Model 1 system.' * 4D2008-00 MASTER .ASM * 2D2008-00 ASSY .ASM * 1D2008-00 LISTING .PRN * 4D1008-00 MASTER .COM * 2D1008-00 ASSY .COM LIST -F ;4-25, Do not list opted out code ; Initial Monitor for Osborne-One System. ; +-------------------------------+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV A ;DATE = 180 ;DEB ; Assembly Constants ORG 0 ;FWA of memory @XFRMT = TRUE ;FALSE IF FORMAT IS IN ROM INACMD = FALSE INBCMD = TRUE INDCMD = FALSE INFCMD = FALSE INGCMD = FALSE INHCMD = FALSE INMCMD = FALSE INRCMD = FALSE INSCMD = FALSE INTCMD = FALSE INXCMD = FALSE INZCMD = FALSE INDIA = TRUE ;INTERNAL DIAGNOSTICS INDMON = FALSE INUTIL = FALSE NULINT MACRO NUMB ORG %1*8 DI JMP ILINT NOP ! NOP ! NOP ! NOP ENDM PUSHAL MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM POPALL MACRO POP IY POP IX POP HL POP DE POP BC POP AF OS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT routines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; ; Disk layout Definition ; --Note: Tracks 0, 1, and 2 are reserved for CPM.-- ; Track 0----------- ; 1 thru 8 CCP 2k ; 9 thru 10 BDOS ; Track 1----------- ; 1 thru 10 BDOS ; Track 2----------- ; 1 thru 2 BDOS 3.5k ; 3 thru 10 CBIOS 2k ; Sectors 3,4,5,6 are currently used. page CBOOT: ;Entry C= drive to boot from ; Exit A= drive Proc LDK A,6 ;read 5 sectors of trk 3 STO A,TEM MOV A,C CALL BCPM ;boot system LD A,SDISK ;use requested drive JMP BIOS ;enter CPM ; LK A,3 ; STO A,SEKDEL ;set step rate =3 (slowest) ; CALL HOMED ;send A: home ; ; LK BC,12 ; CALL SETTRK ;track 12 ; LK C,0 ; CALL SETSEC ;sector 0 ; CALL SEEK ;do (slM BCPME1: PUSH DE LDK A,low(256) CALL DELAY ;Delay 256 milli-seconds POP DE ;FWA of message CALL ODER ;indicate drive NOT ready JR BCPM1 ;try again ; Here on Boot READ error BRDE: LDK DE,BRDEMG JR BCPME1 ;delay output error DNRMSG: DCE 'Drive NOT ready.' BRDEMG: DCE 'Boot READ error.' ; Endx BMboot.asm date track to read DJNZ :4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCPU ;Ask user for input SUB 'A' JRZ :2 ;if 'A' DEC A JRNZ DIAG ;if not A or B INC A :2: STO A,SDISK ;set drive CALL DRDT ;test reading entire disk CALL DSEKT ;test random seeks JMP NEXTC ;next DIAMSG: DBE 'Z'-40h DBE ' ROM DIAGNOSTICs' DBE cr,lf,'Select Test:' DBE cr,lf,'A,B Boot Sys' DBE cr,lf,' D isk' DBE cr,lf,' K ey-vdt' DBE cr,lf,' M emory' DBE cr,lf,' R ead in test' DBE lf,cr,lf,' :' DCE ' ' DSKMSG: DBE cr,lf DCE 'Select (A,B): ' ; Disk diagnostic section. DRDT: ;Disk read test ; reads each sector on disk and reports any errors proc CALL DSKDI ;initialize disk LDK A,0 :2: STO A,SAVTRK LDK A,1 :3: STO A,SAVSEC LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if error LD A,SAVSEC INC A CMP MSEC+1 JRNZ :3 ;if not full track LD A,SAVTRK INC A CMP MTRK JRNZ :2 ;if not full disk JR DERC ;display error count space 4,10 DSEKT: ;Disk seek test ; Routine performs random seeks followed by reads validating ; drive correctly. ; Fixed limits on memory test are 4000h to EF00h ; (TEM = EF00h) ; Entry none. ; Exit To error if any errors occurred during ; the testing ; Calls GETNM proc LDK DE,TSMSG CALL ESTR ;prompt user about mem test LDK DE,TEM LDK HL,4000h LDK C,0A5h ;initial test pattern ; Loop thu testing memory within limits ; HL= FWA ; DE= LWA :2: DI PUSH DE ;save LWA PUSH HL ;save FWA :3: STO C,[hl] ;data to memory INC HL ;update address CALL CDEHL JRNZ :3 ;if not all done ; Now perform test on memory reading ; what was just written and comparing ; with pattern C. POP HL ;restore FWA PUSH H :5: DI LD A,[hl] CMP C ;validate good write JRZ :7 ;If GOOD compare EI MOV B,A ;save BAD data PUSH BC CALL OCRLF ;output new line CALL ADRD ;Output Location in error CALL OSP ;Output space char POP BC PUSH BC MOV A,C CALL NMOUT ;Output good data LDK C,'=' CALL COUT MOV A,B CALL NMOUT ;Output BAD data POP BC ;restore pattern CALL BREAK :7:  is aligned and data path is valid. ; Entry None. ; Exit Back to diag main loop. proc CALL DSKDI ;initialize LDK A,100 :2: STO A,TEM CALL GNRN ;get next track STO A,SAVTRK LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if disk error CALL GNRN ;get random CALL DELAY ;delay LD A,TEM DEC A JRNZ :2 ;if not done JR DERC ;display error count space 4,8 ;DDAM: ;Test data address marks ;; Entry None ;; Exit After 1000 tries and displays ; proc ; CALL DSKDI ;initialize disk ; LDK BC,1000 ;:2: PUSH BC ; CALL DRDA ;read address mark ; LDK C,' ' ; JRZ :4 ;if good xfer ; LD HL,ERCNT ; INC HL ; STO HL,ERCNT ;update error count ; LDK C,80h ;pure white space ;:4: CALL COUT ;output indicator ; POP BC ; DEC BC ; MOV A,B ; OR C ; JRNZ :2 ;if not done ; JR DERC ;display error count space 4,8 DERC: ;Display error counter. ; Entry ERCNT = current error count LDK DE,DERCMG CALL ESTR ;output error prompt LD HL,ERCNT JMP ADRD ;output number DERCMG: INC HL CALL CDEHL JRNZ :5 ;If not all done EI ;allow key entry MOV A,C RRC ;shift one position MOV C,A LDK HL,FWAVM+40 INC [hl] ;indicate running POP HL POP DE CALL BREAK JRZ :2 ;if not data MOV C,A ;next test pattern JMP :2 ;keep on looping TSMSG: DBE cr,lf,'Memory tes' DCE 't' page TSERI: ;Input test routine through serial port ; Format of input: ; 8 bit binary data, no parity ; 1st two bytes are DW (length) ; (length) following bytes are placed ; at 4000h in memory; ; Exit: JMP 4000h Proc LK DE,:lmsg ;length msg CALL ESTR CALL READER ;get chr MOV L,C ;low byte of length CALL READER MOV H,C CALL PBWH ;print out length of test routine EX HL,DE ;DE = length LK HL,4000h ;FWA of test program :loop: MOV A,D OR E JRZ :xit ;if finished with input, run prgm CALL READER STO A,[hl] ;get & deposit next byte STO A,FWAVM+40 ;indicate recieved data INC HL DEC DE JR :loop :xit: LK DE,:xmsg ;exit message CALL ESTR JMP TITLE 'Diagnostic section.' ; This section of code is entered either via the 1st prompt ; level by entering ^d, or by using the monitor command of ; 'T' if DEBUG is assembled on. ; ; This section of code contains all of the rom resident ; diagnostics to assist production and distributors. ; ; The diagnostic section uses a menu and contain test ; for major hardware pieces. These diagnostics are NOT ; considered to be all-encompassing...... ; Entry from monitor loop DIAG: proc IF ~INDMON NEXTC = DIAG ENDIF LK SP,ROMSTK LDK DE,DIAMSG CALL ASKU ;ask user for input LDK HL,DSKSWP ;disk swap cell LDK C,0 STO C,[HL] ;SET A=A,B=B CMP 'A' JZ CBOOT ;IF BOOT A DRIVE INC [HL] ;SWAP DRIVES A=B,B=A CMP 'B' JZ CBOOT ;IF BOOT B DRIVE DEC [HL] ;A=A, B=B CMP 'K' JZ KEYBT ;if Keyboard test CMP 'M' JZ TSTMEM ;if memory test CMP 'R' JZ TSERI ;if input test program CMP 'D' JRNZ DIAG ;if illegal DSKD: ;Here to run disk diagnostic LDK DE,DSKMSG CALL ASK DBE cr,lf DCE 'ERR cnt- ' page DSKDI: ;Disk diagnostic initialize ; Entry SDISK set to disk to test(0 or 1) proc LD A,SEC6 STO A,RNDV ;set random seed CALL DDRV ;deselect drive :2: LDK DE,0 STO DE,ERCNT ;clear error count MOV C,E CALL HOMED ;select drive 0, home. JRZ :3 ;if drive ready CALL RDSKC ;reset disk controller LDK DE,DNRMSG CALL ODER ;output disk error JR :2 :3: LDK BC,HSTBUF CALL SETDMA ;set to default dma RET page ASKU: ;Ask user for input, first displaying prompt ; Entry DE= FWA of prompt message ; Exit A= normalized input from user CALL ESTR ;prompt user CALL GETCH ;get next char CMP ESC JZ NEXTC ;if abort RET page KEYBT: ;Perform reading of keyboard and echoing to screen ; Keeps running till user types in ^Z. LDK DE,KEYTM CALL ESTR ;output prompt LDK HL,4000h JMP ACMDD ;enter A command KEYTM: DBE cr,lf DCE 'Enter keys (till ^Z) : ' page TSTMEM: ;performs a test of memory validating that the ; memory is working 4000h ;...to user program :lmsg: DBE cr,lf,'Start input: Len' ! DCE '=' :xmsg: DBE cr,lf,'Program begins' ! DCE ':' space 4,10 GNRN: ;Get next random number ; Exit A= new number to use (0 to MTRK-1) proc MOV A,R ;refresh register XOR [hl] AND 3Fh ;cannot exceed 28h=40d ADD A,17 CMP MTRK JC :4 ;if in range SUB MTRK :4: STO A,[hl] ;update RET space 4,10 IF ~INDMON ACMDD: ;Entry here from Diagnostic loop HL = 4000h proc :3: CALL CI ;read char CPI EOFC JZ DIAG ;if request to quit STO A,[hl] ;into memory INC HL ;update pointer CPI CR JRNZ :5 ;If not carriage return STO LF,[hl] INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of addressBS.TK0 DS.LSD = DS.TK0 ;lost data DS.CRC = 08h ;CRC error in ID field BS.SEK = 4 DS.SEK = 1 shl BS.SEK ;Seek error DS.RNF = DS.SEK ;Record NOT found DS.HDL = 20h ;Head loaded DS.WTF = DS.HDL ;Write fault DS.WTP = 40h ;Write protected DS.NRY = 80h ;Drive NOT ready ; Disk timing counts D.DEL = 20 ;Delay after function page SDMA: ;Set DMA SETDMA: ; Entry BC = DMA address STO BC,DMADR RET space 4,10 SETTRK: ;Set track ; Entry BC = track STO BC,SAVTRK RET space 4,10 SETSEC: ;Set Sector ; Entry C= sector number (1 to MSEC) MOV A,C STO A,SAVSEC RET space 4,10 HOME: ;Home selected disk drive LDK BC,0 JMP SETTRK ;reset track to 0 IF ODEBUG space 4,10 LDSKS: ;List status of disk system CALL OCRLF LDSKS1: LD A,D.STSR CALL PBBH ;output status LDK C,' ' CALL CO CALL RDSKC ;reset disk controller LD A,D.STSR ;get status CALL PBBH ;new status JMP OCRLF ;new line ENDIF space 4,10 SDRV: ;Select Drive ; Entry SDISK= drive ; Exit A= LL LDSKS1 ;list status **** ENDIF XRA A ;clear A SKEX1: PUSH AF LDK A,-1 STO A,DACTVE ;start counter CALL STAT17 ;save disk controller regs POP AF RET ; Here if drive NOT homed, possible NOT ready :4: AND 80h JR SKEX1 space 4,10 SEEK: ;Seek to track defined by SAVTRK ; Entry SAVTRK set to track ; SAVSEC set to sector number ; Exit A= 0, if no error, else status ; MUST NOT destroy DE, HL pair proc CALL SDRV ;select drive ; Here if drive already selected ; Check to see if SEEK is necessary by ; comparing SAVTRK to controller track ; register SEEKN: LD A,SAVTRK STO A,D.DATR ;set track wanted MOV C,A LD A,D.TRKR CMP C JRZ :8 ;if on track ; Disk seek required, function controller ; with SEEK command LDK A,5 SEEKA: STO A,RTRY ;update retry count LDK A,D.SEK CALL PSEKC ;perform seek command MOV C,A AND DS.CRC or DS.SEK JRNZ :10 ;if error ; Now read-address and verify on-track CALL DRDAS ;read address JRNZ :10 ;if error LDK HL, JR PBBH space 4,10 BREAK: ;Check for break key. ; Entry NONE ; Exit To DIAG if char entered is ESC, else ; return to caller A= char or 0 if none ; Calls SKEY, CI ; DESTROYS: A,F/F'S CALL SKEY ;get console status RZ ;If not ready CALL CI ;get char CMP ESC JZ DIAG ;if ESC, abort RET space 4,10 GETCH: ;returns the next character in the input stream ; TO the calling program. ; Entry NONE ; Exit C - next character normalized to UPPER case. ; Calls CI,CO,NORM ; DESTROYS: A,C,F/F'S CALL CI ;Get character from terminal CALL CO ;output it JMP NORM ENDIF ; Endx BMDIA.asm INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of address0, if drive is ready ; Calls OPBD, DELAY ; Uses A,B proc LD A,SDISK SDRV1: LK HL,DSKSWP ;disk drive swap cell XOR [hl] ;swap A for B if DSKSWP=1 AND 1 ;Can only be 0 or 1 CMP 1 JRNZ :2 ;if not drive 1 LDK A,40h :2: ADI 40h MOV C,A LD A,PIABD MOV B,A AND 1100_0000b ;get drive bits only CMP C JZ RDSKD ;if drive already selected ; Check to see if this drive is the same as the last ; one selected. ; IF true, go to 3 ; else ; Save current trk register in LDSEL and ; set trk reg to last track used for newly selected ; drive ; end LD A,LDSEL ;last selected disk CMP C JRZ :3 ;if same drive MOV A,C STO A,LDSEL ;set to new drive PUSH BC LDK HL,LDTRK LD C,[hl] ;get last accessed track for new drive LD A,D.TRKR ;get current track STO A,[hl] ;save in table MOV A,C STO A,D.TRKR ;set trk register to last selected POP BC ; Set drive select perserving vio offset values :3: CALL RDSKD ;reset Controller LDK B,5 ;number of tries :5: LDK A,2DSTSB LD A,SAVTRK CMP [hl] JRZ :8 ;if ON track LD A,RTRY DEC A JRNZ SEEKA ;if not max retrys ; here if seek error :10: MOV A,C ORI 80h ;indicate movement error JR SKEX1 ; Now set the sector register to requested ; Sector :8: CALL WBUSY ;wait for FDC quiescence LD A,SAVSEC STO A,D.SECR ;set sector register XRA A ;indicate good RET space 4,10 DRDA: ;Read Address info. ; Entry SDISK= drive ; Exit D.STSB = data bytes ; MUST NOT destroy DE pair proc CALL SDRV ;select drive DRDAS: LDK A,D.RDA CALL FDSK ;function disk ; Get status bytes LDK HL,DSTSB LDK B,6 DI PUSH DE ;save DE :2: LDK DE,4000 ;time out :3: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRNZ :4 ;if data ready DEC DE MOV A,D OR E JRNZ :3 ;if NOT time out LK C,SEKTMO ;seek time out JR RWEX ;error exit :4: LD A,D.DATR STO A,[hl] ;save byte INC HL DJNZ :2 ;if not done POP DE XRA A ;indicate good EI ! RET space 4,10 DREAD: TITLE 'Disk I/O routines.' ; Disk interface definitions and functions. ; 1792 functions. DML = 4 ;= 15 ms delay on function LTRKB = 3125 ;length of a track ; Note: Shugart says LTRKB = 3125... NRTRYS = 4 ;Number of retries MSECB = 10h ;Multi-sector r/w bit ; Function codes D.RES = 00h+0Ch ;restore D.SEK = 10h+08h ;seek D.STP = 20h ;step D.STPI = 40h ;Step IN D.STPO = 60h ;Step out D.RDS = 80h ;Read sector D.WRTS = 0A0h+DML ;Write sector D.RDA = 0C0h+DML ;read address D.RDT = 0E0h+DML ;read track D.WRTT = 0F0h+DML ;write track D.FINT = 0D0h ;Force interrupt ; Disk status and command registers D.CMDR = H.FDC ;Disk command reg (write) D.STSR = H.FDC ;Status reg (read) D.TRKR = D.CMDR+1 ;track reg D.SECR = D.CMDR+2 ;Sector reg D.DATR = D.CMDR+3 ;Data reg (r/w) ; Status definitions BS.BSY = 0 ;Busy DS.BSY = 1 shl BS.BSY BS.DRQ = 1 DS.INX = 1 shl BS.DRQ ;Index mark detected DS.DRQ = DS.INX ;DR is full on read, empty on write BS.TK0 = 2 DS.TK0 = 1 shl 50 CALL DELAY LK A,250 ;2nd delay CALL DELAY LD A,D.STSR AND DS.INX RZ ;if index DJNZ :5 ;keep trying OR 80h or DS.INX ;indicate NOT ready RET space 4,10 DDRV: ;Deselect drive ; Entry SDISK = current disk drive LD A,PIABD AND 1_1111b MOV C,A JMP OPBD ;deselect last drive page PSEKC: ;Perform seek type command ; Entry A= command to perform without r1, and r0. ; PSEKC will or in the low two bits as defined ; by SEKDEL. ; Exit A= last value of D.STSr LDK HL,SEKDEL OR [hl] ;or in delay time for seek CALL FDSK ;function disk RNZ ;if Drive NOT ready JMP WBUSY space 4,10 SELDSK: ;Select disk in register C MOV A,C ;drive to home CALL SDRV1 ;C= drive JR HOMED1 HOMED: ;Home disk drive ; Entry SDISK= drive ; Exit A=0 if drive on home. proc CALL SDRV ;select drive HOMED1: LDK A,D.RES CALL PSEKC ;perform seek command CMP -1 JRZ SKEX1 ;if error BIT BS.SEK,A JRNZ SKEX1 ;if error BIT BS.TK0,A JRZ :4 ;if NOT home IF ODEBUG CA DRSECS: ;Read disk sectors. ; Entry SDISK= drive ; B = number of sectors to read ; Number from 1 to MSEC ; DMADR= FWA for data. ; Exit DSTSB= A= 0, if no error ; HL = next DMA ; Uses All registers proc MOV D,B ;save sectors CALL SEEK ;seek to track, set sector JRNZ RWEX1 ;if seek error MOV B,D PUSH BC LDK A,D.RDS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' bit :3: CALL FDSK POP BC CMP -1 JRZ RWEX1 ;if drive NOT ready ; Now xfer bytes from controller to DMA. DI LD HL,DMADR :5: PUSH BC LDK B,low LSECB :6: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRZ :6 ;if no data LD A,D.DATR STO A,[hl] INC HL DJNZ :6 ;if not all data ; Now check if multi sector POP BC DJNZ :5 ;continue XRA A JR RWEX1 ; here on error RWEX: CALL STAT17 ;save disk controller regs POP DE ;restore stack OR 80h ;if busy cleared, indicate with 80h RWEX1: OR A ;set status PUSH AF LDK A,-1 STO A,DACTVE POP A ; Entry BC = length ; HL = FWA ; Exit HL = next address ; A=0 if no error, else status ; Uses A,BC,E, HL proc LD A,D.STSR BIT BS.BSY,A JRZ :5 ;if possible error BIT BS.DRQ,A JRZ XDD ;if no data LD A,[hl] STO A,D.DATR ;send to controller INC HL DEC BC MOV A,B OR C JRNZ XDD ;if not done XRA A ;indicate good xfer RET ; here if error :5: OR 80h ;indicate busy dropped RET page FDSK: ;Function disk routine ; All functions for DSK controller SHALL do so by using ; this routine. FDSK sets DACTVE to 0 indicating activity ; UPTIM uses this cell to turn off select if one sec has ; occurred. ; Entry A= function code ; Exit A= 0, if chip accepted function ; else, A=-1, indicating time-out, See WBUSY ; Uses A, B, C proc MOV B,A ;save function code LD A,PIABD AND 1100_0000b JRNZ :1 ;if drive active PUSH BC CALL SDRV ;reselect drive POP BC :1: CALL WBUSY ;Wait for busy to clear RM ;if will NOT clear busy ; Controller NOT busy, issue comm regs POP BC POP HL POP DE RET DERMSG: DBE cr,lf DCE 'Dsk ERR (sts trk sec)- ' space 4,10 STAT17: ;save 179x status ;called when disk error discovered: ;...saves 179x regs in high RAM. PUSH BC ! PUSH DE ! PUSH HL LK HL,D.STSR ;1st (lowest) 179x register LK DE,R179x ;register save area LK BC,4 ;move 4 bytes LDIR POP HL ! POP DE ! POP BC RET ; endx BMDSK tput error POP AF ;get status value CALL PBBH ;output status CALL O2SP LD A,SAVTRK CALL PBBH ;output track LDK C,',' CALL COUT ;output comma LD A,D.TRKR CALL PBBH ;output controller track CALL O2SP LD A,SAVSEC CALL PBBH ;output sector LDK C,',' CALL COUT ;output comma LD A,D.SECR CALL PBBH ;output controller sector ; Update error counter LD HL,ERCNT INC HL STO HL,ERCNT ;update error count ; Clear controller CALL RDSKC ;reset disk controller ; RestoreF EI ! RET space 4,10 DWRT: ;Write to disk ; Entry SDISK= drive ; B= Number of sectors to xmit. ; DMADR= FWA of data ; Exit same as DREAD ; Uses All registers proc MOV D,B CALL SEEK JRNZ RWEX1 ;if seek error MOV B,D PUSH BC LDK A,D.WRTS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' bit :3: CALL FDSK POP BC ; Now xfer bytes to controller from DMA. DI LD HL,DMADR :5: PUSH BC LDK BC,LSECB ;length of std sector :6: CALL XDD ;xfer to disk JRNZ RWEX ;if error ; Now check if multi sector POP BC DJNZ :5 ;continue XRA A :8: JR RWEX1 space 4,10 IF ODEBUG DTREAD: ;Read disk track ; Entry SDISK= drive ; DMADR= FWA for data. ; Exit DSTSB= status proc CALL SEEK LDK A,D.RDT ;read track command CALL FDSK ; Now xfer bytes from controller to DMA. DI LDK BC,LTRKB LD HL,DMADR :2: LD A,D.STSR BIT BS.BSY,A JRZ :5 ;if all done ANI DS.DRQ JRZ :2 ;if no data LD A,D.DATR STO A,[hl] INC HL DEC BC ;lower counter MOV A,and MOV A,B STO A,D.CMDR ;function drive ; Wait for busy to be set LDK C,0 :2: LD A,D.STSR RAR ;DS.BSY JRC :3 ;if chip went busy DEC C JRNZ :2 ;if not time-out JR WBUSYX ;exit, error ; Set DACTVE indicating activity on drive :3: XRA A STO A,DACTVE RET space 4,10 WBUSY: ;Wait for Busy to clear ; Exit A= -1, if time out occurred, ; else ; A= last status and is positive. ; Uses A, C proc PUSH BC LDK BC,0 :1: LD A,D.STSR RAR ;DS.BSY JRNC :1A ;if NOT busy, proceed DEC BC MOV A,B OR C JRNZ :1 ;if not time-out WBUSYX: LDK A,-1 ;indicate error, drive NOT ready POP BC OR A ;set flags RET :1A: RAL ;restore A POP BC ;restore BC AND 7Fh ;make sure its positive RET space 4,8 RDSKD: ;Reset PIA and disk controller ; selecting drive specified by C ; Entry C= drive ; B= PIABD MOV A,B AND 0001_1111b ;get vio offset only OR C MOV C,A CALL OPBD ;function PIO-b ; JMP RDSKC RDSKC: ;reset disk controller ; Entry None ; ExiB OR C JRNZ :2 ;if not done ; Here if all done :5: EI RET ENDIF page ; Code to load system from external hardware and to write ; code onto the system tracks is totally contained in this ; section. RDSYS: ;Read in system data in binary from external box. ; Entry None ; Exit Data contained from 4000h to xxxxh proc DI LDK HL,4000h :2: CALL READER ;read in data STO A,[hl] INC HL JR :2 ;infinite loop space 4,10 WRTSYS: ;Write out system tracks as specified by ; the current setting of DMADR ; Entry Memory has valid system image. ; Exit system written. proc CALL HOMED ;initialization LDK HL,4000h STO HL,DMADR ;set DMA LDK A,1 STO A,SAVSEC ;set to 1st sector LDK HL,0 STO HL,SAVTRK ;set track ; loop writing data out :2: LDK B,MSEC CALL DWRT ;write entire track CNZ DERR ;if error STO HL,DMADR ;reset DMA LD HL,SAVTRK INC HL STO HL,SAVTRK ;update track MOV A,L CMP 3 JRNZ :2 ;if not done RET page XDD: ;Xfer data from memory to disk t Busy cleared. ; A= 0. LDK A,D.FINT STO A,D.STSR ;clear controller XRA A ;clear A and flags RET ODER: ;Output disk error to console ; Entry DE= FWA of message ; SDISK = drive with error PUSH DE CALL OCRLF ;new line LD A,SDISK ADD A,'A' MOV C,A CALL CO ;output drive name CALL O2SP POP DE ;get message JMP ESTR DERR: ;Output disk system error ; Entry A= status from controller ; Exit error output PUSH DE PUSH HL PUSH BC PUSH AF LDK DE,DERMSG CALL ESTR ;output error POP AF ;get status value CALL PBBH ;output status CALL O2SP LD A,SAVTRK CALL PBBH ;output track LDK C,',' CALL COUT ;output comma LD A,D.TRKR CALL PBBH ;output controller track CALL O2SP LD A,SAVSEC CALL PBBH ;output sector LDK C,',' CALL COUT ;output comma LD A,D.SECR CALL PBBH ;output controller sector ; Update error counter LD HL,ERCNT INC HL STO HL,ERCNT ;update error count ; Clear controller CALL RDSKC ;reset disk controller ; Restore  page FORMT: ;Format one track ; Format will format one disk as specified by SDISK ; in IBM 3740 format consisting of 40 tracks, with each ; track containing 10 sectors. ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Drive already selected and ready ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK OR A JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RE A=C= LAST KEY PROC CALL SKEY JRZ RKEY ;IF NO DATA DI MOV C,A XRA A STO A,LKEY ;CLEAR KEY FROM HOLD MOV A,C AND 7FH MOV C,A ;A=C EI RET SPACE 4,10 NORM: ;NORMALIZE TO UPPER CASE ; ENTRY A= CHAR ; EXIT A= CHAR CMP 'A' RC ;IF UPPER CMP 'Z'+1 RNC ;IF NOT LOWER SUI 'A'-'A' RET REPD = 45 ;INITIAL REP DELAY REPK = 5 ;REPEAT CONSTANT .NKBD IF @KEY = 0 ;IF NOT NEW KEYBOARD, USE OLD CODE GKEY: ;KEYBOARD INTERRUPT PROCESSOR. ; SCANS BOTH SETS OF DATA LINES TO SEE IF ANY KEY ; PRESSED. IF SO THEN DETERMINES KEY AND ; SETS TKEY TO VALUE. ; IF TKEY AND NEXT KEY SAME THEN HKCNT SET. ; IF HKCNT SET AND NO KEY ON THIS ENTRY, THEN ; LKEY IS SET AND WE HAVE FOUND A VALID KEY CLOSURE. ; ENTRY NONE ; EXIT CBIT SET IF KEY RNK5: = 21H ;RANK 5 RNK6: = 01H ;RANK 6 RNKCTL: = 0A0H ;CONTROL RANK PROC .MAC IF RSIZE = 64 DI .MAC ENDIF STO SP,IESTK ;SAVE INT PROCESS STACK LDK SP,ISTK ;SET TO RAM INT STK PUSHAL ; UPDATE AND DISPLAY CURRENT TIME ;IF @, SHIFTED = '\' CMP '[' LDK C,']' JRZ :20 ;IF [, SHIFTED = ']' CMP '1' JRC :19 ;IF NOT SHIFTABLE CMP 'A' JRNC :18 ;IF POSSIBLE ALPHA SUB 10H JR :19 :18: CALL NORM :19: MOV C,A ; HERE TO ACTUAL SET KEY ; ENTRY C= CURRENT KEYSTROKE VALUE :20: SBIT 7,C ;SET BIT 2**7 LD A,TKEY CMP C JRZ :16 ;IF LAST = CURRENT MOV A,C STO A,TKEY ;CONFIRM KEY (DEBOUNCE) STO A,LKEY LDK A,REPD STO A,HKCNT ;SET TO SURFACE NEXT TIME ; JR GKEYX ;EXIT ; RESTORE REGS, CLEAR INTERRUPT AND RETURN GKEYX: JMP EXITI ;EXIT INTERRUPT ; HERE IF DEBOUNCED KEY, PROCESS SHIFT, CONTROL AND ; REPEAT FUNCTIONS ; ENTRY C= CURRENT CHARACTER :16: LDK HL,HKCNT DEC [HL] ;RESET HOLD COUNT JRNZ GKEYX ;IF KEEP HOLDING MOV A,C :16A: STO A,LKEY ;SHOW KEEP TO USER MOV C,A ;SAVE CURRENT KEY LDK A,REPK STO A,HKCNT ;RESET HOLD FOR REPEAT JR GKEYX ;EXIT PAGE RDKEY: ;READ KEYBOARD FOR VALID KEY PRESSURE ; EXIT A= CURRENT KEY ; IF A = -1, EXIT TO GKEYX ; = -2, NO T ; endx BMXFMT.asm ks, with each ; track containing 10 sectors. ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Drive already selected and ready ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK OR A JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RE CALL UPTIM ;UPDATE TIME ; PERFORM SCAN OF KEYBOARD LD A,KEYLCK ;LOCKED KEYBOARD? OR A JZ GKEYX ;IF LOCKED KEYBOARD, CAN'T READ CHRS CALL RDKEY ;READ KEYBOARD CMP -2 JRNZ :4 ;IF KEY DEPRESSED ; HERE IF NO KEY PRESS, CHECK FOR HOLDING ; DEBOUNCED KEY, IF SO SURFACE KEY. :2: LD A,TKEY BIT 7,A JRZ :3 ;IF NO KEY HOLDING LD A,LKEY STO A,TKEY ;CLEAR-SET HOLD :3: JMP GKEYX ;EXIT :4: PUSH AF CALL RDKEY ;TRY AGAIN POP DE ;LAST A CMP D JRNZ :2 ;IF NOT MATCH, ERROR CMP -1 JZ GKEYX ;IF NULL CONTROL KEY ; A= CURRENT KEY PRESSED ; TKEY = LAST SCAN KEY FOUND GKEY10: MOV C,A ;SAVE CURRENT KEY LD A,CKEY ;CONTROL KEY VALUE OR A JRZ :20 ;IF NO SPECIAL FUNCTION KEYS ; IF SPECIAL, CHECK TYPE BIT 6,A ;40H JRZ :17 ;IF NOT CONTRL KEY ; PROCESS CONTROL KEY ; CHECK FOR ^1, 2, OR 3 FOR FIXED ALIGNMENT MOV A,C CMP '1' LDK C,VFLO JRZ :10B ;IF ^0, ALIGN TO 0 OFFSET CMP '2' LDK C,VFLO+2*52 ;2*52 COMPENSATES FOR 1/2 CHR SHIFT JRZ :10B ;IF ^1,KEY PRESSURE PROC .RDKEY IF @KEY = 0 LD A,H.KEY+0DFH CMA MOV B,A LD A,H.KEY+07FH ;EVERYTHING BUT CNTRL RANK CMA OR B LDK A,-2 RZ ;IF NO KEY PRESSURE ; SAVE ANY CONTRL KEYS LD A,H.KEY+RNKCTL CMA STO A,CKEY ;SAVE CONTROL KEY ; B <> 0 MEANS BIT 5 TABLE MOV A,B OR A JRZ :5 ;IF BIT 5 TABLE :3: LDK HL,H.KEY+1 LDK DE,T6KEY-1 JR :5A ;PROCESS ; HERE IF BIT 5 SET :5: LDK HL,H.KEY+21H LDK DE,T5KEY-1 :5A: LDK BC,0 :5B: LD A,[HL] ;GET NEXT SCAN LINE CMA OR A JRNZ :6 ;IF KEY ACTIVE PUSH BC LDK IX,SCANI ADD IX,BC LD C,[IX+0] ADD HL,BC ;NEXT LINE POP BC INC BC JR :5B ;LOOP TO NEXT SCANI: DB 1,2,4,8,30H,40H ; HERE WITH C = ADDRESS LINE ; A= KEY DOWN BIT :6: PUSH AF ; CHECK FOR CONTROL KEY RANK MOV A,L CMP RNKCTL JRNZ :6A ;IF NOT CONTROL RANK LD A,H.KEY+0DFH CMA OR A JRNZ :3 ;IF KEY ACTIVE IN OTHER RANK STO A,TKEY ;CLEAR KEY POP AF ;RESTORE STACK LDK A,-1 ;INDICATE EXIT RET ; PROCESS ACTIVE KEY :6A: MOV A, TITLE 'KEYBOARD AND CONSOLE ROUTINES.' ; ASSEMBLY CONSTANT @KEY = 1 ;PRODUCTION KEYBOARD ; CONTROL KEYS CBELL = 'G'-40H ;RING THE BELL MCUP = 'K'-40H ;MOVE CURSOR UP MCDOWN = LF ;MOVE CURSOR DOWN MCLEFT = BKS ;MOVE CURSOR LEFT MCRIGH = 'L'-40H ;MOVE CURSOR RIGHT VCLRS = 'Z'-40H ;CLEAR AND HOME CURSOR VHOME = '^'-40H ;HOME CURSOR ; ESCAPE KEYS VLOCK: = '#' ;LOCK KEYBOARD VUNLK = '"' ;UNLOCK KEYBOARD VCAD: = '=' ;CURSOR ADDRESSING VSAD: = 'S' ;SCREEN ADDRESSING VINC: = 'Q' ;INSERT CHAR VDELC: = 'W' ;DELETE CHAR VINL: = 'E' ;INSERT LINE VDELL: = 'R' ;DELETE LINE VCEOL: = 'T' ;CLEAR TO END OF LINE VSHI: = ')' ;START HALF INTENSITY VEHI: = '(' ;END VSUL: = 'L' ;START UNDERLINE VEUL: = 'M' ;END VSGH: = 'G' ;START GRAPHICS VEGH: = 'G' ;END SKEY: ;GET STATUS OF KEYBOARD ; EXIT CBIT SET IF NO DATA READY LD A,KEYLCK OR A RZ ;IF LOCKED KEYBOARD LD A,LKEY BIT 7,A RET ;=0 IF NO DATA SPACE 4,10 CI: RKEY: ;READ NEXT KEY FROM KEYBOARD ; EXIT ALIGN TO 52 CMP '3' LDK C,VFLO+4*52 ;4*52 = 208 SHIFTS = 104 CHARACTERS JRZ :10B ;IF ^2, ALIGN TO 104 ; CHECK FOR SPECIAL CONTROL CODE SCEEN MOVEMENT CODES ; IF SO PROCESS LOCAL AND RETURN LDK E,2 CMP MCLEFT JRZ :10A ;IF MOVE SCREEN LDK E,-2 CMP MCRIGH JRNZ :10C ;IF NOT SCREEN RIGHT :10A: LD A,PIAAD ;CURRENT HORZ OFFSET ADD A,E MOV C,A :10B: CALL OPAD ;RESET OFFSET HARDWARE XRA A ;CLEAR ENTRY KEY JR GKEYX ;EXIT :10C: CMP ' ' JC :20 ;IF LITERAL CMP '@' LDK C,0 JC :20 ;IF ILLEGAL CODE CALL NORM SUB '@' CMP ' ' JNC :20 ;IF ILLEGAL JR :19 ;CONVERTED CONTROL CODE ; CHECK FOR SHIFT KEY ; A= SHIFT STATUS ; C= CURRENT CHARACTER :17: BIT 5,A ;20H JRZ :20 ;IF NOT SHIFTED MOV A,C ;GET ACTUAL CHAR ; CHECK FOR LEGAL SHIFTED CODE :17B: CMP ',' JRC :19 ;IF IMPOSSIBLE SHIFT CMP '/'+1 JRNC :17C ;IF NOT ASCII REVERSE PAIRING ADD A,10H JR :19 :17C: CMP '0' LDK C,'^' JRZ :20 ;IF O, SHIFTED = '^' CMP '@' LDK C,'\' JRZ :20  C ANI 7 ;GET RELATIVE TO 0 RAL ! RAL ! RAL ;*8 MOV C,A LDK B,0 EX DE,HL ;BASE TO HL ADD HL,BC LDK BC,0 POP AF ;GET BIT BACK OR A ;CLEAR CARRY ; NOW CONVERT BIT VALUE TO BINARY :7: INC C RRC JRNC :7 ;IF NOT BIT ADD HL,BC ;ADD IN VALUE ; GET ACTUAL KEY PRESSURE VALUE INTO A. LD A,[HL] ;GET TABLE VALUE RET .RDKEY ELSE LD A,H.KEY+0FFH XOR 0FFH ;1S COMPLEMENT, SET FLAGS MOV B,A LDK A,-2 RZ ;IF NO KEY ; READ CNTRL RANK AND SAVE LD A,H.KEY+01 CMA STO A,CKEY ;SAVE IT ; KEY DEPRESSED, CHECK FOR WHICH RANK, MAKE ; SURE ITS LEGAL, IE. NOT JUST CNTRL KEY. LDK DE,2 ;IGNORE CONTRL RANK LDK B,6 ;NUMBER OF RANKS-CNTRL RANK :3: LDK HL,H.KEY ;BASE ADD HL,DE ;ADDRESS OF NEXT RANK LD A,[HL] ;GET POSSIBLE ENTRY XOR 0FFH JRNZ :7 ;IF FOUND KEY PRESSURE DEC B JRZ :5 ;IF ALL DONE WITH SCAN EX DE,HL ;POWER OF 2 TO DE ADD HL,HL ;*2 EX DE,HL ;NEXT RANK TO DE JR :3 ;CONTINUE ; HERE IF SUPPOSE TO BE KEY DOWN, BUT NONE ; FOUND  'P', 'O', 'P' DB MCRIGH DB LF, ':', '/', ';', '\', '1', '-' ENDIF .NKBD ENDIF PAGE UPTIM: ;UPDATE TIME VIA 60HZ INTERRUPT ; TIME IS KEPT IN VIDEO MEMORY AS ; HHMMSS (3 LOCATIONS) ; ROUTINE ALSO CHECKS TO SEE IF THE DISK DRIVE MOTOR ; SHOULD BE TURNED OFF BY UPDATING DACTIVE ; ...ROUTINE ALSO CHECKS TO SEE IF BELL IS CURRENTLY ; RINGING: IF SO, DECREMENT COUNTER. ; IF COUNTER TURNS ZERO, SHUT OFF BELL. PROC LK HL,BELCNT XOR A OR [HL] ;CELL=ZERO ? JRZ :2 ;IF BELL NOW OFF DEC [HL] ;...BELL IS ON. DECREMENT COUNTER JRNZ :2 ;IF BELL SHOULD STAY ON AWHILE YET LD A,PIABD AND 1101_1111B ;CLEAR BELL BIT MOV C,A CALL OPBD :2: DEC HL ;HL => DACTVE LD A,[HL] OR A JRZ :3 ;IF INACTIVE DEC [HL] ;RESET DELAY CZ DDRV ;IF DESELECT DRIVE :3: DEC HL ;HL => SEC6 DEC [HL] RNZ ;IF NOT 1 SEC TRANSITION STO 59,[HL] ;60TH TICK IS NOW XOR A ;A:=0, CY:=0 FOR DAA DEC HL ;HL => SECS LD A,[HL] ! INC A ! DAA ! STO A,[HL] CMP 60H RC ;IF NOT 60 SECESCEE ;INSERT LINE DB VDELL ! DW ESCRR ;DELETE LINE DB VCEOL ! DW EEOL ;CLEAR TO END OF LINE DB VLOCK ! DW ESCLCK ;LOCK KEYBOARD DB VUNLK ! DW ESCULK ;UNLOCK KEYBOARD :END: DW COUT2 ;NO MATCH EXIT ; IGNORE CHAR UPON UNDEFINED ESC-SEQUENCE ; (TO TREAT UNDEFINED CHAR AFTER ESC AS A REGULAR ; DATA CHAR, SHOULD GO TO COUT2). VALETS: = (:END-VALIDE)/3 ;# OF ENTRIES IN TABLE SPACE 4,10 VALIDC: ;VALID CONTROL CHARACTER TABLE ; 3 BYTES PER ENTRY: ASCII CHAR , "DW"- VECTOR ; NO. OF ENTRIES IS VALCTS ; FOLLOWING BODY OF TABLE IS 2 BYTE NO-MATCH ADRS DB CR ! DW VC_CR ;CARRIAGE RETURN ROUTINE DB LF ! DW VC_LF ;LINE FEED DB BKS ! DW VC_BKS ;BACK SPACE DB MCRIGH ! DW VC_MCRT ;MOVE CURSOR RIGHT DB MCUP ! DW VC_MCUP ;MOVE CURSOR UP DB 'A'-40H ! DW VSHFT_L ;SHIFT SCREEN LEFT DB 'B'-40H ! DW VSHFT_R ;SHIFT RIGHT DB 'C'-40H ! DW VSHFT_0 ;LEFT COLUMN (^1) DB CBELL ! DW VC_BEL ;RING BELL DB VCLRS ! DW VC_CLRS ;CLEAR SCREEN DB VHOME ! DW VC_HOME ;CURSOR HOME ; DW VOUT9IN NON-CNTRL KEY RANKS. CHECK FOR TAB, ; ELSE KEY DOWN IS TO BE IGNORED. :5: LDK HL,T5KEY LD A,CKEY OR A JRZ :NOKEY ;IF NO CNTL-KEY SENSED EITHER CALL DRNK ;CHECK FOR TAB CMP TAB RZ ;IF TAB :NOKEY: LDK A,-2 ;INDICATE NO KEY, JUST CNTRL RET ; HERE IF FOUND KEY DOWN I NON-CNTRL RANKS ; HL = RANK ADDRESS ; A = VALUE ; B = 7..1, 7-(ORDINAL OF RANK) :7: PUSH AF ;SAVE VALUE LK A,8 SUB B ;A = ORDINAL OF RANK RLC ! RLC ! RLC ;*8 TO GET ADDRESS MOV E,A LDK HL,T5KEY ;BASE FOR DECODE LDK D,0 ADD HL,DE ;GET KEY DECODE BASE POP AF DRNK: ;DECODE RANK VALUE ; ENTRY A= RANK VALUE READ ; HL=FWA OF RANK ENTRY ; EXIT A= KEY VALUE IN ASCII LDK BC,-1 OR A ;CLEAR CARRY :8: INC BC ;UPDATE BASE ADDER RRC JRNC :8 ADD HL,BC LD A,[HL] ;GET ACTUAL KEY RET .RDKEY ENDIF PAGE ; CHARACTER INPUT TRANSLATION TABLE IF @KEY = 0 T5KEY: DB ESC, ESC, ERC, ERC, ERC, ERC, ERC, ERC ;5KEY: DB TAB, ESC, ERC, ERC, ERC, ERC, ERC, ERC DB '1', '2', 'S STO 0,[HL] ;RESET SECONDS DEC HL LD A,[HL] ! INC A ! DAA ! STO A,[HL] CMP 60H RC ;IF NOT 60 MINUTES STO 0,[HL] DEC HL LD A,[HL] ! INC A ! DAA ! STO A,[HL] CMP 25H RC ;IF TIME <= 24:59:59 STO 1,[HL] RET PAGE CO: ;OUTPUT ROUTINE FOR MONITOR ; ENTRY C= CHAR ; CO WILL PROCESS ^P TO TOGGLE ; ECHO TO LIST DEVICE ALA CPM. ; EXIT C=C=A. PROC MOV A,C CMP 'P'-40H JRNZ :5 ;IF NOT TOGGLE ECHO LIST LD A,ECHOP CMA STO A,ECHOP ;TOGGLE LIST ECHO :2: MOV A,C ;PERSERVE A RET :5: CALL COUT ;OUTPUT CHAR LD A,ECHOP OR A JRZ :2 ;IF NO ECHO TO LIST JMP LIST ;ECHO IT PAGE ; BIT DEFINITIONS FOR ESCH FLAG BYTE ; NOTE BIT 7 IS CURRENTLY FREE. EF_X: = 64 ;B6= EXTEGTING X-COORDINATE EF_SCR: = 32 ;B5= SCREEN/CURSOR ADDRESSING EF_ADR: = 16 ;B4= EXPEGTING ADDRESS-CHR EF_ESC: = 8 ;B3=$LAST CHAR WAS ESC EF_UN: = 4 ;B2= UNDERLINE MODE EF_HA: = 2 ;B1= HALF INTENSITY MODE EF_GR: = 1 ;B0= GRAPHICS MODE EF_MSK: = EF_UN+EF_HA+EF_GR ;MASK TO GET MODE. 7 ;NO MATCH--IGNORE UNDEF CONTROL CHAR ; VALCTS: = ((*-2)-VALIDC)/3 ;NUMBER OF VALID ENTRIES PAGE COUT: ;GENERAL OUTPUT ROUTINE TO VIDEO SCREEN ; ENTRY C=CHARACTER, CURS=CURSOR, ESCH=FLAG+MODE ; EXIT CURS & ESCH UPDATED, A=CHARACTER ; (BC, DE, HL PRESERVED) ; ; ESCH IS FLAG + MODE BYTE AS FOLLOWS ; =00 NORMAL MODE & LAST CHR ESC FLAG FALSE ; =08 NORMAL MODE & LAST CHR ESC FLAG TRUE ; =01,02,04 MODE IS GRAPHICS, HALF, OR UNDER, RESPECTIVELY ; , AND LAST CHR ESC FLAG IS FALSE. ; =3,5,6,7 AS ABOVE, BUT MODE IS COMBINATION ; =9-15 LAST CHR ESC FLAG TRUE;OTHERWISE LIKE 1-7. PROC PUSH HL PUSH DE PUSH BC LD HL,CURS ;HL WILL USUALLY BE CURSOR. LD A,ESCH MOV B,A ;B WILL BE ESCH FOR A WHILE AND EF_ESC ;TEST FLAG BIT JRNZ PSTESC ;IF LAST CHR WAS ESC ;CURRENT CHR IS NOT ESCAPED. IS THIS CHR ESC? MOV A,C ;CHR CMP ESC MOV A,B ;(A=ESCH) JRZ :ESC ;IF THIS CHR = ESC SPACE 4,10 ;HERE WITH A=B= ESCH :OUT: PUSH HL LK HL,ESCHTB AND EF_MSK ;MO3', '4', '9', '0', ':', '-' ; DB '1', '2', '3', '4', '9', '0', '-', '~' DB 'Q', 'W', 'E', 'R', 'O', 'P', '@', 7FH ; DB 'Q', 'W', 'E', 'R', 'O', 'P', '{', '}' DB 'A', 'S', 'D', 'F', 'L', ';', BKS, FMFD ; DB 'A', 'S', 'D', 'F', 'L', ';', ':', '\' DB 'Z', 'X', 'C', 'V', ERC, '.', '/', ERC DB ' ', ERC, ERC, ERC, ERC, ERC, ERC, ERC DB ERC, ERC, ERC, REP, CAPS, SHTK, CTRL, ERC T6KEY: DB ERC, ERC, ERC, BKS, VTAB, ERC, ERC, ERC DB '6', '5', '7', '8', '[', ERC, ERC, ERC DB 'Y', 'T', 'U', 'I', '-', ERC, ERC, ERC DB 'H', 'G', 'J', 'K', CR, ERC, ERC, ERC DB 'N', 'B', 'M', ',', LF, ERC, ERC, ERC ELSE T5KEY: T6KEY: DB ESC, CTRL, CAPS, SHTK, CR, TAB, TAB, '_' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I' DB 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K' DB 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',' DB MCUP, BKS, '0', ' ', '.', SPACE 4,10 ; VECTOR (BRANCH) TABLE FOR VIDEO OUTPUT MODE SELECTION ; CONTROLLED BY ESCH MODE ESCHTB: DW VNORM ;0 NORMAL MODE DW VGRAPH ;1 GRAPHICS MODE DW VHALF ;2 HALF INTENSITY MODE DW VHA_GR ;3 HALF AND GRAPHICS DW VUNDER ;4 UNDERLINE MODE DW VUN_GR ;5 UNDER AND GRAPHICS DW VUN_HA ;6 UNDER AND HALF INTENSITY DW VUN_HA_GR ;7 UNDER AND HALF AND GRAPHICS SPACE 4,10 VALIDE: ;VALID ESC-SEQUENCE TABLE ; 3 BYTES PER ENTRY:ASCII CHAR , "DW"-VECTOR. ; NO. OF ENTRIES IS VALETS ; FOLLOWING BODY OF TABLE IS 2 BYTE NO-MATCH ADRS DB VCAD ! DW ESCCAD ;CURSOR ADDRESSING DB VSAD ! DW ESCSAD ;SCREEN ADDRESSING DB VSGH ! DW ESCSGR ;SET GRAPHICS MODE DB VEGH ! DW ESCCGR ;CLR GRAPHICS MODE DB VSHI ! DW ESCSHA ;SET HALF INT. MODE DB VEHI ! DW ESCCHA ;CLR HALF INT. MODE DB VSUL ! DW ESCSUN ;SET UNDERLINE MODE DB VEUL ! DW ESCCUN ;CLR UNDERLINE MODE DB VCLRS ! DW ESCZZ ;CLEAR SCREEN TO BLANKS DB VINC ! DW EINSRT ;INSERT CHAR DB VDELC ! DW EDELC ;DELETE CHAR DB VINL ! DW  DE BITS ONLY ADD A,A ;TIMES TWO MOV E,A LK D,0 ;DE = OFFSET ADD HL,DE ;HL = TBL ADDRS VECTOR: ;ENTRY POINT. NOTE HL ON STACK. LD A,[HL] ;1ST BYTE (LOW ORDER ADRS) INC HL LD H,[HL] ;2ND BYTE (HI ORDER ADRS) MOV L,A ;HL=ADRS FROM TABLE XTHL ;RESTORE HL FROM STACK ;STACK=TBL ADRS MOV A,C ;CHR. NOTE B=ESCH BYTE VALUE RET ;ENTER ROUTINE PER TABLE ADRS. COUT2: MOV A,B ;RECALL ESCH VALUE JR :OUT ;OUTPUT CHR PER CURRENT SETTINGS :ESC: ;CURRENT CHR IS ESC. SET FLAG AND EXIT OR EF_ESC ;INDICATE LAST CHAR= ESC STO A,ESCH JMP VOUT97 ;EXIT SPACE 4,17 PSTESC: ;LAST CHR WAS ESC ; ENTRY A= EF_ESC ; B= ESCH ; C= CHAR TO OUTPUT ; HL=CURS PROC BIT 4,B ;IS THIS CHR REALLY AN ADDRESS? JRNZ SETXY ;...IF CHR IS PART OF AN ADDR ;NO CURSOR/SCREEN ADDRESSING IN EFFECT: XOR B ;CLR EF_ESC BIT (FOR NEXT TIME) MOV B,A ;SET UP B = ESCH BYTE VALUE. STO A,ESCH PUSH HL ;SAVE CURS LDK HL,VALIDE ;BRANCH TABLE ADRS LDK E,VALETS ;TABLE SIZE MOV A,C ;CHROC BIT 6,B JRNZ :SX ;IF X-COORDINATE :SY: AND 0001_1111B ;MOD 32 MOV C,A LD A,PIABD AND 1110_0000B OR C MOV C,A CALL OPBD ;SET Y COORDINATE JR :EXITY :SX: ADD A,A ;DOUBLE A ADD A,VFLO ;PIA A-REG MAGIC OFFSET CONSTANT AND 1111_1110B ;CLEAR BIT 0 => NO 1/2 CHR SHIFT MOV C,A CALL OPAD ;SET X COORDINATE CBIT 5,B ;FINISHED SCREEN-ADDRESSING JR :EXITX SPACE 4,10 SETXY: ;SET X-Y VALUE FOR CURSOR/SCREEN ADDRESSING ; ENTRY HL= CURSOR_ADDR ; B = ESCH ; C = CHR ; EXIT TO VOUT90; ESCH UPDATED CALL UN_CUR LK A,-(' ') ADD C ;REMOVE CURSOR BIAS BIT 5,B ;CURSOR/SCREEN ADDRESSING? JRNZ SCREEN ;IF SCREEN ADDRESSING ;CURSOR ADDRESSING: ADD HL,HL ;SHIFT HL LEFT BIT 6,B ;X/Y COORDINATE? JRNZ :CX ;IF X COORDINATE :CY: MOV H,A ;SAVE LD A,PIABD ADD H ;OFFSET BY START-Y CO-ORD OF VIDEO RAR ;BIT0(A) -> CY, SHIFT A RIGHT RR L ;CY -> BIT7(L) OR 0F0H ;TURN ON UPPER NYBL MOV H,A ;HL= NEW CURSOR ADDR ; JR :EXITY :EXITY: LK A,0100_0000B ;NEXT ADDR-CHR ,[HL] ; JR VOUT80 ;RE-ECHO CURRENT CHR PAGE ; EXIT POINTS FOR COUT ; HERE TO STORE NEW DATA AND TO UPDATE CURSOR VGRAPH: VOUT80: STO A,[HL] ;THIS EXIT PATH STORES A (NEW CHAR) MOV E,L CBIT 7,E ;E = COL(CURSOR) LD A,LLIMIT DEC A ;A = LAST_LEGAL_COL SUB E ;A = LAST_LEGAL_COL - COL(CUR) JRNZ VOUT85 ;IF NOT @LLIMIT LK A,80H AND L MOV L,A ;DO CR... CALL DO_LF2 ;...AND LF. JR VOUT90 VOUT85: INC HL ;MOVE CURSOR ; HERE IF NO CURSOR UPDATE VOUT90: LD A,[HL] ;THIS EXIT PATH TURNS ON 80H BIT ; HERE IF NEW DATA ALREADY IN A VOUT95: RAL ;MAKE THIS CHR CURSOR VOUT96: CMC ;INVERT CURSOR BIT RAR STO A,[HL] STO HL,CURS ;UPDATE CURSOR ; HERE IF NO CHANGE TO CURSOR, RESTORE REG AND EXIT VOUT97: POP BC POP DE POP HL MOV A,C ;EXIT WITH A=CHR RET ;RETURN, END OF COUT SUBR. SPACE 4 :FIRST = VOUT97 - (127 + 2) ;EARLIEST POSSIBLE JR :LAST = VOUT80 + (128 - 2) ;LATEST POSSIBLE JR PAGE ESC_LCK: ;LOCK KEYBOARD PROC XOR A JR :2 ESC_ULK: ;UNLOR TO A JR LOOKUPB ;GO TO ROUTINE TO BRANCH PER TBL SPACE 4,15 VNORM: ;NORMAL MODE CHARACTER PROCESSING. ; ENTRY A= CHAR TO OUTPUT ; HL=CURS CMP ' ' JRC :2 ;IF CONTROL CHR VBRIGH: DI ! ENADIM ;9TH BIT MEMORY STO BRTBIT,[HL] ;SET THIS CHR BRIGHT DISDIM ! EI JMP VOUT80 :2: PUSH HL ;SAVE CURS LDK HL,VALIDC ;BRANCH TABLE ADRS LDK E,VALCTS ;TABLE SIZE ; JMP LOOKUPB ;SCAN TABLE OF VALID CONTROL CHRS ; ;AND BRANCH TO APPROPRIATE ROUTINE. SPACE 4,20 LOOKUPB: ;LOGIC TO SCAN 3 BYTE BRANCH TABLE ; NOT A SUBROUTINE---DO NOT CALL. ; ENTRY HL =1ST BYTE OF TABLE (MATCH CODE) ; (2ND,3RD BYTES = BRANCH ADRS) ; (TABLE REPEATS [3 BYTE ENTRIES]) ; E IS TABLE SIZE (NO. OF ENTRIES) ; (TABLE BODY IS FOLLOWED WITH ; 2 BYTE "NO-MATCH" ADRS) ; STACK HAS HL SAVED AS TOP ENTRY. ; C = CHAR ; A = VALUE TO SCAN FOR POSSIBLE MATCH CMP [HL] INC HL ;(2ND BYTE OF THIS 3 BYTE ENTRY) JRZ VECTOR ;IF MATCH PROCESS INC HL ;(3RD BYTE OF THIS ENTRY) INC HL ;1ST BYTE OF NEXT ENTRY WILL BE X-COORD OR B JR :EXIT2 :CX: RAL ;TRASH 7TH BIT SRA H ;BIT0(H) -> CY, BIT7 STAYS 1 RAR ;... CY -> BIT7(A) MOV L,A ; JR :EXITX :EXITX: LK A,EF_MSK AND B ;FINISHED ADDRESSING: RESET ADDR BITS :EXIT2: STO A,ESCH JMP VOUT90 PAGE ; CONTROL CODE CHARACTER PROCESSING VC_HOME: ;HOME CURSOR PROC CALL UN_CUR LD A,PIABD RAR ;BIT0 => CY LK L,0 RR L ;CY => BIT7, TRASH BIT0 MOV H,A JR :FIXHL ;HL := HL OR F000H SPACE 4,7 VC_MCUP: ;MOVE CURSOR UP. ; A=C=CHR=MCUP. HL=CURS. CALL UN_CUR PUSH HL ;OLD CURSOR MUST BE ON STACK LK BC,(-VLL) JR :FWA ;...AT THIS ENTRY POINT SPACE 4,28 VC_BKS: ;HL=CURS=CURRENT (OLD) CHAR CALL UN_CUR ;CLEAR 80H BIT LK A,7FH AND L JRZ :WRAP ;IF MUST WRAP FROM COL 0 TO LLIMIT DEC HL JR VOUT90 ;EXIT :WRAP: PUSH HL ;SAVE OLD CURSOR LK BC,-(VLL+1) ADD HL,BC ;HL = PREV_LINE, (-1)ST COLUMN LD A,LLIMIT ;LLIMIT = #COLUMNS ON SCREEN MOV C,A LK B,0 :FWA: ADD HL,BC XTHL ;GET OLD CURSOR, SAVE NEW ADDCK KEYBOARD LK A,0FFH :2: STO A,KEYLCK JR VOUT97 SPACE 4,5 EEOL: ;ERASE TO END OF LINE PUSH HL ;SAVE CURSOR CALL CLRLN POP HL JR VOUT90 SPACE 4,12 ESC_CAD: ;CURSOR ADDRESSING LK A,EF_MSK AND B OR EF_ESC OR EF_ADR ;NEXT CHR WILL BE Y-COORD :EXIT3: STO A,ESCH JR VOUT97 ESC_SAD: ;SCREEN ADDRESSING LK A,EF_MSK AND B OR EF_ESC OR EF_ADR OR EF_SCR JR :EXIT3 PAGE ;SUBROUTINE FOR USE WITH EDELC AND EINSRT: ;CALCULATE #CHRS TO MOVE; IF MOVE ZERO CHRS, NEVER RETURN. PROC :CALC: LK A,VLL-1 ;A= MAX #CHRS TO BE MOVED MOV C,L CBIT 7,C ;C = COL(CURSOR) SUB C ;A = #CHRS TO MOVE JRZ :END ;IF MOVE ZERO CHARACTERS MOV C,A LK B,0 ;BC = #CHRS TO MOVE RET :END: POP HL ;TRASH RETURN_ADDR POP HL ;CURSOR_ADDR JR VOUT90 SPACE 4,14 EDELC: ;DELETE CHARACTER PUSH HL ;SAVE CURSOR_ADDR CALL :CALC ;CALCULATE BC MOV D,H MOV E,L ;DE = CURSOR_ADDR INC HL ;HL = CURSOR_ADDR + 1 CALL VLDIR ;MOVE CHARACTERS STO ' ',[HL] ;LAST CHR BECOMES BLANK DI ! ENADIM ; DEC E ;DEC COUNT OF ENTRIES REMAINING JRNZ LOOKUPB ;CONTINUE THRU BODY OF TABLE JR VECTOR ;NO-MATCH. HL=POINTS TO VECTOR PAGE ; PROCESSING FOR MODES OTHER THAN NORMAL. ; -------------------------------------- ;VGRAPH = VOUT80 ;NORMAL MODE EXCEPT: CNTL CHRS ARE PRINTED VUNDER: ;UNDERLINE ONLY CMP ' ' JRC VNORM ;IF CNTL-CHR, PROCESS AS NORMAL ; JR VUN_GR ;CONTINUE VUN_GR: ;UNDERLINED GRAPHICS OR 80H ;UNDERLINE BIT JR VBRIGH ;SET THIS CHR BRIGHT VUN_HA: ;UNDERLINE AND HALF INTENSITY CMP ' ' JRC VNORM ;IF CNTL-CHR, PROCESS AS NORMAL ; JR VUN_HA_GR VUN_HA_GR: ;UNDERLINE, HALF INTENSITY, GRAPHICS OR 80H ;SET UNDERLINE BIT ; JR VHA_GR VHALF: ;HALF INTENSITY CMP ' ' JRC VNORM ;IF CNTL-CHR, PROCESS AS NORMAL ; JR VHA_GR VHA_GR: ;C=CHR, HL=CURS DI ENADIM STO DIMBIT,[HL] ;SET DIM FIELD BIT ; LD E,[HL] ;DIAGNOSTIC DISDIM EI JMP VOUT80 ;CONTINUE SPACE 4,22 SCREEN: ;SETXY FOR SCREEN MOVEMENT ; ENTRY B= ESCH ; A= NEW CO-ORD VAL, NO OFFSET P HL,HL ;SHIFT LINE# INTO H REG. LD A,PIABD OR 1110_0000B ;A = LINE# OF UL CORNER CMP H ;SET ZFLAG: @HOME? POP HL ;GET NEW CURSOR... JRNZ :FIXHL ;IF NOT @VIDEO HOME LK BC,(24*VLL) ;WRAP CONSTANT ADD HL,BC :FIXHL: LK A,0F0H OR H ;MODULO RESULT: KEEP CURSOR MOV H,A ;INSIDE VIDEO MEMORY. JR VOUT90 SPACE 4,8 VC_BEL: ;RING THE BELL VIA SETTING PIAB 2**5 BIT LD A,PIABD OR 0010_0000B ;BELL BIT MOV C,A CALL OPBD ;FUNCTION PIAB LK A,30 ;RING BELL FOR 30 TICKS STO A,BELCNT ;... = 1/2 SECOND JR VOUT97 ;EXIT NO CHANGE SPACE 4,10 VC_CLRS: LK HL,FWAVM CALL CLRLN ;CLEAR 1ST LINE LK BC,LVMEM-VLL CALL VLDIR ;CLEAR REMAINING LINES LD A,PIABD ;RESET FOR 1ST LINE OF DISPLAY MEM AND NOT(1_1111B) MOV C,A CALL OPBD LK HL,FWAVM ;NEW CURSOR JR VOUT90 ;EXIT SPACE 4,8 VC_CR: CALL UN_CUR ;ERASE CURSOR LK A,80H ;CARRIAGE RETURN AND L MOV L,A JR VOUT90 VC_LF: CALL DO_LF ;LINE FEED JR VOUT90 SPACE 4,3 VC_MCRT ;MOVE CURSOR RIGHT CALL UN_CUR LD A ENABLE 9TH BIT MEMORY DEC HL ;HL = LAST CHR ON THIS LINE STO BRTBIT,[HL] ;SET CHR BRIGHT DISDIM ! EI ;MAIN MEMORY POP HL ;RESTORE CURSOR_ADDR JR VOUT90 ;NEXT SPACE 4,14 EINSRT: ;INSERT CHARACTER CALL UN_CUR PUSH HL ;SAVE CURSOR_ADDR CALL :CALC ;CALCULATE BC LK A,7FH OR L MOV L,A ;HL = LAST_CHR ON THIS LINE MOV E,A MOV D,H ;DE = HL DEC HL CALL VLDDR ;DO MOVE POP HL ;RESTORE CURSOR LD A,[HL] ;GET UNDERLINE BIT OF THIS CHR. RAL ;INTO CY LK A,' ' SHL 1 ;CHANGE THIS CHR TO ' ' JR VOUT96 ;EXIT PAGE ; ESC-SEQUENCE PROCESSING. PROC ESCSGR: LDK A,EF_GR ;ESC-G JR :125 ;SET GRAPHICS MODE. ESCSHA: LDK A,EF_HA ;ESC-) SET HALF INTENSITY JR :125 ;GO SET FLAG BIT ESCSUN: LDK A,EF_UN ;ESC-L SET UNDERLINE :125: OR B ;REG B IS ESCH BYTE VALUE :130: STO A,ESCH ;STORE DESIRED VALUE. JR VOUT97 ;EXIT ESCCGR: LDK A,NOT EF_GR ;ESC-G CLEAR GRAPHICS MODE JR :140 ;GO CLEAR ESCH BIT ESCCHA: LDK A,NOT EF_HA ;ESC-( CLEAR HALF INTENSITY JR :140 ECOUNT RET SPACE 4,30 CLRLN: ;CLEAR TO END OF LINE ; ENTRY HL= CURSOR ; EXIT CLEAR TO EOL ; USES ALL. PROC STO ' ',[HL] ;CLEAR CURSOR... DI ENADIM STO BRTBIT,[HL] ;SET CURSOR BRIGHT DISDIM EI LD A,LLIMIT DEC A ;MAX_#COLS => MAXIMUM_COL_# MOV E,L CBIT 7,E SUB E ;A = COL(EOL) - COL(CURSOR) RZ ;IF @EOL, DONE JRNC :2 ;IF INSIDE LOGICAL_VIDEO_LINE LK A,VLL SUB E ;...ELSE CLR TO END OF 128-CHR LINE RZ ;IF CURSOR @ COLUMN #127 :2: MOV C,A LK B,0 ;BC = CHRS TO MOVE MOV E,L MOV D,H INC DE ;DE = HL + 1 JR VLDIR PAGE DO_LF: ;DO LINE FEED PROCESSING ; ENTRY HL = CURSOR_ADDR ; EXIT CURSOR CLEARED ; HL UPDATED FOR CURRENT CURSOR POS ; WINDOW MOVED IF NECESSARY PROC CALL UN_CUR ;CLEAR CURSOR DO_LF2: PUSH HL ;SAVE ORIGINAL CURSOR LK BC,VLL ;LINE LENGTH ADD HL,BC JRNC :NOWAP ;IF NOT WRAPPING FROM LWAVM TO FWAVM LK BC,FWAVM ADD HL,BC ;HL = NEW CURSOR @ TOP OF VM :NOWAP: XTHL ;SAVE NEW CURSOR, GET OLD ADD HL,HL ;SHIFT HL LEFT LD if no key being pressed ;Debounce the Keyboard: LK HL,TKEY CMP [hl] ;same as last time? (set Z flag) STO A,[hl] ;set TKEY to current value MOV B,A ;save chr LK HL,HKCNT JRNZ :1st ;if this is first such keypress MOV A,[HL] CMP 0 JZ :2ND ;SECOND TIME FOR THIS KEY :AUTO: DEC [HL] JRNZ GKEYX ;IF STILL WAITING FOR REPD/REPK STO REPK,[HL] ;...ELSE SET REPK FOR NEXT CHR, JR :DCODE ;AND RETURN CHR :1ST: LD A,KBDLY ;GET # OF INTERRUPTS TO DEBOUNCE CALL DELAY XRA A ;ZERO "HKCNT" STO A,HKCNT JR :SCAN :2ND: STO REPD,[HL] ;SET "REPD" DELAY :dcode: MOV A,B ;restore chr CALL SHIFT ;shift processing LK HL,CKEY BIT 2,[hl] ;ck for CNTL key JRZ :fin ;if CNTL-key is NOT pressed CALL SLIDE ;ck for screen slide keys CALL CNTRL ;cntrl key processing :fin: OR 80h ;set parity bit for CI STO A,LKEY ;make chr available to CI GKEYX: JMP EXITI ;exit interrupt GKEYAB: ;Abort Processing: set TKEY := -2 and return. LK A,-2 STO A,TKEY JR GKEYX SCCUN: LDK A,NOT EF_UN ;ESC-M CLEAR UNDERLINE :140: AND B ;CLEAR BIT JR :130 ;GO STORE ESCH BYTE ESCZZ: = VC_CLRS ;ESC-Z CLEAR SCREEN -SAME AS ; ;CONTROL-Z ROUTINE. PAGE PROC VSHFT_L: ;SHIFT SCREEN LEFT LK C,+2 JR :SLIDE VSHFT_R: ;SHIFT SCREEN RIGHT LK C,-2 :SLIDE: DI LD A,PIAAD ;GET OLD OFFSET ADD C ;MODIFY... MOV C,A :1: CALL OPAD ;NEW SETTING FOR VIDEO OFFSET EI JMP VOUT97 VSHFT_0: ;SHIFT TO COLUMN #0 (LIKE ^1) LK C,VFLO ;CONSTANT FOR COLUMN #0 JR :1 ;SET VIDEO OFFSET PAGE ESCRR: ;DELETE LINE ESCEE: ;INSERT LINE ; ENTRY HL = CURSOR ; C = CHR ; EXIT SCREEN UPDATED ; HL = NEW CURSOR ; ...TO VOUT90 PROC CALL UN_CUR LK A,1000_0000B AND L MOV L,A ;DO CR PUSH HL ;SAVE NEW CURSOR ADD HL,HL LD A,PIABD ADD A,24 ;A = ADDR(25TH LINE) SUB H ;A = LINES_TO_MOVE + 1 AND 0001_1111B ;MOD 32 MOV B,A LK A,VDELL CMP C MOV A,B ;RECALL #LINES TO MOVE JRZ :DELT ;IF DELETING A LINE SPACE 3,17 :INSRT: ;INSERT A LINE ADD HA,PIABD ADD A,23 ;START + 23 = LAST_VIDEO_LINE SUB H ;A = L_LINE - CURR_LINE AND 0001_1111B ;MODULO 32 JRZ :VMOV ;IF CURSOR IS ON 24TH LINE OF SCREEN :END: POP HL ;GET NEW CURSOR RET :VMOV: LD A,LLIMIT SRL L ;UNSHIFT L REGISTER SUB L ;A = LLIMIT - COL(CURSOR) JRC :END ;IF CURSOR IS OUTSIDE LOGICAL LINE ;CURSOR IS ON LAST LINE OF SCREEN, INSIDE OF LOGICAL LINE. ;MUST MOVE SCREEN TO FOLLOW CURSOR DOWN THROUGH VIDEO MEMORY. POP HL PUSH HL LK A,80H AND L MOV L,A ;HL = BEGINNING OF LINE CALL CLRLN ;ERASE TO EOL LD A,PIABD MOV B,A AND NOT 31 ;A = LINE ZERO MOV C,A ;C = HOUSEKEEPING BITS 5..7 LK A,31 INC B ;INCREMENT LINE# AND B ;A = LINE# OR C ;A = NEW LINE# OR HOUSEKEEPING_BITS MOV C,A ;C = NEW VALUE FOR OPBD CALL OPBD ;MOVE VIDEO SCREEN DOWN 1 LINE IN MEMORY POP HL RET SPACE 4,12 VLDDR: ;VIDEO BLOCK MOVE ; ENTRY BC, DE, HL SET ; EXIT LDDR ON MAIN & 9TH BIT MEMORY ; USES BC, DE, HL PUSH BC ! PUSH DE ! PUSH HL LDDR ;MAIN MEMORY POP HL ! PO page SHIFT: ;Shift key processing ; Entry A = chr from RDKEY ; Exit A = shifted value from SHIFT and ALPHA LOCK keys Proc CMP ' ' + 1 RC ;if cntl-chr (<=space), unshiftable LK HL,CKEY BIT 4,[hl] ;shift key bit JRNZ :shift ;if shift key pressed BIT 3,[hl] ;alpha lock key bit JRNZ :alpha ;if alpha key pressed RET ;if no shifting necessary :shift: CMP 'a' JRNC :alpha ;if 'a'..'z' CMP '[' JRC :tblsf ;if chr < '[', use shift table ;must be '[' or '\' JRNZ :alphx ;if '\', shift as alpha LK A,']' RET ;...else '[' shifted is ']' :tblsf: MOV E,A LK D,0 ;DE = chr LK HL, :stbl - '''' ;table FWA - apostrophe ADD HL,DE ;HL => shifted character LD A,[hl] ;A = shifted chr RET :alpha: CMP 'a' RC ;if <'a', ignored by ALPHA lock :alphx: XOR 20h ;UPPER/lower case bit RET ;shifted "comma" becomes "less than", ;shifted "hyphen" becomes "underbar", (etc.) ; ''', ...these 4 are unused :stbl: DB '"', '{', '}', '|', '~' ; ',', '-', ;A = ADDR(25TH LINE) MOV D,A LK E,0 RR D ! RR E ;SHIFT RIGHT DE DEC DE ;DE = ADDR(LST_CHR_ON_LST_LINE) MOV A,B ;A = #LINES TO MOVE LK HL,-VLL ADD HL,DE ;HL = ADDR(LINE ABOVE DE) ;DE := DE OR F000H; HL := HL OR F000H JR :ISTRT :ICONT: CALL VLDDR ;MOVE 1 LINE DOWN :ISTRT: CALL :VMOD JRNZ :ICONT ;IF MUST MOVE MORE LINES INC HL ;HL => 1ST CHR OF NEW LINE ; JR :EXIT SPACE 3,3 :EXIT: CALL CLRLN POP HL ;RECOVER CURSOR JMP VOUT90 ;MAIN EXIT SPACE 3,11 :DELT: POP DE ;RECOVER NEW CURSOR PUSH DE LK HL,VLL ADD HL,DE ;HL = LINE_BELOW_CURSOR JR :DSTRT :DCONT: CALL VLDIR ;MOVE 1 LINE UP :DSTRT: CALL :VMOD JRNZ :DCONT EX HL,DE ;GET ADDR OF LINE TO CLEAR JR :EXIT SPACE 3,13 ;HL := HL OR F000H; DE := DE OR F000H; ;SIMPLE MOD-4096 ARITHMETIC TO KEEP POINTERS INSIDE VIDEO MEMORY :VMOD: PUSH AF ;SAVE A = #LINES TO MOVE LK A,0F0H OR H MOV H,A ;SET UPPER NYBL OF H LK A,0F0H OR D MOV D,A ;MODULO 4096 LK BC,VLL POP AF DEC A ;DECREMENT LINE_P DE ! POP BC DI ENADIM LDDR ;9TH BIT MEMORY DISDIM EI RET SPACE 4,12 VLDIR: ;VIDEO BLOCK MOVE ; ENTRY BC, DE, HL SET ; EXIT LDIR ON MAIN & 9TH BIT MEMORY ; USES BC, DE, HL PUSH BC ! PUSH DE ! PUSH HL LDIR ;MAIN MEMORY POP HL ! POP DE ! POP BC DI ENADIM LDIR ;9TH BIT MEMORY DISDIM EI RET SPACE 4,10 UN_CUR: ;UNDO/INVERT CURSOR ; ENTRY HL = CURSOR_ADDR ; EXIT CURSOR INVERTED ; USES A, CY. LD A,[HL] ;GET THE CHR RAL ;CURSOR_BIT => CY CMC ;INVERT IT RAR STO A,[HL] ;... RET ; ENDX BMKEY.ASM ***************** Title 'bmSCAN - Keyboard scanning & decode' GKEY: ;Keyboard Interrupt processor ; Entry None ; Exit keyboard processing done, result in LKEY. ; system clock updated by UPTIM. Proc DI STO SP,IESTK ;save INTerrupted process stk LK SP,ISTK ;set to RAM int stk PUSHAL CALL UPTIM ;update system clock LD A,KEYLCK OR A JRZ GKEYX ;if locked keyboard :SCAN: CALL RDKEY ;scan keyboard CMP -2 JRZ GKEYAB ;  '.', '/', '0', '1', '2', '3', '4', '5' DB '<', '_', '>', '?', ')', '!', '@', '#', '$', '%' ; '6', '7', '8', '9', (:), ';', (<), '=', (>) DB '^', '&', '*', '(', ' ', ':', ' ', '+', ' ' page CNTRL: ;Control key processing ; Entry A = chr, CNTL key pressed simultaneously ; Exit A = ^chr Proc CMP ' ' + 1 RC ;if space, TAB, ESC, RET, etc. CMP '@' JRC :cheat ;IF <'@', CK FOR CHEATED CHR CMP 'z'+1 JRNC GKEYAB ;if greater than 'z', no cntl-chr AND ' ' - 1 ;kill cntl & lowercase bits RET :cheat: MOV B,A ;save chr AND ',' CMP ',' JRNZ GKEYAB ;if not a legal cheated chr MOV A,B ;restore chr LK HL,:tbl1-',' CMP '/'+1 ;ck for 1st group JRC :look ;if in :tbl1 LK HL,:tbl2-'<' ;...else in :tbl2 :look: ADD L ;do indexed load from base in HL MOV L,A JRNC :get INC H ;if carry, propagate into H :get: LD A,[hl] RET space 3 ; , - . / :tbl1: DB '{' , '_'-40h, '}' , '~' ; < = > ? :tbl2: DB ('{'),turn. ; Entry D = data read from keyboard ; E = 7-rank# of above data :fbit: LK A,7 ;#ranks SUB E ;A = table row to use (0..7) RAL ! RAL ! RAL ;A := A * 8 MOV C,A LK B,0 ;BC = offset into table LK HL,T5KEY ;HL = FWA(table) ADD HL,BC ;HL => rank(key) page MOV A,D ;restore data from keyboard LK BC, 0800h ;B := 8, C := 0 :loop2: RRC ;shift corresponding bit into CY JRNC :3 ;if didn't find bit this time thru DEC C ;...else record that a key was pressed ; MOV E,B ;don't need to save loop-index LD D,[hl] ;get chr from table :3: INC HL ;...else try next chr & bit DJNZ :loop2 INC C JZ :EXIT LDK A,-2 RET :exit: MOV A,D ;return chr in A RET space 4,10 T5KEY: T6KEY: DB ESC, TAB, ERC, ERC, ERC, CR, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',' DB MCUP, BKS, '0', ' ', '.', 'p', 'o', '9' DB MCRIGH,  TITLE 'MONITOR MAIN LOOP.' DISDIM ;DISABLE DIM JMP BMON ;RESET/RESTART USER: ;EXIT TO USER PROGRAM FROM 'G' COMMAND EI ! RET ;EXIT FROM G COMMAND .MAC IF RSIZE = 48 LIST G ; LEVEL 1 = BREAKPOINT ORG 1*8 IBKP: DI JMP PBKP ;PROCESS BREAKPOINT NULINT 2 NULINT 3 ; LEVEL 4 = KEYBOARD INT4: DI ;KEYBOARD INTERRUPT JMP GKEY NULINT 5 ; LEVEL 6 = SERIAL INTERRUPT NULINT 6 DI ; JMP ILINT LIST * .MAC ELSE .PBKP IF DEF PBKP ORG 1*8 IBKP: DI JMP PBKP ;PROCESS BREAKPOINT .PBKP ENDIF .MAC ENDIF ILINT: ;HERE ON UNKNOWN INTERRUPT .MAC IF RSIZE = 64 DI .MAC ENDIF DISDIM STO SP,IESTK ;SAVE INTERRUPTED PROC STACK LDK SP,ISTK ;INSURE STACK IN RAM PUSHAL ;SAVE ALL REGISTERS LDK A,'I' STO A,MPCHR ;SET PROMPT TO INTER LEVEL EXITI: ;EXIT INTERRUPT CODE VIA EXITING TO RAM AND ; THEN ENABLE OR DISABLE ROM CODE DEPENDING ON ; THE VALUE CONTAINED IN ROMRAM CELL. LD A,H.VIO ;CLEAR INTERRUPT LD A,ROMRAM OR A JNZ RORAME ;IF RETURN TO RAM, CPM  '`' , ('}'), 7Fh SLIDE: ;process ^1, ^2, ^3, ^(larrow), ^(rarrow) ; Entry A = chr, CNTL key pressed ; Exit 1) RET if chr not a special SLIDING chr ; 2) to GKEYX after acting on SLIDING chr Proc LK C,+2 CMP MCLEFT ;left arrow JRZ :slide LK C,-2 CMP MCRIGH ;right arrow JRZ :slide CMP '1' RC ;if not a SLIDING chr LK C, VFLO + 2*00 ;set screen to 0th column JRZ :set CMP '4' RNC ;if >3, not a SLIDING chr LK C, VFLO + 2*52 ;set 52nd col CMP '2' JRZ :set LK C, VFLO + 2*104 ;set 104th col JR :set :slide: LD A,PIAAD ;old screen offset value ADD A,C MOV C,A :set: CALL OPAD ;move the screen LK A,1 STO A,HKCNT ;short-circuit debounce/auto-repeat ;delay logic POP DE ;CLEAR STACK JMP GKEYX ;ignore RET-addr on stk: ;stk will be reset on next irupt. page RDKEY: ;Scan keyboard ; Entry none ; Exit A = chr (if available) ; -2 (if no key pressed) Proc LD A, H.KEY + 0FFh ;read ALL keyboard ports XOR 0FFh ;invert all  LF, '-', '/', ';', '\', 'l', '=' ; ENDX BMSCAN.ASM e (0..7) RAL ! RAL ! RAL ;A := A * 8 MOV C,A LK B,0 ;BC = offset into table LK HL,T5KEY ;HL = FWA(table) ADD HL,BC ;HL => rank(key) page MOV A,D ;restore data from keyboard LK BC, 0800h ;B := 8, C := 0 :loop2: RRC ;shift corresponding bit into CY JRNC :3 ;if didn't find bit this time thru DEC C ;...else record that a key was pressed ; MOV E,B ;don't need to save loop-index LD D,[hl] ;get chr from table :3: INC HL ;...else try next chr & bit DJNZ :loop2 INC C JZ :EXIT LDK A,-2 RET :exit: MOV A,D ;return chr in A RET space 4,10 T5KEY: T6KEY: DB ESC, TAB, ERC, ERC, ERC, CR, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',' DB MCUP, BKS, '0', ' ', '.', 'p', 'o', '9' DB MCRIGH,  .MAC IF RSIZE = 48 JR RESREG .MAC ELSE POPALL LD SP,IESTK ;GET USERS STACK BACK EI ! RET .MAC ENDIF .MAC IF RSIZE = 64 BMON: DI LDK SP,ROMSTK LDK A,0 STO A,SEC6 STO A,SDISK ;SET DISK TO DRIVE 0 CALL HINT ;INITIALIZE HARDWARE LDK HL,(HIGH MRAM)*100H STO HL,SSAVE ;INITIALIZE USER STACK IN RAM LDK HL,0 STO HL,LDSEL ;CLEAR SELECT AND LAST TRACK LDK DE,IBMSG CALL OSTR ;OUTPUT INITIAL MESSAGE JR BMON1 ;CONTINUE .MAC ENDIF IF * > NMIA MSG 'ILINT CODE IS TOO LARGE ', * ERROR ENDIF SPACE 4,10 ORG NMIA DI JMP BMON ;NMI PAGE ; MAIN START UP FOR MONITOR. IF RSIZE = 48 BMON: DI LDK SP,ROMSTK LDK A,0 STO A,SEC6 STO A,SDISK ;SET DISK TO DRIVE 0 LDK C,' ' ;FILL WITH BLANKS CALL FVIO ;CLEAR VIDEO MEMORY CALL HINT ;INITIALIZE HARDWARE LDK HL,(HIGH MRAM)*100H STO HL,SSAVE ;INITIALIZE USER STACK IN RAM LDK HL,0 STO HL,LDSEL ;CLEAR SELECT AND LAST TRACK LDK DE,IBMSG CALL OSTR ;OUTPUT INITIAL MESSAGE ENDIF ; GET 1ST USER RESPONbits, set flags LK A,-2 RZ ;if no key is pressed LDK HL, H.KEY + 001h ;control key rank MOV A,L ;ADDR BYTE TO A MOV R,A LD A,[hl] ;read control rank CMA ;complement the 1s STO A,CKEY ;save for shift & ctrl procs AND 1110_0011b ;clear SHIFT, CNTRL, & ALPHA bits LK BC,0700h ;loop 7 times, C := 0 JR :midle ;jump into middle of :loop1 :loop1: SLA L ;shift rank-select bit left MOV A,L ;ADDR BYTE TO A MOV R,A LD A,[hl] ;read rank XOR 0FFh ;invert 1s, set flags :midle: JRZ :2 ;if no key pressed in this rank DEC C ;record that a key was pressed MOV E,B ;record 7-rank# of key pressed MOV D,A ;save the data read :2: DJNZ :loop1 ;if not finished reading all ranks INC C ;ck for C = -1 JRZ :fbit ;if found EXACTLY ONE key press ;here if found 1) no keys pressed ; 2) many (more than 1) keys pressed LK A,-2 ;return NO keys pressed RET ;here to find the key pressed in a particular rank: ;load up the appropriate table entry & reSE. BMON1: CALL CI ;GET NEXT CHARACTER CMP CR LK HL,DSKSWP ;DISK SWAP CELL LK C,0 ;BOOT FROM A: STO C,[HL] ;SET TO A=A, B=B JZ CBOOT ;IF COLD BOOT IF INDIA INC [HL] ;SWAP DRIVES: A=B, B=A CMP '"' JZ CBOOT ;IF COLD BOOT OFF OF B CMP 'D'-40H JZ DIAG ;IF ENTER DEBUGGER JR BMON ELSE JR BMON1 ENDIF ; HERE ON NMI AND RESET ;BMNI: LDK SP,ROMSTK ;STACK MUST BE IN RAM (NOT 0,1 PAGE) ; CALL HINT ;INITIALIZE HARDWARE ; JMP DMON ;ENTER LOOP .MAC IF RSIZE = 48 RESREG: ;RESTORE REGISTERS AND EXIT INTERRUPT POPALL LD SP,IESTK ;GET USERS STACK BACK EI ! RET .MAC ENDIF PAGE .MAC IF INDMON ; MAIN LOOP FOR OSB DEBUG MONITOR. ; ENTRY NONE. ; EXIT TO COMMAND PROCESSOR. ; C= 2. DMON: LDK DE,IMMSG CALL OSTR ;OUTPUT SIGNON MESSAGE ; COMMAND PROCESSOR NEXTC: EI LDK SP,ROMSTK ;RESET ALWAYS CALL OCRLF ;NEW LINE LD A,MPCHR MOV C,A CALL CO ;PROMPT :2: CALL GETCH ;GET NEXT CHAR CMP ' ' JRZ :2 ;IF LEADING BLANK LDK B,NCMDS LDK HL,CTAB :3:T OUTPUT JMP PUNCH ;PUNCH OUTPUT JMP READER ;READER INPUT ; DISK I/O JMP HOME JMP SELDSK ;SELECT DISK JMP SETTRK ;SET TRACK JMP SETSEC ;SET SECTOR JMP SETDMA ;SET DMA JMP DREAD ;DISK READ JMP DWRT ;DISK WRITE JMP SLST ;LIST DEVICE STATUS RET ! NOP ! NOP ;SECTOR TRANSLATE ; END OF STANDARD CP/M FUNCTIONS RORAME: JMP BIOS+BRRXT JMP BIOS+BROMJP JMP FORMT ;FORMAT ONE TRACK JMP SIRST ;SIO RESET ; JMP BIOS+BRDXY ; JMP BIOS+BWTXY JMP IE.CO ;IEEE CONTROL OUT JMP IE.SI ; STATUS IN JMP IE.GTS ; GO TO STANDBY JMP IE.TC ; TAKE CONTROL JMP IE.OIM ; OUTPUT INTERFACE MESSAGE JMP IE.ODM ; OUTPUT DEVICE MESSAGE JMP IE.IDM ; INPUT DEVICE MESSAGE JMP IE.PP ; PARALLEL POLL PAGE .MAC IF RSIZE = 48 ; MAIN LOOP FOR OSB DEBUG MONITOR. ; ENTRY NONE. ; EXIT TO COMMAND PROCESSOR. ; C= 2. DMON: LDK DE,IMMSG CALL OSTR ;OUTPUT SIGNON MESSAGE ; COMMAND PROCESSOR NEXTC: EI LDK SP,ROMSTK ;RESET ALWAYS CALL OCRLF ;NEW LINE LD A,MPCHR MOV C,A 080 Registers. ; Each entry in the RTAB consists of: ; DB ASCII name ; DB Address ; DB flag, where flag is ; 0= 8 bit register ; 1= 16 bit ; 8x=8 bit but do not display in X command RTABS EQU 3 ;Length of each register entry RTAB: DB 'A', low ASAVE ,0 DB 'B', low BSAVE ,1 DB 'C'+80h, low CSAVE ,0 DB 'D', low DSAVE ,1 DB 'E'+80h, low ESAVE ,0 DB 'H', low HSAVE ,1 DB 'L'+80h, low LSAVE ,0 DB 'F', low FSAVE ,0 DB 'S', low SSAVE+1 ,1 DB 'P', low PSAVE+1 ,1 DB 0 ;Indicate end of table ; Z80 register control table. RTAX: DB 'A', low AFSAX+1 ,0 DB 'B', low BCSAX+1 ,1 DB 'C'+80h, low BCSAX ,0 DB 'D', low DESAX+1 ,1 DB 'E'+80h, low DESAX ,0 DB 'H', low HLSAX+1 ,1 DB 'L'+80h, low HLSAX ,0 DB 'F', low AFSAX ,0 DB 'I'+80h, low IVSAX+1 ,0 DB 'X', low IXSAX+1 ,1 DB 'Y', low IYSAX+1 ,1 DB 0 ; endx bmromd.asm diagnostic section COMAND Z ;examine Z80 regs NCMDS EQU (*-CTAB)/3 ;NUMBER OF VALID COMMANDS space 4,10 ; Table of ALL 8 CMP [HL] INC HL JRZ :4 ;IF COMMAND MATCH INC HL ! INC HL DJNZ :3 ;IF NOT END JMP ERROR ;IF ILLEGAL ; HERE ON COMMAND MATCH :4: LD A,[HL] INC HL LD H,[HL] MOV L,A LDK C,2 JMP [HL] ;PROCESS COMMAND .MAC ENDIF PAGE HINT: ;INITIALIZE ALL DEPENDENT HARDWARE. ; ENTRY NONE. ; EXIT ALL HARDWARE INITIALIZED. ; SET FLAG INDICATING IN ROM ENAROM DISDIM ;DISABLE DIM BIT .MAC IF RSIZE = 48 IM0 ;MODE 0 MACHINE .MAC ELSE LDK HL,GKEY STO HL,INTBL+(4*2) ;SET KEYBOARD INTERRUPT IM2 LDK A,HIGH INTBL MOV I,A ;SET INTERRUPT PAGE .MAC ENDIF ; INITIALIZE KEYBOARD XRA A STO A,BELCNT ;CLEAR BELL TIMER CELL STO A,LKEY ;CLEAR LAST KEY CELL STO A,HKCNT ;CLEAR DEBOUNCE STO A,ECHOP ;CLEAR ECHO TO LIST DEV STO A,ESCH ;CLEAR ESC HOLD FLAG CMA STO A,IDAY ;SET DATE INVALID FOR SETUP.COM STO A,TKEY ;CLEAR HOLDING KEY STO A,KEYLCK ;INDICATE NOT LOCKED ; LDK HL,FWAVM ; STO HL,CURS ;SET CURSOR LDK A,VLL STO A,LLIMIT ;SET MAX LINE LIMIT ; SET KEYBO CALL CO ;PROMPT :2: CALL GETCH ;GET NEXT CHAR CMP ' ' JRZ :2 ;IF LEADING BLANK LDK B,NCMDS LDK HL,CTAB :3: CMP [HL] INC HL JRZ :4 ;IF COMMAND MATCH INC HL ! INC HL DJNZ :3 ;IF NOT END JMP ERROR ;IF ILLEGAL ; HERE ON COMMAND MATCH :4: LD A,[HL] INC HL LD H,[HL] MOV L,A LDK C,2 JMP [HL] ;PROCESS COMMAND .MAC ENDIF ; ENDX BMLOP TITLE 'MROMD - Debug Monitor ROM data and constants.' ; ROM storage and constants IMMSG: ;Sign-on message to user, Version is current date for ; this assembly. DB cr DC lf ; DB 'OCC-1 ' ; DB ' SORCIM Monitor ' ; VFD 16\VER,8\'.',16\LEVEL ; DC ' ' IBMSG: DB 'Z'-40h,lf,lf,lf,lf DB ESC,VSGH DB 'Q'-40h DB 07Fh, 24, 'W'-40h DB 'E'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH,1, ESC,VEGH DB ' ' DB ESC,'l' DB 'Osborne System ONE.' DB ESC,'m' DB ' ' DB ESC,VSGH,4, ESC,VEGH DB cr,lf DB ESC,VSGH DB 'A'-40h DB 07Fh,24,' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'A'-40h DB ' ARD DEBOUNCE DELAY CELL LK A,KBDTM ;DEBOUNCE CONSTANT STO A,KBDLY ;SET DEBOUNCE-DELAY CELL ; NOW FUNCTION PIA TO SET STARTING ADDRESS ; AND CONTINUE TO MOVE DISPLAY WINDOW OVER ; THE FIRST DISPLAY LINE. ; SET CURSOR AS 1-40 ON 1ST LINE. CALL SPAO ;SET UP FOR OUTPUT LDK C,VFLO CALL OPAD ;SET FOR -10 CHAR POSITIONS ; SET BEGINNING LINE TO 0 LDK A,0 STO A,PIABD ;SET DATA REG MOV C,A CALL OPBD ;SET LINE ; RESET-MASTER CLEAR THE SIO (ACIA) LK C,SI.S16 ;SELECT 16X CLOCK FOR 1200 BAUD CALL SIRST ;RESET ; SET DEFAULT SEEK TO AS DEFINED BY SYSTEXT LDK A,SEEKTM ;DEFINED FROM SYSTEXT STO A,SEKDEL ;SET SEEK STEP RATE ; SET DEFAULT PROMPT CHAR LDK A,PMCHR STO A,MPCHR ;SET UP DEFAULT EI ! RET PAGE IF * > 100H MSG 'BMON IS TOO LONG > 100H ',* ERROR ENDIF ORG 100H ; JUMP VECTOR FOR DEBUGGER AND CP/M RVEC: JMP CBOOT ;COLD BOOT JMP WBOOT ;WARM BOOT JMP SKEY ;KEYBOARD STATUS JMP CI ;KEYBOARD INPUT JMP COUT ;CONSOLE OUTPUT JMP LIST ;LIS ' DB ESC,')' DB ' Rev A 180 ' DB ESC,'(' DB ' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'Z'-40h DB 07Fh, 24, 'X'-40h DB 'C'-40h DB ESC,VEGH DB cr,lf,lf,lf DB 'Insert disk in Drive ' DB ESC,'l' DB 'A' DB ESC,'m' DB ' and type RETURN' DC '.' BKPTA: DB CR DC 'Bkp' XCMDA: DB CR DC 'X ' ZCMDA: DB CR DC 'Zrg' ; Table of all valid Monitor command Characters COMAND MACRO CHR,ADR .incmd IF IN_%1_CMD DB '%1' IF ' %2' <> ' ' DW %2 ELSE DW %1_CMD ENDIF .incmd ENDIF ENDM CTAB: COMAND A ;Ascii core entry COMAND B,CBOOT ;Boot up system COMAND D ;Display memory COMAND F ;Fill memory COMAND G ;Go execute/breakpoint COMAND H ;Hex sum & difference COMAND M ;Move data COMAND R ;Read Intel-format hex COMAND S ;Substitute data into memory COMAND X ;eXamine register(s) COMAND T,DIAG ;Tests diagnostic section COMAND Z ;examine Z80 regs NCMDS EQU (*-CTAB)/3 ;NUMBER OF VALID COMMANDS space 4,10 ; Table of ALL 8 TITLE 'SIO - Serial I/O Processors.' SIRST: ;Master reset SIO ; Entry C= SI.S16 or SI.S64 for 1200/300 baud LDK A,SI.MRST STO A,H.SCTRL ;master reset NOP ! NOP ! NOP MOV A,C STO A,ACIAD ;last-command cell STO A,H.SCTRL ;select SIO RET space 4,10 READER: ;Input one byte from reader port ; Entry None ; Exit A=C= character read LD A,H.SSTS ; MOV B,A ;save status AND SI.RRDY ; LD A,H.SREC ;clear ~DCD JRZ READER ;if not ready LD A,H.SREC ;get data MOV C,A ;A=C ; LK A,SI.RERR ;error check ; AND B ;...with status ; MOV A,C ;recover data ; RZ ;if OK ; STC ;...else error RET space 4,10 SLST: ;Get list device status ; Exit A= 0, if NOT ready LD A,H.SSTS AND SI.TRDY ;ck for Xmit buf empty RET ;set status space 4,10 LIST: ;Output one byte to list port PUNCH: ;Output one byte to punch port ; Entry C= character to output ; Exit C=C. ; LD A,ACIAD ;get last command byte ; CBIT 6,A ;...invert RTS status ; STO A,H.SCTRL ;make request (~RTS := low) K C,0 ;FILL WITH ZERO .OLD IF FALSE ; 8080 VERSION MOV A,D OR E RZ ;IF ALL DONE STO C,[HL] INC HL DEC DE JR FILLC ;CONTINUE .OLD ENDIF FILLC: MOV A,E OR D RZ ; RETURN HERE IF BROADCAST 0 BYTES STO C,[HL] ; 1ST BYTE DEC DE MOV A,E OR D RZ ; RETURN HERE IF BROADCAST 1 BYTE MOV B,D MOV C,E ; BC := (COUNT) MOV D,H MOV E,L INC DE ; DE := HL + 1 LDIR ; OVERLAPPING MOVE RET SPACE 4,10 OSTR: ;OUTPUT STRING TO CONSOLE ; ENTRY DE=FWA OF SOURCE ; NOTE : OSTR RECOGNIZES 7F AS AN ESCAPE SEQUENCE ; TO REPEAT CHAR N TIMES. FORMAT IS: ; 7F, REPEAT COUNT, CHAR PROC LD A,[DE] OR A PUSH AF AND 07FH CMP 07FH MOV C,A JRNZ :4 ;IF NOT REPEAT INC DE ! LD A,[DE] ! DEC A MOV B,A ;REPEAT COUNT INC DE ! LD A,[DE] ;GET REPEAT CHAR MOV C,A :2: CALL CO ;OUTPUT CHAR DJNZ :2 ;IF NOT DONE :4: CALL CO ;OUTPUT IT INC DE POP AF JP OSTR ;IF NOT DONE RET SPACE 4,13 ESTR: ;OUTPUT ENCODED STRING TO CONSOLE ; ENTRY DE=FWA OF SOURCE OR A ;CLEAR Con ;of data through each corresponding peripheral data line. ;A data direction register bit set at "0" configures ;the corresponding peripheral data line as an input. ; ;A reset at power up has the effect of zeroing all PIA registers. ;This will set PA0-PA7, PB0-PB7, CA2, and CB2 as inputs, ;and all interrupts disabled. ;Signals ATN, REN, and IFC will be driven low ;until initialized by software. ; ;Data direction is always set for output for the data register. ;Data must be set to all ones when inputting. ;The interface is in source handshake mode if data enable (PB0) ;is set to "0", and in acceptor handshake mode if set to "1". ;When switching from source to acceptor handshake, ;ATN will always be low. ;TAKE CONTROL can only be called following a GO TO STANDBY. ;After a fatal error, perform an IFC reset. ; ;Standard values used: ; ;CCRA 0011(IFC)(DIR)10 ; ;CCRB 0011(REN)(DIR)00 ; ;CPDRA Source Direction 1111_1111 ; Data DATA ; ;CPDRA Acceptor Direction 1111_1111 ; Data 1:wait: LD A,H.SSTS AND SI.TRDY ;wait for CTS go-ahead JRZ :wait ;if CTS high, wait again MOV A,C STO A,H.SXMT ;send chr ; NOP ! NOP ! NOP ;...wait... ; LD A,ACIAD ;get last command ; STO A,H.SCTRL ;set RTS high (no request) RET ; Endx BMSIO.asm atus AND SI.RRDY ; LD A,H.SREC ;clear ~DCD JRZ READER ;if not ready LD A,H.SREC ;get data MOV C,A ;A=C ; LK A,SI.RERR ;error check ; AND B ;...with status ; MOV A,C ;recover data ; RZ ;if OK ; STC ;...else error RET space 4,10 SLST: ;Get list device status ; Exit A= 0, if NOT ready LD A,H.SSTS AND SI.TRDY ;ck for Xmit buf empty RET ;set status space 4,10 LIST: ;Output one byte to list port PUNCH: ;Output one byte to punch port ; Entry C= character to output ; Exit C=C. ; LD A,ACIAD ;get last command byte ; CBIT 6,A ;...invert RTS status ; STO A,H.SCTRL ;make request (~RTS := low) BIT LD A,[DE] RRC ;NORMALIZE CHAR PUSH AF AND 07FH MOV C,A CALL CO ;OUTPUT IT INC DE POP AF JRNC ESTR ;IF NOT DONE RET PAGE .OLD IF FALSE FVIO: ;FILL VIDEO MEMORY WITH FIXED DATA ; ENTRY C= DATA TO BROADCAST ; NOTE: INTERRUPTS MUST BE DISABLED.. PROC LDK HL,FWAVM LDK DE,LVMEM PUSH HL ! PUSH DE CALL FILLC ;CLEAR MAIN VIO POP DE ! POP HL .MAC IF RSIZE = 64 ENADIM LDK C,0 ;CLEAR 9TH BIT :2: MOV A,D ;FILL 9TH BIT MEMORY OR E JRZ :4 ;IF DONE STO C,[HL] INC HL DEC DE JR :2 ;LOOP :4: DISDIM .MAC ENDIF RET .OLD ENDIF SPACE 4,10 SPAO: ;SET PIA FOR OUTPUT LDK A,03H ;CRA1-0, INTERRUPT INPUTS CA1 STO A,H.VIO+1 ;SET DATA DIRECTION LDK A,0FFH STO A,H.VIO ;SET ALL A LINES AS OUTPUT LDK A,0 STO A,H.VIO+3 LDK A,0FFH STO A,H.VIO+2 ;SET ALL B LINES AS OUTPUT RET SPACE 4,10 OPAD: ;OUTPUT DATA TO PIA A REGISTER ; ENTRY C= DATA ; EXIT PIAAD = NEW VALUE LDK A,4+3 STO A,H.VIO+1 MOV A,C STO A,PIAAD STO A,H.VIO ;SEND DA111_1111 ; ;CPDRB Source Direction 0011_1111 ; Data 000A_0010 ;A = ATN ; ;CPDRB Acceptor Direction 1101_0111 ; Data 0100_0101 Page ;PIA signal definitions: ;All signals are low on the IEEE bus when PIA register contains "1". ; ; PA0 DIO 1 ; PA1 DIO 2 ; PA2 DIO 3 ; PA3 DIO 4 ; PA4 DIO 5 ; PA5 DIO 6 ; PA6 DIO 7 ; PA7 DIO 8 ; ; CA1 SRQ ; CA2 IFC ; ; PB0 Enable data out (enabled when "0") ; PB1 Enable NDAC/NRFD (enabled when "0") ; PB2 Enable EOI/DAV (enabled when "0") ; PB3 EOI ; PB4 ATN ; PB5 DAV ; PB6 NDAC ; PB7 NRFD ; ; CB1 Not Used ; CB2 REN ; ;Control Word format ; ;[ 7 ][ 6 ][ 5 ][ 4 ][ 3 ][ 2 ][ 1 ][ 0 ] ; ;[IRQA1][IRQA2][ CA2 Control ][ DDRA][ CA1 Control] ;[IRQB1][IRQB2][ CB2 Control ][ DDRB][ CB1 Control] ; ; IRQA1 0 Interrupt flag set by fall of SRQ ; IRQA2 0 Not Used ; CA2 110 Set IFC high ; 111 Set IFC low ; DDRA 0 R/W data direction register A ; 1 R/W peripheral register A ; CA1 10 Set IRQA1 high on rise of SRQ  TITLE 'HARDWARE PIO FUNCTION PROCESSORS.' CDEHL: ;COMPARE DE TO HL AS UNSIGNED INTEGERS. ; ENTRY DE,HL SET TO VALUES TO COMPARE ; EXIT ZBIT SET IF DE = HL ; CBIT SET IF DE < HL. ; USES AF. MOV A,D CMP H RNZ ;IF D .NE. H MOV A,E CMP L RNZ ;IF DE .NE. HL STC RET SPACE 4,10 CNVBN: ;CONVERT ASCII TO BINARY ; ENTRY C= ASCII CHAR ; EXIT A = CHAR MOV A,C SUI '0' CPI 9+1 RM SUI 7 RET SPACE 4,10 DELAY: ;'N' MILLISECONDS ; ENTRY A=NUMBER OF MILLISECONDS TO DELAY ; SCLFRE= (FREQ/1000)/25 ; EXIT TIME PASSED. PROC PUSH BC MOV C,A :1: LDK A,SCLFRE :2: DEC A ;(4 TICS) MOV B,B ;(4 TICS) MOV C,C ;(4 TICS) JNZ :2 ;(10 TICS) IF 1 MS NOT ELAPSED DEC C JNZ :1 ;IF REQUESTED MSEC NOT DONE POP BC ;RESTORE REGISTERS RET ;SCLFRE: = 2000/22 ;Z80, 2MHZ ;...DEFINED IN OCCTXT.AST SPACE 4,32 FILLZ: ;FILL BLOCK OF MEMORY WITH BYTE VALUE. ; ENTRY DE=LENGTH TO BROADCAST CHARACTER ; C =CHARACTER TO BROADCAST ; HL=FWA TO START BROADCAST ; EXIT FILL DONE LTA RET SPACE 4,10 OPBD: ;OUTPUT DATA TO PIA B REGISTER ; PIA DEFINITION. ; 7 6 5 4 3 2 1 0 ; +--+--+--+--+--+--+--+--+ ; |D1|D0|^G| VERT OFFSET | ; +--+--+--+--+--+--+--+--+ ; ; ENTRY C= DATA ; EXIT PIABD = NEW VALUE LDK A,4 STO A,H.VIO+3 MOV A,C STO A,PIABD STO A,H.VIO+2 ;SEND DATA RET ; ENDX BMPIO TITLE 'bmIEEE.asm - IEEE-488 interface.' ; +---------------------------------------+ ; | Entered 05/01/81 from TNW xerox, seh. | ; +---------------------------------------+ ; ;Last edited at 09:29 on 11 NOV 80 ; ;There are four commands to the 6821 ; ; 00 Peripheral/direction register A CPDRA ; 01 Control register A CCRA ; 10 Peripheral/direction register B CPDRB ; 11 Control register B CCRB ; ;Bit 2 of the control register (A and B) allows selection of either ;a peripheral interface register or a data direction register. ;A "1" in bit 2 selects the peripheral register. ; ;The two data direction registers allow control of the directi ; ; IRQB1 0 Not Used ; IRQB2 0 Not Used ; CB2 110 Set REN high ; 111 Set REN low ; DDRB 0 R/W data direction register B ; 1 R/W peripheral register B ; CB1 00 Not Used Page ;Bios call 1: CONTROL OUT ; ; Can be called while in any state. ; ; Exits in the controller standby state (ATN high), ; source handshake mode ; ;Parameter passed in register C: ; ; Bit 0 If "1", the IFC signal is set low for 101 micro-sec ; and all pia signals are initialized ; ; Bit 2 1 ; 0 X No action ; 1 0 Sets REN high ; 1 1 Sets REN low ; IE.CO: Proc PUSH AF PUSH HL BIT 0,C ;check IFC sub-command JRZ :b1c20 ;Initialize all IEEE-488 signals LK HL,CCRA STO 0011_1010b,[hl] ;enable SRQ and set IFC-out low LK A,1111_1111b ;direct data out STO A,CPDRA STO 0011_1110b,[hl] XOR A ;set data to zero STO A,CPDRA LK HL,CCRB STO 0011_0000b,[hl] ;set REN-out high LK A,0011_1111b ;direction for source handshake STO A,CPDRB STO 0011_0100b,[hl] LK A,0000_0010b ;values forile in any mode or state ; ; Exits in the source handshake mode with ATN low. ; ;Multi-line message in register C ; ;Error!code returned in register A ; IE.OIM: Proc PUSH HL LK HL,CPDRB SBIT 4,[hl] ;set ATN low BIT 0,[hl] JRZ IE.shk ;set-up for source handshake STO 0001_0111b,[hl] ;disable drivers LD A,CCRB CBIT 2,A STO A,CCRB STO 0011_1111b,[hl] ;direction register SBIT 2,A STO A,CCRB XOR A ;float external data bus STO A,CPDRA STO 0001_0010b,[hl] ;control signal initial value JR IE.shk Page ;Bios call 6: OUTPUT DEVICE MESSAGE ; ; Can be called only while in the source handshake mode ; with ATN high or low. ; ; Exits in the source handshake mode with ATN high. ; ;Multi-line message in register C ;EOI request in register B ; ;Error code returned in register A ; IE.ODM: Proc PUSH HL LK HL,CPDRB CBIT 4,[hl] ;set ATN high BIT 0,B ;check if EOI requested JRZ IE.shk SBIT 3,[hl] ;Perform source handshake IE.shk: BIT 5,[hl] ; JRNZ :b6c50  to registers A and HL MOV A,H POP DE RET space 4,21 ;Bios call 8: PARALLEL POLL ; ; Can be called only while in the source handshake mode ; with ATN high or low. ; ; Exits in the source handshake mode with ATN low. ; ;Parallel poll value returned in A. ; IE.PP: Proc PUSH HL LK HL,CPDRA LK A,0001_1011b ;form parallel poll STO A,CPDRB STO 1111_1111b,[hl] ;float internal data bus LD A,[hl] ;read parallel poll data STO 0,[hl] ;re-store source handshake mode LK HL,CPDRB STO 0001_0010b,[hl] POP HL RET ; Endx bmIEEE.asm low LD A,CPDRA ;read data MOV D,A LK E,0 ;read EOI BIT 3,[hl] JRZ :b7c40 LK E,1 :b7c40: CBIT 6,[hl] ;set NDAC high :b7c50: LK A,255 :b7c60: BIT 5,[hl] JRZ :b7c70 ;data valid dropped DEC A JRNZ :b7c60 ;wait 1000 micro-sec SBIT 2,E ;set data invalid timeout error SBIT 7,E JR :b7c80 :b7c70: SBIT 6,[hl] ;set NDAC low :b7c80: EX DE,HL ;move results source handshake STO A,CPDRB ;Leave IFC low for 100 micro-sec LK A,25 ;delay 100 micro-sec :b1c10: DEC A JRNZ :b1c10 LK A,0011_0110b ;set IFC high STO A,CCRA :b1c20: BIT 2,C ;check REN sub-command JRZ :b1c40 ;set/clear REN LK A,0011_0000b BIT 1,C JRZ :b1c30 LK A,0011_1000b :b1c30: STO A,CCRB :b1c40: POP HL POP AF RET Page ;Bios call 2: STATUS IN ; ; Can be called only while in source handshake mode. ; ;Bit 0 of register A set if SRQ is low ; IE.SI: Proc PUSH HL LD A,CPDRA ;clear IRQA1 LK HL,CPDRB ;pulse enable DAV/EOI CBIT 2,[hl] SBIT 2,[hl] LD A,CCRA ;set SRQ value in A AND 1000_0000b RLC A POP HL RET space 4,14 ;Bios call 3: GO TO STANDBY ; ; Can be called only while in source handshake mode ; ;No parameters passed ; IE.GTS: Proc PUSH AF LK A,0000_0010b ;set ATN high STO A,CPDRB XOR A ;float data bus STO A,CPDRA POP AF RET Page ;Bios call 4: TAKE CONTROL ; ; Can be called only while in the controller standby sta;DAC timeout re-entry MOV A,C ;place data on bus STO A,CPDRA LK A,10 :b6c20: BIT 7,[hl] JRZ :b6c30 ;ready for data DEC A JRNZ :b6c20 ;wait for 100 micro-sec LK A,1000_0010b ;set RFD timeout error JR :b6c80 :b6c30: BIT 6,[hl] JRNZ :b6c40 ;data accepted low LK A,1000_0001b ;set device not present error JR :b6c80 :b6c40: SBIT 5,[hl] ;set DAV low :b6c50: LK A,255 :b6c60: BIT 6,[hl] JRZ :b6c70 ;data accepted DEC A JRNZ :b6c60 ;wait 1000 micro-sec LK A,1000_0100b ;set DAC timeout error JR :b6c80 :b6c70: CBIT 5,[hl] ;set DAV high CBIT 3,[hl] ;set EOI high XOR A ;remove data from bus STO A,CPDRA :b6c80: POP HL RET Page ;Bios call 7: INPUT DEVICE MESSAGE ; ; Can be called while in any mode or state ; ; Exits in the acceptor handshake mode with ATN high. ; ;Device message returned in both registers A and H ;Error code returned in register L ; IE.IDM: Proc PUSH DE EX DE,HL ;save re-entry data LK HL,CPDRB BIT 0,[hl] JRNZ :b7c10 ;set-te ; (ATN high). ; ; Exits in the controller active state (ATN low), ; source handshake mode. ; ;Bit 0 of register C set to take control asynchronous ; ;Error code returned in register A. ; IE.TC: Proc PUSH HL LK HL,CPDRB BIT 0,C JRNZ :b4c30 ;take control synchronously STO 0000_0111b,[hl] ;disable drivers LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111b,[hl] ;direction register SBIT 2,A STO A,CCRB STO 1000_0101b,[hl] ;set NRFD low LK A,25 :b4c10: BIT 5,[hl] JRZ :b4c20 ;data valid has dropped DEC A JRNZ :b4c10 ;wait 100 micro-sec LK A,1000_0001b ;set data valid timeout error JR :b4c40 :b4c20: STO 1100_0101b,[hl] ;set NDAC low :b4c30: SBIT 4,[hl] ;set ATN low ;set-up for source handshake LD A,CCRB CBIT 2,A STO A,CCRB STO 0011_1111b,[hl] ;direction register SBIT 2,A STO A,CCRB STO 0001_0010b,[hl] ;control signal initial value XOR A ;clear error code :b4c40: POP HL RET Page ;Bios call 5: OUTPUT INTERFACE MESSAGE ; ; Can be called whup for acceptor handshake STO 0001_0111b,[hl] ;disable drivers LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111b,[hl] ;direction register SBIT 2,A STO A,CCRB LK A,1111_1111b ;float internal data bus STO A,CPDRA STO 0101_0101b,[hl] ;control signals initial value STO 0100_0101b,[hl] ;set ATN high ;Perform acceptor handshake :b7c10: BIT 6,[hl] JRZ :b7c50 ;data invalid timeout error re-entry CBIT 7,[hl] ;set NRFD high LK A,10 :b7c20: BIT 5,[hl] JRNZ :b7c30 ;data valid DEC A JRNZ :b7c20 ;wait 100 micro-sec LK DE,1000_0010b ;set data valid timeout error JR :b7c80 :b7c30: SBIT 7,[hl] ;set NRFD low LD A,CPDRA ;read data MOV D,A LK E,0 ;read EOI BIT 3,[hl] JRZ :b7c40 LK E,1 :b7c40: CBIT 6,[hl] ;set NDAC high :b7c50: LK A,255 :b7c60: BIT 5,[hl] JRZ :b7c70 ;data valid dropped DEC A JRNZ :b7c60 ;wait 1000 micro-sec SBIT 2,E ;set data invalid timeout error SBIT 7,E JR :b7c80 :b7c70: SBIT 6,[hl] ;set NDAC low :b7c80: EX DE,HL ;move results TITLE 'BMUTIL2 - Osborne 1 Utility routines.' NMOUT: PBBH: ;Print Binary Byte in Hex. ; Converts the 8 BIT, unsigned integer in the ; A register into 2 ASCII characters. ; Entry A= 8 bit integer ; Exit NONE ; Calls CO,PRVAL ; DESTROYS: AF, C. PUSH AF ;Save argument RRC RRC RRC RRC ;Get upper 4 bits to LOW 4 bit positions CALL PRVAL ;Convert lower 4 bits to ASCII CALL CO ;SEND to terminal POP AF ;Get back argument CALL PRVAL JMP CO space 4,10 PRVAL: ;Converts a number in the range 0 to F HEX to ; the corresponding ASCII character, 0-9,A-F. PRVAL ; does not check the validity of its input argument. ; Entry A= integer, range 0 to F ; Exit A= ASCII character. ; C= A ; Calls NONE. ; DESTROYS: AF AND 0Fh ADD A,90h ;Set UP a so that A-F CAUSE a Carry DAA ;adjust contents of a register ADC A,40h ;ADD in Carry and adjust upper 4 bits DAA ;adjust contents of a register again MOV C,A RET OCRLF: ;Output CR,LF on console screen LK C,CR CALL COUT LK C,L ORG NMIA DI JMP BMON ;NMI page ; Main start up for Monitor. ; Get 1st user response. BMON1: CALL CI ;Get next character CMP CR LK HL,DSKSWP ;disk swap cell LK C,0 ;boot from A: STO C,[hl] ;set to A=A, B=B JZ CBOOT ;if cold boot INC [hl] ;swap drives: A=B, B=A CMP '"' JZ CBOOT ;if cold boot off of B CMP 'D'-40h JZ DIAG ;if enter debugger JR BMON page HINT: ;Initialize all dependent hardware. ;Entry None. ;Exit All hardware initialized. ;Set flag indicating in ROM PROC ENAROM DISDIM ;disable DIM bit LDK HL,GKEY STO HL,INTBL+(4*2) ;set keyboard interrupt IM2 LDK A,high INTBL MOV I,A ;set interrupt page ; Initialize keyboard XRA A STO A,0EFF0H STO A,BELCNT ;clear bell timer cell STO A,LKEY ;clear last key cell STO A,ECHOP ;clear echo to list dev STO A,ESCH ;clear ESC hold flag LDK HL,KEYLST LDK B,KL_LEN*KLE_LEN :1: STO A,[HL] INC HL DJNZ :1 CMA STO A,IDAY ;set date invalid for SETUP.COM STO A,KEYLCK ;indicate EPEAT CHAR MOV C,A :2: CALL CO ;OUTPUT CHAR DJNZ :2 ;IF NOT DONE :4: CALL CO ;OUTPUT IT INC DE POP AF JP OSTR ;IF NOT DONE RET PAGE TITLE 'MONITOR ROM CONSTANTS.' IBMSG: DB 'Z'-40h,lf,lf,lf,lf DB ESC,VSGH DB 'Q'-40h DB 07Fh, 24, 'W'-40h DB 'E'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH,1, ESC,VEGH DB ' ' DB ESC,'l' DB 'Osborne System ONE.' DB ESC,'m' DB ' ' DB ESC,VSGH,4, ESC,VEGH DB cr,lf DB ESC,VSGH DB 'A'-40h DB 07Fh,24,' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'A'-40h DB ' ' DB ESC,')' DB 'BIOS REV C 256' DB ESC,'(' DB ' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'Z'-40h DB 07Fh, 24, 'X'-40h DB 'C'-40h DB ESC,VEGH DB cr,lf,lf,lf DB 'Insert disk in Drive ' DB ESC,'l' DB 'A' DB ESC,'m' DB ' and press RETURN' DC '.' ; END OCCROM1?.???  CMP 07FH MOV C,A JRNZ :4 ;IF NOT REPEAT INC DE ! LD A,[DE] ! DEC A MOV B,A ;REPEAT COUNT INC DE ! LD A,[DE] ;GET RF JMP COUT O2SP: ;Output 2 spaces on console CALL OSP OSP: LK C,' ' JMP COUT RLWA = * ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',RLWA IF RLWA > 0FFFH .9 ERROR CODE TOO LARGE.. ENDIF ; endx BMUTIL2.asm PUSH AF ;Save argument RRC RRC RRC RRC ;Get upper 4 bits to LOW 4 bit positions CALL PRVAL ;Convert lower 4 bits to ASCII CALL CO ;SEND to terminal POP AF ;Get back argument CALL PRVAL JMP CO space 4,10 PRVAL: ;Converts a number in the range 0 to F HEX to ; the corresponding ASCII character, 0-9,A-F. PRVAL ; does not check the validity of its input argument. ; Entry A= integer, range 0 to F ; Exit A= ASCII character. ; C= A ; Calls NONE. ; DESTROYS: AF AND 0Fh ADD A,90h ;Set UP a so that A-F CAUSE a Carry DAA ;adjust contents of a register ADC A,40h ;ADD in Carry and adjust upper 4 bits DAA ;adjust contents of a register again MOV C,A RET OCRLF: ;Output CR,LF on console screen LK C,CR CALL COUT LK C,LNOT locked LDK A,VLL STO A,LLIMIT ;set max line limit ; Now function PIA to set starting address ; and continue to move display window over ; the first display line. ; Set cursor as 1-40 on 1st line. CALL SPAO ;set up for output LDK C,VFLO CALL OPAD ;set for -10 char positions ; Set beginning line to 0 XRA A STO A,PIABD ;set data reg MOV C,A CALL OPBD ;set line ; Reset-Master clear the SIO (ACIA) LK C,SI.S16 ;select 16x clock for 1200 baud CALL SIRST ;reset ; Set default seek to as defined by systext LDK A,SEEKTM ;defined from systext STO A,SEKDEL ;set seek step rate ; Set default prompt char LDK A,PMCHR STO A,MPCHR ;set up default EI ! RET page ORG 100h ; Jump vector for debugger and CP/M RVEC: JMP CBOOT ;cold boot JMP WBOOT ;warm boot JMP SKEY ;keyboard status JMP CI ;keyboard input JMP COUT ;console output JMP LIST ;list output JMP PUNCH ;punch output JMP READER ;reader input ; Disk I/O JMP HOME JMP SELDSK ;select d TITLE 'Monitor Main Loop.' DISDIM ;disable DIM JMP BMON ;reset/restart USER: ;Exit to user program from 'G' command EI ! RET ;Exit from G command ILINT: ;Here on unknown interrupt DI DISDIM STO SP,IESTK ;save interrupted proc stack LDK SP,ISTK ;insure stack in RAM ALPUSH ;save all registers LDK A,'I' STO A,MPCHR ;set prompt to inter level EXITI: ;Exit interrupt code via exiting to RAM and ; then enable or disable ROM code depending on ; the value contained in ROMRAM cell. LD A,H.VIO ;clear interrupt LD A,ROMRAM OR A JNZ RORAME ;if return to RAM, CPM ALLPOP LD SP,IESTK ;get users stack back EI ! RET BMON: DI LDK SP,ROMSTK XRA A STO A,SEC6 STO A,SDISK ;set disk to drive 0 STO A,VRTOFF ;OFFSET TO ZERO USED IN COUT CALL HINT ;Initialize hardware LDK HL,(high MRAM)*100h STO HL,SSAVE ;Initialize User stack in ram LDK HL,0 STO HL,LDSEL ;clear select and last track LDK DE,IBMSG CALL OSTR ;Output initial message JR BMON1 ;continueisk JMP SETTRK ;set track JMP SETSEC ;set sector JMP SETDMA ;set DMA JMP DREAD ;Disk read JMP DWRT ;Disk write JMP SLST ;List device status RET ! NOP ! NOP ;Sector translate ; End of standard CP/m functions RORAME: JMP BIOS+BRRXT JMP BIOS+BROMJP JMP FORMT ;Format one track JMP SIRST ;SIO reset JMP IE.CO ;IEEE Control Out JMP IE.SI ; Status In JMP IE.GTS ; Go To Standby JMP IE.TC ; Take Control JMP IE.OIM ; Output Interface Message JMP IE.ODM ; Output Device Message JMP IE.IDM ; Input Device Message JMP IE.PP ; Parallel Poll JMP VLDDR ;VIDEO BLOCK MOVE JMP VLDIR JMP STODIM ;STO reg B IN [HL] PAGE OSTR: ;OUTPUT STRING TO CONSOLE ;ENTRY ;DE = FWA OF SOURCE ;NOTE : OSTR RECOGNIZES 7F AS AN ESCAPE SEQUENCE ;TO REPEAT CHAR N TIMES. FORMAT IS: ;7F, REPEAT COUNT, CHAR PROC LD A,[DE] OR A PUSH AF AND 07FH CMP 07FH MOV C,A JRNZ :4 ;IF NOT REPEAT INC DE ! LD A,[DE] ! DEC A MOV B,A ;REPEAT COUNT INC DE ! LD A,[DE] ;GET R TITLE 'Disk I/O routines.' ; Disk interface definitions and functions. ; 1792 functions. DML = 4 ;= 15 ms delay on function LTRKB = 3125 ;length of a track ; Note: Shugart says LTRKB = 3125... NRTRYS = 4 ;Number of retries MSECB = 10h ;Multi-sector r/w bit ; Function codes D.RES = 00h+0Ch ;restore D.SEK = 10h+08h ;seek D.STP = 20h ;step D.STPI = 40h ;Step IN D.STPO = 60h ;Step out D.RDS = 80h ;Read sector D.WRTS = 0A0h+DML ;Write sector D.RDA = 0C0h+DML ;read address D.RDT = 0E0h+DML ;read track D.WRTT = 0F0h+DML ;write track D.FINT = 0D0h ;Force interrupt ; Disk status and command registers D.CMDR = H.FDC ;Disk command reg (write) D.STSR = H.FDC ;Status reg (read) D.TRKR = D.CMDR+1 ;track reg D.SECR = D.CMDR+2 ;Sector reg D.DATR = D.CMDR+3 ;Data reg (r/w) ; Status definitions BS.BSY = 0 ;Busy DS.BSY = 1 shl BS.BSY BS.DRQ = 1 DS.INX = 1 shl BS.DRQ ;Index mark detected DS.DRQ = DS.INX ;DR is full on read, empty on write BS.TK0 = 2 DS.TK0 = 1 shl C,A JMP OPBD ;deselect last drive page PSEKC: ;Perform seek type command ; Entry A= command to perform without r1, and r0. ; PSEKC will or in the low two bits as defined ; by SEKDEL. ; Exit A= last value of D.STSr LDK HL,SEKDEL OR [hl] ;or in delay time for seek CALL FDSK ;function disk RNZ ;if Drive NOT ready JMP WBUSY space 4,10 SELDSK: ;Select disk in register C MOV A,C ;drive to home CALL SDRV1 ;C= drive JR HOMED1 HOMED: ;Home disk drive ; Entry SDISK= drive ; Exit A=0 if drive on home. proc CALL SDRV ;select drive HOMED1: LDK A,D.RES CALL PSEKC ;perform seek command CMP -1 JRZ SKEX1 ;if error BIT BS.SEK,A JRNZ SKEX1 ;if error BIT BS.TK0,A JRZ :4 ;if NOT home IF ODEBUG CALL LDSKS1 ;list status **** ENDIF XRA A ;clear A SKEX1: PUSH AF LDK A,-1 STO A,DACTVE ;start counter CALL STAT17 ;save disk controller regs POP AF RET ; Here if drive NOT homed, possible NOT ready :4: AND 80h JR SKEX1 space 4,10 SEEK: ;Seek toack, set sector JRNZ RWEX1 ;if seek error MOV B,D PUSH BC LDK A,D.RDS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' bit :3: CALL FDSK POP BC CMP -1 JRZ RWEX1 ;if drive NOT ready ; Now xfer bytes from controller to DMA. DI LD HL,DMADR :5: PUSH BC LDK B,low LSECB :6: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRZ :6 ;if no data LD A,D.DATR STO A,[hl] INC HL DJNZ :6 ;if not all data ; Now check if multi sector POP BC DJNZ :5 ;continue XRA A JR RWEX1 ; here on error RWEX: CALL STAT17 ;save disk controller regs POP DE ;restore stack OR 80h ;if busy cleared, indicate with 80h RWEX1: OR A ;set status PUSH AF LDK A,-1 STO A,DACTVE POP AF EI ! RET space 4,10 DWRT: ;Write to disk ; Entry SDISK= drive ; B= Number of sectors to xmit. ; DMADR= FWA of data ; Exit same as DREAD ; Uses All registers proc MOV D,B CALL SEEK JRNZ RWEX1 ;if seek error MOV B,D PUSH BC LDK A,D.WRTS DEC BS.TK0 DS.LSD = DS.TK0 ;lost data DS.CRC = 08h ;CRC error in ID field BS.SEK = 4 DS.SEK = 1 shl BS.SEK ;Seek error DS.RNF = DS.SEK ;Record NOT found DS.HDL = 20h ;Head loaded DS.WTF = DS.HDL ;Write fault DS.WTP = 40h ;Write protected DS.NRY = 80h ;Drive NOT ready ; Disk timing counts D.DEL = 20 ;Delay after function page SDMA: ;Set DMA SETDMA: ; Entry BC = DMA address STO BC,DMADR RET space 4,10 SETTRK: ;Set track ; Entry BC = track STO BC,SAVTRK RET space 4,10 SETSEC: ;Set Sector ; Entry C= sector number (1 to MSEC) MOV A,C STO A,SAVSEC RET space 4,10 HOME: ;Home selected disk drive LDK BC,0 JMP SETTRK ;reset track to 0 PAGE SDRV: ;Select Drive ; Entry SDISK= drive ; Exit A= 0, if drive is ready ; Calls OPBD, DELAY ; Uses A,B proc LD A,SDISK SDRV1: LK HL,DSKSWP ;disk drive swap cell XOR [hl] ;swap A for B if DSKSWP=1 AND 1 ;Can only be 0 or 1 CMP 1 JRNZ :2 ;if not drive 1 LDK A,40h :2: ADI 40h MOV C,A LD A,PIABD M track defined by SAVTRK ; Entry SAVTRK set to track ; SAVSEC set to sector number ; Exit A= 0, if no error, else status ; MUST NOT destroy DE, HL pair proc CALL SDRV ;select drive ; Here if drive already selected ; Check to see if SEEK is necessary by ; comparing SAVTRK to controller track ; register SEEKN: LD A,SAVTRK STO A,D.DATR ;set track wanted MOV C,A LD A,D.TRKR CMP C JRZ :8 ;if on track ; Disk seek required, function controller ; with SEEK command LDK A,5 SEEKA: STO A,RTRY ;update retry count LDK A,D.SEK CALL PSEKC ;perform seek command MOV C,A AND DS.CRC or DS.SEK JRNZ :10 ;if error ; Now read-address and verify on-track CALL DRDAS ;read address JRNZ :10 ;if error LDK HL,DSTSB LD A,SAVTRK CMP [hl] JRZ :8 ;if ON track LD A,RTRY DEC A JRNZ SEEKA ;if not max retrys ; here if seek error :10: MOV A,C ORI 80h ;indicate movement error JR SKEX1 ; Now set the sector register to requested ; Sector :8: CALL WBUSY ;waitD JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' bit :3: CALL FDSK POP BC ; Now xfer bytes to controller from DMA. DI LD HL,DMADR :5: PUSH BC LDK BC,LSECB ;length of std sector :6: CALL XDD ;xfer to disk JRNZ RWEX ;if error ; Now check if multi sector POP BC DJNZ :5 ;continue XRA A :8: JR RWEX1 page XDD: ;Xfer data from memory to disk ; Entry BC = length ; HL = FWA ; Exit HL = next address ; A=0 if no error, else status ; Uses A,BC,E, HL proc LD A,D.STSR BIT BS.BSY,A JRZ :5 ;if possible error BIT BS.DRQ,A JRZ XDD ;if no data LD A,[hl] STO A,D.DATR ;send to controller INC HL DEC BC MOV A,B OR C JRNZ XDD ;if not done XRA A ;indicate good xfer RET ; here if error :5: OR 80h ;indicate busy dropped RET page FDSK: ;Function disk routine ; All functions for DSK controller SHALL do so by using ; this routine. FDSK sets DACTVE to 0 indicating activity ; UPTIM uses this cell to turn off select if one sec has ; occurred. ; EntOV B,A AND 1100_0000b ;get drive bits only CMP C JZ RDSKD ;if drive already selected ; Check to see if this drive is the same as the last ; one selected. ; IF true, go to 3 ; else ; Save current trk register in LDSEL and ; set trk reg to last track used for newly selected ; drive ; end LD A,LDSEL ;last selected disk CMP C JRZ :3 ;if same drive MOV A,C STO A,LDSEL ;set to new drive PUSH BC LDK HL,LDTRK LD C,[hl] ;get last accessed track for new drive LD A,D.TRKR ;get current track STO A,[hl] ;save in table MOV A,C STO A,D.TRKR ;set trk register to last selected POP BC ; Set drive select perserving vio offset values :3: CALL RDSKD ;reset Controller LDK B,5 ;number of tries :5: LDK A,250 CALL DELAY LK A,250 ;2nd delay CALL DELAY LD A,D.STSR AND DS.INX RZ ;if index DJNZ :5 ;keep trying OR 80h or DS.INX ;indicate NOT ready RET space 4,10 DDRV: ;Deselect drive ; Entry SDISK = current disk drive LD A,PIABD AND 1_1111b MOV  for FDC quiescence LD A,SAVSEC STO A,D.SECR ;set sector register XRA A ;indicate good RET space 4,10 DRDA: ;Read Address info. ; Entry SDISK= drive ; Exit D.STSB = data bytes ; MUST NOT destroy DE pair proc CALL SDRV ;select drive DRDAS: LDK A,D.RDA CALL FDSK ;function disk ; Get status bytes LDK HL,DSTSB LDK B,6 DI PUSH DE ;save DE :2: LDK DE,4000 ;time out :3: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRNZ :4 ;if data ready DEC DE MOV A,D OR E JRNZ :3 ;if NOT time out LK C,SEKTMO ;seek time out JR RWEX ;error exit :4: LD A,D.DATR STO A,[hl] ;save byte INC HL DJNZ :2 ;if not done POP DE XRA A ;indicate good EI ! RET space 4,10 DREAD: DRSECS: ;Read disk sectors. ; Entry SDISK= drive ; B = number of sectors to read ; Number from 1 to MSEC ; DMADR= FWA for data. ; Exit DSTSB= A= 0, if no error ; HL = next DMA ; Uses All registers proc MOV D,B ;save sectors CALL SEEK ;seek to trry A= function code ; Exit A= 0, if chip accepted function ; else, A=-1, indicating time-out, See WBUSY ; Uses A, B, C proc MOV B,A ;save function code LD A,PIABD AND 1100_0000b JRNZ :1 ;if drive active PUSH BC CALL SDRV ;reselect drive POP BC :1: CALL WBUSY ;Wait for busy to clear RM ;if will NOT clear busy ; Controller NOT busy, issue command MOV A,B STO A,D.CMDR ;function drive ; Wait for busy to be set LDK C,0 :2: LD A,D.STSR RAR ;DS.BSY JRC :3 ;if chip went busy DEC C JRNZ :2 ;if not time-out JR WBUSYX ;exit, error ; Set DACTVE indicating activity on drive :3: XRA A STO A,DACTVE RET space 4,10 WBUSY: ;Wait for Busy to clear ; Exit A= -1, if time out occurred, ; else ; A= last status and is positive. ; Uses A, C proc PUSH BC LDK BC,0 :1: LD A,D.STSR RAR ;DS.BSY JRNC :1A ;if NOT busy, proceed DEC BC MOV A,B OR C JRNZ :1 ;if not time-out WBUSYX: LDK A,-1 ;indicate error, drive NOT ready POP BC OR A ;set f TITLE 'Hardware PIO function processors.' CDEHL: ;Compare DE to HL as unsigned integers. ; Entry DE,HL set to values to compare ; Exit Zbit set if DE = HL ; Cbit set if DE < HL. ; Uses AF. MOV A,D CMP H RNZ ;If D .ne. H MOV A,E CMP L RNZ ;if DE .ne. HL STC RET space 4,10 CNVBN: ;Convert Ascii to binary ; Entry C= ascii char ; Exit A = char MOV A,C SUI '0' CPI 9+1 RM SUI 7 RET space 4,10 DELAY: ;'N' Milliseconds ; Entry A=Number of Milliseconds to delay ; SCLFRE= (Freq/1000)/25 ; Exit Time passed. Proc PUSH BC MOV C,A :1: LDK A,SCLFRE :2: DEC A ;(4 tics) MOV B,B ;(4 tics) MOV C,C ;(4 tics) JNZ :2 ;(10 tics) If 1 ms not elapsed DEC C JNZ :1 ;If requested msec not done POP BC ;restore registers RET ;SCLFRE: = 2000/22 ;Z80, 2mhz ;...defined in OCCTXT.ast space 4,32 FILLZ: ;Fill block of memory with byte value. ; Entry DE=LENGTH TO broadcast character ; C =character TO broadcast ; HL=FWA TO START broadcast ; EXIT FILL DONE Llags RET :1A: RAL ;restore A POP BC ;restore BC AND 7Fh ;make sure its positive RET space 4,8 RDSKD: ;Reset PIA and disk controller ; selecting drive specified by C ; Entry C= drive ; B= PIABD MOV A,B AND 0001_1111b ;get vio offset only OR C MOV C,A CALL OPBD ;function PIO-b ; JMP RDSKC RDSKC: ;reset disk controller ; Entry None ; Exit Busy cleared. ; A= 0. LDK A,D.FINT STO A,D.STSR ;clear controller XRA A ;clear A and flags RET ODER: ;Output disk error to console ; Entry DE= FWA of message ; SDISK = drive with error PUSH DE CALL OCRLF ;new line LD A,SDISK ADD A,'A' MOV C,A CALL CO ;output drive name CALL O2SP POP DE ;get message JMP ESTR DERR: ;Output disk system error ; Entry A= status from controller ; Exit error output PUSH DE PUSH HL PUSH BC PUSH AF LDK DE,DERMSG CALL ESTR ;output error POP AF ;get status value CALL PBBH ;output status CALL O2SP LD A,SAVTRK CALL PBBH ;output track LDK C,',' CAL page FORMT: ;Format one track ; in IBM 3740 format consisting of 40 tracks, with each ; track containing 10 sectors. ; Drive already selected and ready ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK LDK HL,D.TRKR ;PRESENT TRACK OR [HL] JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RET ; endx BMXFMTK C,0 ;FILL WITH ZERO .old IF FALSE ; 8080 version MOV A,D OR E RZ ;IF ALL DONE STO C,[hl] INC HL DEC DE JR FILLC ;CONTINUE .old ENDIF FILLC: MOV A,E OR D RZ ; return here if broadcast 0 bytes STO C,[hl] ; 1st byte DEC DE MOV A,E OR D RZ ; return here if broadcast 1 byte MOV B,D MOV C,E ; BC := (count) MOV D,H MOV E,L INC DE ; DE := HL + 1 LDIR ; overlapping move RET space 4,10 OSTR: ;Output string to console ; Entry DE=FWA of source ; Note : OSTR recognizes 7F as an escape sequence ; to repeat char N times. Format is: ; 7F, Repeat count, Char proc LD A,[de] OR A PUSH AF AND 07Fh CMP 07Fh MOV C,A JRNZ :4 ;if not repeat INC DE ! LD A,[de] ! DEC A MOV B,A ;repeat count INC DE ! LD A,[de] ;get repeat char MOV C,A :2: CALL CO ;output char DJNZ :2 ;if not done :4: CALL CO ;output it INC DE POP AF JP OSTR ;if not done RET space 4,13 ESTR: ;Output ENCODED string to console ; Entry DE=FWA of source OR A ;clear cL COUT ;output comma LD A,D.TRKR CALL PBBH ;output controller track CALL O2SP LD A,SAVSEC CALL PBBH ;output sector LDK C,',' CALL COUT ;output comma LD A,D.SECR CALL PBBH ;output controller sector ; Update error counter LD HL,ERCNT INC HL STO HL,ERCNT ;update error count ; Clear controller CALL RDSKC ;reset disk controller ; Restore regs POP BC POP HL POP DE RET DERMSG: DBE cr,lf DCE 'Dsk ERR (sts trk sec)- ' space 4,10 STAT17: ;save 179x status ;called when disk error discovered: ;...saves 179x regs in high RAM. PUSH BC ! PUSH DE ! PUSH HL LK HL,D.STSR ;1st (lowest) 179x register LK DE,R179x ;register save area LK BC,4 ;move 4 bytes LDIR POP HL ! POP DE ! POP BC RET ; endx BMDSK r POP AF ;get status value CALL PBBH ;output status CALL O2SP LD A,SAVTRK CALL PBBH ;output track LDK C,',' CAL.asm e already selected and ready ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK LDK HL,D.TRKR ;PRESENT TRACK OR [HL] JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RET ; endx BMXFMTbit LD A,[de] RRC ;normalize char PUSH AF AND 07Fh MOV C,A CALL CO ;output it INC DE POP AF JRNC ESTR ;if not done RET page .old IF FALSE FVIO: ;Fill video memory with fixed data ; Entry C= data to broadcast ; NOTE: Interrupts MUST be disabled.. proc LDK HL,FWAVM LDK DE,LVMEM PUSH HL ! PUSH DE CALL FILLC ;clear main vio POP DE ! POP HL .mac IF RSIZE = 64 ENADIM LDK C,0 ;clear 9th bit :2: MOV A,D ;fill 9th bit memory OR E JRZ :4 ;if done STO C,[hl] INC HL DEC DE JR :2 ;loop :4: DISDIM .mac ENDIF RET .old ENDIF space 4,10 SPAO: ;Set PIA for output LDK A,03h ;CRA1-0, Interrupt inputs CA1 STO A,H.VIO+1 ;set data direction LDK A,0FFh STO A,H.VIO ;set all A lines as output LDK A,0 STO A,H.VIO+3 LDK A,0FFh STO A,H.VIO+2 ;set all B lines as output RET space 4,10 OPAD: ;Output data to pia A register ; Entry C= data ; Exit PIAAD = new value LDK A,4+3 STO A,H.VIO+1 MOV A,C STO A,PIAAD STO A,H.VIO ;send da111_1111 ; ;CPDRB SOURCE DIRECTION 0011_1111 ; DATA 000A_0010 ;A = ATN ; ;CPDRB ACCEPTOR DIRECTION 1101_0111 ; DATA 0100_0101 PAGE ;PIA SIGNAL DEFINITIONS: ;ALL SIGNALS ARE LOW ON THE IEEE BUS WHEN PIA REGISTER CONTAINS "1". ; ; PA0 DIO 1 ; PA1 DIO 2 ; PA2 DIO 3 ; PA3 DIO 4 ; PA4 DIO 5 ; PA5 DIO 6 ; PA6 DIO 7 ; PA7 DIO 8 ; ; CA1 SRQ ; CA2 IFC ; ; PB0 ENABLE DATA OUT (ENABLED WHEN "0") ; PB1 ENABLE NDAC/NRFD (ENABLED WHEN "0") ; PB2 ENABLE EOI/DAV (ENABLED WHEN "0") ; PB3 EOI ; PB4 ATN ; PB5 DAV ; PB6 NDAC ; PB7 NRFD ; ; CB1 NOT USED ; CB2 REN ; ;CONTROL WORD FORMAT ; ;[ 7 ][ 6 ][ 5 ][ 4 ][ 3 ][ 2 ][ 1 ][ 0 ] ; ;[IRQA1][IRQA2][ CA2 CONTROL ][ DDRA][ CA1 CONTROL] ;[IRQB1][IRQB2][ CB2 CONTROL ][ DDRB][ CB1 CONTROL] ; ; IRQA1 0 INTERRUPT FLAG SET BY FALL OF SRQ ; IRQA2 0 NOT USED ; CA2 110 SET IFC HIGH ; 111 SET IFC LOW ; DDRA 0 R/W DATA DIRECTION REGISTER A ; 1 R/W PERIPHERAL REGISTER A ; CA1 10 SET IRQA1 HIGH ON RISE OF SRQ TE ; (ATN HIGH). ; ; EXITS IN THE CONTROLLER ACTIVE STATE (ATN LOW), ; SOURCE HANDSHAKE MODE. ; ;BIT 0 OF REGISTER C SET TO TAKE CONTROL ASYNCHRONOUS ; ;ERROR CODE RETURNED IN REGISTER A. ; IE.TC: PROC PUSH HL LK HL,CPDRB BIT 0,C JRNZ :B4C30 ;TAKE CONTROL SYNCHRONOUSLY STO 0000_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB STO 1000_0101B,[HL] ;SET NRFD LOW LK A,25 :B4C10: BIT 5,[HL] JRZ :B4C20 ;DATA VALID HAS DROPPED DEC A JRNZ :B4C10 ;WAIT 100 MICRO-SEC LK A,1000_0001B ;SET DATA VALID TIMEOUT ERROR JR :B4C40 :B4C20: STO 1100_0101B,[HL] ;SET NDAC LOW :B4C30: SBIT 4,[HL] ;SET ATN LOW ;SET-UP FOR SOURCE HANDSHAKE LD A,CCRB CBIT 2,A STO A,CCRB STO 0011_1111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB STO 0001_0010B,[HL] ;CONTROL SIGNAL INITIAL VALUE XOR A ;CLEAR ERROR CODE :B4C40: POP HL RET PAGE ;BIOS CALL 5: OUTPUT INTERFACE MESSAGE ; ; CAN BE CALLED WHta RET space 4,10 OPBD: ;Output data to pia B register ; PIA definition. ; 7 6 5 4 3 2 1 0 ; +--+--+--+--+--+--+--+--+ ; |D1|D0|^G| vert offset | ; +--+--+--+--+--+--+--+--+ ; ; Entry C= data ; Exit PIABD = new value LDK A,4 STO A,H.VIO+3 MOV A,C STO A,PIABD STO A,H.VIO+2 ;send data RET ; endx BMpio TITLE 'BMIEEE.ASM - IEEE-488 INTERFACE.' ; +---------------------------------------+ ; | ENTERED 05/01/81 FROM TNW XEROX, SEH. | ; +---------------------------------------+ ; ;LAST EDITED AT 09:29 ON 11 NOV 80 ; ;THERE ARE FOUR COMMANDS TO THE 6821 ; ; 00 PERIPHERAL/DIRECTION REGISTER A CPDRA ; 01 CONTROL REGISTER A CCRA ; 10 PERIPHERAL/DIRECTION REGISTER B CPDRB ; 11 CONTROL REGISTER B CCRB ; ;BIT 2 OF THE CONTROL REGISTER (A AND B) ALLOWS SELECTION OF EITHER ;A PERIPHERAL INTERFACE REGISTER OR A DATA DIRECTION REGISTER. ;A "1" IN BIT 2 SELECTS THE PERIPHERAL REGISTER. ; ;THE TWO DATA DIRECTION REGISTERS ALLOW CONTROL OF THE DIRECTI ; ; IRQB1 0 NOT USED ; IRQB2 0 NOT USED ; CB2 110 SET REN HIGH ; 111 SET REN LOW ; DDRB 0 R/W DATA DIRECTION REGISTER B ; 1 R/W PERIPHERAL REGISTER B ; CB1 00 NOT USED PAGE ;BIOS CALL 1: CONTROL OUT ; ; CAN BE CALLED WHILE IN ANY STATE. ; ; EXITS IN THE CONTROLLER STANDBY STATE (ATN HIGH), ; SOURCE HANDSHAKE MODE ; ;PARAMETER PASSED IN REGISTER C: ; ; BIT 0 IF "1", THE IFC SIGNAL IS SET LOW FOR 101 MICRO-SEC ; AND ALL PIA SIGNALS ARE INITIALIZED ; ; BIT 2 1 ; 0 X NO ACTION ; 1 0 SETS REN HIGH ; 1 1 SETS REN LOW ; IE.CO: PROC PUSH AF PUSH HL BIT 0,C ;CHECK IFC SUB-COMMAND JRZ :B1C20 ;INITIALIZE ALL IEEE-488 SIGNALS LK HL,CCRA STO 0011_1010B,[HL] ;ENABLE SRQ AND SET IFC-OUT LOW LK A,1111_1111B ;DIRECT DATA OUT STO A,CPDRA STO 0011_1110B,[HL] XOR A ;SET DATA TO ZERO STO A,CPDRA LK HL,CCRB STO 0011_0000B,[HL] ;SET REN-OUT HIGH LK A,0011_1111B ;DIRECTION FOR SOURCE HANDSHAKE STO A,CPDRB STO 0011_0100B,[HL] LK A,0000_0010B ;VALUES FORILE IN ANY MODE OR STATE ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ; ;MULTI-LINE MESSAGE IN REGISTER C ; ;ERROR CODE RETURNED IN REGISTER A ; IE.OIM: PROC PUSH HL LK HL,CPDRB SBIT 4,[HL] ;SET ATN LOW BIT 0,[HL] JRZ IE.SHK ;SET-UP FOR SOURCE HANDSHAKE STO 0001_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 0011_1111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB XOR A ;FLOAT EXTERNAL DATA BUS STO A,CPDRA STO 0001_0010B,[HL] ;CONTROL SIGNAL INITIAL VALUE JR IE.SHK PAGE ;BIOS CALL 6: OUTPUT DEVICE MESSAGE ; ; CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE ; WITH ATN HIGH OR LOW. ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN HIGH. ; ;MULTI-LINE MESSAGE IN REGISTER C ;EOI REQUEST IN REGISTER B ; ;ERROR CODE RETURNED IN REGISTER A ; IE.ODM: PROC PUSH HL LK HL,CPDRB CBIT 4,[HL] ;SET ATN HIGH BIT 0,B ;CHECK IF EOI REQUESTED JRZ IE.SHK SBIT 3,[HL] ;PERFORM SOURCE HANDSHAKE IE.SHK: BIT 5,[HL] ; JRNZ :B6C50 ON ;OF DATA THROUGH EACH CORRESPONDING PERIPHERAL DATA LINE. ;A DATA DIRECTION REGISTER BIT SET AT "0" CONFIGURES ;THE CORRESPONDING PERIPHERAL DATA LINE AS AN INPUT. ; ;A RESET AT POWER UP HAS THE EFFECT OF ZEROING ALL PIA REGISTERS. ;THIS WILL SET PA0-PA7, PB0-PB7, CA2, AND CB2 AS INPUTS, ;AND ALL INTERRUPTS DISABLED. ;SIGNALS ATN, REN, AND IFC WILL BE DRIVEN LOW ;UNTIL INITIALIZED BY SOFTWARE. ; ;DATA DIRECTION IS ALWAYS SET FOR OUTPUT FOR THE DATA REGISTER. ;DATA MUST BE SET TO ALL ONES WHEN INPUTTING. ;THE INTERFACE IS IN SOURCE HANDSHAKE MODE IF DATA ENABLE (PB0) ;IS SET TO "0", AND IN ACCEPTOR HANDSHAKE MODE IF SET TO "1". ;WHEN SWITCHING FROM SOURCE TO ACCEPTOR HANDSHAKE, ;ATN WILL ALWAYS BE LOW. ;TAKE CONTROL CAN ONLY BE CALLED FOLLOWING A GO TO STANDBY. ;AFTER A FATAL ERROR, PERFORM AN IFC RESET. ; ;STANDARD VALUES USED: ; ;CCRA 0011(IFC)(DIR)10 ; ;CCRB 0011(REN)(DIR)00 ; ;CPDRA SOURCE DIRECTION 1111_1111 ; DATA DATA ; ;CPDRA ACCEPTOR DIRECTION 1111_1111 ; DATA 1 SOURCE HANDSHAKE STO A,CPDRB ;LEAVE IFC LOW FOR 100 MICRO-SEC LK A,25 ;DELAY 100 MICRO-SEC :B1C10: DEC A JRNZ :B1C10 LK A,0011_0110B ;SET IFC HIGH STO A,CCRA :B1C20: BIT 2,C ;CHECK REN SUB-COMMAND JRZ :B1C40 ;SET/CLEAR REN LK A,0011_0000B BIT 1,C JRZ :B1C30 LK A,0011_1000B :B1C30: STO A,CCRB :B1C40: POP HL POP AF RET PAGE ;BIOS CALL 2: STATUS IN ; ; CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE. ; ;BIT 0 OF REGISTER A SET IF SRQ IS LOW ; IE.SI: PROC PUSH HL LD A,CPDRA ;CLEAR IRQA1 LK HL,CPDRB ;PULSE ENABLE DAV/EOI CBIT 2,[HL] SBIT 2,[HL] LD A,CCRA ;SET SRQ VALUE IN A AND 1000_0000B RLC A POP HL RET SPACE 4,14 ;BIOS CALL 3: GO TO STANDBY ; ; CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE ; ;NO PARAMETERS PASSED ; IE.GTS: PROC PUSH AF LK A,0000_0010B ;SET ATN HIGH STO A,CPDRB XOR A ;FLOAT DATA BUS STO A,CPDRA POP AF RET PAGE ;BIOS CALL 4: TAKE CONTROL ; ; CAN BE CALLED ONLY WHILE IN THE CONTROLLER STANDBY STA;DAC TIMEOUT RE-ENTRY MOV A,C ;PLACE DATA ON BUS STO A,CPDRA LK A,10 :B6C20: BIT 7,[HL] JRZ :B6C30 ;READY FOR DATA DEC A JRNZ :B6C20 ;WAIT FOR 100 MICRO-SEC LK A,1000_0010B ;SET RFD TIMEOUT ERROR JR :B6C80 :B6C30: BIT 6,[HL] JRNZ :B6C40 ;DATA ACCEPTED LOW LK A,1000_0001B ;SET DEVICE NOT PRESENT ERROR JR :B6C80 :B6C40: SBIT 5,[HL] ;SET DAV LOW :B6C50: LK A,255 :B6C60: BIT 6,[HL] JRZ :B6C70 ;DATA ACCEPTED DEC A JRNZ :B6C60 ;WAIT 1000 MICRO-SEC LK A,1000_0100B ;SET DAC TIMEOUT ERROR JR :B6C80 :B6C70: CBIT 5,[HL] ;SET DAV HIGH CBIT 3,[HL] ;SET EOI HIGH XOR A ;REMOVE DATA FROM BUS STO A,CPDRA :B6C80: POP HL RET PAGE ;BIOS CALL 7: INPUT DEVICE MESSAGE ; ; CAN BE CALLED WHILE IN ANY MODE OR STATE ; ; EXITS IN THE ACCEPTOR HANDSHAKE MODE WITH ATN HIGH. ; ;DEVICE MESSAGE RETURNED IN BOTH REGISTERS A AND H ;ERROR CODE RETURNED IN REGISTER L ; IE.IDM: PROC PUSH DE EX DE,HL ;SAVE RE-ENTRY DATA LK HL,CPDRB BIT 0,[HL] JRNZ :B7C10 ;SET-ow) seek to trk 12, sec 0 ; ;:fastr: LK HL,SAVTRK ; LK A,-4 ;seek 4 tracks out ; ADD [hl] ; STO A,[hl] ; LK HL,SEKDEL ; DEC [hl] ;speed up step rate ; CALL SEEK ;seek 4 track outwards, faster ; JRNZ :err ;if stepping too fast ; LD A,SEKDEL ; OR A ;stepping fastest possible? ; JRNZ :fastr ;try a faster seek ;; JR :end ;..else seeking fastest already ; ;:end: CALL BCPM1 ;read in cpm ; JMP BIOS ;cold start ; ;:err: LK HL,SEKDEL ; INC [hl] ;seek at previous (slower) speed ; LK A,0000_0011b ; AND [hl] ;limit seek to (slowest) 3 ; STO A,[hl] ; JR :end WBOOT: Proc LDK A,6-4 ;don't read CBIOS STO A,TEM ;save sectors LD A,CDISK ;Current logged in drive ; JR BCPM ;Boot CP/M space 4,10 BCPM: ;Boot CPM from disk ; Entry A = Drive to boot from. ; TEM = Number of sectors to read from ; track 3. ; A = Drive to boot or warm-boot from ; Exit A = 0, load sucessful. ; Z bit = 1, load successful. proc STO A,SDISK ;Set drive to boot from BCPM1: CALL HOMUP FOR ACCEPTOR HANDSHAKE STO 0001_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB LK A,1111_1111B ;FLOAT INTERNAL DATA BUS STO A,CPDRA STO 0101_0101B,[HL] ;CONTROL SIGNALS INITIAL VALUE STO 0100_0101B,[HL] ;SET ATN HIGH ;PERFORM ACCEPTOR HANDSHAKE :B7C10: BIT 6,[HL] JRZ :B7C50 ;DATA INVALID TIMEOUT ERROR RE-ENTRY CBIT 7,[HL] ;SET NRFD HIGH LK A,10 :B7C20: BIT 5,[HL] JRNZ :B7C30 ;DATA VALID DEC A JRNZ :B7C20 ;WAIT 100 MICRO-SEC LK DE,1000_0010B ;SET DATA VALID TIMEOUT ERROR JR :B7C80 :B7C30: SBIT 7,[HL] ;SET NRFD LOW LD A,CPDRA ;READ DATA MOV D,A LK E,0 ;READ EOI BIT 3,[HL] JRZ :B7C40 LK E,1 :B7C40: CBIT 6,[HL] ;SET NDAC HIGH :B7C50: LK A,255 :B7C60: BIT 5,[HL] JRZ :B7C70 ;DATA VALID DROPPED DEC A JRNZ :B7C60 ;WAIT 1000 MICRO-SEC SBIT 2,E ;SET DATA INVALID TIMEOUT ERROR SBIT 7,E JR :B7C80 :B7C70: SBIT 6,[HL] ;SET NDAC LOW :B7C80: EX DE,HL ;MOVE RESULTS TITLE 'B o o t C P / M f r o m d i s k.' ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; ; Before any data is read in, the maximum drive step rate ; must be determined: ; 1. set slowest seek ; 2. home drive A: ; 3. seek track #12 ; 4. speed up step rate ; 5. seek 4 tracks outward (12=>8,8=>4,4=>0) ; 6. if error, slow down step rate by 1, ; load in CP/M, boot, exit, etc. ; 7. else try faster step rate ; (if not fastest, GOTO #4 above) ; 8. if stepping fastest rate, boot CP/M. ; The exit address is to the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDED ;home drive OR A JRNZ BCPME ;if drive NOT ready LDK BC,CCP ;Set buffer address CALL SETDMA LDK HL,0 STO HL,SAVTRK ;set track LDK A,1 STO A,SAVSEC ;set sector=1 ; Read in 1st two track LDK B,2 :4: PUSH BC LDK B,MSEC CALL DREAD ;read 1st track POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LD HL,SAVTRK INC HL STO HL,SAVTRK ;update track to read DJNZ :4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCP TO REGISTERS A AND HL MOV A,H POP DE RET SPACE 4,21 ;BIOS CALL 8: PARALLEL POLL ; ; CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE ; WITH ATN HIGH OR LOW. ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ; ;PARALLEL POLL VALUE RETURNED IN A. ; IE.PP: PROC PUSH HL LK HL,CPDRA LK A,0001_1011B ;FORM PARALLEL POLL STO A,CPDRB STO 1111_1111B,[HL] ;FLOAT INTERNAL DATA BUS LD A,[HL] ;READ PARALLEL POLL DATA STO 0,[HL] ;RE-STORE SOURCE HANDSHAKE MODE LK HL,CPDRB STO 0001_0010B,[HL] POP HL RET ; ENDX BMIEEE.ASM LOW LD A,CPDRA ;READ DATA MOV D,A LK E,0 ;READ EOI BIT 3,[HL] JRZ :B7C40 LK E,1 :B7C40: CBIT 6,[HL] ;SET NDAC HIGH :B7C50: LK A,255 :B7C60: BIT 5,[HL] JRZ :B7C70 ;DATA VALID DROPPED DEC A JRNZ :B7C60 ;WAIT 1000 MICRO-SEC SBIT 2,E ;SET DATA INVALID TIMEOUT ERROR SBIT 7,E JR :B7C80 :B7C70: SBIT 6,[HL] ;SET NDAC LOW :B7C80: EX DE,HL ;MOVE RESULTSOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT routines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; ; Disk layout Definition ; --Note: Tracks 0, 1, and 2 are reserved for CPM.-- ; Track 0----------- ; 1 thru 8 CCP 2k ; 9 thru 10 BDOS ; Track 1----------- ; 1 thru 10 BDOS ; Track 2----------- ; 1 thru 2 BDOS 3.5k ; 3 thru 10 CBIOS 2k ; Sectors 3,4,5,6 are currently used. page CBOOT: ;Entry C= drive to boot from ; Exit A= drive Proc LDK A,6 ;read 5 sectors of trk 3 STO A,TEM MOV A,C CALL BCPM ;boot system LD A,SDISK ;use requested drive JMP BIOS ;enter CPM ; LK A,3 ; STO A,SEKDEL ;set step rate =3 (slowest) ; CALL HOMED ;send A: home ; ; LK BC,12 ; CALL SETTRK ;track 12 ; LK C,0 ; CALL SETSEC ;sector 0 ; CALL SEEK ;do (slM BCPME1: PUSH DE LDK A,low(256) CALL DELAY ;Delay 256 milli-seconds POP DE ;FWA of message CALL ODER ;indicate drive NOT ready JR BCPM1 ;try again ; Here on Boot READ error BRDE: LDK DE,BRDEMG JR BCPME1 ;delay output error DNRMSG: DCE 'Drive NOT ready.' BRDEMG: DCE 'Boot READ error.' ; Endx BMboot.asm date track to read DJNZ :4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCPOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT routines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; ; Disk layout Definition ; --Note: Tracks 0, 1, and 2 are reserved for CPM.-- ; Track 0----------- ; 1 thru 8 CCP 2k ; 9 thru 10 BDOS ; Track 1----------- ; 1 thru 10 BDOS ; Track 2----------- ; 1 thru 2 BDOS 3.5k ; 3 thru 10 CBIOS 2k page CBOOT: ;Entry C= drive to boot from ; Exit A= drive Proc LDK A,10 ;read 5 sectors of trk 3 STO A,TEM MOV A,C CALL BCPM ;boot system LD A,SDISK ;use requested drive JMP BIOS ;enter CPM ; LK A,3 ; STO A,SEKDEL ;set step rate =3 (slowest) ; CALL HOMED ;send A: home ; ; LK BC,12 ; CALL SETTRK ;track 12 ; LK C,0 ; CALL SETSEC ;sector 0 ; CALL SEEK ;do (slow) seek to trk 12, sec 0 ; ;:fastr: LDK A,low(256) CALL DELAY ;Delay 256 milli-seconds POP DE ;FWA of message CALL ODER ;indicate drive NOT ready JR BCPM1 ;try again ; Here on Boot READ error BRDE: LDK DE,BRDEMG JR BCPME1 ;delay output error DNRMSG: DCE 'Drive NOT ready.' BRDEMG: DCE 'Boot READ error.' ; END OCCROM2?.??? 4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCPM BCPME1: PUSH DE  LK HL,SAVTRK ; LK A,-4 ;seek 4 tracks out ; ADD [hl] ; STO A,[hl] ; LK HL,SEKDEL ; DEC [hl] ;speed up step rate ; CALL SEEK ;seek 4 track outwards, faster ; JRNZ :err ;if stepping too fast ; LD A,SEKDEL ; OR A ;stepping fastest possible? ; JRNZ :fastr ;try a faster seek ;; JR :end ;..else seeking fastest already ; ;:end: CALL BCPM1 ;read in cpm ; JMP BIOS ;cold start ; ;:err: LK HL,SEKDEL ; INC [hl] ;seek at previous (slower) speed ; LK A,0000_0011b ; AND [hl] ;limit seek to (slowest) 3 ; STO A,[hl] ; JR :end WBOOT: Proc LDK A,2 ;don't read CBIOS STO A,TEM ;save sectors LD A,CDISK ;Current logged in drive ; JR BCPM ;Boot CP/M space 4,10 BCPM: ;Boot CPM from disk ; Entry A = Drive to boot from. ; TEM = Number of sectors to read from ; track 3. ; A = Drive to boot or warm-boot from ; Exit A = 0, load sucessful. ; Z bit = 1, load successful. proc STO A,SDISK ;Set drive to boot from BCPM1: CALL HOMED ;home drive OR A JRNZ  TITLE 'B o o t C P / M f r o m d i s k.' ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; ; Before any data is read in, the maximum drive step rate ; must be determined: ; 1. set slowest seek ; 2. home drive A: ; 3. seek track #12 ; 4. speed up step rate ; 5. seek 4 tracks outward (12=>8,8=>4,4=>0) ; 6. if error, slow down step rate by 1, ; load in CP/M, boot, exit, etc. ; 7. else try faster step rate ; (if not fastest, GOTO #4 above) ; 8. if stepping fastest rate, boot CP/M. ; The exit address is to the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDBCPME ;if drive NOT ready LDK HL,CCP ;Set buffer address STO HL,DMADR LDK HL,0 STO HL,SAVTRK ;set track LDK A,1 STO A,SAVSEC ;set sector=1 ; Read in 1st two track LDK B,2 :4: PUSH BC LDK B,MSEC CALL DREAD ;read 1st track POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LD HL,SAVTRK INC HL STO HL,SAVTRK ;update track to read DJNZ :4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCPM BCPME1: PUSH DE ;OCCROM01.ASM TITLE 'Osborne-One Monitor for Model 1 system.' *NOTE* USE ONLY WITH OCCTXT4.AST * 4D2008-00 MASTER .ASM * 2D2008-00 ASSY .ASM * 1D2008-00 LISTING .PRN * 4D1008-00 MASTER .COM * 2D1008-00 ASSY .COM ; +-------------------------------+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV B1 ;DATE = 256 ;DEB ORG 0 ;FWA of memory ALPUSH: MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM ALLPOP: MACRO POP IY POP IX POP HL POP DE POP BC POP AF ENDM PAGE LINK OCCROM11.ASM ;ROM STANDARDS ;LOP,ROMD LINK OCCROM21.ASM ;CPM BOOT ;BOOT LINK OCCROM31.ASM ;CONSOL ROUTINES ;KEY LINK OCCROM41.ASM ;PIA ROUTINES ;PIO,IEEE LINK OCCROM51.ASM ;SIA ROUTINES ;SIO LINK OCCROM61.ASM ;DISK ROUTINES ;DSK LINK OCCROM71.ASM ;DIAGNOSIC ROUTINES ;DIA LINK OCCROM81.ASM ;FORMAT ROUTINE ;XFMT LINK OCCROM91.ASM ;UTILITES ;UTIL2 LI ORG NMIA DI JMP BMON ;NMI page ; Main start up for Monitor. ; Get 1st user response. BMON1: CALL CI ;Get next character CMP CR LK HL,DSKSWP ;disk swap cell LK C,0 ;boot from A: STO C,[hl] ;set to A=A, B=B JZ CBOOT ;if cold boot INC [hl] ;swap drives: A=B, B=A CMP '"' JZ CBOOT ;if cold boot off of B CMP 'D'-40h JZ DIAG ;if enter debugger JR BMON page HINT: ;Initialize all dependent hardware. ; Entry None. ; Exit All hardware initialized. ; Set flag indicating in ROM ENAROM DISDIM ;disable DIM bit LDK HL,GKEY STO HL,INTBL+(4*2) ;set keyboard interrupt IM2 LDK A,high INTBL MOV I,A ;set interrupt page ; Initialize keyboard XRA A STO A,0EFF0H STO A,BELCNT ;clear bell timer cell STO A,LKEY ;clear last key cell STO A,HKCNT ;clear debounce STO A,ECHOP ;clear echo to list dev STO A,ESCH ;clear ESC hold flag CMA STO A,IDAY ;set date invalid for SETUP.COM STO A,TKEY ;clear holding key STO A,KEYLCK ;indicate NOT locked ; LDKIE.GTS ; Go To Standby JMP IE.TC ; Take Control JMP IE.OIM ; Output Interface Message JMP IE.ODM ; Output Device Message JMP IE.IDM ; Input Device Message JMP IE.PP ; Parallel Poll JMP VLDDR ;VIDEO BLOCK MOVE JMP VLDIR PAGE ; END TITLE 'MONITOR ROM CONSTANTS.' IBMSG: DB 'Z'-40h,lf,lf,lf,lf DB ESC,VSGH DB 'Q'-40h DB 07Fh, 24, 'W'-40h DB 'E'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH,1, ESC,VEGH DB ' ' DB ESC,'l' DB 'Osborne System ONE.' DB ESC,'m' DB ' ' DB ESC,VSGH,4, ESC,VEGH DB cr,lf DB ESC,VSGH DB 'A'-40h DB 07Fh,24,' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'A'-40h DB ' ' DB ESC,')' DB 'BIOS REV C 256' DB ESC,'(' DB ' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'Z'-40h DB 07Fh, 24, 'X'-40h DB 'C'-40h DB ESC,VEGH DB cr,lf,lf,lf DB 'Insert disk in Drive ' DB ESC,'l' DB 'A' DB ESC,'m' DB ' and press RETURN' DC '.' ; END OCCROM1?.??? NK OCCRAM1.ASM ;RAM LOCATIONS ; Endx * 2D2008-00 ASSY .ASM * 1D2008-00 LISTING .PRN * 4D1008-00 MASTER .COM * 2D1008-00 ASSY .COM ; +-------------------------------+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV B1 ;DATE = 256 ;DEB ORG 0 ;FWA of memory ALPUSH: MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM ALLPOP: MACRO POP IY POP IX POP HL POP DE POP BC POP AF ENDM PAGE LINK OCCROM11.ASM ;ROM STANDARDS ;LOP,ROMD LINK OCCROM21.ASM ;CPM BOOT ;BOOT LINK OCCROM31.ASM ;CONSOL ROUTINES ;KEY LINK OCCROM41.ASM ;PIA ROUTINES ;PIO,IEEE LINK OCCROM51.ASM ;SIA ROUTINES ;SIO LINK OCCROM61.ASM ;DISK ROUTINES ;DSK LINK OCCROM71.ASM ;DIAGNOSIC ROUTINES ;DIA LINK OCCROM81.ASM ;FORMAT ROUTINE ;XFMT LINK OCCROM91.ASM ;UTILITES ;UTIL2 LI HL,FWAVM ; STO HL,CURS ;set cursor LDK A,VLL STO A,LLIMIT ;set max line limit ; Set keyboard debounce delay cell LK A,KBDTM ;debounce constant STO A,KBDLY ;set debounce-delay cell ; Now function PIA to set starting address ; and continue to move display window over ; the first display line. ; Set cursor as 1-40 on 1st line. CALL SPAO ;set up for output LDK C,VFLO CALL OPAD ;set for -10 char positions ; Set beginning line to 0 XRA A STO A,PIABD ;set data reg MOV C,A CALL OPBD ;set line ; Reset-Master clear the SIO (ACIA) LK C,SI.S16 ;select 16x clock for 1200 baud CALL SIRST ;reset ; Set default seek to as defined by systext LDK A,SEEKTM ;defined from systext STO A,SEKDEL ;set seek step rate ; Set default prompt char LDK A,PMCHR STO A,MPCHR ;set up default EI ! RET OSTR: ;OUTPUT STRING TO CONSOLE ; ENTRY DE=FWA OF SOURCE ; NOTE : OSTR RECOGNIZES 7F AS AN ESCAPE SEQUENCE ; TO REPEAT CHAR N TIMES. FORMAT IS: ; 7F, REPEAT COUNT, CHAR PRO TITLE 'Monitor Main Loop.' DISDIM ;disable DIM JMP BMON ;reset/restart USER: ;Exit to user program from 'G' command EI ! RET ;Exit from G command ILINT: ;Here on unknown interrupt DI DISDIM STO SP,IESTK ;save interrupted proc stack LDK SP,ISTK ;insure stack in RAM ALPUSH ;save all registers LDK A,'I' STO A,MPCHR ;set prompt to inter level EXITI: ;Exit interrupt code via exiting to RAM and ; then enable or disable ROM code depending on ; the value contained in ROMRAM cell. LD A,H.VIO ;clear interrupt LD A,ROMRAM OR A JNZ RORAME ;if return to RAM, CPM ALLPOP LD SP,IESTK ;get users stack back EI ! RET BMON: DI LDK SP,ROMSTK XRA A STO A,SEC6 STO A,SDISK ;set disk to drive 0 STO A,VRTOFF ;OFFSET TO ZERO USED IN COUT CALL HINT ;Initialize hardware LDK HL,(high MRAM)*100h STO HL,SSAVE ;Initialize User stack in ram LDK HL,0 STO HL,LDSEL ;clear select and last track LDK DE,IBMSG CALL OSTR ;Output initial message JR BMON1 ;continueC LD A,[DE] OR A PUSH AF AND 07FH CMP 07FH MOV C,A JRNZ :4 ;IF NOT REPEAT INC DE ! LD A,[DE] ! DEC A MOV B,A ;REPEAT COUNT INC DE ! LD A,[DE] ;GET REPEAT CHAR MOV C,A :2: CALL CO ;OUTPUT CHAR DJNZ :2 ;IF NOT DONE :4: CALL CO ;OUTPUT IT INC DE POP AF JP OSTR ;IF NOT DONE RET page ORG 100h ; Jump vector for debugger and CP/M RVEC: JMP CBOOT ;cold boot JMP WBOOT ;warm boot JMP SKEY ;keyboard status JMP CI ;keyboard input JMP COUT ;console output JMP LIST ;list output JMP PUNCH ;punch output JMP READER ;reader input ; Disk I/O JMP HOME JMP SELDSK ;select disk JMP SETTRK ;set track JMP SETSEC ;set sector JMP SETDMA ;set DMA JMP DREAD ;Disk read JMP DWRT ;Disk write JMP SLST ;List device status RET ! NOP ! NOP ;Sector translate ; End of standard CP/m functions RORAME: JMP BIOS+BRRXT JMP BIOS+BROMJP JMP FORMT ;Format one track JMP SIRST ;SIO reset JMP IE.CO ;IEEE Control Out JMP IE.SI ; Status In JMP  TITLE 'Hardware PIO function processors.' CDEHL: ;Compare DE to HL as unsigned integers. ; Entry DE,HL set to values to compare ; Exit Zbit set if DE = HL ; Cbit set if DE < HL. ; Uses AF. MOV A,D CMP H RNZ ;If D .ne. H MOV A,E CMP L RNZ ;if DE .ne. HL STC RET space 4,10 DELAY: ;'N' Milliseconds ; Entry A=Number of Milliseconds to delay ; SCLFRE= (Freq/1000)/25 ; Exit Time passed. Proc PUSH BC MOV C,A :1: LDK A,SCLFRE :2: DEC A ;(4 tics) MOV B,B ;(4 tics) MOV C,C ;(4 tics) JNZ :2 ;(10 tics) If 1 ms not elapsed DEC C JNZ :1 ;If requested msec not done POP BC ;restore registers RET ;SCLFRE: = 2000/22 ;Z80, 2mhz ;...defined in OCCTXT.ast space 4,32 FILLZ: ;Fill block of memory with byte value. ; Entry DE=LENGTH TO broadcast character ; C =character TO broadcast ; HL=FWA TO START broadcast ; EXIT FILL DONE LK C,0 ;FILL WITH ZERO FILLC: MOV A,E OR D RZ ; return here if broadcast 0 bytes STO C,[hl] ; 1st byte DEC DE MOV A,E OR DNTROL REGISTER (A AND B) ALLOWS SELECTION OF EITHER ;A PERIPHERAL INTERFACE REGISTER OR A DATA DIRECTION REGISTER. ;A "1" IN BIT 2 SELECTS THE PERIPHERAL REGISTER. ; ;THE TWO DATA DIRECTION REGISTERS ALLOW CONTROL OF THE DIRECTION ;OF DATA THROUGH EACH CORRESPONDING PERIPHERAL DATA LINE. ;A DATA DIRECTION REGISTER BIT SET AT "0" CONFIGURES ;THE CORRESPONDING PERIPHERAL DATA LINE AS AN INPUT. ; ;A RESET AT POWER UP HAS THE EFFECT OF ZEROING ALL PIA REGISTERS. ;THIS WILL SET PA0-PA7, PB0-PB7, CA2, AND CB2 AS INPUTS, ;AND ALL INTERRUPTS DISABLED. ;SIGNALS ATN, REN, AND IFC WILL BE DRIVEN LOW ;UNTIL INITIALIZED BY SOFTWARE. ; ;DATA DIRECTION IS ALWAYS SET FOR OUTPUT FOR THE DATA REGISTER. ;DATA MUST BE SET TO ALL ONES WHEN INPUTTING. ;THE INTERFACE IS IN SOURCE HANDSHAKE MODE IF DATA ENABLE (PB0) ;IS SET TO "0", AND IN ACCEPTOR HANDSHAKE MODE IF SET TO "1". ;WHEN SWITCHING FROM SOURCE TO ACCEPTOR HANDSHAKE, ;ATN WILL ALWAYS BE LOW. ;TAKE CONTROL CAN ONLY BE CALLED FOLLOWING A GO TO STANDBY.  STO 0011_1110B,[HL] XOR A ;SET DATA TO ZERO STO A,CPDRA LK HL,CCRB STO 0011_0000B,[HL] ;SET REN-OUT HIGH LK A,0011_1111B ;DIRECTION FOR SOURCE HANDSHAKE STO A,CPDRB STO 0011_0100B,[HL] LK A,0000_0010B ;VALUES FOR SOURCE HANDSHAKE STO A,CPDRB ;LEAVE IFC LOW FOR 100 MICRO-SEC LK A,25 ;DELAY 100 MICRO-SEC :B1C10: DEC A JRNZ :B1C10 LK A,0011_0110B ;SET IFC HIGH STO A,CCRA :B1C20: BIT 2,C ;CHECK REN SUB-COMMAND JRZ :B1C40 ;SET/CLEAR REN LK A,0011_0000B BIT 1,C JRZ :B1C30 LK A,0011_1000B :B1C30: STO A,CCRB :B1C40: POP HL POP AF RET PAGE ;BIOS CALL 2: STATUS IN ; ; CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE. ; ;BIT 0 OF REGISTER A SET IF SRQ IS LOW ; IE.SI: PROC PUSH HL LD A,CPDRA ;CLEAR IRQA1 LK HL,CPDRB ;PULSE ENABLE DAV/EOI CBIT 2,[HL] SBIT 2,[HL] LD A,CCRA ;SET SRQ VALUE IN A AND 1000_0000B RLC A POP HL RET SPACE 4,14 ;BIOS CALL 3: GO TO STANDBY ; ; CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE ; ;NO PARAMETE RZ ; return here if broadcast 1 byte MOV B,D MOV C,E ; BC := (count) MOV D,H MOV E,L INC DE ; DE := HL + 1 LDIR ; overlapping move RET space 4,10 ESTR: ;Output ENCODED string to console ; Entry DE=FWA of source OR A ;clear cbit LD A,[de] RRC ;normalize char PUSH AF AND 07Fh MOV C,A CALL CO ;output it INC DE POP AF JRNC ESTR ;if not done RET page .old IF FALSE FVIO: ;Fill video memory with fixed data ; Entry C= data to broadcast ; NOTE: Interrupts MUST be disabled.. proc LDK HL,FWAVM LDK DE,LVMEM PUSH HL ! PUSH DE CALL FILLC ;clear main vio POP DE ! POP HL .mac IF RSIZE = 64 ENADIM LDK C,0 ;clear 9th bit :2: MOV A,D ;fill 9th bit memory OR E JRZ :4 ;if done STO C,[hl] INC HL DEC DE JR :2 ;loop :4: DISDIM .mac ENDIF RET .old ENDIF space 4,10 SPAO: ;Set PIA for output LDK A,03h ;CRA1-0, Interrupt inputs CA1 STO A,H.VIO+1 ;set data direction LDK A,0FFh STO A,H.VIO ;set all A lines as output LDK A;AFTER A FATAL ERROR, PERFORM AN IFC RESET. ; ;STANDARD VALUES USED: ; ;CCRA 0011(IFC)(DIR)10 ; ;CCRB 0011(REN)(DIR)00 ; ;CPDRA SOURCE DIRECTION 1111_1111 ; DATA DATA ; ;CPDRA ACCEPTOR DIRECTION 1111_1111 ; DATA 1111_1111 ; ;CPDRB SOURCE DIRECTION 0011_1111 ; DATA 000A_0010 ;A = ATN ; ;CPDRB ACCEPTOR DIRECTION 1101_0111 ; DATA 0100_0101 PAGE ;PIA SIGNAL DEFINITIONS: ;ALL SIGNALS ARE LOW ON THE IEEE BUS WHEN PIA REGISTER CONTAINS "1". ; ; PA0 DIO 1 ; PA1 DIO 2 ; PA2 DIO 3 ; PA3 DIO 4 ; PA4 DIO 5 ; PA5 DIO 6 ; PA6 DIO 7 ; PA7 DIO 8 ; ; CA1 SRQ ; CA2 IFC ; ; PB0 ENABLE DATA OUT (ENABLED WHEN "0") ; PB1 ENABLE NDAC/NRFD (ENABLED WHEN "0") ; PB2 ENABLE EOI/DAV (ENABLED WHEN "0") ; PB3 EOI ; PB4 ATN ; PB5 DAV ; PB6 NDAC ; PB7 NRFD ; ; CB1 NOT USED ; CB2 REN ; ;CONTROL WORD FORMAT ; ;[ 7 ][ 6 ][ 5 ][ 4 ][ 3 ][ 2 ][ 1 ][ 0 ] ; ;[IRQA1][IRQA2][ CA2 CONTROL ][ DDRA][ CA1 CONTROL] ;[IRQB1][IRQB2][ CB2 CONTROL ][ DDRB][ CB1 CRS PASSED ; IE.GTS: PROC PUSH AF LK A,0000_0010B ;SET ATN HIGH STO A,CPDRB XOR A ;FLOAT DATA BUS STO A,CPDRA POP AF RET PAGE ;BIOS CALL 4: TAKE CONTROL ; ; CAN BE CALLED ONLY WHILE IN THE CONTROLLER STANDBY STATE ; (ATN HIGH). ; ; EXITS IN THE CONTROLLER ACTIVE STATE (ATN LOW), ; SOURCE HANDSHAKE MODE. ; ;BIT 0 OF REGISTER C SET TO TAKE CONTROL ASYNCHRONOUS ; ;ERROR CODE RETURNED IN REGISTER A. ; IE.TC: PROC PUSH HL LK HL,CPDRB BIT 0,C JRNZ :B4C30 ;TAKE CONTROL SYNCHRONOUSLY STO 0000_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB STO 1000_0101B,[HL] ;SET NRFD LOW LK A,25 :B4C10: BIT 5,[HL] JRZ :B4C20 ;DATA VALID HAS DROPPED DEC A JRNZ :B4C10 ;WAIT 100 MICRO-SEC LK A,1000_0001B ;SET DATA VALID TIMEOUT ERROR JR :B4C40 :B4C20: STO 1100_0101B,[HL] ;SET NDAC LOW :B4C30: SBIT 4,[HL] ;SET ATN LOW ;SET-UP FOR SOURCE HANDSHAKE LD A,CCRB CBIT 2,A STO A,CCRB ST,0 STO A,H.VIO+3 LDK A,0FFh STO A,H.VIO+2 ;set all B lines as output RET space 4,10 OPAD: ;Output data to pia A register ; Entry C= data ; Exit PIAAD = new value LDK A,4+3 STO A,H.VIO+1 MOV A,C STO A,PIAAD STO A,H.VIO ;send data RET space 4,10 OPBD: ;Output data to pia B register ; PIA definition. ; 7 6 5 4 3 2 1 0 ; +--+--+--+--+--+--+--+--+ ; |D1|D0|^G| vert offset | ; +--+--+--+--+--+--+--+--+ ; ; Entry C= data ; Exit PIABD = new value LDK A,4 STO A,H.VIO+3 MOV A,C STO A,PIABD STO A,H.VIO+2 ;send data RET TITLE 'BMIEEE.ASM - IEEE-488 INTERFACE.' ; +---------------------------------------+ ; | ENTERED 05/01/81 FROM TNW XEROX, SEH. | ; +---------------------------------------+ ; ;LAST EDITED AT 09:29 ON 11 NOV 80 ; ;THERE ARE FOUR COMMANDS TO THE 6821 ; ; 00 PERIPHERAL/DIRECTION REGISTER A CPDRA ; 01 CONTROL REGISTER A CCRA ; 10 PERIPHERAL/DIRECTION REGISTER B CPDRB ; 11 CONTROL REGISTER B CCRB ; ;BIT 2 OF THE COONTROL] ; ; IRQA1 0 INTERRUPT FLAG SET BY FALL OF SRQ ; IRQA2 0 NOT USED ; CA2 110 SET IFC HIGH ; 111 SET IFC LOW ; DDRA 0 R/W DATA DIRECTION REGISTER A ; 1 R/W PERIPHERAL REGISTER A ; CA1 10 SET IRQA1 HIGH ON RISE OF SRQ ; ; IRQB1 0 NOT USED ; IRQB2 0 NOT USED ; CB2 110 SET REN HIGH ; 111 SET REN LOW ; DDRB 0 R/W DATA DIRECTION REGISTER B ; 1 R/W PERIPHERAL REGISTER B ; CB1 00 NOT USED PAGE ;BIOS CALL 1: CONTROL OUT ; ; CAN BE CALLED WHILE IN ANY STATE. ; ; EXITS IN THE CONTROLLER STANDBY STATE (ATN HIGH), ; SOURCE HANDSHAKE MODE ; ;PARAMETER PASSED IN REGISTER C: ; ; BIT 0 IF "1", THE IFC SIGNAL IS SET LOW FOR 100 MICRO-SEC ; AND ALL PIA SIGNALS ARE INITIALIZED ; ; BIT 2 1 ; 0 X NO ACTION ; 1 0 SETS REN HIGH ; 1 1 SETS REN LOW ; IE.CO: PROC PUSH AF PUSH HL BIT 0,C ;CHECK IFC SUB-COMMAND JRZ :B1C20 ;INITIALIZE ALL IEEE-488 SIGNALS LK HL,CCRA STO 0011_1010B,[HL] ;ENABLE SRQ AND SET IFC-OUT LOW LK A,1111_1111B ;DIRECT DATA OUT STO A,CPDRAO 0011_1111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB STO 0001_0010B,[HL] ;CONTROL SIGNAL INITIAL VALUE XOR A ;CLEAR ERROR CODE :B4C40: POP HL RET PAGE ;BIOS CALL 5: OUTPUT INTERFACE MESSAGE ; ; CAN BE CALLED WHILE IN ANY MODE OR STATE ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ; ;MULTI-LINE MESSAGE IN REGISTER C ; ;ERROR CODE RETURNED IN REGISTER A ; IE.OIM: PROC PUSH HL LK HL,CPDRB SBIT 4,[HL] ;SET ATN LOW BIT 0,[HL] JRZ IE.SHK ;SET-UP FOR SOURCE HANDSHAKE STO 0001_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 0011_1111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB XOR A ;FLOAT EXTERNAL DATA BUS STO A,CPDRA STO 0001_0010B,[HL] ;CONTROL SIGNAL INITIAL VALUE JR IE.SHK PAGE ;BIOS CALL 6: OUTPUT DEVICE MESSAGE ; ; CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE ; WITH ATN HIGH OR LOW. ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN HIGH. ; ;MULTI-LINE MESSAGE IN REGISTER C ;EOI REQUEST IN REGISTER B ; 7C60: BIT 5,[HL] JRZ :B7C70 ;DATA VALID DROPPED DEC A JRNZ :B7C60 ;WAIT 1000 MICRO-SEC SBIT 2,E ;SET DATA INVALID TIMEOUT ERROR SBIT 7,E JR :B7C80 :B7C70: SBIT 6,[HL] ;SET NDAC LOW :B7C80: EX DE,HL ;MOVE RESULTS TO REGISTERS A AND HL MOV A,H POP DE RET SPACE 4,21 ;BIOS CALL 8: PARALLEL POLL ; ; CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE ; WITH ATN HIGH OR LOW. ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ; ;PARALLEL POLL VALUE RETURNED IN A. ; IE.PP: PROC PUSH HL LK HL,CPDRA LK A,0001_1011B ;FORM PARALLEL POLL STO A,CPDRB STO 1111_1111B,[HL] ;FLOAT INTERNAL DATA BUS LD A,[HL] ;READ PARALLEL POLL DATA STO 0,[HL] ;RE-STORE SOURCE HANDSHAKE MODE LK HL,CPDRB STO 0001_0010B,[HL] POP HL RET ; END OCCROM4?.??? DATA MOV D,A LK E,0 ;READ EOI BIT 3,[HL] JRZ :B7C40 LK E,1 :B7C40: CBIT 6,[HL] ;SET NDAC HIGH :B7C50: LK A,255 :B TITLE 'Disk I/O routines.' ; Disk interface definitions and functions. ; 1792 functions. DML = 4 ;= 15 ms delay on function LTRKB = 3125 ;length of a track ; Note: Shugart says LTRKB = 3125... NRTRYS = 4 ;Number of retries MSECB = 10h ;Multi-sector r/w bit ; FUNCTION CODES D.RES = 00H ;RESTORE D.SEK = 14H ;SEEK D.STP = 20H ;STEP D.STPI = 40H ;STEP IN D.STPO = 60H ;STEP OUT D.RDS = 80H ;READ SECTOR D.WRTS = 0A0H ;WRITE SECTOR D.RDA = 0C0H ;READ ADDRESS D.RDT = 0E0H ;READ TRACK D.WRTT = 0F0H ;WRITE TRACK D.FINT = 0D0H ;FORCE INTERRUPT ; Disk status and command registers D.CMDR = H.FDC ;Disk command reg (write) D.STSR = H.FDC ;Status reg (read) D.TRKR = D.CMDR+1 ;track reg D.SECR = D.CMDR+2 ;Sector reg D.DATR = D.CMDR+3 ;Data reg (r/w) ; Status definitions BS.BSY = 0 ;Busy DS.BSY = 1 shl BS.BSY BS.DRQ = 1 DS.INX = 1 shl BS.DRQ ;Index mark detected DS.DRQ = DS.INX ;DR is full on read, empty on write BS.TK0 = 2 DS.TK0 = 1 shl BS.TK0 DS.LSD = DS.TK0 ;ERROR CODE RETURNED IN REGISTER A ; IE.ODM: PROC PUSH HL LK HL,CPDRB CBIT 4,[HL] ;SET ATN HIGH BIT 0,B ;CHECK IF EOI REQUESTED JRZ IE.SHK SBIT 3,[HL] ;PERFORM SOURCE HANDSHAKE IE.SHK: BIT 5,[HL] ; JRNZ :B6C50 ;DAC TIMEOUT RE-ENTRY MOV A,C ;PLACE DATA ON BUS STO A,CPDRA LK A,10 :B6C20: BIT 7,[HL] JRZ :B6C30 ;READY FOR DATA DEC A JRNZ :B6C20 ;WAIT FOR 100 MICRO-SEC LK A,1000_0010B ;SET RFD TIMEOUT ERROR JR :B6C80 :B6C30: BIT 6,[HL] JRNZ :B6C40 ;DATA ACCEPTED LOW LK A,1000_0001B ;SET DEVICE NOT PRESENT ERROR JR :B6C80 :B6C40: SBIT 5,[HL] ;SET DAV LOW :B6C50: LK A,255 :B6C60: BIT 6,[HL] JRZ :B6C70 ;DATA ACCEPTED DEC A JRNZ :B6C60 ;WAIT 1000 MICRO-SEC LK A,1000_0100B ;SET DAC TIMEOUT ERROR JR :B6C80 :B6C70: CBIT 5,[HL] ;SET DAV HIGH CBIT 3,[HL] ;SET EOI HIGH XOR A ;REMOVE DATA FROM BUS STO A,CPDRA :B6C80: POP HL RET PAGE ;BIOS CALL 7: INPUT DEVICE MESSAGE ; ; CAN BE CALLED WHILE IN ANY MODE OR STATE ; ; EXITS IN THE ACCEPT TITLE 'SIO - Serial I/O Processors.' SIRST: ;Master reset SIO ; Entry C= SI.S16 or SI.S64 for 1200/300 baud LDK A,SI.MRST STO A,H.SCTRL ;master reset MOV A,C STO A,ACIAD ;last-command cell STO A,H.SCTRL ;select SIO RET space 4,10 READER: ;Input one byte from reader port ; Entry None ; Exit A=C= character read LD A,H.SSTS AND SI.RRDY JRZ READER ;if not ready LD A,H.SREC ;get data MOV C,A ;A=C RET space 4,10 SLST: ;Get list device status ; Exit A= 0, if NOT ready LD A,H.SSTS AND SI.TRDY ;ck for Xmit buf empty RET ;set status space 4,10 LIST: ;Output one byte to list port PUNCH: ;Output one byte to punch port ; Entry C= character to output ; Exit C=C. :wait: LD A,H.SSTS AND SI.TRDY ;wait for CTS go-ahead JRZ :wait ;if CTS high, wait again MOV A,C STO A,H.SXMT ;send chr RET ; END OCCROM5?.???  ;lost data DS.CRC = 08h ;CRC error in ID field BS.SEK = 4 DS.SEK = 1 shl BS.SEK ;Seek error DS.RNF = DS.SEK ;Record NOT found DS.HDL = 20h ;Head loaded DS.WTF = DS.HDL ;Write fault DS.WTP = 40h ;Write protected DS.NRY = 80h ;Drive NOT ready ; Disk timing counts D.DEL = 20 ;Delay after function page SDMA: ;Set DMA SETDMA: ; Entry BC = DMA address STO BC,DMADR RET space 4,10 SETTRK: ;Set track ; Entry BC = track STO BC,SAVTRK RET space 4,10 SETSEC: ;Set Sector ; Entry C= sector number (1 to MSEC) MOV A,C STO A,SAVSEC RET space 4,10 HOME: ;Home selected disk drive XRA A ;reset track to 0 STO A,SAVTRK RET PAGE SDRV: ;Select Drive ; Entry SDISK= drive ; Exit A= 0, if drive is ready ; Calls OPBD, DELAY ; Uses A,B proc LD A,SDISK SDRV1: LK HL,DSKSWP ;disk drive swap cell XOR [hl] ;swap A for B if DSKSWP=1 AND 1 ;Can only be 0 or 1 CMP 1 JRNZ :2 ;if not drive 1 LDK A,40h :2: ADI 40h MOV C,A LD A,PIABD MOV B,OR HANDSHAKE MODE WITH ATN HIGH. ; ;DEVICE MESSAGE RETURNED IN BOTH REGISTERS A AND H ;ERROR CODE RETURNED IN REGISTER L ; IE.IDM: PROC PUSH DE EX DE,HL ;SAVE RE-ENTRY DATA LK HL,CPDRB BIT 0,[HL] JRNZ :B7C10 ;SET-UP FOR ACCEPTOR HANDSHAKE STO 0001_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB LK A,1111_1111B ;FLOAT INTERNAL DATA BUS STO A,CPDRA STO 0101_0101B,[HL] ;CONTROL SIGNALS INITIAL VALUE STO 0100_0101B,[HL] ;SET ATN HIGH ;PERFORM ACCEPTOR HANDSHAKE :B7C10: BIT 6,[HL] JRZ :B7C50 ;DATA INVALID TIMEOUT ERROR RE-ENTRY CBIT 7,[HL] ;SET NRFD HIGH LK A,10 :B7C20: BIT 5,[HL] JRNZ :B7C30 ;DATA VALID DEC A JRNZ :B7C20 ;WAIT 100 MICRO-SEC LK DE,1000_0010B ;SET DATA VALID TIMEOUT ERROR JR :B7C80 :B7C30: SBIT 7,[HL] ;SET NRFD LOW LD A,CPDRA ;READ DATA MOV D,A LK E,0 ;READ EOI BIT 3,[HL] JRZ :B7C40 LK E,1 :B7C40: CBIT 6,[HL] ;SET NDAC HIGH :B7C50: LK A,255 :BA AND 1100_0000b ;get drive bits only CMP C JZ RDSKD ;if drive already selected ; Check to see if this drive is the same as the last ; one selected. ; IF true, go to 3 ; else ; Save current trk register in LDSEL and ; set trk reg to last track used for newly selected ; drive ; end LD A,LDSEL ;last selected disk CMP C JRZ :3 ;if same drive MOV A,C STO A,LDSEL ;set to new drive PUSH BC LDK HL,LDTRK LD C,[hl] ;get last accessed track for new drive LD A,D.TRKR ;get current track STO A,[hl] ;save in table MOV A,C STO A,D.TRKR ;set trk register to last selected POP BC ; Set drive select perserving vio offset values :3: CALL RDSKD ;RESET CONTROLLER LDK B,5 ;NUMBER OF TRIES :5: LDK A,250 CALL DELAY LK A,250 ;2ND DELAY CALL DELAY LD A,D.STSR AND DS.INX RZ ;IF INDEX DJNZ :5 ;KEEP TRYING OR 80H OR DS.INX ;INDICATE NOT READY RET space 4,10 DDRV: ;Deselect drive ; Entry SDISK = current disk drive LD A,PIABD AND 1_1111b MCALL WBUSY ;wait for FDC quiescence LD A,SAVSEC STO A,D.SECR ;set sector register XRA A ;indicate good RET space 4,10 DRDAS: ;Read Address info. ; Exit D.STSB = data bytes ; MUST NOT destroy DE pair proc LDK A,D.RDA CALL FDSK ;function disk ; Get status bytes LDK HL,DSTSB LDK B,6 DI PUSH DE ;save DE :2: LDK DE,4000 ;time out :3: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRNZ :4 ;if data ready DEC DE MOV A,D OR E JRNZ :3 ;if NOT time out LK C,SEKTMO ;seek time out JR RWEX ;error exit :4: LD A,D.DATR STO A,[hl] ;save byte INC HL DJNZ :2 ;if not done POP DE XRA A ;indicate good EI ! RET space 4,10 DREAD: ;Read disk sectors. ; Entry SDISK= drive ; B = number of sectors to read ; Number from 1 to MSEC ; DMADR= FWA for data. ; Exit DSTSB= A= 0, if no error ; HL = next DMA ; Uses All registers proc MOV D,B ;save sectors CALL SEEK ;seek to track, set sector JRNZ RWEX1 ;if se sec has ; occurred. ; Entry A= function code ; Exit A= 0, if chip accepted function ; else, A=-1, indicating time-out, See WBUSY ; Uses A, B, C proc MOV B,A ;save function code LD A,PIABD AND 1100_0000b JRNZ :1 ;if drive active PUSH BC CALL SDRV ;reselect drive POP BC :1: CALL WBUSY ;Wait for busy to clear RM ;if will NOT clear busy ; Controller NOT busy, issue command MOV A,B STO A,D.CMDR ;function drive ; Wait for busy to be set LDK C,0 :2: LD A,D.STSR RAR ;DS.BSY JRC :3 ;if chip went busy DEC C JRNZ :2 ;if not time-out JR WBUSYX ;exit, error ; Set DACTVE indicating activity on drive :3: LDK A,-1 STO A,DACTVE XRA A ;ZERO A RET space 4,10 WBUSY: ;Wait for Busy to clear ; Exit A= -1, if time out occurred, ; else ; A= last status and is positive. ; Uses A, C proc PUSH BC LDK BC,0 :1: LD A,D.STSR RAR ;DS.BSY JRNC :1A ;if NOT busy, proceed DEC BC MOV A,B OR C JRNZ :1 ;if not time-out WBUSYX: LDK AOV C,A JMP OPBD ;deselect last drive page PSEKC: ;Perform seek type command ; Entry A= command to perform without r1, and r0. ; PSEKC will or in the low two bits as defined ; by SEKDEL. ; Exit A= last value of D.STSr LDK HL,SEKDEL OR [hl] ;or in delay time for seek CALL FDSK ;function disk RNZ ;if Drive NOT ready JMP WBUSY space 4,10 SELDSK: ;Select disk in register C MOV A,C ;drive to home CALL SDRV1 ;C= drive JR HOMED1 HOMED: ;Home disk drive ; Entry SDISK= drive ; Exit A=0 if drive on home. proc CALL SDRV ;select drive HOMED1: LDK A,D.RES CALL PSEKC ;perform seek command CMP -1 JRZ SKEX1 ;if error BIT BS.SEK,A JRNZ SKEX1 ;if error BIT BS.TK0,A JRZ :4 ;if NOT home IF ODEBUG CALL LDSKS1 ;list status **** ENDIF XRA A ;clear A SKEX1: PUSH AF LDK A,-1 STO A,DACTVE ;start counter CALL STAT17 ;save disk controller regs POP AF RET ; Here if drive NOT homed, possible NOT ready :4: AND 80h JR SKEX1 space 4,10 ek error MOV B,D LDK C,0 PUSH BC LDK A,D.RDS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' cit :3: CALL FDSK POP BC CMP -1 JRZ RWEX1 ;if drive NOT ready ; Now xfer bytes from controlles to DMA. DI LD HL,DMADR :5: PUSH BC LDK B,low LSECB :6: LD A,D.STSR BIT BS.BSY,A JRZ RWEX ;if possible error BIT BS.DRQ,A JRZ :6 ;if no data LD A,D.DATR STO A,[hl] INC HL ;FOR EDIT DJNZ :6 ;if not all data ; Now check if multi sector ;GOR THE EDITOR POP BC DJNZ :5 ;continue XRA A JR RWEX1 ; here on error RWEX: CALL STAT17 ;save disk controller regs POP DE ;restore stack OR 80h ;if busy cleared, indicate with 80h RWEX1: OR A ;set status PUSH AF LDK A,-1 STO A,DACTVE POP AF EI ! RET space 4,10 DWRT: ;Write to disk ; Entry SDISK= drive ; B= Number of sectors to xmit. ; DMADR= FWA of data ; Exit same as DREAD ; Uses All registers proc MOV D,B CALL SEEK JRNZ RWEX1 ;if seek error MOV B,D PUSH BC LDK A,-1 ;indicate error, drive NOT ready POP BC OR A ;set flags RET :1A: RAL ;restore A POP BC ;restore BC AND 7Fh ;make sure its positive RET space 4,8 RDSKD: ;Reset PIA and disk controller ; selecting drive specified by C ; Entry C= drive ; B= PIABD MOV A,B AND 0001_1111b ;get vio offset only OR C MOV C,A CALL OPBD ;function PIO-b ; JMP RDSKC RDSKC: ;reset disk controller ; Entry None ; Exit Busy cleared. ; A= 0. LDK A,D.FINT STO A,D.STSR ;clear controller XRA A ;clear A and flags RET ODER: ;Output disk error to console ; Entry DE= FWA of message ; SDISK = drive with error PUSH DE CALL OCRLF ;new line LD A,SDISK ADD A,'A' MOV C,A CALL CO ;output drive name CALL O2SP POP DE ;get message JMP ESTR DERR: ;Output disk system error ; Entry A= status from controller ; Exit error output PUSH DE PUSH HL PUSH BC PUSH AF LDK DE,DERMSG CALL ESTR ;output error POP AF ;get status value CALL PBBH ;output status SEEK: ;Seek to track defined by SAVTRK ; Entry SAVTRK set to track ; SAVSEC set to sector number ; Exit A= 0, if no error, else status ; MUST NOT destroy DE, HL pair proc CALL SDRV ;select drive ; Here if drive already selected ; Check to see if SEEK is necessary by ; comparing SAVTRK to controller track ; register LD A,SAVTRK STO A,D.DATR ;set track wanted MOV C,A LD A,D.TRKR CMP C JRZ :8 ;if on track ; Disk seek required, function controller ; with SEEK command LDK A,5 SEEKA: STO A,RTRY ;update retry count LDK A,D.SEK CALL PSEKC ;perform seek command MOV C,A AND DS.CRC or DS.SEK JRNZ :10 ;if error ; Now read-address and verify on-track CALL DRDAS ;read address JRNZ :10 ;if error LDK HL,DSTSB LD A,SAVTRK CMP [hl] JRZ :8 ;if ON track LD A,RTRY DEC A JRNZ SEEKA ;if not max retrys ; here if seek error :10: MOV A,C ORI 80h ;indicate movement error JR SKEX1 ; Now set the sector register to requested ; Sector :8: ,D.WRTS DEC D JRZ :3 ;if NOT multi-sectors OR MSECB ;add 'm' bit :3: CALL FDSK POP BC ; Now xfer bytes to controller from DMA. DI LD HL,DMADR :5: PUSH BC LDK BC,LSECB ;length of std sector :6: CALL XDD ;xfer to disk JRNZ RWEX ;if error ; Now check if multi sector POP BC DJNZ :5 ;continue XRA A :8: JR RWEX1 page XDD: ;Xfer data from memory to disk ; Entry BC = length ; HL = FWA ; Exit HL = next address ; A=0 if no error, else status ; Uses A,BC,E, HL proc LD A,D.STSR BIT BS.BSY,A JRZ :5 ;if possible error BIT BS.DRQ,A JRZ XDD ;if no data LD A,[hl] STO A,D.DATR ;send to controller INC HL DEC BC MOV A,B OR C JRNZ XDD ;if not done XRA A ;indicate good xfer RET ; here if error :5: OR 80h ;indicate busy dropped RET page FDSK: ;Function disk routine ; All functions for DSK controller SHALL do so by using ; this routine. FDSK sets DACTVE to 0 indicating activity ; UPTIM uses this cell to turn off select if one CALL O2SP LD A,SAVTRK CALL PBBH ;output track LDK C,',' CALL COUT ;output comma LD A,D.TRKR CALL PBBH ;output controller track CALL O2SP LD A,SAVSEC CALL PBBH ;output sector LDK C,',' CALL COUT ;output comma LD A,D.SECR CALL PBBH ;output controller sector ; Update error counter LD HL,ERCNT INC HL STO HL,ERCNT ;update error count ; Clear controller CALL RDSKC ;reset disk controller ; Restore regs POP BC POP HL POP DE RET DERMSG: DBE cr,lf DCE 'Dsk ERR (sts trk sec)- ' space 4,10 STAT17: ;save 179x status ;called when disk error discovered: ;...saves 179x regs in high RAM. PUSH BC ! PUSH DE ! PUSH HL LK HL,D.STSR ;1st (lowest) 179x register LK DE,R179x ;register save area LK BC,4 ;move 4 bytes LDIR POP HL ! POP DE ! POP BC RET ; END OCCROM6?.???  PUSH HL PUSH BC PUSH AF LDK DE,DERMSG CALL ESTR ;output error POP AF ;get status value CALL PBBH ;output statusZ ORI 0FFH ;IF NOT ZERO MAKE 0FFH RET ;IF DATA space 4,10 CI: RKEY: ;Read next key from keyboard ; Exit A= last key proc CALL SKEY JRZ RKEY ;if NO data DI LD A,LKEY ;GET CHARACTER MOV C,A XRA A STO A,LKEY ;clear key from hold MOV A,C EI RET space 4,10 NORM: ;Normalize to UPPER case ; Entry A= char ; Exit A= CHAR CMP 'a' RC ;if upper CMP 'z'+1 RNC ;if not lower SUI 'a'-'A' RET REPD = 45 ;initial rep delay REPK = 5 ;repeat constant page UPTIM: ;Update time via 60hz interrupt ; Time is kept in video memory as ; hhmmss (3 locations) ; Routine also checks to see if the disk drive motor ; should be turned off by updating DACTIVE ; ...Routine ALSO checks to see if bell is currently ; ringing: if so, decrement counter. ; if counter turns zero, shut off bell. Proc LDK HL,BELCNT XOR A OR [hl] ;cell=zero ? JRZ :2 ;if bell now off DEC [hl] ;...bell is on. decrement counter JRNZ :2 ;if bell should stay on awhile yet LD A,PIABAD ! DW ESCSAD ;Screen Addressing DB VSGH ! DW ESCSGR ;Set graphics mode DB VEGH ! DW ESCCGR ;Clr graphics mode DB VSHI ! DW ESCSHA ;Set half int. mode DB VEHI ! DW ESCCHA ;Clr half int. mode DB VSUL ! DW ESCSUN ;Set underline mode DB VEUL ! DW ESCCUN ;Clr underline mode DB VCLRS ! DW ESCZZ ;Clear screen to blanks DB VINC ! DW EINSRT ;Insert char DB VDELC ! DW EDELC ;Delete char DB VINL ! DW ESCEE ;Insert line DB VDELL ! DW ESCRR ;Delete line DB VCEOL ! DW EEOL ;Clear to end of line DB VLOCK ! DW ESCLCK ;Lock Keyboard DB VUNLK ! DW ESCULK ;Unlock Keyboard :end: DW COUT2 ;No Match exit ; Ignore char upon undefined ESC-Sequence ; (to treat undefined char after ESC as a regular ; data char, should go to COUT2). VALETS: = (:end-VALIDE)/3 ;# of entries in table space 4,10 VALIDC: ;Valid control character table ; 3 bytes per entry: Ascii char , "DW"- Vector ; no. of entries is VALCTS ; Following body of table is 2 byte No-Match adrs DB CR ! DW VC_CR ;carriage retuD AND 1101_1111b ;clear bell bit MOV C,A CALL OPBD :2: DEC HL ;HL => DACTVE LD A,[hl] OR A JRZ :3 ;if inactive DEC [hl] ;reset delay CZ DDRV ;if deselect drive :3: DEC HL ;HL => SEC6 DEC [hl] RNZ ;if not 1 sec transition STO 59,[hl] ;60th tick is NOW XOR A ;A:=0, CY:=0 for DAA DEC HL ;HL => SECS LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 60h RC ;if not 60 secs STO 0,[hl] ;reset seconds DEC HL LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 60h RC ;if not 60 minutes STO 0,[hl] DEC HL LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 25h RC ;if time <= 24:59:59 STO 1,[hl] RET page CO: ;Output routine for monitor ; Entry C= char ; CO will process ^p to toggle ; echo to list device ala cpm. ; Exit C=C=A. proc MOV A,C CMP 'P'-40h JRNZ :5 ;if not toggle echo list LD A,ECHOP CMA STO A,ECHOP ;toggle list echo :2: MOV A,C ;perserve A RET :5: CALL COUT ;output char LD A,ECHOP OR A JRZ :2 ;if no echo to list JMP rn routine DB LF ! DW VC_LF ;line feed DB BKS ! DW VC_BKS ;back space DB MCRIGH ! DW VC_MCRT ;move cursor right DB MCUP ! DW VC_MCUP ;move cursor up DB CBELL ! DW VC_BEL ;Ring bell DB VCLRS ! DW VC_CLRS ;clear screen DB VHOME ! DW VC_HOME ;Cursor Home DW VOUT97 ;No match--ignore undef control char VALCTS: = ((*-2)-VALIDC)/3 ;Number of valid entries page COUT: ;General output routine to Video Screen ; ENTRY C=Character, CURS=Cursor, ESCH=Flag+Mode ; EXIT CURS & ESCH updated, A=Character ; (bc, de, hl preserved) ; ESCH is flag + mode byte as follows ; =00 Normal mode & Last chr Esc flag false ; =08 Normal mode & Last chr Esc flag True ; =01,02,04 Mode is Graphics, Half, or Under, respectively ; , and Last chr Esc flag is False. ; =3,5,6,7 As above, but mode is combination ; =9-15 Last chr Esc flag True;otherwise like 1-7. proc ;RESET VETICAL OFFSET WITH VRTOFF PUSH AF PUSH BC LD A,PIABD ;PRESENT VALUE AND 11100000B ;HOUSE TITLE 'Keyboard and Console Routines.' ; Assembly constant @KEY = 1 ;production keyboard ; Control keys CBELL = 'G'-40h ;Ring the Bell MCUP = 'K'-40h ;Move cursor up MCDOWN = LF ;Move cursor down MCLEFT = BKS ;Move cursor left MCRIGH = 'L'-40h ;Move cursor right VCLRS = 'Z'-40h ;Clear and home cursor VHOME = '^'-40h ;Home Cursor ; Escape keys VLOCK: = '#' ;Lock Keyboard VUNLK = '"' ;Unlock Keyboard VCAD: = '=' ;Cursor Addressing VSAD: = 'S' ;Screen Addressing VINC: = 'Q' ;Insert Char VDELC: = 'W' ;Delete char VINL: = 'E' ;Insert line VDELL: = 'R' ;Delete line VCEOL: = 'T' ;Clear to end of line VSHI: = ')' ;Start half intensity VEHI: = '(' ;end VSUL: = 'l' ;Start underline VEUL: = 'm' ;end VSGH: = 'g' ;Start graphics VEGH: = 'G' ;End ;ARROW KEYS UP = 8AH RIGHT = 8BH DOWN = 8CH LEFT = 8DH SKEY: ;Get status of keyboard ; Exit Cbit set if no data ready LD A,KEYLCK OR A RZ ;if locked keyboard LD A,LKEY ORA A ;CHECK FOR ZERO RLIST ;echo it page ; Bit definitions for ESCH flag byte ; Note Bit 7 is currently free. EF_X: = 64 ;B6= extegting X-coordinate EF_SCR: = 32 ;B5= Screen/Cursor Addressing EF_ADR: = 16 ;B4= expegting address-chr EF_ESC: = 8 ;B3=$last char was ESC EF_UN: = 4 ;B2= Underline mode EF_HA: = 2 ;B1= Half Intensity mode EF_GR: = 1 ;B0= Graphics mode EF_MSK: = EF_UN+EF_HA+EF_GR ;Mask to get mode. space 4,10 ; Vector (branch) table for video output mode selection ; controlled by ESCH mode ESCHTB: DW VNORM ;0 Normal mode DW VGRAPH ;1 Graphics mode DW VHALF ;2 Half intensity mode DW VHA_GR ;3 Half and graphics DW VUNDER ;4 Underline mode DW VUN_GR ;5 Under and graphics DW VUN_HA ;6 Under and half intensity DW VUN_HA_GR ;7 Under and half and graphics space 4,10 VALIDE: ;Valid ESC-Sequence Table ; 3 bytes per entry:ascii char , "DW"-Vector. ; no. of entries is VALETS ; Following body of table is 2 byte No-Match adrs DB VCAD ! DW ESCCAD ;Cursor Addressing DB VSKEEPING MOV B,A LD A,VRTOFF ;LAST VERTICAL OFFSET AND 00011111B ;ONLY VIDIO ORA B ;ADD HOUSEKEEPING MOV C,A CALL OPBD ;SET OFFSET POP BC POP AF PUSH HL PUSH DE PUSH BC LD HL,CURS ;HL will usually be cursor/ LD A,ESCH MOV B,A ;B will be ESCH for a while AND EF_ESC ;test flag bit JRNZ PSTESC ;IF last chr was ESC ;Current chr is NOT ESCaped. Is this chr ESC? MOV A,C ;Chr CMP ESC MOV A,B ;(A=ESCH) JRZ :ESC ;if this chr = ESC space 4,10 ;Here with A=B= ESCH :out: PUSH HL LDK HL,ESCHTB AND EF_MSK ;Mode bits only ADD A,A ;Times two MOV E,A LDK D,0 ;DE = offset ADD HL,DE ;HL = tbl addrs VECTOR: ;entry point. note hl on stack. LD A,[HL] ;1st byte (low order adrs) INC HL LD H,[HL] ;2nd byte (hi order adrs) MOV L,A ;HL=adrs from table XTHL ;Restore hl from stack ;stack=tbl adrs MOV A,C ;Chr. note B=ESCH byte value RET ;enter routine per table adrs. COUT2: MOV A,B ;recall ESCH value JR :out ;output chr perline bit JR VBRIGH ;set this chr BRIGHT VUN_HA: ;Underline and Half intensity CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VUN_HA_GR VUN_HA_GR: ;Underline, Half Intensity, Graphics OR 80h ;set underline bit ; JR VHA_GR VHALF: ;Half Intensity CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VHA_GR VA_GR: ;C=Chr, HL=Curs DI ENADIM STO DIMBIT,[hl] ;set dim field bit ; LD E,[hl] ;diagnostic DISDIM EI JMP VOUT80 ;continue space 4,22 SCREEN: ;SetXY for Screen movement ; Entry B= ESCH ; A= new co-ord val, NO OFFSET Proc BIT 6,B JRNZ :sX ;if X-coordinate :sY: AND 0001_1111b ;mod 32 MOV C,A STO A,VRTOFF ;SET VERTICAL OFFSET FOR COUT LD A,PIABD AND 1110_0000b OR C MOV C,A CALL OPBD ;set Y coordinate JR :exitY :sX: ADD A,A ;double A ADD A,VFLO ;PIA A-reg magic offset constant AND 1111_1110b ;clear bit 0 => no 1/2 chr shift MOV C,A CALL OPAD ;set X coordinate CBIT 5,B ;finished screen-addressing ng the bell via setting PIAB 2**5 bit LD A,PIABD OR 0010_0000b ;bell bit MOV C,A CALL OPBD ;function PIAB LDK A,30 ;ring bell for 30 ticks STO A,BELCNT ;... = 1/2 second JR VOUT97 ;exit no change space 4,10 VC_CLRS: LDK HL,FWAVM CALL CLRLN ;clear 1st line LDK BC,LVMEM-VLL PUSH DE POP IX CALL VLDIR ;clear remaining lines LD A,PIABD ;Reset for 1st line of display mem AND not(1_1111b) MOV C,A CALL OPBD XRA A ;ZERO A STO A,VRTOFF ;SET VERTICAL OFFSET FOR COUT LDK HL,FWAVM ;new cursor JR VOUT90 ;Exit space 4,8 VC_CR: CALL UN_CUR ;erase cursor LDK A,80h ;Carriage Return AND L MOV L,A JR VOUT90 VC_LF: CALL DO_LF ;Line Feed JR VOUT90 space 4,3 VC_MCRT ;Move Cursor Right CALL UN_CUR LD A,[hl] ; JR VOUT80 ;re-echo current chr page ; Exit points for COUT ; Here to store new data and to update cursor VGRAPH: VOUT80: STO A,[hl] ;This exit path stores A (new char) MOV E,L CBIT 7,E ;E = col(cursor) LD A,LLIMIT DEC A ;A =  current settings :ESC: ;Current chr is ESC. Set flag and exit OR EF_ESC ;indicate last char= ESC STO A,ESCH JMP VOUT97 ;Exit space 4,17 PSTESC: ;Last chr was ESC ;Entry ;A = EF_ESC ;B = ESCH ;C = Char to output ;HL = curs Proc BIT 4,B ;is this chr really an address? JRNZ SETXY ;...if chr is part of an addr ;no cursor/screen addressing in effect: XOR B ;Clr EF_ESC bit (for next time) MOV B,A ;Set up B = ESCH byte value. STO A,ESCH PUSH HL ;save Curs LDK HL,VALIDE ;Branch table adrs LDK E,VALETS ;Table size MOV A,C ;Chr to A JR LOOKUPB ;Go to routine to branch per tbl space 4,15 VNORM: ;NORMAL mode character processing. ; Entry A= char to output ; HL=curs CMP ' ' JRC :2 ;IF control chr VBRIGH: DI ! ENADIM ;9th bit memory STO BRTBIT,[hl] ;set this chr BRIGHT DISDIM ! EI JMP VOUT80 :2: PUSH HL ;Save Curs LDK HL,VALIDC ;Branch table adrs LDK E,VALCTS ;Table size ; JMP LOOKUPB ;Scan table of valid control chrs ; ;and bra JR :exitX space 4,10 SETXY: ;Set X-Y value for Cursor/Screen Addressing ; Entry HL= cursor_addr ; B = ESCH ; C = chr ; Exit to VOUT90; ESCH updated CALL UN_CUR LDK A,-(' ') ADD C ;remove cursor bias BIT 5,B ;cursor/screen addressing? JRNZ SCREEN ;if screen addressing ;cursor addressing: ADD HL,HL ;shift HL left BIT 6,B ;X/Y coordinate? JRNZ :cX ;if X coordinate :cY: MOV H,A ;save LD A,PIABD ADD H ;offset by start-Y co-ord of video RAR ;bit0(A) -> CY, shift A right RR L ;CY -> bit7(L) OR 0F0h ;turn on upper nybl MOV H,A ;HL= new cursor addr ; JR :exitY :exitY: LDK A,0100_0000b ;next addr-chr will be X-coord OR B JR :exit2 :cX: RAL ;trash 7th bit SRA H ;bit0(H) -> CY, bit7 stays 1 RAR ;... CY -> bit7(A) MOV L,A ; JR :exitX :exitX: LDK A,EF_MSK AND B ;finished addressing: reset addr bits :exit2: STO A,ESCH JMP VOUT90 page ; Control Code character processing VC_HOME: ;Home Cursor Proc CALL UN_CUR LD A,PIABD RAR ;last_legal_col SUB E ;A = last_legal_col - col(cur) JRNZ VOUT85 ;if not @LLIMIT LDK A,80h AND L MOV L,A ;do CR... CALL DO_LF2 ;...and LF. JR VOUT90 VOUT85: INC HL ;move cursor ; Here if NO cursor update VOUT90: LD A,[HL] ;This exit path turns on 80h bit ; Here if new data already in A VOUT95: RAL ;Make this chr cursor VOUT96: CMC ;invert cursor bit RAR STO A,[hl] STO HL,CURS ;update cursor ; Here if no change to cursor, restore reg and exit VOUT97: POP BC POP DE POP HL MOV A,C ;Exit with A=chr RET ;return, end of cout subr. space 4 :First = VOUT97 - (127 + 2) ;earliest possible JR :Last = VOUT80 + (128 - 2) ;latest possible JR page ESC_LCK: ;Lock Keyboard Proc XOR A JR :2 ESC_ULK: ;Unlock Keyboard LDK A,0FFh :2: STO A,KEYLCK JR VOUT97 space 4,5 EEOL: ;Erase to end of line PUSH HL ;save cursor CALL CLRLN POP HL JR VOUT90 space 4,12 ESC_CAD: ;Cursor Addressing LDK A,EF_MSK AND B OR EF_ESC or EF_Anch to appropriate routine. space 4,20 LOOKUPB: ;Logic to scan 3 byte branch table ; NOT a subroutine---do not CALL. ; Entry HL =1st byte of table (match code) ; (2nd,3rd bytes = branch adrs) ; (table repeats [3 byte entries]) ; E is table size (no. of entries) ; (table body is followed with ; 2 byte "No-Match" adrs) ; Stack has HL saved as top entry. ; C = char ; A = value to scan for possible match CMP [HL] INC HL ;(2nd byte of this 3 byte entry) JRZ VECTOR ;If match process INC HL ;(3rd byte of this entry) INC HL ;1st byte of next entry DEC E ;Dec count of entries remaining JRNZ LOOKUPB ;Continue thru body of table JR VECTOR ;No-Match. hl=points to vector page ; Processing for modes other than normal. ; -------------------------------------- ;VGRAPH = VOUT80 ;Normal mode EXCEPT: cntl chrs are printed VUNDER: ;Underline only CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VUN_GR ;continue VUN_GR: ;Underlined Graphics OR 80h underbit0 => CY LDK L,0 RR L ;CY => bit7, trash bit0 MOV H,A JR :fixhl ;HL := HL or F000h space 4,7 VC_MCUP: ;Move Cursor Up. ; A=C=Chr=MCUP. HL=Curs. CALL UN_CUR PUSH HL ;old cursor must be on stack LDK BC,(-VLL) JR :fwa ;...at this entry point space 4,28 VC_BKS: ;HL=Curs=current (old) char CALL UN_CUR ;clear 80h bit LDK A,7Fh AND L JRZ :wrap ;if must wrap from col 0 to LLIMIT DEC HL JR VOUT90 ;Exit :wrap: PUSH HL ;save old cursor LDK BC,-(VLL+1) ADD HL,BC ;HL = prev_line, (-1)st column LD A,LLIMIT ;LLIMIT = #columns on screen MOV C,A LDK B,0 :fwa: ADD HL,BC XTHL ;get old cursor, save new ADD HL,HL ;shift line# into H reg. LD A,PIABD OR 1110_0000b ;A = line# of UL corner CMP H ;set Zflag: @home? POP HL ;get new cursor... JRNZ :fixhl ;if NOT @video home LDK BC,(24*VLL) ;wrap constant ADD HL,BC :fixhl: LDK A,0F0h OR H ;modulo result: keep cursor MOV H,A ;inside video memory. JR VOUT90 space 4,8 VC_BEL: ;RiDR ;next chr will be Y-coord :exit3: STO A,ESCH JR VOUT97 ESC_SAD: ;Screen Addressing LDK A,EF_MSK AND B OR EF_ESC or EF_ADR or EF_SCR JR :exit3 page ;Subroutine for use with EDELC and EINSRT: ;Calculate #chrs to move; if move zero chrs, never return. Proc :calc: LDK A,VLL-1 ;A= max #chrs to be moved MOV C,L CBIT 7,C ;C = col(cursor) SUB C ;A = #chrs to move JRZ :end ;if move zero characters MOV C,A LDK B,0 ;BC = #chrs to move RET :end: POP HL ;trash return_addr POP HL ;cursor_addr JR VOUT90 space 4,14 EDELC: ;Delete Character PUSH HL ;save cursor_addr CALL :calc ;calculate BC ; MOV D,H ; MOV E,L ;DE = cursor_addr PUSH HL POP IX INC HL ;HL = cursor_addr + 1 CALL VLDIR ;move characters STO ' ',[hl] ;last chr becomes blank DI ! ENADIM ;enable 9th bit memory DEC HL ;HL = last chr on this line STO BRTBIT,[hl] ;set chr BRIGHT DISDIM ! EI ;main memory POP HL ;restore cursor_addr JR VOUT90 ;next space 4,14 EINSRT: ;Inspace 3,11 :delt: POP DE ;recover new cursor PUSH DE LDK HL,VLL ADD HL,DE ;HL = line_below_cursor JR :dstrt :dcont: PUSH DE POP IX CALL VLDIR ;move 1 line up :dstrt: CALL :vmod JRNZ :dcont EX HL,DE ;get addr of line to clear JR :exit space 3,13 ;HL := HL or F000h; DE := DE or F000h; ;simple mod-4096 arithmetic to keep pointers INSIDE video memory :vmod: PUSH AF ;save A = #lines to move LDK A,0F0h OR H MOV H,A ;set upper nybl of H LDK A,0F0h OR D MOV D,A ;modulo 4096 LDK BC,VLL POP AF DEC A ;decrement line_count RET space 4,30 CLRLN: ;Clear to end of line ; Entry HL= Cursor ; Exit clear to EOL ; Uses All. proc STO ' ',[hl] ;clear cursor... DI ENADIM STO BRTBIT,[hl] ;set cursor BRIGHT DISDIM EI LD A,LLIMIT DEC A ;max_#cols => maximum_col_# MOV E,L CBIT 7,E SUB E ;A = col(EOL) - col(cursor) RZ ;if @EOL, done JRNC :2 ;if inside logical_video_line LDK A,VLL SUB E ;...else clr to end of 128-chr line RMove ; Entry BC, IX, HL set ; Exit LDIR on main & 9th bit memory ; Uses BC, DE, HL,IX PUSH IX POP DE PUSH BC ! PUSH DE ! PUSH HL LDIR ;main memory POP HL ! POP DE ! POP BC DI ENADIM LDIR ;9th bit memory DISDIM EI RET space 4,10 UN_CUR: ;Undo/Invert Cursor ; Entry HL = cursor_addr ; Exit cursor inverted ; Uses A, CY. LD A,[hl] ;get the chr RAL ;cursor_bit => CY CMC ;invert it RAR STO A,[hl] ;... RET PAGE ;KEYBOARD SCANNING & DECODE GKEY: ;KEYBOARD INTERRUPT PROCESSOR ;ENTRY ;NONE ;EXIT ;KEYBOARD PROCESSING DONE, RESULT IN LDKEY. ;SYSTEM CLOCK UPDATED BY UPTIM. PROC DI STO SP,IESTK ;SAVE INTERRUPTED PROCESS STK LDK SP,ISTK ;SET TO RAM INT STK ALPUSH CALL UPTIM ;UPDATE SYSTEM CLOCK LD A,KEYLCK OR A CNZ KBDRVR GKEYX: JMP EXITI ;EXIT INTERRUPT PAGE ; This file contains the 2-key roll over keyboard driver for ; the OSBORNE 1 comuter. ; Author: ; Microcode Corporation. ; Fremont, CA. ; Y. N. Sahae ; ert Character CALL UN_CUR PUSH HL ;save cursor_addr CALL :calc ;calculate BC LDK A,7Fh OR L MOV L,A ;HL = last_chr on this line ; MOV E,A ; MOV D,H ;DE = HL PUSH HL POP IX DEC HL CALL VLDDR ;do move POP HL ;restore cursor LD A,[hl] ;get underline bit of this chr. RAL ;into CY LDK A,' ' shl 1 ;change this chr to ' ' JR VOUT96 ;exit page ; ESC-Sequence processing. Proc ESCSGR: LDK A,EF_GR ;ESC-g JR :125 ;set graphics mode. ESCSHA: LDK A,EF_HA ;ESC-) set half intensity JR :125 ;go set flag bit ESCSUN: LDK A,EF_UN ;ESC-l set underline :125: OR B ;Reg B is ESCH Byte value :130: STO A,ESCH ;store desired value. JR VOUT97 ;Exit ESCCGR: LDK A,NOT EF_GR ;ESC-G Clear graphics mode JR :140 ;go clear ESCH bit ESCCHA: LDK A,NOT EF_HA ;ESC-( Clear half intensity JR :140 ESCCUN: LDK A,NOT EF_UN ;ESC-m Clear underline :140: AND B ;Clear bit JR :130 ;Go store ESCH byte ESCZZ: = VC_CLRS ;ESC-Z Clear screen -same as ;ControlZ ;if cursor @ column #127 :2: MOV C,A LDK B,0 ;BC = chrs to move ; MOV E,L ; MOV D,H PUSH HL POP IX ; INC DE ;DE = HL + 1 INC IX JR VLDIR page DO_LF: ;Do Line Feed processing ; Entry HL = cursor_addr ; Exit Cursor cleared ; HL updated for current cursor pos ; window moved if necessary proc CALL UN_CUR ;clear cursor DO_LF2: PUSH HL ;save original cursor LDK BC,VLL ;line length ADD HL,BC JRNC :nowap ;if not wrapping from LWAVM to FWAVM LDK BC,FWAVM ADD HL,BC ;HL = new cursor @ top of VM :nowap: XTHL ;save new cursor, get old ADD HL,HL ;shift HL left LD A,PIABD ADD A,23 ;start + 23 = last_video_line SUB H ;A = l_line - curr_line AND 0001_1111b ;modulo 32 JRZ :vmov ;if cursor is on 24th line of screen :end: POP HL ;get new cursor RET :vmov: LD A,LLIMIT SRL L ;unshift L register SUB L ;A = LLIMIT - col(cursor) JRC :end ;if cursor is outside logical line ;cursor is on last line of screen, inside of logical line. ;must move screeSeptember 1981 ; Revisions: ; 2-Key roll over keyboard driver. ; DESCRIPTION: ; The keyboard driver gets control via the 60hz interrupt, i.e. once ; every 16 ms. It scans the keyboard to detect any struck keys. If a ; key is found, it is entered into the keylist if there is space ; in the keylist and the key is not already in the list. At the end of ; the scan, the keys in the list are proecessed. If the key is still ; on, it is placed in lkey (or special action taken) after translating ; the keynumber. A count is also stored in the list and the key will ; be serviced again at the end of this count if it is still on. Thus ; the key will repeat if it is held down. If a key which is in the ; list is not on it is removed from the list. ; ; The keyboard driver consists of the following routines: ; ; KBDRVR - Examines the keylist, calls CHKEY to determine if key ; is still on. Removes the key from the list if it is not on. If ; key is on, it decrements the count associated with-Z routine. page ESCRR: ;Delete Line ESCEE: ;Insert Line ; Entry HL = cursor ; C = chr ; Exit screen updated ; HL = new cursor ; ...to VOUT90 Proc CALL UN_CUR LDK A,1000_0000b AND L MOV L,A ;do CR PUSH HL ;save new cursor ADD HL,HL LD A,PIABD ADD A,24 ;A = addr(25th line) SUB H ;A = lines_to_move + 1 AND 0001_1111b ;mod 32 MOV B,A LDK A,VDELL CMP C MOV A,B ;recall #lines to move JRZ :delt ;if deleting a line space 3,17 :insrt: ;Insert a line ADD H ;A = addr(25th line) MOV D,A LDK E,0 RR D ! RR E ;shift right DE DEC DE ;DE = addr(lst_chr_on_lst_line) MOV A,B ;A = #lines to move LDK HL,-VLL ADD HL,DE ;HL = addr(line above DE) ;DE := DE or F000h; HL := HL or F000h JR :istrt :icont: PUSH DE POP IX CALL VLDDR ;move 1 line down :istrt: CALL :vmod JRNZ :icont ;if must move more lines INC HL ;HL => 1st chr of new line ; JR :exit space 3,3 :exit: CALL CLRLN POP HL ;recover cursor JMP VOUT90 ;Main Exit sn to follow cursor down through video memory. POP HL PUSH HL LDK A,80h AND L MOV L,A ;HL = beginning of line CALL CLRLN ;erase to EOL LD A,PIABD MOV B,A AND not 31 ;A = line zero MOV C,A ;C = housekeeping bits 5..7 LDK A,31 INC B ;increment line# AND B ;A = line# STO A,VRTOFF ;SET VERTICAL OFFSET FOR COUT OR C ;A = new line# OR housekeeping_bits MOV C,A ;C = new value for OPBD CALL OPBD ;move video screen down 1 line in memory POP HL RET PAGE STODIM: ;STORE THE CONTENTS OF THE B REG IN THE ADDR POINTED TO BY THE HL PAIR ;ENTRY ;B = VALUE ;HL = ADDRESS ;EXIT ;NONE PROC DI ENADIM ;ENABLE DIM STO B,[HL] ;STORE DISDIM ;DISABLE DIM EI RET VLDDR: ;Video Block Move ; Entry BC, IX, HL set ; Exit LDDR on main & 9th bit memory ; Uses BC, DE, HL,IX PUSH IX POP DE PUSH BC ! PUSH DE ! PUSH HL LDDR ;main memory POP HL ! POP DE ! POP BC DI ENADIM LDDR ;9th bit memory DISDIM EI RET space 4,12 VLDIR: ;Video Block  the key. when ; the count goes to zero, it calls KBSERV to service the key. Calls ; KBSCAN to enter any new keys into the list. ; ; KBSCAN - This routine scans the keyboard, detects a struck ; key and enters it into the keylist. The key is entered ; into the keylist if the key is not already present in the keylist ; and there is an empty slot in the keylist. ; ; KBSERV - It calls the routine CHKEY to check if shift/ctl or alphlock ; keys are on. It then translates the keynumber into the ASCII ; code and places it in the LKEY for the CBIOS to read. For some ; special cases, it calls ROM resident routines to process the key. ; ; CHKEY - It checks if a given key is on. ; ; ; Data structure: ; The main structure used is the keylist. The format of each entry is: ; ; Byte 0: ; bit 7 : Set indicates entry is in use. ; bit 6 : Set indicates key has been serviced once. ; bits 5..3 : contain the row number of struck key. ; bits 2..0 : contain the column number of struck key. ; Bytw ; in this loop, reg b contains totrow- current row being scanned :10: jrz :50 ;if any key is pressed then push bc ;save loop count mov e,a ;e = columns LDK a,tot_row sub b ral ral ral mov d,a ;d = row number * 8 LDK c,0 ;initialize column counter ; scan this row from right to left to get the column number :15: ;repeat srl e ;shift column bit into carry jrnc :30 ;if a key is found then ; enter the key whose column number is in c and row*8 is in d ; into the keylst provided the key is not already in list and ; there is an empty slot in the list. mov a,d add a,c push bc mov c,a ;c = key number push de ;save de push hl ;save hl LDK b,kl_len ;length of keylist LDK hl,keylst LDK de,0 :18: ld a,[hl] bit kl_used,a ; jrz :22 ;if entry is used then and krow_m+kcol_m cmp c ;check with current key jrz :27 ;exit ifch hm_scrn equ '[' KBSERV: proc ; setup hl to point to keycode table entry for this key mov e,a LDK d,0 ;used here and later LDK hl,kycdtb add hl,de ld a,[hl] cmp ' '+1 jrc :12 ;ignore shift/ctl etc for chars less than 21h push af LDK l,row0_m ;row 0 adrs call rdrow ;get row containing ctl,shift and alpha key mov e,a pop af ;restore keycode bit ctl_ky,e jrnz :50 ;go process ctl key bit shft_ky,e jrnz :30 ;go process shift key bit alph_ky,e jrnz :25 ;go process alpha key ; ; store key code into lkey :12: sto a,lkey ret :25: ;process alpha key cmp 'a' jrc :12 ;exit when less than 'a'. Alpha has no effect :27: cmp 80h jrnc :12 ;or when >= 80h :28: xor 20h ;fold char to upper case jr :12 :30: ;process shift key cmp 'a' jrnc :27 ;goto alpha when char > 'a' cmp '[' jrc :35 ;goto process shift numerics etc jrnz :28 ;invert shift bit for '\' LDK a,']' jr :12 ;convert [ to ] :35: ; chars ' to > (ascii codese 1: ; bits 7..0 : contain the repeat count for the key. ; PAGE KBDRVR: ; Routine name: KBDRVR - Detects and processes keystrokes. ; Input: none ; Output: LKEY contains keystroke. proc call kbscan ;scan keyboard and enter keys into keylist ; Examine keylist. If key found in keylist, call CHKEY to see ; if key is still on. remove from list when not on. LDK hl,keylst ;point to first entry of keylist LDK b,kl_len :10: ld a,lkey or a RNZ ;exit when a key is waiting in lkey ld a,[hl] ;get byte 0 of entry bit kl_used,a jrz :40 ;if entry is in use then call chkey ;check if still on jrnz :20 ;if key is now off then sto 0,[hl] ;remove key from list jr :40 :20: ;else ; key is on. decrement its repeat count. If count goes to zero ; then it is time to service the key. push hl ;save ptr to first byte of entry inc hl ;point to repeat count dec [hl] jrnz :30 ;exit when not time to service the key. ; it is time to  this key is in list jr :25 :22: ;else (an empty entry is found) mov e,l mov d,h ;save adrs of empty entry in de :25: ;endif echo kle_len inc hl ENDM ;next entry djnz :18 ;till list scanned ; check if an empty entry was found. mov a,d or a jz :27 ;if empty entry was found then ex de,hl ;hl = empty entry sto c,[hl] ;store the key in the list sbit kl_used,[hl] ;set used flag inc hl sto DB_ct,[hl] ;store debounce delay ;endif :27: ;restore all regsters pop hl pop de pop bc :30: ;endif inc c ;increment column number xor a cmp e jrnz :15 ;until all columns scanned pop bc ;rstore bc :50: ;endif sla l ;move to next row call rdrow djnz :10 ret PAGE ;** ; sbrt: CHKEY - checks if key number is on. ; input: ; Reg A = Keynumber ; output: ; Z ind clr = Key is off. ; Z ind set = Key is on. CHKEY 27h to 3eh) are converted using ; the shft_tb mov e,a ;d=0 from before LDK hl,shft_tb - '''' add hl,de :37: ld a,[hl] jr :12 :50: ;process control key ; if char is between a..z then turn off the 3 high order ; bits. ; if char is between ','..'?' it is translated as per table ctl_tb' ; if char is the arrow keys or the ']'/'[' key the slide functions ; are called. cmp lft_arw jrz slidel cmp rt_arw jrz slider cmp up_arw jrz slideu cmp dn_arw jrz slided cmp hm_scrn jrz dohome cmp '@' jrc :54 ;goto translate chars from table cmp 'z'+1 jrnc :12 and 1fh jr :12 :54: cmp ',' jrc :12 ;no translation if char below ',' LDK hl,ctl_tb-',' mov e,a ;d=0 from above add hl,de jr :37 ; slide functions. slidel: LDK c,2 jr :70 slider: LDK c,-2 :70: ld a,piaad ;get horizontal coord. add a,c mov c,a :72: call opad ;set pia a data :74: ; set repeat count for these keys (override count set by the kbdrvr) pop de service the key. Set the next repeat count ex [sp],hl ;point back to the first byte of entry ld a,[hl] bit ky_srvd,a ;check if it is serviced before sbit ky_srvd,[hl] ;set the serviced once flag ex [sp],hl ;point back to the repeat count sto irptct,[hl] ;and store rpt count as per serviced flag jrz :22 sto srptct,[hl] :22: and krow_m+kcol_m call kbserv ;call to service the key :30: pop hl ;get ptr to first byte of entry again ;endif :40: ;endif echo kle_len inc hl ;point to next entry ENDM djnz :10 ;until complete list scanned RET ;return to exiti code in rom PAGE ;** ; sbrt: KBSCAN - Scan keyboard and enter detected keys in the ; keylist. ; input: ; none ; output: ; keylst = contains any keys detected. KBSCAN: proc LDK l,0ffh ;see if any key pressed call rdrow rz ;return when none LDK l,row0_m ;get row 0 call rdrow and 11100011b ;remove ctl/shift and alpha lock LDK b,tot_ro: proc push hl ;save callers hl push af ;save keynumber rar rar rar ;right justify row number call gtmask pop af ;get key number push de ;save row mask call gtmask ;get col mask (col num is in bits 0..2) pop hl ;move row mask to l call rdrow ;get row of keys adrsed by l and e ;z ind = value of key pop hl ret ;** ; sbrt: GTMASK - generates mask with one bit set. ; input: ; a = bit number (0..7) ; output: ; e = mask GTMASK: proc LDK e,1 and 7 :10: rz sla e dec a jr :10 ;** ; sbrt: RDROW - Reads a row of keys ; input: ; reg L = lower 8 bits of adrs to read the row ; output: ; reg A = row value ; RDROW: proc LDK h,high(h.key) ;hl = prt adrs for given row ld a,[hl] xor 0ffh ;invert values ret PAGE ;** ; sbrt: KBSERV - services the key ; input: ; reg A = keynumber ; [SP]-4 = pointer to keylst entry (used for slide fnc only) ; preserves reg B lft_arw equ 8dh rt_arw equ 8bh up_arw equ 8ah dn_arw equ 8;get return adrs pop hl ;pointer to repeat entry sto sld_rct,[hl] ;repeat count for slide keys push hl push de ;restore stack ret slideu: LDK c,1 jr :76 slided: LDK c,-1 :76: ;merge new vertoffset to lower 5 bits of ;PIAB LDK hl,piabd ld a,[hl] add a,c and 1fh ;modify current with +1/or-1 mov c,a ld a,[hl] and 0e0h :78: or c mov c,a call opbd jr :74 dohome: LDK c,vflo ;just the fuzz factor call opad ;set horiz to 0 ld A,piabd AND 0E0H ;HOUSE KEEPING BITS MOV C,A LD A,VRTOFF ;GET LAST VERTICAL OFFSET jr :78 ;and the vert to 0 also ; key code translation tables kycdtb: DB esc, tab, erc, erc DB erc, cr, '''', '[' DB '1', '2', '3', '4' DB '5', '6', '7', '8' DB 'q', 'w', 'e', 'r' DB 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f' DB 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v' DB 'b', 'n', 'm', ',' DB 8ah, 8dh, '0', ' ' DB '.', 'p', 'o', '9' DB 8bh, 8ch, '-', '/' DB ';', '\', 'l', ' RZ ; return here if broadcast 1 byte MOV B,D MOV C,E ; BC := (count) MOV D,H MOV E,L INC DE ; DE := HL + 1 LDIR ; overlapping move RET space 4,10 ESTR: ;Output ENCODED string to console ; Entry DE=FWA of source OR A ;clear cbit LD A,[de] RRC ;normalize char PUSH AF AND 07Fh MOV C,A CALL CO ;output it INC DE POP AF JRNC ESTR ;if not done RET page .old IF FALSE FVIO: ;Fill video memory with fixed data ; Entry C= data to broadcast ; NOTE: Interrupts MUST be disabled.. proc LDK HL,FWAVM LDK DE,LVMEM PUSH HL ! PUSH DE CALL FILLC ;clear main vio POP DE ! POP HL .mac IF RSIZE = 64 ENADIM LDK C,0 ;clear 9th bit :2: MOV A,D ;fill 9th bit memory OR E JRZ :4 ;if done STO C,[hl] INC HL DEC DE JR :2 ;loop :4: DISDIM .mac ENDIF RET .old ENDIF space 4,10 SPAO: ;Set PIA for output LDK A,03h ;CRA1-0, Interrupt inputs CA1 STO A,H.VIO+1 ;set data direction LDK A,0FFh STO A,H.VIO ;set all A lines as output LDK A;AFTER A FATAL ERROR, PERFORM AN IFC RESET. ; ;STANDARD VALUES USED: ; ;CCRA 0011(IFC)(DIR)10 ; ;CCRB 0011(REN)(DIR)00 ; ;CPDRA SOURCE DIRECTION 1111_1111 ; DATA DATA ; ;CPDRA ACCEPTOR DIRECTION 1111_1111 ; DATA 1111_1111 ; ;CPDRB SOURCE DIRECTION 0011_1111 ; DATA 000A_0010 ;A = ATN ; ;CPDRB ACCEPTOR DIRECTION 1101_0111 ; DATA 0100_0101 PAGE ;PIA SIGNAL DEFINITIONS: ;ALL SIGNALS ARE LOW ON THE IEEE BUS WHEN PIA REGISTER CONTAINS "1". ; ; PA0 DIO 1 ; PA1 DIO 2 ; PA2 DIO 3 ; PA3 DIO 4 ; PA4 DIO 5 ; PA5 DIO 6 ; PA6 DIO 7 ; PA7 DIO 8 ; ; CA1 SRQ ; CA2 IFC ; ; PB0 ENABLE DATA OUT (ENABLED WHEN "0") ; PB1 ENABLE NDAC/NRFD (ENABLED WHEN "0") ; PB2 ENABLE EOI/DAV (ENABLED WHEN "0") ; PB3 EOI ; PB4 ATN ; PB5 DAV ; PB6 NDAC ; PB7 NRFD ; ; CB1 NOT USED ; CB2 REN ; ;CONTROL WORD FORMAT ; ;[ 7 ][ 6 ][ 5 ][ 4 ][ 3 ][ 2 ][ 1 ][ 0 ] ; ;[IRQA1][IRQA2][ CA2 CONTROL ][ DDRA][ CA1 CONTROL] ;[IRQB1][IRQB2][ CB2 CONTROL ][ DDRB][ CB1 C=' shft_tb: DB '"', 00h, 00h, 00h, 00h DB '<', '_', '>', '?', ')' DB '!', '@', '#', '$', '%' DB '^', '&', '*', '(', 00h DB ':', 00h, '+', 00h ctl_tb: DB '{', '_'-40h, '}', '~' DB 80h, 81h, 82h, 83h, 84h DB 85h, 86h, 87h, 88h, 89h DB 00h, 00h ; END OCCROM3?.??? a call opbd jr :74 dohome: LDK c,vflo ;just the fuzz factor call opad ;set horiz to 0 ld A,piabd AND 0E0H ;HOUSE KEEPING BITS MOV C,A LD A,VRTOFF ;GET LAST VERTICAL OFFSET jr :78 ;and the vert to 0 also ; key code translation tables kycdtb: DB esc, tab, erc, erc DB erc, cr, '''', '[' DB '1', '2', '3', '4' DB '5', '6', '7', '8' DB 'q', 'w', 'e', 'r' DB 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f' DB 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v' DB 'b', 'n', 'm', ',' DB 8ah, 8dh, '0', ' ' DB '.', 'p', 'o', '9' DB 8bh, 8ch, '-', '/' DB ';', '\', 'l', ',0 STO A,H.VIO+3 LDK A,0FFh STO A,H.VIO+2 ;set all B lines as output RET space 4,10 OPAD: ;Output data to pia A register ; Entry C= data ; Exit PIAAD = new value LDK A,4+3 STO A,H.VIO+1 MOV A,C STO A,PIAAD STO A,H.VIO ;send data RET space 4,10 OPBD: ;Output data to pia B register ; PIA definition. ; 7 6 5 4 3 2 1 0 ; +--+--+--+--+--+--+--+--+ ; |D1|D0|^G| vert offset | ; +--+--+--+--+--+--+--+--+ ; ; Entry C= data ; Exit PIABD = new value LDK A,4 STO A,H.VIO+3 MOV A,C STO A,PIABD STO A,H.VIO+2 ;send data RET TITLE 'BMIEEE.ASM - IEEE-488 INTERFACE.' ; +---------------------------------------+ ; | ENTERED 05/01/81 FROM TNW XEROX, SEH. | ; +---------------------------------------+ ; ;LAST EDITED AT 09:29 ON 11 NOV 80 ; ;THERE ARE FOUR COMMANDS TO THE 6821 ; ; 00 PERIPHERAL/DIRECTION REGISTER A CPDRA ; 01 CONTROL REGISTER A CCRA ; 10 PERIPHERAL/DIRECTION REGISTER B CPDRB ; 11 CONTROL REGISTER B CCRB ; ;BIT 2 OF THE COONTROL] ; ; IRQA1 0 INTERRUPT FLAG SET BY FALL OF SRQ ; IRQA2 0 NOT USED ; CA2 110 SET IFC HIGH ; 111 SET IFC LOW ; DDRA 0 R/W DATA DIRECTION REGISTER A ; 1 R/W PERIPHERAL REGISTER A ; CA1 10 SET IRQA1 HIGH ON RISE OF SRQ ; ; IRQB1 0 NOT USED ; IRQB2 0 NOT USED ; CB2 110 SET REN HIGH ; 111 SET REN LOW ; DDRB 0 R/W DATA DIRECTION REGISTER B ; 1 R/W PERIPHERAL REGISTER B ; CB1 00 NOT USED PAGE ;BIOS CALL 1: CONTROL OUT ; ; CAN BE CALLED WHILE IN ANY STATE. ; ; EXITS IN THE CONTROLLER STANDBY STATE (ATN HIGH), ; SOURCE HANDSHAKE MODE ; ;PARAMETER PASSED IN REGISTER C: ; ; BIT 0 IF "1", THE IFC SIGNAL IS SET LOW FOR 100 MICRO-SEC ; AND ALL PIA SIGNALS ARE INITIALIZED ; ; BIT 2 1 ; 0 X NO ACTION ; 1 0 SETS REN HIGH ; 1 1 SETS REN LOW ; IE.CO: PROC PUSH AF PUSH HL BIT 0,C ;CHECK IFC SUB-COMMAND JRZ :B1C20 ;INITIALIZE ALL IEEE-488 SIGNALS LK HL,CCRA STO 0011_1010B,[HL] ;ENABLE SRQ AND SET IFC-OUT LOW LK A,1111_1111B ;DIRECT DATA OUT STO A,CPDRA TITLE 'Hardware PIO function processors.' CDEHL: ;Compare DE to HL as unsigned integers. ; Entry DE,HL set to values to compare ; Exit Zbit set if DE = HL ; Cbit set if DE < HL. ; Uses AF. MOV A,D CMP H RNZ ;If D .ne. H MOV A,E CMP L RNZ ;if DE .ne. HL STC RET space 4,10 DELAY: ;'N' Milliseconds ; Entry A=Number of Milliseconds to delay ; SCLFRE= (Freq/1000)/25 ; Exit Time passed. Proc PUSH BC MOV C,A :1: LDK A,SCLFRE :2: DEC A ;(4 tics) MOV B,B ;(4 tics) MOV C,C ;(4 tics) JNZ :2 ;(10 tics) If 1 ms not elapsed DEC C JNZ :1 ;If requested msec not done POP BC ;restore registers RET ;SCLFRE: = 2000/22 ;Z80, 2mhz ;...defined in OCCTXT.ast space 4,32 FILLZ: ;Fill block of memory with byte value. ; Entry DE=LENGTH TO broadcast character ; C =character TO broadcast ; HL=FWA TO START broadcast ; EXIT FILL DONE LK C,0 ;FILL WITH ZERO FILLC: MOV A,E OR D RZ ; return here if broadcast 0 bytes STO C,[hl] ; 1st byte DEC DE MOV A,E OR DNTROL REGISTER (A AND B) ALLOWS SELECTION OF EITHER ;A PERIPHERAL INTERFACE REGISTER OR A DATA DIRECTION REGISTER. ;A "1" IN BIT 2 SELECTS THE PERIPHERAL REGISTER. ; ;THE TWO DATA DIRECTION REGISTERS ALLOW CONTROL OF THE DIRECTION ;OF DATA THROUGH EACH CORRESPONDING PERIPHERAL DATA LINE. ;A DATA DIRECTION REGISTER BIT SET AT "0" CONFIGURES ;THE CORRESPONDING PERIPHERAL DATA LINE AS AN INPUT. ; ;A RESET AT POWER UP HAS THE EFFECT OF ZEROING ALL PIA REGISTERS. ;THIS WILL SET PA0-PA7, PB0-PB7, CA2, AND CB2 AS INPUTS, ;AND ALL INTERRUPTS DISABLED. ;SIGNALS ATN, REN, AND IFC WILL BE DRIVEN LOW ;UNTIL INITIALIZED BY SOFTWARE. ; ;DATA DIRECTION IS ALWAYS SET FOR OUTPUT FOR THE DATA REGISTER. ;DATA MUST BE SET TO ALL ONES WHEN INPUTTING. ;THE INTERFACE IS IN SOURCE HANDSHAKE MODE IF DATA ENABLE (PB0) ;IS SET TO "0", AND IN ACCEPTOR HANDSHAKE MODE IF SET TO "1". ;WHEN SWITCHING FROM SOURCE TO ACCEPTOR HANDSHAKE, ;ATN WILL ALWAYS BE LOW. ;TAKE CONTROL CAN ONLY BE CALLED FOLLOWING A GO TO STANDBY.   STO 0011_1110B,[HL] XOR A ;SET DATA TO ZERO STO A,CPDRA LK HL,CCRB STO 0011_0000B,[HL] ;SET REN-OUT HIGH LK A,0011_1111B ;DIRECTION FOR SOURCE HANDSHAKE STO A,CPDRB STO 0011_0100B,[HL] LK A,0000_0010B ;VALUES FOR SOURCE HANDSHAKE STO A,CPDRB ;LEAVE IFC LOW FOR 100 MICRO-SEC LK A,25 ;DELAY 100 MICRO-SEC :B1C10: DEC A JRNZ :B1C10 LK A,0011_0110B ;SET IFC HIGH STO A,CCRA :B1C20: BIT 2,C ;CHECK REN SUB-COMMAND JRZ :B1C40 ;SET/CLEAR REN LK A,0011_0000B BIT 1,C JRZ :B1C30 LK A,0011_1000B :B1C30: STO A,CCRB :B1C40: POP HL POP AF RET PAGE ;BIOS CALL 2: STATUS IN ; ; CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE. ; ;BIT 0 OF REGISTER A SET IF SRQ IS LOW ; IE.SI: PROC PUSH HL LD A,CPDRA ;CLEAR IRQA1 LK HL,CPDRB ;PULSE ENABLE DAV/EOI CBIT 2,[HL] SBIT 2,[HL] LD A,CCRA ;SET SRQ VALUE IN A AND 1000_0000B RLC A POP HL RET SPACE 4,14 ;BIOS CALL 3: GO TO STANDBY ; ; CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE ; ;NO PARAMETE;ERROR CODE RETURNED IN REGISTER A ; IE.ODM: PROC PUSH HL LK HL,CPDRB CBIT 4,[HL] ;SET ATN HIGH BIT 0,B ;CHECK IF EOI REQUESTED JRZ IE.SHK SBIT 3,[HL] ;PERFORM SOURCE HANDSHAKE IE.SHK: BIT 5,[HL] ; JRNZ :B6C50 ;DAC TIMEOUT RE-ENTRY MOV A,C ;PLACE DATA ON BUS STO A,CPDRA LK A,10 :B6C20: BIT 7,[HL] JRZ :B6C30 ;READY FOR DATA DEC A JRNZ :B6C20 ;WAIT FOR 100 MICRO-SEC LK A,1000_0010B ;SET RFD TIMEOUT ERROR JR :B6C80 :B6C30: BIT 6,[HL] JRNZ :B6C40 ;DATA ACCEPTED LOW LK A,1000_0001B ;SET DEVICE NOT PRESENT ERROR JR :B6C80 :B6C40: SBIT 5,[HL] ;SET DAV LOW :B6C50: LK A,255 :B6C60: BIT 6,[HL] JRZ :B6C70 ;DATA ACCEPTED DEC A JRNZ :B6C60 ;WAIT 1000 MICRO-SEC LK A,1000_0100B ;SET DAC TIMEOUT ERROR JR :B6C80 :B6C70: CBIT 5,[HL] ;SET DAV HIGH CBIT 3,[HL] ;SET EOI HIGH XOR A ;REMOVE DATA FROM BUS STO A,CPDRA :B6C80: POP HL RET PAGE ;BIOS CALL 7: INPUT DEVICE MESSAGE ; ; CAN BE CALLED WHILE IN ANY MODE OR STATE ; ; EXITS IN THE ACCEPT TITLE 'OSBORNE 1 UTILITY ROUTINES.' NMOUT: PBBH: ;PRINT BINARY BYTE IN HEX. ; CONVERTS THE 8 BIT, UNSIGNED INTEGER IN THE ; A REGISTER INTO 2 ASCII CHARACTERS. ; ENTRY A= 8 BIT INTEGER ; EXIT NONE ; CALLS CO,PRVAL ; DESTROYS: AF, C. PUSH AF ;SAVE ARGUMENT RRC RRC RRC RRC ;GET UPPER 4 BITS TO LOW 4 BIT POSITIONS CALL PRVAL ;CONVERT LOWER 4 BITS TO ASCII CALL CO ;SEND TO TERMINAL POP AF ;GET BACK ARGUMENT CALL PRVAL JMP CO SPACE 4,10 PRVAL: ;CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO ; THE CORRESPONDING ASCII CHARACTER, 0-9,A-F. PRVAL ; DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT. ; ENTRY A= INTEGER, RANGE 0 TO F ; EXIT A= ASCII CHARACTER. ; C= A ; CALLS NONE. ; DESTROYS: AF AND 0FH ADD A,90H ;SET UP A SO THAT A-F CAUSE A CARRY DAA ;ADJUST CONTENTS OF A REGISTER ADC A,40H ;ADD IN CARRY AND ADJUST UPPER 4 BITS DAA ;ADJUST CONTENTS OF A REGISTER AGAIN MOV C,A RET OCRLF: ;OUTPUT CR,LF ON CONSOLE SCREEN LK C,CR CALL COUT LK C,LF RS PASSED ; IE.GTS: PROC PUSH AF LK A,0000_0010B ;SET ATN HIGH STO A,CPDRB XOR A ;FLOAT DATA BUS STO A,CPDRA POP AF RET PAGE ;BIOS CALL 4: TAKE CONTROL ; ; CAN BE CALLED ONLY WHILE IN THE CONTROLLER STANDBY STATE ; (ATN HIGH). ; ; EXITS IN THE CONTROLLER ACTIVE STATE (ATN LOW), ; SOURCE HANDSHAKE MODE. ; ;BIT 0 OF REGISTER C SET TO TAKE CONTROL ASYNCHRONOUS ; ;ERROR CODE RETURNED IN REGISTER A. ; IE.TC: PROC PUSH HL LK HL,CPDRB BIT 0,C JRNZ :B4C30 ;TAKE CONTROL SYNCHRONOUSLY STO 0000_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB STO 1000_0101B,[HL] ;SET NRFD LOW LK A,25 :B4C10: BIT 5,[HL] JRZ :B4C20 ;DATA VALID HAS DROPPED DEC A JRNZ :B4C10 ;WAIT 100 MICRO-SEC LK A,1000_0001B ;SET DATA VALID TIMEOUT ERROR JR :B4C40 :B4C20: STO 1100_0101B,[HL] ;SET NDAC LOW :B4C30: SBIT 4,[HL] ;SET ATN LOW ;SET-UP FOR SOURCE HANDSHAKE LD A,CCRB CBIT 2,A STO A,CCRB STOR HANDSHAKE MODE WITH ATN HIGH. ; ;DEVICE MESSAGE RETURNED IN BOTH REGISTERS A AND H ;ERROR CODE RETURNED IN REGISTER L ; IE.IDM: PROC PUSH DE EX DE,HL ;SAVE RE-ENTRY DATA LK HL,CPDRB BIT 0,[HL] JRNZ :B7C10 ;SET-UP FOR ACCEPTOR HANDSHAKE STO 0001_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 1101_0111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB LK A,1111_1111B ;FLOAT INTERNAL DATA BUS STO A,CPDRA STO 0101_0101B,[HL] ;CONTROL SIGNALS INITIAL VALUE STO 0100_0101B,[HL] ;SET ATN HIGH ;PERFORM ACCEPTOR HANDSHAKE :B7C10: BIT 6,[HL] JRZ :B7C50 ;DATA INVALID TIMEOUT ERROR RE-ENTRY CBIT 7,[HL] ;SET NRFD HIGH LK A,10 :B7C20: BIT 5,[HL] JRNZ :B7C30 ;DATA VALID DEC A JRNZ :B7C20 ;WAIT 100 MICRO-SEC LK DE,1000_0010B ;SET DATA VALID TIMEOUT ERROR JR :B7C80 :B7C30: SBIT 7,[HL] ;SET NRFD LOW LD A,CPDRA ;READ DATA MOV D,A LK E,0 ;READ EOI BIT 3,[HL] JRZ :B7C40 LK E,1 :B7C40: CBIT 6,[HL] ;SET NDAC HIGH :B7C50: LK A,255 :BJMP COUT O2SP: ;OUTPUT 2 SPACES ON CONSOLE CALL OSP OSP: LK C,' ' JMP COUT RLWA = * ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',RLWA IF RLWA > 0FFFH .9 ERROR CODE TOO LARGE.. ENDIF ; endx BMUTIL2.asm ; END OCCROM9?.??? ALL CO ;SEND TO TERMINAL POP AF ;GET BACK ARGUMENT CALL PRVAL JMP CO SPACE 4,10 PRVAL: ;CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO ; THE CORRESPONDING ASCII CHARACTER, 0-9,A-F. PRVAL ; DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT. ; ENTRY A= INTEGER, RANGE 0 TO F ; EXIT A= ASCII CHARACTER. ; C= A ; CALLS NONE. ; DESTROYS: AF AND 0FH ADD A,90H ;SET UP A SO THAT A-F CAUSE A CARRY DAA ;ADJUST CONTENTS OF A REGISTER ADC A,40H ;ADD IN CARRY AND ADJUST UPPER 4 BITS DAA ;ADJUST CONTENTS OF A REGISTER AGAIN MOV C,A RET OCRLF: ;OUTPUT CR,LF ON CONSOLE SCREEN LK C,CR CALL COUT LK C,LF O 0011_1111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB STO 0001_0010B,[HL] ;CONTROL SIGNAL INITIAL VALUE XOR A ;CLEAR ERROR CODE :B4C40: POP HL RET PAGE ;BIOS CALL 5: OUTPUT INTERFACE MESSAGE ; ; CAN BE CALLED WHILE IN ANY MODE OR STATE ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ; ;MULTI-LINE MESSAGE IN REGISTER C ; ;ERROR CODE RETURNED IN REGISTER A ; IE.OIM: PROC PUSH HL LK HL,CPDRB SBIT 4,[HL] ;SET ATN LOW BIT 0,[HL] JRZ IE.SHK ;SET-UP FOR SOURCE HANDSHAKE STO 0001_0111B,[HL] ;DISABLE DRIVERS LD A,CCRB CBIT 2,A STO A,CCRB STO 0011_1111B,[HL] ;DIRECTION REGISTER SBIT 2,A STO A,CCRB XOR A ;FLOAT EXTERNAL DATA BUS STO A,CPDRA STO 0001_0010B,[HL] ;CONTROL SIGNAL INITIAL VALUE JR IE.SHK PAGE ;BIOS CALL 6: OUTPUT DEVICE MESSAGE ; ; CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE ; WITH ATN HIGH OR LOW. ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN HIGH. ; ;MULTI-LINE MESSAGE IN REGISTER C ;EOI REQUEST IN REGISTER B ; 7C60: BIT 5,[HL] JRZ :B7C70 ;DATA VALID DROPPED DEC A JRNZ :B7C60 ;WAIT 1000 MICRO-SEC SBIT 2,E ;SET DATA INVALID TIMEOUT ERROR SBIT 7,E JR :B7C80 :B7C70: SBIT 6,[HL] ;SET NDAC LOW :B7C80: EX DE,HL ;MOVE RESULTS TO REGISTERS A AND HL MOV A,H POP DE RET SPACE 4,21 ;BIOS CALL 8: PARALLEL POLL ; ; CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE ; WITH ATN HIGH OR LOW. ; ; EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ; ;PARALLEL POLL VALUE RETURNED IN A. ; IE.PP: PROC PUSH HL LK HL,CPDRA LK A,0001_1011B ;FORM PARALLEL POLL STO A,CPDRB STO 1111_1111B,[HL] ;FLOAT INTERNAL DATA BUS LD A,[HL] ;READ PARALLEL POLL DATA STO 0,[HL] ;RE-STORE SOURCE HANDSHAKE MODE LK HL,CPDRB STO 0001_0010B,[HL] POP HL RET ; END OCCROM4?.??? DATA MOV D,A LK E,0 ;READ EOI BIT 3,[HL] JRZ :B7C40 LK E,1 :B7C40: CBIT 6,[HL] ;SET NDAC HIGH :B7C50: LK A,255 :B!;OCCROM0B.ASM TITLE 'Osborne-One Monitor for Model 1 system.' * 4D2008-00 MASTER .ASM * 2D2008-00 ASSY .ASM * 1D2008-00 LISTING .PRN * 4D1008-00 MASTER .COM * 2D1008-00 ASSY .COM LIST -F ;4-25, Do not list opted out code ; Initial Monitor for Osborne-One System. ; +-------------------------------+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV B ;DATE = 227 ;DEB ; Assembly Constants ORG 0 ;FWA of memory @XFRMT = TRUE ;FALSE IF FORMAT IS IN ROM INACMD = FALSE INBCMD = TRUE INDCMD = FALSE INFCMD = FALSE INGCMD = FALSE INHCMD = FALSE INMCMD = FALSE INRCMD = FALSE INSCMD = FALSE INTCMD = FALSE INXCMD = FALSE INZCMD = FALSE INDIA = TRUE ;INTERNAL DIAGNOSTICS INDMON = FALSE INUTIL = FALSE NULINT MACRO NUMB ORG %1*8 DI JMP ILINT NOP ! NOP ! NOP ! NOP ENDM PUSHAL MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM POPALL MACRO POP IY POP IX POP HL POP DE POP BC POP AFY ;if NO data DI MOV C,A XRA A STO A,LKEY ;clear key from hold MOV A,C AND 7Fh MOV C,A ;A=C EI RET space 4,10 NORM: ;Normalize to UPPER case ; Entry A= char ; Exit A= CHAR CMP 'a' RC ;if upper CMP 'z'+1 RNC ;if not lower SUI 'a'-'A' RET REPD = 45 ;initial rep delay REPK = 5 ;repeat constant .nkbd IF @KEY = 0 ;if not new keyboard, use old code GKEY: ;Keyboard interrupt processor. ; Scans both sets of data lines to see if any key ; pressed. If so then determines key and ; Sets TKEY to value. ; If TKEY and next key same then HKCNT set. ; If HKCNT set and no key on this entry, then ; LKEY is set and we have found a valid key closure. ; Entry None ; Exit Cbit set if key RNK5: = 21h ;rank 5 RNK6: = 01h ;rank 6 RNKCTL: = 0A0h ;Control rank proc .mac IF RSIZE = 64 DI .mac ENDIF STO SP,IESTK ;save int process stack LDK SP,ISTK ;set to RAM int stk PUSHAL ; Update and display current time CALL UPTIM ;update time ; Perform Scan JRZ :20 ;if [, shifted = ']' CMP '1' JRC :19 ;if not shiftable CMP 'A' JRNC :18 ;if possible alpha SUB 10h JR :19 :18: CALL NORM :19: MOV C,A ; Here to actual set key ; Entry C= current keystroke value :20: SBIT 7,C ;set bit 2**7 LD A,TKEY CMP C JRZ :16 ;if last = current MOV A,C STO A,TKEY ;confirm key (debounce) STO A,LKEY LDK A,REPD STO A,HKCNT ;set to surface next time ; JR GKEYX ;exit ; restore regs, clear interrupt and return GKEYX: JMP EXITI ;Exit interrupt ; Here if debounced key, process SHIFT, Control and ; REpeat functions ; Entry C= current character :16: LDK HL,HKCNT DEC [hl] ;reset hold count JRNZ GKEYX ;if keep holding MOV A,C :16A: STO A,LKEY ;show keep to user MOV C,A ;save current key LDK A,REPK STO A,HKCNT ;reset hold for repeat JR GKEYX ;exit page RDKEY: ;Read keyboard for valid key pressure ; Exit A= current key ; if A = -1, exit to GKEYX ; = -2, NO key pressure proc .rdkey IF @KEY = 0 L ENDM PAGE LINK OCCROM1B.ASM ;ROM STANDARDS ;LOP,ROMD LINK OCCROM2B.ASM ;CPM BOOT ;BOOT LINK OCCROM3B.ASM ;CONSOL ROUTINES ;KEY LINK OCCROM4B.ASM ;PIA ROUTINES ;PIO,IEEE LINK OCCROM5B.ASM ;SIA ROUTINES ;SIO LINK OCCROM6B.ASM ;DISK ROUTINES ;DSK LINK OCCROM7B.ASM ;DIAGNOSIC ROUTINES ;DIA LINK OCCROM8B.ASM ;FORMAT ROUTINE ;XFMT LINK OCCROM9B.ASM ;UTILITES ;UTIL2 LINK OCCRAMA.ASM ;RAM LOCATIONS ; Endx F FORMAT IS IN ROM INACMD = FALSE INBCMD = TRUE INDCMD = FALSE INFCMD = FALSE INGCMD = FALSE INHCMD = FALSE INMCMD = FALSE INRCMD = FALSE INSCMD = FALSE INTCMD = FALSE INXCMD = FALSE INZCMD = FALSE INDIA = TRUE ;INTERNAL DIAGNOSTICS INDMON = FALSE INUTIL = FALSE NULINT MACRO NUMB ORG %1*8 DI JMP ILINT NOP ! NOP ! NOP ! NOP ENDM PUSHAL MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM POPALL MACRO POP IY POP IX POP HL POP DE POP BC POP AF of Keyboard LD A,KEYLCK ;locked keyboard? OR A JZ GKEYX ;if locked keyboard, can't read chrs CALL RDKEY ;read keyboard CMP -2 JRNZ :4 ;if key depressed ; Here if no key press, check for holding ; debounced key, if so surface key. :2: LD A,TKEY BIT 7,A JRZ :3 ;if no key holding LD A,LKEY STO A,TKEY ;clear-set hold :3: JMP GKEYX ;exit :4: PUSH AF CALL RDKEY ;Try again POP DE ;last A CMP D JRNZ :2 ;if not match, error CMP -1 JZ GKEYX ;if null control key ; A= current key pressed ; TKEY = last scan key found GKEY10: MOV C,A ;save current key LD A,CKEY ;control key value OR A JRZ :20 ;if no special function keys ; If special, check type BIT 6,A ;40h JRZ :17 ;if NOT contrl key ; Process Control key ; Check for ^1, 2, or 3 for fixed alignment MOV A,C CMP '1' LDK C,VFLO JRZ :10B ;if ^0, align to 0 offset CMP '2' LDK C,VFLO+2*52 ;2*52 compensates for 1/2 chr shift JRZ :10B ;if ^1, align to 52 CMP '3' LDK C,VFLO+4*52 ;4D A,H.KEY+0DFh CMA MOV B,A LD A,H.KEY+07Fh ;everything but cntrl rank CMA OR B LDK A,-2 RZ ;if NO key pressure ; save any contrl keys LD A,H.KEY+RNKCTL CMA STO A,CKEY ;save control key ; B <> 0 means Bit 5 table MOV A,B OR A JRZ :5 ;if bit 5 table :3: LDK HL,H.KEY+1 LDK DE,T6KEY-1 JR :5A ;process ; Here if Bit 5 set :5: LDK HL,H.KEY+21h LDK DE,T5KEY-1 :5A: LDK BC,0 :5B: LD A,[hl] ;get next scan line CMA OR A JRNZ :6 ;if key active PUSH BC LDK IX,SCANI ADD IX,BC LD C,[ix+0] ADD HL,BC ;next line POP BC INC BC JR :5B ;loop to next SCANI: DB 1,2,4,8,30h,40h ; Here with C = address line ; A= key down bit :6: PUSH AF ; Check for control key rank MOV A,L CMP RNKCTL JRNZ :6A ;if not control rank LD A,H.KEY+0DFh CMA OR A JRNZ :3 ;if key active in other rank STO A,TKEY ;clear key POP AF ;restore stack LDK A,-1 ;indicate exit RET ; Process active key :6A: MOV A,C ANI 7 ;get relative to 0 RAL ! RAL ! TITLE 'Keyboard and Console Routines.' @KEY = 1 ; Control keys CBELL = 'G'-40h ;Ring the Bell MCUP = 'K'-40h ;Move cursor up MCDOWN = LF ;Move cursor down MCLEFT = BKS ;Move cursor left MCRIGH = 'L'-40h ;Move cursor right VCLRS = 'Z'-40h ;Clear and home cursor VHOME = '^'-40h ;Home Cursor ; Escape keys VLOCK: = '#' ;Lock Keyboard VUNLK = '"' ;Unlock Keyboard VCAD: = '=' ;Cursor Addressing VSAD: = 'S' ;Screen Addressing VINC: = 'Q' ;Insert Char VDELC: = 'W' ;Delete char VINL: = 'E' ;Insert line VDELL: = 'R' ;Delete line VCEOL: = 'T' ;Clear to end of line VSHI: = ')' ;Start half intensity VEHI: = '(' ;end VSUL: = 'l' ;Start underline VEUL: = 'm' ;end VSGH: = 'g' ;Start graphics VEGH: = 'G' ;End SKEY: ;Get status of keyboard ; Exit Cbit set if no data ready LD A,KEYLCK OR A RZ ;if locked keyboard LD A,LKEY BIT 7,A RET ;=0 if NO DATA space 4,10 CI: RKEY: ;Read next key from keyboard ; Exit A=C= last key proc CALL SKEY JRZ RKE*52 = 208 shifts = 104 characters JRZ :10B ;if ^2, align to 104 ; Check for special control code sceen movement codes ; if so process local and return LDK E,2 CMP MCLEFT JRZ :10A ;if move screen LDK E,-2 CMP MCRIGH JRNZ :10C ;if not screen right :10A: LD A,PIAAD ;current horz offset ADD A,E MOV C,A :10B: CALL OPAD ;reset offset hardware XRA A ;clear entry key JR GKEYX ;exit :10C: CMP ' ' JC :20 ;if literal CMP '@' LDK C,0 JC :20 ;if illegal code CALL NORM SUB '@' CMP ' ' JNC :20 ;if illegal JR :19 ;converted control code ; Check for SHIFT key ; A= shift status ; C= current character :17: BIT 5,A ;20h JRZ :20 ;if NOT shifted MOV A,C ;get actual char ; Check for legal SHIFTED code :17B: CMP ',' JRC :19 ;if impossible shift CMP '/'+1 JRNC :17C ;if not ascii reverse pairing ADD A,10h JR :19 :17C: CMP '0' LDK C,'^' JRZ :20 ;if O, shifted = '^' CMP '@' LDK C,'\' JRZ :20 ;if @, shifted = '\' CMP '[' LDK C,']' " RAL ;*8 MOV C,A LDK B,0 EX DE,HL ;base to HL ADD HL,BC LDK BC,0 POP AF ;get bit back OR A ;clear carry ; Now convert bit value to binary :7: INC C RRC JRNC :7 ;if not bit ADD HL,BC ;add in value ; Get Actual Key pressure value into A. LD A,[hl] ;get table value RET .rdkey ELSE LD A,H.KEY+0FFh XOR 0FFh ;1s complement, set flags MOV B,A LDK A,-2 RZ ;if no key ; Read CNTRL rank and save LD A,H.KEY+01 CMA STO A,CKEY ;save it ; Key depressed, check for which rank, make ; sure its legal, ie. not just CNTRL key. LDK DE,2 ;ignore contrl rank LDK B,6 ;number of ranks-CNTRL rank :3: LDK HL,H.KEY ;base ADD HL,DE ;address of next rank LD A,[hl] ;get possible entry XOR 0FFh JRNZ :7 ;if found key pressure DEC B JRZ :5 ;if all done with scan EX DE,HL ;power of 2 to DE ADD HL,HL ;*2 EX DE,HL ;next rank to DE JR :3 ;continue ; Here if suppose to be key down, but none ; found in non-CNTRL key ranks. Check for TAB, ; eF, ':', '/', ';', '\', '1', '-' ENDIF .nkbd ENDIF page UPTIM: ;Update time via 60hz interrupt ; Time is kept in video memory as ; hhmmss (3 locations) ; Routine also checks to see if the disk drive motor ; should be turned off by updating DACTIVE ; ...Routine ALSO checks to see if bell is currently ; ringing: if so, decrement counter. ; if counter turns zero, shut off bell. Proc LK HL,BELCNT XOR A OR [hl] ;cell=zero ? JRZ :2 ;if bell now off DEC [hl] ;...bell is on. decrement counter JRNZ :2 ;if bell should stay on awhile yet LD A,PIABD AND 1101_1111b ;clear bell bit MOV C,A CALL OPBD :2: DEC HL ;HL => DACTVE LD A,[hl] OR A JRZ :3 ;if inactive DEC [hl] ;reset delay CZ DDRV ;if deselect drive :3: DEC HL ;HL => SEC6 DEC [hl] RNZ ;if not 1 sec transition STO 59,[hl] ;60th tick is NOW XOR A ;A:=0, CY:=0 for DAA DEC HL ;HL => SECS LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 60h RC ;if not 60 secs STO 0,[hl] ;reset seconds DEC HL Lelete line DB VCEOL ! DW EEOL ;Clear to end of line DB VLOCK ! DW ESCLCK ;Lock Keyboard DB VUNLK ! DW ESCULK ;Unlock Keyboard :end: DW COUT2 ;No Match exit ; Ignore char upon undefined ESC-Sequence ; (to treat undefined char after ESC as a regular ; data char, should go to COUT2). VALETS: = (:end-VALIDE)/3 ;# of entries in table space 4,10 VALIDC: ;Valid control character table ; 3 bytes per entry: Ascii char , "DW"- Vector ; no. of entries is VALCTS ; Following body of table is 2 byte No-Match adrs DB CR ! DW VC_CR ;carriage return routine DB LF ! DW VC_LF ;line feed DB BKS ! DW VC_BKS ;back space DB MCRIGH ! DW VC_MCRT ;move cursor right DB MCUP ! DW VC_MCUP ;move cursor up DB 'A'-40H ! DW VSHFT_L ;shift screen left DB 'B'-40H ! DW VSHFT_R ;shift right DB 'C'-40H ! DW VSHFT_0 ;left column (^1) DB CBELL ! DW VC_BEL ;Ring bell DB VCLRS ! DW VC_CLRS ;clear screen DB VHOME ! DW VC_HOME ;Cursor Home ; DW VOUT97 ;No match--ignore undef control char ; lse key down is to be ignored. :5: LDK HL,T5KEY LD A,CKEY OR A JRZ :nokey ;if no CNTL-key sensed either CALL DRNK ;check for tab CMP TAB RZ ;if tab :nokey: LDK A,-2 ;indicate NO key, just CNTRL RET ; Here if found key down i non-CNTRL ranks ; HL = rank address ; A = value ; B = 7..1, 7-(ordinal of rank) :7: PUSH AF ;save value LK A,8 SUB B ;A = ordinal of rank RLC ! RLC ! RLC ;*8 to get address MOV E,A LDK HL,T5KEY ;base for decode LDK D,0 ADD HL,DE ;get key decode base POP AF DRNK: ;Decode rank value ; Entry A= rank value read ; HL=fwa of rank entry ; Exit A= key value in ASCII LDK BC,-1 OR A ;clear carry :8: INC BC ;update base adder RRC JRNC :8 ADD HL,BC LD A,[hl] ;get actual key RET .rdkey ENDIF page ; Character input translation table IF @KEY = 0 T5KEY: DB ESC, ESC, ERC, ERC, ERC, ERC, ERC, ERC ;5KEY: DB TAB, ESC, ERC, ERC, ERC, ERC, ERC, ERC DB '1', '2', '3', '4', '9', '0', ':', '-' ; DB '1',D A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 60h RC ;if not 60 minutes STO 0,[hl] DEC HL LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 25h RC ;if time <= 24:59:59 STO 1,[hl] RET page CO: ;Output routine for monitor ; Entry C= char ; CO will process ^p to toggle ; echo to list device ala cpm. ; Exit C=C=A. proc MOV A,C CMP 'P'-40h JRNZ :5 ;if not toggle echo list LD A,ECHOP CMA STO A,ECHOP ;toggle list echo :2: MOV A,C ;perserve A RET :5: CALL COUT ;output char LD A,ECHOP OR A JRZ :2 ;if no echo to list JMP LIST ;echo it page ; Bit definitions for ESCH flag byte ; Note Bit 7 is currently free. EF_X: = 64 ;B6= extegting X-coordinate EF_SCR: = 32 ;B5= Screen/Cursor Addressing EF_ADR: = 16 ;B4= expegting address-chr EF_ESC: = 8 ;B3=$last char was ESC EF_UN: = 4 ;B2= Underline mode EF_HA: = 2 ;B1= Half Intensity mode EF_GR: = 1 ;B0= Graphics mode EF_MSK: = EF_UN+EF_HA+EF_GR ;Mask to get mode. space 4,10 ; Vector (branch) table for v VALCTS: = ((*-2)-VALIDC)/3 ;Number of valid entries page COUT: ;General output routine to Video Screen ; ENTRY C=Character, CURS=Cursor, ESCH=Flag+Mode ; EXIT CURS & ESCH updated, A=Character ; (bc, de, hl preserved) ; ; ESCH is flag + mode byte as follows ; =00 Normal mode & Last chr Esc flag false ; =08 Normal mode & Last chr Esc flag True ; =01,02,04 Mode is Graphics, Half, or Under, respectively ; , and Last chr Esc flag is False. ; =3,5,6,7 As above, but mode is combination ; =9-15 Last chr Esc flag True;otherwise like 1-7. proc PUSH HL PUSH DE PUSH BC LD HL,CURS ;HL will usually be cursor. LD A,ESCH MOV B,A ;B will be ESCH for a while AND EF_ESC ;test flag bit JRNZ PSTESC ;IF last chr was ESC ;Current chr is NOT ESCaped. Is this chr ESC? MOV A,C ;Chr CMP ESC MOV A,B ;(A=ESCH) JRZ :ESC ;if this chr = ESC space 4,10 ;Here with A=B= ESCH :out: PUSH HL LK HL,ESCHTB AND EF_MSK ;Mode bits only ADD A,A ;Times two MOV E, '2', '3', '4', '9', '0', '-', '~' DB 'q', 'w', 'e', 'r', 'o', 'p', '@', 7Fh ; DB 'q', 'w', 'e', 'r', 'o', 'p', '{', '}' DB 'a', 's', 'd', 'f', 'l', ';', BKS, FMFD ; DB 'a', 's', 'd', 'f', 'l', ';', ':', '\' DB 'z', 'x', 'c', 'v', ERC, '.', '/', ERC DB ' ', ERC, ERC, ERC, ERC, ERC, ERC, ERC DB ERC, ERC, ERC, REP, CAPS, SHTK, CTRL, ERC T6KEY: DB ERC, ERC, ERC, BKS, VTAB, ERC, ERC, ERC DB '6', '5', '7', '8', '[', ERC, ERC, ERC DB 'y', 't', 'u', 'i', '-', ERC, ERC, ERC DB 'h', 'g', 'j', 'k', CR, ERC, ERC, ERC Db 'n', 'b', 'm', ',', LF, ERC, ERC, ERC ELSE T5KEY: T6KEY: DB ESC, CTRL, CAPS, SHTK, CR, TAB, TAB, '_' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',' DB MCUP, BKS, '0', ' ', '.', 'p', 'o', 'p' DB MCRIGH DB Lideo output mode selection ; controlled by ESCH mode ESCHTB: DW VNORM ;0 Normal mode DW VGRAPH ;1 Graphics mode DW VHALF ;2 Half intensity mode DW VHA_GR ;3 Half and graphics DW VUNDER ;4 Underline mode DW VUN_GR ;5 Under and graphics DW VUN_HA ;6 Under and half intensity DW VUN_HA_GR ;7 Under and half and graphics space 4,10 VALIDE: ;Valid ESC-Sequence Table ; 3 bytes per entry:ascii char , "DW"-Vector. ; no. of entries is VALETS ; Following body of table is 2 byte No-Match adrs DB VCAD ! DW ESCCAD ;Cursor Addressing DB VSAD ! DW ESCSAD ;Screen Addressing DB VSGH ! DW ESCSGR ;Set graphics mode DB VEGH ! DW ESCCGR ;Clr graphics mode DB VSHI ! DW ESCSHA ;Set half int. mode DB VEHI ! DW ESCCHA ;Clr half int. mode DB VSUL ! DW ESCSUN ;Set underline mode DB VEUL ! DW ESCCUN ;Clr underline mode DB VCLRS ! DW ESCZZ ;Clear screen to blanks DB VINC ! DW EINSRT ;Insert char DB VDELC ! DW EDELC ;Delete char DB VINL ! DW ESCEE ;Insert line DB VDELL ! DW ESCRR ;D#A LK D,0 ;DE = offset ADD HL,DE ;HL = tbl addrs VECTOR: ;entry point. note hl on stack. LD A,[HL] ;1st byte (low order adrs) INC HL LD H,[HL] ;2nd byte (hi order adrs) MOV L,A ;HL=adrs from table XTHL ;Restore hl from stack ;stack=tbl adrs MOV A,C ;Chr. note B=ESCH byte value RET ;enter routine per table adrs. COUT2: MOV A,B ;recall ESCH value JR :out ;output chr per current settings :ESC: ;Current chr is ESC. Set flag and exit OR EF_ESC ;indicate last char= ESC STO A,ESCH JMP VOUT97 ;Exit space 4,17 PSTESC: ;Last chr was ESC ; Entry A= EF_ESC ; B= ESCH ; C= Char to output ; HL=curs Proc BIT 4,B ;is this chr really an address? JRNZ SETXY ;...if chr is part of an addr ;no cursor/screen addressing in effect: XOR B ;Clr EF_ESC bit (for next time) MOV B,A ;Set up B = ESCH byte value. STO A,ESCH PUSH HL ;save Curs LDK HL,VALIDE ;Branch table adrs LDK E,VALETS ;Table size MOV A,C ;Chr to A JR LOOKUPB ;Go to routine to bran :sY: AND 0001_1111b ;mod 32 MOV C,A LD A,PIABD AND 1110_0000b OR C MOV C,A CALL OPBD ;set Y coordinate JR :exitY :sX: ADD A,A ;double A ADD A,VFLO ;PIA A-reg magic offset constant AND 1111_1110b ;clear bit 0 => no 1/2 chr shift MOV C,A CALL OPAD ;set X coordinate CBIT 5,B ;finished screen-addressing JR :exitX space 4,10 SETXY: ;Set X-Y value for Cursor/Screen Addressing ; Entry HL= cursor_addr ; B = ESCH ; C = chr ; Exit to VOUT90; ESCH updated CALL UN_CUR LK A,-(' ') ADD C ;remove cursor bias BIT 5,B ;cursor/screen addressing? JRNZ SCREEN ;if screen addressing ;cursor addressing: ADD HL,HL ;shift HL left BIT 6,B ;X/Y coordinate? JRNZ :cX ;if X coordinate :cY: MOV H,A ;save LD A,PIABD ADD H ;offset by start-Y co-ord of video RAR ;bit0(A) -> CY, shift A right RR L ;CY -> bit7(L) OR 0F0h ;turn on upper nybl MOV H,A ;HL= new cursor addr ; JR :exitY :exitY: LK A,0100_0000b ;next addr-chr will be X-coord OR B JR :exit2 :cX: page ; Exit points for COUT ; Here to store new data and to update cursor VGRAPH: VOUT80: STO A,[hl] ;This exit path stores A (new char) MOV E,L CBIT 7,E ;E = col(cursor) LD A,LLIMIT DEC A ;A = last_legal_col SUB E ;A = last_legal_col - col(cur) JRNZ VOUT85 ;if not @LLIMIT LK A,80h AND L MOV L,A ;do CR... CALL DO_LF2 ;...and LF. JR VOUT90 VOUT85: INC HL ;move cursor ; Here if NO cursor update VOUT90: LD A,[HL] ;This exit path turns on 80h bit ; Here if new data already in A VOUT95: RAL ;Make this chr cursor VOUT96: CMC ;invert cursor bit RAR STO A,[hl] STO HL,CURS ;update cursor ; Here if no change to cursor, restore reg and exit VOUT97: POP BC POP DE POP HL MOV A,C ;Exit with A=chr RET ;return, end of cout subr. space 4 :First = VOUT97 - (127 + 2) ;earliest possible JR :Last = VOUT80 + (128 - 2) ;latest possible JR page ESC_LCK: ;Lock Keyboard Proc XOR A JR :2 ESC_ULK: ;Unlock Keyboard LK A,0FFh :2: STO A,KEYLCK ch per tbl space 4,15 VNORM: ;NORMAL mode character processing. ; Entry A= char to output ; HL=curs CMP ' ' JRC :2 ;IF control chr VBRIGH: DI ! ENADIM ;9th bit memory STO BRTBIT,[hl] ;set this chr BRIGHT DISDIM ! EI JMP VOUT80 :2: PUSH HL ;Save Curs LDK HL,VALIDC ;Branch table adrs LDK E,VALCTS ;Table size ; JMP LOOKUPB ;Scan table of valid control chrs ; ;and branch to appropriate routine. space 4,20 LOOKUPB: ;Logic to scan 3 byte branch table ; NOT a subroutine---do not CALL. ; Entry HL =1st byte of table (match code) ; (2nd,3rd bytes = branch adrs) ; (table repeats [3 byte entries]) ; E is table size (no. of entries) ; (table body is followed with ; 2 byte "No-Match" adrs) ; Stack has HL saved as top entry. ; C = char ; A = value to scan for possible match CMP [HL] INC HL ;(2nd byte of this 3 byte entry) JRZ VECTOR ;If match process INC HL ;(3rd byte of this entry) INC HL ;1st byte of next entry DEC E ;Dec count of entries remaining JRAL ;trash 7th bit SRA H ;bit0(H) -> CY, bit7 stays 1 RAR ;... CY -> bit7(A) MOV L,A ; JR :exitX :exitX: LK A,EF_MSK AND B ;finished addressing: reset addr bits :exit2: STO A,ESCH JMP VOUT90 page ; Control Code character processing VC_HOME: ;Home Cursor Proc CALL UN_CUR LD A,PIABD RAR ;bit0 => CY LK L,0 RR L ;CY => bit7, trash bit0 MOV H,A JR :fixhl ;HL := HL or F000h space 4,7 VC_MCUP: ;Move Cursor Up. ; A=C=Chr=MCUP. HL=Curs. CALL UN_CUR PUSH HL ;old cursor must be on stack LK BC,(-VLL) JR :fwa ;...at this entry point space 4,28 VC_BKS: ;HL=Curs=current (old) char CALL UN_CUR ;clear 80h bit LK A,7Fh AND L JRZ :wrap ;if must wrap from col 0 to LLIMIT DEC HL JR VOUT90 ;Exit :wrap: PUSH HL ;save old cursor LK BC,-(VLL+1) ADD HL,BC ;HL = prev_line, (-1)st column LD A,LLIMIT ;LLIMIT = #columns on screen MOV C,A LK B,0 :fwa: ADD HL,BC XTHL ;get old cursor, save new ADD HL,HL ;shift line# into H reg. LD A,PIA JR VOUT97 space 4,5 EEOL: ;Erase to end of line PUSH HL ;save cursor CALL CLRLN POP HL JR VOUT90 space 4,12 ESC_CAD: ;Cursor Addressing LK A,EF_MSK AND B OR EF_ESC or EF_ADR ;next chr will be Y-coord :exit3: STO A,ESCH JR VOUT97 ESC_SAD: ;Screen Addressing LK A,EF_MSK AND B OR EF_ESC or EF_ADR or EF_SCR JR :exit3 page ;Subroutine for use with EDELC and EINSRT: ;Calculate #chrs to move; if move zero chrs, never return. Proc :calc: LK A,VLL-1 ;A= max #chrs to be moved MOV C,L CBIT 7,C ;C = col(cursor) SUB C ;A = #chrs to move JRZ :end ;if move zero characters MOV C,A LK B,0 ;BC = #chrs to move RET :end: POP HL ;trash return_addr POP HL ;cursor_addr JR VOUT90 space 4,14 EDELC: ;Delete Character PUSH HL ;save cursor_addr CALL :calc ;calculate BC MOV D,H MOV E,L ;DE = cursor_addr INC HL ;HL = cursor_addr + 1 CALL VLDIR ;move characters STO ' ',[hl] ;last chr becomes blank DI ! ENADIM ;enable 9th bit memory DEC HL ;HL = last RNZ LOOKUPB ;Continue thru body of table JR VECTOR ;No-Match. hl=points to vector page ; Processing for modes other than normal. ; -------------------------------------- ;VGRAPH = VOUT80 ;Normal mode EXCEPT: cntl chrs are printed VUNDER: ;Underline only CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VUN_GR ;continue VUN_GR: ;Underlined Graphics OR 80h ;underline bit JR VBRIGH ;set this chr BRIGHT VUN_HA: ;Underline and Half intensity CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VUN_HA_GR VUN_HA_GR: ;Underline, Half Intensity, Graphics OR 80h ;set underline bit ; JR VHA_GR VHALF: ;Half Intensity CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VHA_GR VHA_GR: ;C=Chr, HL=Curs DI ENADIM STO DIMBIT,[hl] ;set dim field bit ; LD E,[hl] ;diagnostic DISDIM EI JMP VOUT80 ;continue space 4,22 SCREEN: ;SetXY for Screen movement ; Entry B= ESCH ; A= new co-ord val, NO OFFSET Proc BIT 6,B JRNZ :sX ;if X-coordinate BD OR 1110_0000b ;A = line# of UL corner CMP H ;set Zflag: @home? POP HL ;get new cursor... JRNZ :fixhl ;if NOT @video home LK BC,(24*VLL) ;wrap constant ADD HL,BC :fixhl: LK A,0F0h OR H ;modulo result: keep cursor MOV H,A ;inside video memory. JR VOUT90 space 4,8 VC_BEL: ;Ring the bell via setting PIAB 2**5 bit LD A,PIABD OR 0010_0000b ;bell bit MOV C,A CALL OPBD ;function PIAB LK A,30 ;ring bell for 30 ticks STO A,BELCNT ;... = 1/2 second JR VOUT97 ;exit no change space 4,10 VC_CLRS: LK HL,FWAVM CALL CLRLN ;clear 1st line LK BC,LVMEM-VLL CALL VLDIR ;clear remaining lines LD A,PIABD ;Reset for 1st line of display mem AND not(1_1111b) MOV C,A CALL OPBD LK HL,FWAVM ;new cursor JR VOUT90 ;Exit space 4,8 VC_CR: CALL UN_CUR ;erase cursor LK A,80h ;Carriage Return AND L MOV L,A JR VOUT90 VC_LF: CALL DO_LF ;Line Feed JR VOUT90 space 4,3 VC_MCRT ;Move Cursor Right CALL UN_CUR LD A,[hl] ; JR VOUT80 ;re-echo current chr $chr on this line STO BRTBIT,[hl] ;set chr BRIGHT DISDIM ! EI ;main memory POP HL ;restore cursor_addr JR VOUT90 ;next space 4,14 EINSRT: ;Insert Character CALL UN_CUR PUSH HL ;save cursor_addr CALL :calc ;calculate BC LK A,7Fh OR L MOV L,A ;HL = last_chr on this line MOV E,A MOV D,H ;DE = HL DEC HL CALL VLDDR ;do move POP HL ;restore cursor LD A,[hl] ;get underline bit of this chr. RAL ;into CY LK A,' ' shl 1 ;change this chr to ' ' JR VOUT96 ;exit page ; ESC-Sequence processing. Proc ESCSGR: LDK A,EF_GR ;ESC-g JR :125 ;set graphics mode. ESCSHA: LDK A,EF_HA ;ESC-) set half intensity JR :125 ;go set flag bit ESCSUN: LDK A,EF_UN ;ESC-l set underline :125: OR B ;Reg B is ESCH Byte value :130: STO A,ESCH ;store desired value. JR VOUT97 ;Exit ESCCGR: LDK A,NOT EF_GR ;ESC-G Clear graphics mode JR :140 ;go clear ESCH bit ESCCHA: LDK A,NOT EF_HA ;ESC-( Clear half intensity JR :140 ESCCUN: LDK A,NOT EF_UN ;ESC-m Clear underlend of line ; Entry HL= Cursor ; Exit clear to EOL ; Uses All. proc STO ' ',[hl] ;clear cursor... DI ENADIM STO BRTBIT,[hl] ;set cursor BRIGHT DISDIM EI LD A,LLIMIT DEC A ;max_#cols => maximum_col_# MOV E,L CBIT 7,E SUB E ;A = col(EOL) - col(cursor) RZ ;if @EOL, done JRNC :2 ;if inside logical_video_line LK A,VLL SUB E ;...else clr to end of 128-chr line RZ ;if cursor @ column #127 :2: MOV C,A LK B,0 ;BC = chrs to move MOV E,L MOV D,H INC DE ;DE = HL + 1 JR VLDIR page DO_LF: ;Do Line Feed processing ; Entry HL = cursor_addr ; Exit Cursor cleared ; HL updated for current cursor pos ; window moved if necessary proc CALL UN_CUR ;clear cursor DO_LF2: PUSH HL ;save original cursor LK BC,VLL ;line length ADD HL,BC JRNC :nowap ;if not wrapping from LWAVM to FWAVM LK BC,FWAVM ADD HL,BC ;HL = new cursor @ top of VM :nowap: XTHL ;save new cursor, get old ADD HL,HL ;shift HL left LD A,PIABD ADD A,23 ;start + 23 = last_videoYBOARD: LK HL,TKEY CMP [HL] ;SAME AS LAST TIME? (SET Z FLAG) STO A,[HL] ;SET TKEY TO CURRENT VALUE MOV B,A ;SAVE CHR LK HL,HKCNT JRNZ :1ST ;IF THIS IS FIRST SUCH KEYPRESS MOV A,[HL] CMP 0 JZ :2ND ;SECOND TIME FOR THIS KEY :AUTO: DEC [HL] JRNZ GKEYX ;IF STILL WAITING FOR REPD/REPK STO REPK,[HL] ;...ELSE SET REPK FOR NEXT CHR, JR :DCODE ;AND RETURN CHR :1ST: LD A,KBDLY ;GET # OF INTERRUPTS TO DEBOUNCE CALL DELAY XRA A ;ZERO "HKCNT" STO A,HKCNT JR :SCAN :2ND: STO REPD,[HL] ;SET "REPD" DELAY :DCODE: MOV A,B ;RESTORE CHR CALL SHIFT ;SHIFT PROCESSING LK HL,CKEY BIT 2,[HL] ;CK FOR CNTL KEY JRZ :FIN ;IF CNTL-KEY IS NOT PRESSED CALL SLIDE ;CK FOR SCREEN SLIDE KEYS CALL CNTRL ;CNTRL KEY PROCESSING :FIN: OR 80H ;SET PARITY BIT FOR CI STO A,LKEY ;MAKE CHR AVAILABLE TO CI GKEYX: JMP EXITI ;EXIT INTERRUPT GKEYAB: ;ABORT PROCESSING: SET TKEY := -2 AND RETURN. LK A,-2 STO A,TKEY JR GKEYX PAGE SHIFT: ;SHIFT KEY PROCESSING ; ENTRine :140: AND B ;Clear bit JR :130 ;Go store ESCH byte ESCZZ: = VC_CLRS ;ESC-Z Clear screen -same as ; ;Control-Z routine. page Proc VSHFT_L: ;shift screen left LK C,+2 JR :slide VSHFT_R: ;shift screen right LK C,-2 :slide: DI LD A,PIAAD ;get old offset ADD C ;modify... MOV C,A :1: CALL OPAD ;new setting for video offset EI JMP VOUT97 VSHFT_0: ;shift to column #0 (like ^1) LK C,VFLO ;constant for column #0 JR :1 ;set video offset page ESCRR: ;Delete Line ESCEE: ;Insert Line ; Entry HL = cursor ; C = chr ; Exit screen updated ; HL = new cursor ; ...to VOUT90 Proc CALL UN_CUR LK A,1000_0000b AND L MOV L,A ;do CR PUSH HL ;save new cursor ADD HL,HL LD A,PIABD ADD A,24 ;A = addr(25th line) SUB H ;A = lines_to_move + 1 AND 0001_1111b ;mod 32 MOV B,A LK A,VDELL CMP C MOV A,B ;recall #lines to move JRZ :delt ;if deleting a line space 3,17 :insrt: ;Insert a line ADD H ;A = addr(25th line) MOV D,A LK E,0 _line SUB H ;A = l_line - curr_line AND 0001_1111b ;modulo 32 JRZ :vmov ;if cursor is on 24th line of screen :end: POP HL ;get new cursor RET :vmov: LD A,LLIMIT SRL L ;unshift L register SUB L ;A = LLIMIT - col(cursor) JRC :end ;if cursor is outside logical line ;cursor is on last line of screen, inside of logical line. ;must move screen to follow cursor down through video memory. POP HL PUSH HL LK A,80h AND L MOV L,A ;HL = beginning of line CALL CLRLN ;erase to EOL LD A,PIABD MOV B,A AND not 31 ;A = line zero MOV C,A ;C = housekeeping bits 5..7 LK A,31 INC B ;increment line# AND B ;A = line# OR C ;A = new line# OR housekeeping_bits MOV C,A ;C = new value for OPBD CALL OPBD ;move video screen down 1 line in memory POP HL RET space 4,12 VLDDR: ;Video Block Move ; Entry BC, DE, HL set ; Exit LDDR on main & 9th bit memory ; Uses BC, DE, HL PUSH BC ! PUSH DE ! PUSH HL LDDR ;main memory POP HL ! POP DE ! POP BC DI ENADIM LDDR ;9thY A = CHR FROM RDKEY ; EXIT A = SHIFTED VALUE FROM SHIFT AND ALPHA LOCK KEYS PROC CMP ' ' + 1 RC ;IF CNTL-CHR (<=SPACE), UNSHIFTABLE LK HL,CKEY BIT 4,[HL] ;SHIFT KEY BIT JRNZ :SHIFT ;IF SHIFT KEY PRESSED BIT 3,[HL] ;ALPHA LOCK KEY BIT JRNZ :ALPHA ;IF ALPHA KEY PRESSED RET ;IF NO SHIFTING NECESSARY :SHIFT: CMP 'A' JRNC :ALPHA ;IF 'A'..'Z' CMP '[' JRC :TBLSF ;IF CHR < '[', USE SHIFT TABLE ;MUST BE '[' OR '\' JRNZ :ALPHX ;IF '\', SHIFT AS ALPHA LK A,']' RET ;...ELSE '[' SHIFTED IS ']' :TBLSF: MOV E,A LK D,0 ;DE = CHR LK HL, :STBL - '''' ;TABLE FWA - APOSTROPHE ADD HL,DE ;HL => SHIFTED CHARACTER LD A,[HL] ;A = SHIFTED CHR RET :ALPHA: CMP 'A' RC ;IF <'A', IGNORED BY ALPHA LOCK :ALPHX: XOR 20H ;UPPER/LOWER CASE BIT RET ;SHIFTED "COMMA" BECOMES "LESS THAN", ;SHIFTED "HYPHEN" BECOMES "UNDERBAR", (ETC.) ; ''', ...THESE 4 ARE UNUSED :STBL: DB '"', '{', '}', '|', '~' ; ',', '-', '.', '/', '0', '1', '2', '3', '4', '5' D RR D ! RR E ;shift right DE DEC DE ;DE = addr(lst_chr_on_lst_line) MOV A,B ;A = #lines to move LK HL,-VLL ADD HL,DE ;HL = addr(line above DE) ;DE := DE or F000h; HL := HL or F000h JR :istrt :icont: CALL VLDDR ;move 1 line down :istrt: CALL :vmod JRNZ :icont ;if must move more lines INC HL ;HL => 1st chr of new line ; JR :exit space 3,3 :exit: CALL CLRLN POP HL ;recover cursor JMP VOUT90 ;Main Exit space 3,11 :delt: POP DE ;recover new cursor PUSH DE LK HL,VLL ADD HL,DE ;HL = line_below_cursor JR :dstrt :dcont: CALL VLDIR ;move 1 line up :dstrt: CALL :vmod JRNZ :dcont EX HL,DE ;get addr of line to clear JR :exit space 3,13 ;HL := HL or F000h; DE := DE or F000h; ;simple mod-4096 arithmetic to keep pointers INSIDE video memory :vmod: PUSH AF ;save A = #lines to move LK A,0F0h OR H MOV H,A ;set upper nybl of H LK A,0F0h OR D MOV D,A ;modulo 4096 LK BC,VLL POP AF DEC A ;decrement line_count RET space 4,30 CLRLN: ;Clear to  bit memory DISDIM EI RET space 4,12 VLDIR: ;Video Block Move ; Entry BC, DE, HL set ; Exit LDIR on main & 9th bit memory ; Uses BC, DE, HL PUSH BC ! PUSH DE ! PUSH HL LDIR ;main memory POP HL ! POP DE ! POP BC DI ENADIM LDIR ;9th bit memory DISDIM EI RET space 4,10 UN_CUR: ;Undo/Invert Cursor ; Entry HL = cursor_addr ; Exit cursor inverted ; Uses A, CY. LD A,[hl] ;get the chr RAL ;cursor_bit => CY CMC ;invert it RAR STO A,[hl] ;... RET ; endx BMKEY.asm ***************** TITLE 'BMSCAN - KEYBOARD SCANNING & DECODE' GKEY: ;KEYBOARD INTERRUPT PROCESSOR ; ENTRY NONE ; EXIT KEYBOARD PROCESSING DONE, RESULT IN LKEY. ; SYSTEM CLOCK UPDATED BY UPTIM. PROC DI STO SP,IESTK ;SAVE INTERRUPTED PROCESS STK LK SP,ISTK ;SET TO RAM INT STK PUSHAL CALL UPTIM ;UPDATE SYSTEM CLOCK LD A,KEYLCK OR A JRZ GKEYX ;IF LOCKED KEYBOARD :SCAN: CALL RDKEY ;SCAN KEYBOARD CMP -2 JRZ GKEYAB ;IF NO KEY BEING PRESSED ;DEBOUNCE THE KE%B '<', '_', '>', '?', ')', '!', '@', '#', '$', '%' ; '6', '7', '8', '9', (:), ';', (<), '=', (>) DB '^', '&', '*', '(', ' ', ':', ' ', '+', ' ' PAGE CNTRL: ;CONTROL KEY PROCESSING ; ENTRY A = CHR, CNTL KEY PRESSED SIMULTANEOUSLY ; EXIT A = ^CHR PROC CMP ' ' + 1 RC ;IF SPACE, TAB, ESC, RET, ETC. CMP '@' JRC :CHEAT ;IF <'@', CK FOR CHEATED CHR CMP 'Z'+1 JRNC GKEYAB ;IF GREATER THAN 'Z', NO CNTL-CHR AND ' ' - 1 ;KILL CNTL & LOWERCASE BITS RET :CHEAT: MOV B,A ;SAVE CHR AND ',' CMP ',' JRNZ GKEYAB ;IF NOT A LEGAL CHEATED CHR MOV A,B ;RESTORE CHR LK HL,:TBL1-',' CMP '/'+1 ;CK FOR 1ST GROUP JRC :LOOK ;IF IN :TBL1 LK HL,:TBL2-'<' ;...ELSE IN :TBL2 :LOOK: ADD L ;DO INDEXED LOAD FROM BASE IN HL MOV L,A JRNC :GET INC H ;IF CARRY, PROPAGATE INTO H :GET: LD A,[HL] RET SPACE 3 ; , - . / :TBL1: DB '{' , '_'-40H, '}' , '~' ; < = > ? :TBL2: DB ('{'), '`' , ('}'), 7FH SLIDE: ;PROCESS ^1, CMA ;COMPLEMENT THE 1S STO A,CKEY ;SAVE FOR SHIFT & CTRL PROCS AND 1110_0011B ;CLEAR SHIFT, CNTRL, & ALPHA BITS LK BC,0700H ;LOOP 7 TIMES, C := 0 JR :MIDLE ;JUMP INTO MIDDLE OF :LOOP1 :LOOP1: SLA L ;SHIFT RANK-SELECT BIT LEFT MOV A,L ;ADDR BYTE TO A MOV R,A LD A,[HL] ;READ RANK XOR 0FFH ;INVERT 1S, SET FLAGS :MIDLE: JRZ :2 ;IF NO KEY PRESSED IN THIS RANK DEC C ;RECORD THAT A KEY WAS PRESSED MOV E,B ;RECORD 7-RANK# OF KEY PRESSED MOV D,A ;SAVE THE DATA READ :2: DJNZ :LOOP1 ;IF NOT FINISHED READING ALL RANKS INC C ;CK FOR C = -1 JRZ :FBIT ;IF FOUND EXACTLY ONE KEY PRESS ;HERE IF FOUND 1) NO KEYS PRESSED ; 2) MANY (MORE THAN 1) KEYS PRESSED LK A,-2 ;RETURN NO KEYS PRESSED RET ;HERE TO FIND THE KEY PRESSED IN A PARTICULAR RANK: ;LOAD UP THE APPROPRIATE TABLE ENTRY & RETURN. ; ENTRY D = DATA READ FROM KEYBOARD ; E = 7-RANK# OF ABOVE DATA :FBIT: LK A,7 ;#RANKS SUB E ;A = TABLE ROW TO USE )0..7) RAL ! RAL ! RAL ;A := A * 8 M TITLE 'Diagnostic section.' ; This section of code is entered either via the 1st prompt ; level by entering ^d, or by using the monitor command of ; 'T' if DEBUG is assembled on. ; ; This section of code contains all of the rom resident ; diagnostics to assist production and distributors. ; ; The diagnostic section uses a menu and contain test ; for major hardware pieces. These diagnostics are NOT ; considered to be all-encompassing...... ; Entry from monitor loop DIAG: proc IF ~INDMON NEXTC = DIAG ENDIF LK SP,ROMSTK LDK DE,DIAMSG CALL ASKU ;ask user for input LDK HL,DSKSWP ;disk swap cell LDK C,0 STO C,[HL] ;SET A=A,B=B CMP 'A' JZ CBOOT ;IF BOOT A DRIVE INC [HL] ;SWAP DRIVES A=B,B=A CMP 'B' JZ CBOOT ;IF BOOT B DRIVE DEC [HL] ;A=A, B=B CMP 'K' JZ KEYBT ;if Keyboard test CMP 'M' JZ TSTMEM ;if memory test CMP 'R' JZ TSERI ;if input test program CMP 'D' JRNZ DIAG ;if illegal DSKD: ;Here to run disk diagnostic LDK DE,DSKMSG CALL ASK ^2, ^3, ^(LARROW), ^(RARROW) ; ENTRY A = CHR, CNTL KEY PRESSED ; EXIT 1) RET IF CHR NOT A SPECIAL SLIDING CHR ; 2) TO GKEYX AFTER ACTING ON SLIDING CHR PROC PUSH AF LD A,PIABD ;B=Y MOV B,A POP AF LK C,+2 CMP MCLEFT ;LEFT ARROW JRZ :SLIDH LK C,-2 CMP MCRIGH ;RIGHT ARROW JRZ :SLIDH PUSH AF LD A,PIAAD ;C=X MOV C,A POP AF LK B,+1 CMP MCUP ;UP ARROW JRZ :SLIDV LK B,-1 CMP MCDOWN ;DOWN ARROW JRZ :SLIDV ;1,2,3,4,5,6 CMP '1' RC ;IF NOT A SLIDING CHR PUSH AF ;SAVE VALUE LD A,PIABD ;OLD Y VALUE AND 11100000B ;SET Y TO ZERO MOV B,A ;VALUE TO B POP AF ;RESTORE VALUE LK C, VFLO + 2*00 ;SET SCREEN TO 0TH COLUMN JRZ :SET CMP '7' RNC ;IF >3, NOT A SLIDING CHR LK C, VFLO + 2*52 ;SET 52ND COL CMP '2' JRZ :SET LK C, VFLO + 2*104 ;SET 104TH COL CMP '3' JRZ :SET PUSH AF ;SAVE IT MOV A,B OR 00001000B ;Y VALUE OF 8 MOV B,A POP AF LK C, VFLO + 2*00 ;SET SCREEN TO 0TH COLUMN CMP '4' JRZ :SET LK C,OV C,A LK B,0 ;BC = OFFSET INTO TABLE LK HL,T5KEY ;HL = FWA(TABLE) ADD HL,BC ;HL => RANK(KEY) PAGE MOV A,D ;RESTORE DATA FROM KEYBOARD LK BC, 0800H ;B := 8, C := 0 :LOOP2: RRC ;SHIFT CORRESPONDING BIT INTO CY JRNC :3 ;IF DIDN'T FIND BIT THIS TIME THRU DEC C ;...ELSE RECORD THAT A KEY WAS PRESSED ; MOV E,B ;DON'T NEED TO SAVE LOOP-INDEX LD D,[HL] ;GET CHR FROM TABLE :3: INC HL ;...ELSE TRY NEXT CHR & BIT DJNZ :LOOP2 INC C JZ :EXIT LDK A,-2 RET :EXIT: MOV A,D ;RETURN CHR IN A RET SPACE 4,10 T5KEY: T6KEY: DB ESC, TAB, ERC, ERC, ERC, CR, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I' DB 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K' DB 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',' DB MCUP, BKS, '0', ' ', '.', 'P', 'O', '9' DB MCRIGH, LF, '-', '/', ';', '\', 'L', '=' ; ENDX BMSCAN.ASM U ;Ask user for input SUB 'A' JRZ :2 ;if 'A' DEC A JRNZ DIAG ;if not A or B INC A :2: STO A,SDISK ;set drive CALL DRDT ;test reading entire disk CALL DSEKT ;test random seeks JMP NEXTC ;next DIAMSG: DBE 'Z'-40h DBE ' ROM DIAGNOSTICs' DBE cr,lf,'Select Test:' DBE cr,lf,'A,B Boot Sys' DBE cr,lf,' D isk' DBE cr,lf,' K ey-vdt' DBE cr,lf,' M emory' DBE cr,lf,' R ead in test' DBE lf,cr,lf,' :' DCE ' ' DSKMSG: DBE cr,lf DCE 'Select (A,B): ' ; Disk diagnostic section. DRDT: ;Disk read test ; reads each sector on disk and reports any errors proc CALL DSKDI ;initialize disk LDK A,0 :2: STO A,SAVTRK LDK A,1 :3: STO A,SAVSEC LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if error LD A,SAVSEC INC A CMP MSEC+1 JRNZ :3 ;if not full track LD A,SAVTRK INC A CMP MTRK JRNZ :2 ;if not full disk JR DERC ;display error count space 4,10 DSEKT: ;Disk seek test ; Routine performs random seeks followed by reads validating ; drive VFLO + 2*52 ;SET 52ND COL CMP '5' JRZ :SET LK C, VFLO + 2*104 ;SET 104TH COL JR :SET :SLIDV: LD A,PIABD ;ADD TO VIDEO BITS AND 00011111B ADD A,B ;ADD NEW TO OLD AND 00011111B MOV B,A LD A,PIABD ;LAST VALUE AND 11100000B ;CLEAR VIDIO BITS OR B ;ADD NEW VIDIO OFFSET MOV B,A JMP :SET :SLIDH: LD A,PIAAD ;OLD SCREEN OFFSET VALUE ADD A,C MOV C,A :SET: PUSH BC ;SAVE Y CALL OPAD ;MOVE THE SCREEN POP BC MOV C,B CALL OPBD ;SET Y LK A,1 STO A,HKCNT ;SHORT-CIRCUIT DEBOUNCE/AUTO-REPEAT ;DELAY LOGIC POP DE ;CLEAR STACK JMP GKEYX ;IGNORE RET-ADDR ON STK: ;STK WILL BE RESET ON NEXT IRUPT. PAGE RDKEY: ;SCAN KEYBOARD ; ENTRY NONE ; EXIT A = CHR (IF AVAILABLE) ; -2 (IF NO KEY PRESSED) PROC LD A, H.KEY + 0FFH ;READ ALL KEYBOARD PORTS XOR 0FFH ;INVERT ALL BITS, SET FLAGS LK A,-2 RZ ;IF NO KEY IS PRESSED LDK HL, H.KEY + 001H ;CONTROL KEY RANK MOV A,L ;ADDR BYTE TO A MOV R,A LD A,[HL] ;READ CONTROL RANK & is aligned and data path is valid. ; Entry None. ; Exit Back to diag main loop. proc CALL DSKDI ;initialize LDK A,100 :2: STO A,TEM CALL GNRN ;get next track STO A,SAVTRK LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if disk error CALL GNRN ;get random CALL DELAY ;delay LD A,TEM DEC A JRNZ :2 ;if not done JR DERC ;display error count space 4,8 ;DDAM: ;Test data address marks ;; Entry None ;; Exit After 1000 tries and displays ; proc ; CALL DSKDI ;initialize disk ; LDK BC,1000 ;:2: PUSH BC ; CALL DRDA ;read address mark ; LDK C,' ' ; JRZ :4 ;if good xfer ; LD HL,ERCNT ; INC HL ; STO HL,ERCNT ;update error count ; LDK C,80h ;pure white space ;:4: CALL COUT ;output indicator ; POP BC ; DEC BC ; MOV A,B ; OR C ; JRNZ :2 ;if not done ; JR DERC ;display error count space 4,8 DERC: ;Display error counter. ; Entry ERCNT = current error count LDK DE,DERCMG CALL ESTR ;output error prompt LD HL,ERCNT JMP ADRD ;output number DERCMG: INC HL CALL CDEHL JRNZ :5 ;If not all done EI ;allow key entry MOV A,C RRC ;shift one position MOV C,A LDK HL,FWAVM+40 INC [hl] ;indicate running POP HL POP DE CALL BREAK JRZ :2 ;if not data MOV C,A ;next test pattern JMP :2 ;keep on looping TSMSG: DBE cr,lf,'Memory tes' DCE 't' page TSERI: ;Input test routine through serial port ; Format of input: ; 8 bit binary data, no parity ; 1st two bytes are DW (length) ; (length) following bytes are placed ; at 4000h in memory; ; Exit: JMP 4000h Proc LK DE,:lmsg ;length msg CALL ESTR CALL READER ;get chr MOV L,C ;low byte of length CALL READER MOV H,C CALL PBWH ;print out length of test routine EX HL,DE ;DE = length LK HL,4000h ;FWA of test program :loop: MOV A,D OR E JRZ :xit ;if finished with input, run prgm CALL READER STO A,[hl] ;get & deposit next byte STO A,FWAVM+40 ;indicate recieved data INC HL DEC DE JR :loop :xit: LK DE,:xmsg ;exit message CALL ESTR JMP TITLE 'SIO - Serial I/O Processors.' SIRST: ;Master reset SIO ; Entry C= SI.S16 or SI.S64 for 1200/300 baud LDK A,SI.MRST STO A,H.SCTRL ;master reset NOP ! NOP ! NOP MOV A,C STO A,ACIAD ;last-command cell STO A,H.SCTRL ;select SIO RET space 4,10 READER: ;Input one byte from reader port ; Entry None ; Exit A=C= character read LD A,H.SSTS ; MOV B,A ;save status AND SI.RRDY ; LD A,H.SREC ;clear ~DCD JRZ READER ;if not ready LD A,H.SREC ;get data MOV C,A ;A=C ; LK A,SI.RERR ;error check ; AND B ;...with status ; MOV A,C ;recover data ; RZ ;if OK ; STC ;...else error RET space 4,10 SLST: ;Get list device status ; Exit A= 0, if NOT ready LD A,H.SSTS AND SI.TRDY ;ck for Xmit buf empty RET ;set status space 4,10 LIST: ;Output one byte to list port PUNCH: ;Output one byte to punch port ; Entry C= character to output ; Exit C=C. ; LD A,ACIAD ;get last command byte ; CBIT 6,A ;...invert RTS status ; STO A,H.SCTRL ;make request (~RTS := low)  DBE cr,lf DCE 'ERR cnt- ' page DSKDI: ;Disk diagnostic initialize ; Entry SDISK set to disk to test(0 or 1) proc LD A,SEC6 STO A,RNDV ;set random seed CALL DDRV ;deselect drive :2: LDK DE,0 STO DE,ERCNT ;clear error count MOV C,E CALL HOMED ;select drive 0, home. JRZ :3 ;if drive ready CALL RDSKC ;reset disk controller LDK DE,DNRMSG CALL ODER ;output disk error JR :2 :3: LDK BC,HSTBUF CALL SETDMA ;set to default dma RET page ASKU: ;Ask user for input, first displaying prompt ; Entry DE= FWA of prompt message ; Exit A= normalized input from user CALL ESTR ;prompt user CALL GETCH ;get next char CMP ESC JZ NEXTC ;if abort RET page KEYBT: ;Perform reading of keyboard and echoing to screen ; Keeps running till user types in ^Z. LDK DE,KEYTM CALL ESTR ;output prompt LDK HL,4000h JMP ACMDD ;enter A command KEYTM: DBE cr,lf DCE 'Enter keys (till ^Z) : ' page TSTMEM: ;performs a test of memory validating that the ; memory is working 4000h ;...to user program :lmsg: DBE cr,lf,'Start input: Len' ! DCE '=' :xmsg: DBE cr,lf,'Program begins' ! DCE ':' space 4,10 GNRN: ;Get next random number ; Exit A= new number to use (0 to MTRK-1) proc MOV A,R ;refresh register XOR [hl] AND 3Fh ;cannot exceed 28h=40d ADD A,17 CMP MTRK JC :4 ;if in range SUB MTRK :4: STO A,[hl] ;update RET space 4,10 IF ~INDMON ACMDD: ;Entry here from Diagnostic loop HL = 4000h proc :3: CALL CI ;read char CPI EOFC JZ DIAG ;if request to quit STO A,[hl] ;into memory INC HL ;update pointer CPI CR JRNZ :5 ;If not carriage return STO LF,[hl] INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of address:wait: LD A,H.SSTS AND SI.TRDY ;wait for CTS go-ahead JRZ :wait ;if CTS high, wait again MOV A,C STO A,H.SXMT ;send chr ; NOP ! NOP ! NOP ;...wait... ; LD A,ACIAD ;get last command ; STO A,H.SCTRL ;set RTS high (no request) RET ; Endx BMSIO.asm atus AND SI.RRDY ; LD A,H.SREC ;clear ~DCD JRZ READER ;if not ready LD A,H.SREC ;get data MOV C,A ;A=C ; LK A,SI.RERR ;error check ; AND B ;...with status ; MOV A,C ;recover data ; RZ ;if OK ; STC ;...else error RET space 4,10 SLST: ;Get list device status ; Exit A= 0, if NOT ready LD A,H.SSTS AND SI.TRDY ;ck for Xmit buf empty RET ;set status space 4,10 LIST: ;Output one byte to list port PUNCH: ;Output one byte to punch port ; Entry C= character to output ; Exit C=C. ; LD A,ACIAD ;get last command byte ; CBIT 6,A ;...invert RTS status ; STO A,H.SCTRL ;make request (~RTS := low)  correctly. ; Fixed limits on memory test are 4000h to EF00h ; (TEM = EF00h) ; Entry none. ; Exit To error if any errors occurred during ; the testing ; Calls GETNM proc LDK DE,TSMSG CALL ESTR ;prompt user about mem test LDK DE,TEM LDK HL,4000h LDK C,0A5h ;initial test pattern ; Loop thu testing memory within limits ; HL= FWA ; DE= LWA :2: DI PUSH DE ;save LWA PUSH HL ;save FWA :3: STO C,[hl] ;data to memory INC HL ;update address CALL CDEHL JRNZ :3 ;if not all done ; Now perform test on memory reading ; what was just written and comparing ; with pattern C. POP HL ;restore FWA PUSH H :5: DI LD A,[hl] CMP C ;validate good write JRZ :7 ;If GOOD compare EI MOV B,A ;save BAD data PUSH BC CALL OCRLF ;output new line CALL ADRD ;Output Location in error CALL OSP ;Output space char POP BC PUSH BC MOV A,C CALL NMOUT ;Output good data LDK C,'=' CALL COUT MOV A,B CALL NMOUT ;Output BAD data POP BC ;restore pattern CALL BREAK :7:  JR PBBH space 4,10 BREAK: ;Check for break key. ; Entry NONE ; Exit To DIAG if char entered is ESC, else ; return to caller A= char or 0 if none ; Calls SKEY, CI ; DESTROYS: A,F/F'S CALL SKEY ;get console status RZ ;If not ready CALL CI ;get char CMP ESC JZ DIAG ;if ESC, abort RET space 4,10 GETCH: ;returns the next character in the input stream ; TO the calling program. ; Entry NONE ; Exit C - next character normalized to UPPER case. ; Calls CI,CO,NORM ; DESTROYS: A,C,F/F'S CALL CI ;Get character from terminal CALL CO ;output it JMP NORM ENDIF ; Endx BMDIA.asm INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of address' TITLE 'BMUTIL2 - OSBORNE 1 UTILITY ROUTINES.' NMOUT: PBBH: ;PRINT BINARY BYTE IN HEX. ; CONVERTS THE 8 BIT, UNSIGNED INTEGER IN THE ; A REGISTER INTO 2 ASCII CHARACTERS. ; ENTRY A= 8 BIT INTEGER ; EXIT NONE ; CALLS CO,PRVAL ; DESTROYS: AF, C. PUSH AF ;SAVE ARGUMENT RRC RRC RRC RRC ;GET UPPER 4 BITS TO LOW 4 BIT POSITIONS CALL PRVAL ;CONVERT LOWER 4 BITS TO ASCII CALL CO ;SEND TO TERMINAL POP AF ;GET BACK ARGUMENT CALL PRVAL JMP CO SPACE 4,10 PRVAL: ;CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO ; THE CORRESPONDING ASCII CHARACTER, 0-9,A-F. PRVAL ; DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT. ; ENTRY A= INTEGER, RANGE 0 TO F ; EXIT A= ASCII CHARACTER. ; C= A ; CALLS NONE. ; DESTROYS: AF AND 0FH ADD A,90H ;SET UP A SO THAT A-F CAUSE A CARRY DAA ;ADJUST CONTENTS OF A REGISTER ADC A,40H ;ADD IN CARRY AND ADJUST UPPER 4 BITS DAA ;ADJUST CONTENTS OF A REGISTER AGAIN MOV C,A RET OCRLF: ;OUTPUT CR,LF ON CONSOLE SCREEN LK C,CR CALL COUT LK C,LTINES ;DSK LINK OCCROM72.ASM ;DIAGNOSIC ROUTINES ;DIA LINK OCCROM82.ASM ;FORMAT ROUTINE ;XFMT LINK OCCROM92.ASM ;UTILITES ;UTIL2 LINK OCCRAM2.ASM ;RAM LOCATIONS ; Endx -----+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV B2 ;DATE = 273 ;DEB ;ADD TWO KEY ROLLOVER FROM MICROCODE TO OCCROM3?.ASM ;ADD ONE MORE JMP TO TABLE FOR SORCIM UNDER VLDIR IN OCCROM1?.ASM ;ADD "STODIM" ROUTINE FOR SORCIM TO OCCROM3?.ASM ORG 0 ;FWA of memory ALPUSH: MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM ALLPOP: MACRO POP IY POP IX POP HL POP DE POP BC POP AF ENDM PAGE LINK OCCROM12.ASM ;ROM STANDARDS ;LOP,ROMD LINK OCCROM22.ASM ;CPM BOOT ;BOOT LINK OCCROM32.ASM ;CONSOL ROUTINES ;KEY LINK OCCROM42.ASM ;PIA ROUTINES ;PIO,IEEE LINK OCCROM52.ASM ;SIA ROUTINES ;SIO LINK OCCROM62.ASM ;DISK ROUse. BMON1: CALL CI ;Get next character CMP CR LK HL,DSKSWP ;disk swap cell LK C,0 ;boot from A: STO C,[hl] ;set to A=A, B=B JZ CBOOT ;if cold boot IF INDIA INC [hl] ;swap drives: A=B, B=A CMP '"' JZ CBOOT ;if cold boot off of B CMP 'D'-40h JZ DIAG ;if enter debugger JR BMON ELSE JR BMON1 ENDIF ; Here on NMI and RESET ;BMNI: LDK SP,ROMSTK ;Stack must be in RAM (not 0,1 page) ; CALL HINT ;Initialize hardware ; JMP DMON ;enter loop .mac IF RSIZE = 48 RESREG: ;Restore registers and exit interrupt POPALL LD SP,IESTK ;get users stack back EI ! RET .mac ENDIF page .mac IF INDMON ; Main loop for OSB Debug Monitor. ; Entry None. ; Exit To command processor. ; C= 2. DMON: LDK DE,IMMSG CALL OSTR ;output signon message ; Command processor NEXTC: EI LDK SP,ROMSTK ;reset always CALL OCRLF ;new line LD A,MPCHR MOV C,A CALL CO ;prompt :2: CALL GETCH ;get next char CMP ' ' JRZ :2 ;if leading blank LDK B,NCMDS LDK HL,CTAB :3:F JMP COUT O2SP: ;OUTPUT 2 SPACES ON CONSOLE CALL OSP OSP: LK C,' ' JMP COUT RLWA = * ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',RLWA IF RLWA > 0FFFH .9 ERROR CODE TOO LARGE.. ENDIF ; endx BMUTIL2.asm PUSH AF ;SAVE ARGUMENT RRC RRC RRC RRC ;GET UPPER 4 BITS TO LOW 4 BIT POSITIONS CALL PRVAL ;CONVERT LOWER 4 BITS TO ASCII CALL CO ;SEND TO TERMINAL POP AF ;GET BACK ARGUMENT CALL PRVAL JMP CO SPACE 4,10 PRVAL: ;CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO ; THE CORRESPONDING ASCII CHARACTER, 0-9,A-F. PRVAL ; DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT. ; ENTRY A= INTEGER, RANGE 0 TO F ; EXIT A= ASCII CHARACTER. ; C= A ; CALLS NONE. ; DESTROYS: AF AND 0FH ADD A,90H ;SET UP A SO THAT A-F CAUSE A CARRY DAA ;ADJUST CONTENTS OF A REGISTER ADC A,40H ;ADD IN CARRY AND ADJUST UPPER 4 BITS DAA ;ADJUST CONTENTS OF A REGISTER AGAIN MOV C,A RET OCRLF: ;OUTPUT CR,LF ON CONSOLE SCREEN LK C,CR CALL COUT LK C,L TITLE 'Monitor Main Loop.' DISDIM ;disable DIM JMP BMON ;reset/restart USER: ;Exit to user program from 'G' command EI ! RET ;Exit from G command .mac IF RSIZE = 48 LIST G ; Level 1 = breakpoint ORG 1*8 IBKP: DI JMP PBKP ;process breakpoint NULINT 2 NULINT 3 ; Level 4 = Keyboard INT4: DI ;Keyboard Interrupt JMP GKEY NULINT 5 ; Level 6 = Serial interrupt NULINT 6 DI ; JMP ILINT LIST * .mac ELSE .pbkp IF def PBKP ORG 1*8 IBKP: DI JMP PBKP ;process breakpoint .pbkp ENDIF .mac ENDIF ILINT: ;Here on unknown interrupt .mac IF RSIZE = 64 DI .mac ENDIF DISDIM STO SP,IESTK ;save interrupted proc stack LDK SP,ISTK ;insure stack in RAM PUSHAL ;save all registers LDK A,'I' STO A,MPCHR ;set prompt to inter level EXITI: ;Exit interrupt code via exiting to RAM and ; then enable or disable ROM code depending on ; the value contained in ROMRAM cell. LD A,H.VIO ;clear interrupt LD A,ROMRAM OR A JNZ RORAME ;if return to RAM, CPM  CMP [hl] INC HL JRZ :4 ;if command match INC HL ! INC HL DJNZ :3 ;if not end JMP ERROR ;if illegal ; Here on command match :4: LD A,[hl] INC HL LD H,[hl] MOV L,A LDK C,2 JMP [hl] ;process command .mac ENDIF page HINT: ;Initialize all dependent hardware. ; Entry None. ; Exit All hardware initialized. ; Set flag indicating in ROM ENAROM DISDIM ;disable DIM bit .mac IF RSIZE = 48 IM0 ;mode 0 machine .mac ELSE LDK HL,GKEY STO HL,INTBL+(4*2) ;set keyboard interrupt IM2 LDK A,high INTBL MOV I,A ;set interrupt page .mac ENDIF ; Initialize keyboard XRA A STO A,BELCNT ;clear bell timer cell STO A,LKEY ;clear last key cell STO A,HKCNT ;clear debounce STO A,ECHOP ;clear echo to list dev STO A,ESCH ;clear ESC hold flag CMA STO A,IDAY ;set date invalid for SETUP.COM STO A,TKEY ;clear holding key STO A,KEYLCK ;indicate NOT locked ; LDK HL,FWAVM ; STO HL,CURS ;set cursor LDK A,VLL STO A,LLIMIT ;set max line limit ; Set keybo;OCCROM02.ASM TITLE 'Osborne-One Monitor for Model 1 system.' *NOTE* USE ONLY WITH OCCTXT6.AST * 4D2008-00 MASTER .ASM * 2D2008-00 ASSY .ASM * 1D2008-00 LISTING .PRN * 4D1008-00 MASTER .COM * 2D1008-00 ASSY .COM ; +-------------------------------+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV B2 ;DATE = 273 ;DEB ;ADD TWO KEY ROLLOVER FROM MICROCODE TO OCCROM3?.ASM ;ADD ONE MORE JMP TO TABLE FOR SORCIM UNDER VLDIR IN OCCROM1?.ASM ;ADD "STODIM" ROUTINE FOR SORCIM TO OCCROM3?.ASM ORG 0 ;FWA of memory ALPUSH: MACRO PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY ENDM ALLPOP: MACRO POP IY POP IX POP HL POP DE POP BC POP AF ENDM PAGE LINK OCCROM12.ASM ;ROM STANDARDS ;LOP,ROMD LINK OCCROM22.ASM ;CPM BOOT ;BOOT LINK OCCROM32.ASM ;CONSOL ROUTINES ;KEY LINK OCCROM42.ASM ;PIA ROUTINES ;PIO,IEEE LINK OCCROM52.ASM ;SIA ROUTINES ;SIO LINK OCCROM62.ASM ;DISK ROU .mac IF RSIZE = 48 JR RESREG .mac ELSE POPALL LD SP,IESTK ;get users stack back EI ! RET .mac ENDIF .mac IF RSIZE = 64 BMON: DI LDK SP,ROMSTK LDK A,0 STO A,SEC6 STO A,SDISK ;set disk to drive 0 CALL HINT ;Initialize hardware LDK HL,(high MRAM)*100h STO HL,SSAVE ;Initialize User stack in ram LDK HL,0 STO HL,LDSEL ;clear select and last track LDK DE,IBMSG CALL OSTR ;Output initial message JR BMON1 ;continue .mac ENDIF IF * > NMIA MSG 'ILINT code is too large ', * ERROR ENDIF space 4,10 ORG NMIA DI JMP BMON ;NMI page ; Main start up for Monitor. IF RSIZE = 48 BMON: DI LDK SP,ROMSTK LDK A,0 STO A,SEC6 STO A,SDISK ;set disk to drive 0 LDK C,' ' ;fill with blanks CALL FVIO ;clear video memory CALL HINT ;Initialize hardware LDK HL,(high MRAM)*100h STO HL,SSAVE ;Initialize User stack in ram LDK HL,0 STO HL,LDSEL ;clear select and last track LDK DE,IBMSG CALL OSTR ;Output initial message ENDIF ; Get 1st user respon(ard debounce delay cell LK A,KBDTM ;debounce constant STO A,KBDLY ;set debounce-delay cell ; Now function PIA to set starting address ; and continue to move display window over ; the first display line. ; Set cursor as 1-40 on 1st line. CALL SPAO ;set up for output LDK C,VFLO CALL OPAD ;set for -10 char positions ; Set beginning line to 0 LDK A,0 STO A,PIABD ;set data reg MOV C,A CALL OPBD ;set line ; Reset-Master clear the SIO (ACIA) LK C,SI.S16 ;select 16x clock for 1200 baud CALL SIRST ;reset ; Set default seek to as defined by systext LDK A,SEEKTM ;defined from systext STO A,SEKDEL ;set seek step rate ; Set default prompt char LDK A,PMCHR STO A,MPCHR ;set up default EI ! RET page IF * > 100h MSG 'BMON is too long > 100h ',* ERROR ENDIF ORG 100h ; Jump vector for debugger and CP/M RVEC: JMP CBOOT ;cold boot JMP WBOOT ;warm boot JMP SKEY ;keyboard status JMP CI ;keyboard input JMP COUT ;console output JMP LIST ;lisEGH DB CR,LF,LF,LF DB 'INSERT DISK IN DRIVE ' DB ESC,'L' DB 'A' DB ESC,'M' DB ' AND PRESS RETURN' DC '.' ; TABLE OF ALL VALID MONITOR COMMAND CHARACTERS COMAND MACRO CHR,ADR .INCMD IF IN_%1_CMD DB '%1' IF ' %2' <> ' ' DW %2 ELSE DW %1_CMD ENDIF .INCMD ENDIF ENDM CTAB: COMAND A ;ASCII CORE ENTRY COMAND B,CBOOT ;BOOT UP SYSTEM COMAND D ;DISPLAY MEMORY COMAND F ;FILL MEMORY COMAND G ;GO EXECUTE/BREAKPOINT COMAND H ;HEX SUM & DIFFERENCE COMAND M ;MOVE DATA COMAND R ;READ INTEL-FORMAT HEX COMAND S ;SUBSTITUTE DATA INTO MEMORY COMAND X ;EXAMINE REGISTER(S) COMAND T,DIAG ;TESTS DIAGNOSTIC SECTION COMAND Z ;EXAMINE Z80 REGS NCMDS EQU (*-CTAB)/3 ;NUMBER OF VALID COMMANDS SPACE 4,10 ; TABLE OF ALL 8080 REGISTERS. ; EACH ENTRY IN THE RTAB CONSISTS OF: ; DB ASCII NAME ; DB ADDRESS ; DB FLAG, WHERE FLAG IS ; 0= 8 BIT REGISTER ; 1= 16 BIT ; 8X=8 BIT BUT DO NOT DISPLAY IN X COMMAND RTABS EQU 3 ;LENGTH OF EACH REGISTER ENTRY ; ENDX BMRO TITLE 'SIO - Serial I/O Processors.' SIRST: ;Master reset SIO ; Entry C= SI.S16 or SI.S64 for 1200/300 baud LDK A,SI.MRST STO A,H.SCTRL ;master reset MOV A,C STO A,ACIAD ;last-command cell STO A,H.SCTRL ;select SIO RET space 4,10 READER: ;Input one byte from reader port ; Entry None ; Exit A=C= character read LD A,H.SSTS AND SI.RRDY JRZ READER ;if not ready LD A,H.SREC ;get data MOV C,A ;A=C RET space 4,10 SLST: ;Get list device status ; Exit A= 0, if NOT ready LD A,H.SSTS AND SI.TRDY ;ck for Xmit buf empty RET ;set status space 4,10 LIST: ;Output one byte to list port PUNCH: ;Output one byte to punch port ; Entry C= character to output ; Exit C=C. :wait: LD A,H.SSTS AND SI.TRDY ;wait for CTS go-ahead JRZ :wait ;if CTS high, wait again MOV A,C STO A,H.SXMT ;send chr RET ; END OCCROM5?.??? t output JMP PUNCH ;punch output JMP READER ;reader input ; Disk I/O JMP HOME JMP SELDSK ;select disk JMP SETTRK ;set track JMP SETSEC ;set sector JMP SETDMA ;set DMA JMP DREAD ;Disk read JMP DWRT ;Disk write JMP SLST ;List device status RET ! NOP ! NOP ;Sector translate ; End of standard CP/m functions RORAME: JMP BIOS+BRRXT JMP BIOS+BROMJP JMP FORMT ;Format one track JMP SIRST ;SIO reset ; JMP BIOS+BRDXY ; JMP BIOS+BWTXY JMP IE.CO ;IEEE Control Out JMP IE.SI ; Status In JMP IE.GTS ; Go To Standby JMP IE.TC ; Take Control JMP IE.OIM ; Output Interface Message JMP IE.ODM ; Output Device Message JMP IE.IDM ; Input Device Message JMP IE.PP ; Parallel Poll page .mac IF RSIZE = 48 ; Main loop for OSB Debug Monitor. ; Entry None. ; Exit To command processor. ; C= 2. DMON: LDK DE,IMMSG CALL OSTR ;output signon message ; Command processor NEXTC: EI LDK SP,ROMSTK ;reset always CALL OCRLF ;new line LD A,MPCHR MOV C,A MD.ASM BLE OF ALL VALID MONITOR COMMAND CHARACTERS COMAND MACRO CHR,ADR .INCMD IF IN_%1_CMD DB '%1' IF ' %2' <> ' ' DW %2 ELSE DW %1_CMD ENDIF .INCMD ENDIF ENDM CTAB: COMAND A ;ASCII CORE ENTRY COMAND B,CBOOT ;BOOT UP SYSTEM COMAND D ;DISPLAY MEMORY COMAND F ;FILL MEMORY COMAND G ;GO EXECUTE/BREAKPOINT COMAND H ;HEX SUM & DIFFERENCE COMAND M ;MOVE DATA COMAND R ;READ INTEL-FORMAT HEX COMAND S ;SUBSTITUTE DATA INTO MEMORY COMAND X ;EXAMINE REGISTER(S) COMAND T,DIAG ;TESTS DIAGNOSTIC SECTION COMAND Z ;EXAMINE Z80 REGS NCMDS EQU (*-CTAB)/3 ;NUMBER OF VALID COMMANDS SPACE 4,10 ; TABLE OF ALL 8080 REGISTERS. ; EACH ENTRY IN THE RTAB CONSISTS OF: ; DB ASCII NAME ; DB ADDRESS ; DB FLAG, WHERE FLAG IS ; 0= 8 BIT REGISTER ; 1= 16 BIT ; 8X=8 BIT BUT DO NOT DISPLAY IN X COMMAND RTABS EQU 3 ;LENGTH OF EACH REGISTER ENTRY ; ENDX BMRO CALL CO ;prompt :2: CALL GETCH ;get next char CMP ' ' JRZ :2 ;if leading blank LDK B,NCMDS LDK HL,CTAB :3: CMP [hl] INC HL JRZ :4 ;if command match INC HL ! INC HL DJNZ :3 ;if not end JMP ERROR ;if illegal ; Here on command match :4: LD A,[hl] INC HL LD H,[hl] MOV L,A LDK C,2 JMP [hl] ;process command .mac ENDIF ; Endx BMLOP TITLE 'MROMD - DEBUG MONITOR ROM DATA AND CONSTANTS.' ; ROM STORAGE AND CONSTANTS IBMSG: DB 'Z'-40H,LF,LF,LF,LF DB ESC,VSGH DB 'Q'-40H DB 07FH, 24, 'W'-40H DB 'E'-40H DB ESC,VEGH DB CR,LF DB ESC,VSGH,1, ESC,VEGH DB ' ' DB ESC,'L' DB 'OSBORNE SYSTEM ONE.' DB ESC,'M' DB ' ' DB ESC,VSGH,4, ESC,VEGH DB CR,LF DB ESC,VSGH DB 'A'-40H DB 07FH,24,' ' DB 'D'-40H DB ESC,VEGH DB CR,LF DB ESC,VSGH DB 'A'-40H DB ' ' DB ESC,')' DB ' REV B 227 ' DB ESC,'(' DB ' ' DB 'D'-40H DB ESC,VEGH DB CR,LF DB ESC,VSGH DB 'Z'-40H DB 07FH, 24, 'X'-40H DB 'C'-40H DB ESC,V) TITLE 'Keyboard and Console Routines.' ; Assembly constant @KEY = 1 ;production keyboard ; Control keys CBELL = 'G'-40h ;Ring the Bell MCUP = 'K'-40h ;Move cursor up MCDOWN = LF ;Move cursor down MCLEFT = BKS ;Move cursor left MCRIGH = 'L'-40h ;Move cursor right VCLRS = 'Z'-40h ;Clear and home cursor VHOME = '^'-40h ;Home Cursor ; Escape keys VLOCK: = '#' ;Lock Keyboard VUNLK = '"' ;Unlock Keyboard VCAD: = '=' ;Cursor Addressing VSAD: = 'S' ;Screen Addressing VINC: = 'Q' ;Insert Char VDELC: = 'W' ;Delete char VINL: = 'E' ;Insert line VDELL: = 'R' ;Delete line VCEOL: = 'T' ;Clear to end of line VSHI: = ')' ;Start half intensity VEHI: = '(' ;end VSUL: = 'l' ;Start underline VEUL: = 'm' ;end VSGH: = 'g' ;Start graphics VEGH: = 'G' ;End ;ARROW KEYS UP = 8AH RIGHT = 8BH DOWN = 8CH LEFT = 8DH SKEY: ;Get status of keyboard ; Exit Cbit set if no data ready LD A,KEYLCK OR A RZ ;if locked keyboard LD A,LKEY ORA A ;CHECK FOR ZERO RIST ;echo it page ; Bit definitions for ESCH flag byte ; Note Bit 7 is currently free. EF_X: = 64 ;B6= extegting X-coordinate EF_SCR: = 32 ;B5= Screen/Cursor Addressing EF_ADR: = 16 ;B4= expegting address-chr EF_ESC: = 8 ;B3=$last char was ESC EF_UN: = 4 ;B2= Underline mode EF_HA: = 2 ;B1= Half Intensity mode EF_GR: = 1 ;B0= Graphics mode EF_MSK: = EF_UN+EF_HA+EF_GR ;Mask to get mode. space 4,10 ; Vector (branch) table for video output mode selection ; controlled by ESCH mode ESCHTB: DW VNORM ;0 Normal mode DW VGRAPH ;1 Graphics mode DW VHALF ;2 Half intensity mode DW VHA_GR ;3 Half and graphics DW VUNDER ;4 Underline mode DW VUN_GR ;5 Under and graphics DW VUN_HA ;6 Under and half intensity DW VUN_HA_GR ;7 Under and half and graphics space 4,10 VALIDE: ;Valid ESC-Sequence Table ; 3 bytes per entry:ascii char , "DW"-Vector. ; no. of entries is VALETS ; Following body of table is 2 byte No-Match adrs DB VCAD ! DW ESCCAD ;Cursor Addressing DB VSA5,6,7 As above, but mode is combination ; =9-15 Last chr Esc flag True;otherwise like 1-7. proc ;RESET VETICAL OFFSET WITH VRTOFF PUSH AF PUSH BC LD A,PIABD ;PRESENT VALUE AND 11100000B ;HOUSEKEEPING MOV B,A LD A,VRTOFF ;LAST VERTICAL OFFSET AND 00011111B ;ONLY VIDIO ORA B ;ADD HOUSEKEEPING MOV C,A CALL OPBD ;SET OFFSET POP BC POP AF PUSH HL PUSH DE PUSH BC LD HL,CURS ;HL will usually be cursor/ LD A,ESCH MOV B,A ;B will be ESCH for a while AND EF_ESC ;test flag bit JRNZ PSTESC ;IF last chr was ESC ;Current chr is NOT ESCaped. Is this chr ESC? MOV A,C ;Chr CMP ESC MOV A,B ;(A=ESCH) JRZ :ESC ;if this chr = ESC space 4,10 ;Here with A=B= ESCH :out: PUSH HL LK HL,ESCHTB AND EF_MSK ;Mode bits only ADD A,A ;Times two MOV E,A LK D,0 ;DE = offset ADD HL,DE ;HL = tbl addrs VECTOR: ;entry point. note hl on stack. LD A,[HL] ;1st byte (low order adrs) INC HL LD H,[HL] ;2nd byte (hi order adrs) MOV L,A ;HL=Z ORI 0FFH ;IF NOT ZERO MAKE 0FFH RET ;IF DATA space 4,10 CI: RKEY: ;Read next key from keyboard ; Exit A= last key proc CALL SKEY JRZ RKEY ;if NO data DI LD A,LKEY ;GET CHARACTER MOV C,A XRA A STO A,LKEY ;clear key from hold MOV A,C EI RET space 4,10 NORM: ;Normalize to UPPER case ; Entry A= char ; Exit A= CHAR CMP 'a' RC ;if upper CMP 'z'+1 RNC ;if not lower SUI 'a'-'A' RET REPD = 45 ;initial rep delay REPK = 5 ;repeat constant page UPTIM: ;Update time via 60hz interrupt ; Time is kept in video memory as ; hhmmss (3 locations) ; Routine also checks to see if the disk drive motor ; should be turned off by updating DACTIVE ; ...Routine ALSO checks to see if bell is currently ; ringing: if so, decrement counter. ; if counter turns zero, shut off bell. Proc LK HL,BELCNT XOR A OR [hl] ;cell=zero ? JRZ :2 ;if bell now off DEC [hl] ;...bell is on. decrement counter JRNZ :2 ;if bell should stay on awhile yet LD A,PIABDD ! DW ESCSAD ;Screen Addressing DB VSGH ! DW ESCSGR ;Set graphics mode DB VEGH ! DW ESCCGR ;Clr graphics mode DB VSHI ! DW ESCSHA ;Set half int. mode DB VEHI ! DW ESCCHA ;Clr half int. mode DB VSUL ! DW ESCSUN ;Set underline mode DB VEUL ! DW ESCCUN ;Clr underline mode DB VCLRS ! DW ESCZZ ;Clear screen to blanks DB VINC ! DW EINSRT ;Insert char DB VDELC ! DW EDELC ;Delete char DB VINL ! DW ESCEE ;Insert line DB VDELL ! DW ESCRR ;Delete line DB VCEOL ! DW EEOL ;Clear to end of line DB VLOCK ! DW ESCLCK ;Lock Keyboard DB VUNLK ! DW ESCULK ;Unlock Keyboard :end: DW COUT2 ;No Match exit ; Ignore char upon undefined ESC-Sequence ; (to treat undefined char after ESC as a regular ; data char, should go to COUT2). VALETS: = (:end-VALIDE)/3 ;# of entries in table space 4,10 VALIDC: ;Valid control character table ; 3 bytes per entry: Ascii char , "DW"- Vector ; no. of entries is VALCTS ; Following body of table is 2 byte No-Match adrs DB CR ! DW VC_CR ;carriage returadrs from table XTHL ;Restore hl from stack ;stack=tbl adrs MOV A,C ;Chr. note B=ESCH byte value RET ;enter routine per table adrs. COUT2: MOV A,B ;recall ESCH value JR :out ;output chr per current settings :ESC: ;Current chr is ESC. Set flag and exit OR EF_ESC ;indicate last char= ESC STO A,ESCH JMP VOUT97 ;Exit space 4,17 PSTESC: ;Last chr was ESC ; Entry A= EF_ESC ; B= ESCH ; C= Char to output ; HL=curs Proc BIT 4,B ;is this chr really an address? JRNZ SETXY ;...if chr is part of an addr ;no cursor/screen addressing in effect: XOR B ;Clr EF_ESC bit (for next time) MOV B,A ;Set up B = ESCH byte value. STO A,ESCH PUSH HL ;save Curs LDK HL,VALIDE ;Branch table adrs LDK E,VALETS ;Table size MOV A,C ;Chr to A JR LOOKUPB ;Go to routine to branch per tbl space 4,15 VNORM: ;NORMAL mode character processing. ; Entry A= char to output ; HL=curs CMP ' ' JRC :2 ;IF control chr VBRIGH: DI ! ENADIM ;9th bit memory STO BRTBIT AND 1101_1111b ;clear bell bit MOV C,A CALL OPBD :2: DEC HL ;HL => DACTVE LD A,[hl] OR A JRZ :3 ;if inactive DEC [hl] ;reset delay CZ DDRV ;if deselect drive :3: DEC HL ;HL => SEC6 DEC [hl] RNZ ;if not 1 sec transition STO 59,[hl] ;60th tick is NOW XOR A ;A:=0, CY:=0 for DAA DEC HL ;HL => SECS LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 60h RC ;if not 60 secs STO 0,[hl] ;reset seconds DEC HL LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 60h RC ;if not 60 minutes STO 0,[hl] DEC HL LD A,[hl] ! INC A ! DAA ! STO A,[hl] CMP 25h RC ;if time <= 24:59:59 STO 1,[hl] RET page CO: ;Output routine for monitor ; Entry C= char ; CO will process ^p to toggle ; echo to list device ala cpm. ; Exit C=C=A. proc MOV A,C CMP 'P'-40h JRNZ :5 ;if not toggle echo list LD A,ECHOP CMA STO A,ECHOP ;toggle list echo :2: MOV A,C ;perserve A RET :5: CALL COUT ;output char LD A,ECHOP OR A JRZ :2 ;if no echo to list JMP Ln routine DB LF ! DW VC_LF ;line feed DB BKS ! DW VC_BKS ;back space DB MCRIGH ! DW VC_MCRT ;move cursor right DB MCUP ! DW VC_MCUP ;move cursor up ; DB 'A'-40H ! DW VSHFT_L ;shift screen left ; DB 'B'-40H ! DW VSHFT_R ;shift right ; DB 'C'-40H ! DW VSHFT_0 ;left column (^1) ; DB 'D'-40H ! DW VSHFT_U ;SHIFT UP ; DB 'E'-40H ! DW VSHFT_D ;SHIFT DOWN DB CBELL ! DW VC_BEL ;Ring bell DB VCLRS ! DW VC_CLRS ;clear screen DB VHOME ! DW VC_HOME ;Cursor Home ; DW VOUT97 ;No match--ignore undef control char ; VALCTS: = ((*-2)-VALIDC)/3 ;Number of valid entries page COUT: ;General output routine to Video Screen ; ENTRY C=Character, CURS=Cursor, ESCH=Flag+Mode ; EXIT CURS & ESCH updated, A=Character ; (bc, de, hl preserved) ; ; ESCH is flag + mode byte as follows ; =00 Normal mode & Last chr Esc flag false ; =08 Normal mode & Last chr Esc flag True ; =01,02,04 Mode is Graphics, Half, or Under, respectively ; , and Last chr Esc flag is False. ; =3,*,[hl] ;set this chr BRIGHT DISDIM ! EI JMP VOUT80 :2: PUSH HL ;Save Curs LDK HL,VALIDC ;Branch table adrs LDK E,VALCTS ;Table size ; JMP LOOKUPB ;Scan table of valid control chrs ; ;and branch to appropriate routine. space 4,20 LOOKUPB: ;Logic to scan 3 byte branch table ; NOT a subroutine---do not CALL. ; Entry HL =1st byte of table (match code) ; (2nd,3rd bytes = branch adrs) ; (table repeats [3 byte entries]) ; E is table size (no. of entries) ; (table body is followed with ; 2 byte "No-Match" adrs) ; Stack has HL saved as top entry. ; C = char ; A = value to scan for possible match CMP [HL] INC HL ;(2nd byte of this 3 byte entry) JRZ VECTOR ;If match process INC HL ;(3rd byte of this entry) INC HL ;1st byte of next entry DEC E ;Dec count of entries remaining JRNZ LOOKUPB ;Continue thru body of table JR VECTOR ;No-Match. hl=points to vector page ; Processing for modes other than normal. ; -------------------------------------- ;VGRAPH  LK A,EF_MSK AND B ;finished addressing: reset addr bits :exit2: STO A,ESCH JMP VOUT90 page ; Control Code character processing VC_HOME: ;Home Cursor Proc CALL UN_CUR LD A,PIABD RAR ;bit0 => CY LK L,0 RR L ;CY => bit7, trash bit0 MOV H,A JR :fixhl ;HL := HL or F000h space 4,7 VC_MCUP: ;Move Cursor Up. ; A=C=Chr=MCUP. HL=Curs. CALL UN_CUR PUSH HL ;old cursor must be on stack LK BC,(-VLL) JR :fwa ;...at this entry point space 4,28 VC_BKS: ;HL=Curs=current (old) char CALL UN_CUR ;clear 80h bit LK A,7Fh AND L JRZ :wrap ;if must wrap from col 0 to LLIMIT DEC HL JR VOUT90 ;Exit :wrap: PUSH HL ;save old cursor LK BC,-(VLL+1) ADD HL,BC ;HL = prev_line, (-1)st column LD A,LLIMIT ;LLIMIT = #columns on screen MOV C,A LK B,0 :fwa: ADD HL,BC XTHL ;get old cursor, save new ADD HL,HL ;shift line# into H reg. LD A,PIABD OR 1110_0000b ;A = line# of UL corner CMP H ;set Zflag: @home? POP HL ;get new cursor... JRNZ VOUT97 space 4,5 EEOL: ;Erase to end of line PUSH HL ;save cursor CALL CLRLN POP HL JR VOUT90 space 4,12 ESC_CAD: ;Cursor Addressing LK A,EF_MSK AND B OR EF_ESC or EF_ADR ;next chr will be Y-coord :exit3: STO A,ESCH JR VOUT97 ESC_SAD: ;Screen Addressing LK A,EF_MSK AND B OR EF_ESC or EF_ADR or EF_SCR JR :exit3 page ;Subroutine for use with EDELC and EINSRT: ;Calculate #chrs to move; if move zero chrs, never return. Proc :calc: LK A,VLL-1 ;A= max #chrs to be moved MOV C,L CBIT 7,C ;C = col(cursor) SUB C ;A = #chrs to move JRZ :end ;if move zero characters MOV C,A LK B,0 ;BC = #chrs to move RET :end: POP HL ;trash return_addr POP HL ;cursor_addr JR VOUT90 space 4,14 EDELC: ;Delete Character PUSH HL ;save cursor_addr CALL :calc ;calculate BC ; MOV D,H ; MOV E,L ;DE = cursor_addr PUSH HL POP IX INC HL ;HL = cursor_addr + 1 CALL VLDIR ;move characters STO ' ',[hl] ;last chr becomes blank DI ! ENADIM ;enable 9th b= VOUT80 ;Normal mode EXCEPT: cntl chrs are printed VUNDER: ;Underline only CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VUN_GR ;continue VUN_GR: ;Underlined Graphics OR 80h underline bit JR VBRIGH ;set this chr BRIGHT VUN_HA: ;Underline and Half intensity CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VUN_HA_GR VUN_HA_GR: ;Underline, Half Intensity, Graphics OR 80h ;set underline bit ; JR VHA_GR VHALF: ;Half Intensity CMP ' ' JRC VNORM ;if cntl-chr, process as normal ; JR VHA_GR VA_GR: ;C=Chr, HL=Curs DI ENADIM STO DIMBIT,[hl] ;set dim field bit ; LD E,[hl] ;diagnostic DISDIM EI JMP VOUT80 ;continue space 4,22 SCREEN: ;SetXY for Screen movement ; Entry B= ESCH ; A= new co-ord val, NO OFFSET Proc BIT 6,B JRNZ :sX ;if X-coordinate :sY: AND 0001_1111b ;mod 32 MOV C,A STO A,VRTOFF ;SET VERTICAL OFFSET FOR COUT LD A,PIABD AND 1110_0000b OR C MOV C,A CALL OPBD ;set Y coordinate JR :exi:fixhl ;if NOT @video home LK BC,(24*VLL) ;wrap constant ADD HL,BC :fixhl: LK A,0F0h OR H ;modulo result: keep cursor MOV H,A ;inside video memory. JR VOUT90 space 4,8 VC_BEL: ;Ring the bell via setting PIAB 2**5 bit LD A,PIABD OR 0010_0000b ;bell bit MOV C,A CALL OPBD ;function PIAB LK A,30 ;ring bell for 30 ticks STO A,BELCNT ;... = 1/2 second JR VOUT97 ;exit no change space 4,10 VC_CLRS: LK HL,FWAVM CALL CLRLN ;clear 1st line LK BC,LVMEM-VLL PUSH DE POP IX CALL VLDIR ;clear remaining lines LD A,PIABD ;Reset for 1st line of display mem AND not(1_1111b) MOV C,A CALL OPBD XRA A ;ZERO A STO A,VRTOFF ;SET VERTICAL OFFSET FOR COUT LK HL,FWAVM ;new cursor JR VOUT90 ;Exit space 4,8 VC_CR: CALL UN_CUR ;erase cursor LK A,80h ;Carriage Return AND L MOV L,A JR VOUT90 VC_LF: CALL DO_LF ;Line Feed JR VOUT90 space 4,3 VC_MCRT ;Move Cursor Right CALL UN_CUR LD A,[hl] ; JR VOUT80 ;re-echo current chr page ; Exit pointit memory DEC HL ;HL = last chr on this line STO BRTBIT,[hl] ;set chr BRIGHT DISDIM ! EI ;main memory POP HL ;restore cursor_addr JR VOUT90 ;next space 4,14 EINSRT: ;Insert Character CALL UN_CUR PUSH HL ;save cursor_addr CALL :calc ;calculate BC LK A,7Fh OR L MOV L,A ;HL = last_chr on this line ; MOV E,A ; MOV D,H ;DE = HL PUSH HL POP IX DEC HL CALL VLDDR ;do move POP HL ;restore cursor LD A,[hl] ;get underline bit of this chr. RAL ;into CY LK A,' ' shl 1 ;change this chr to ' ' JR VOUT96 ;exit page ; ESC-Sequence processing. Proc ESCSGR: LDK A,EF_GR ;ESC-g JR :125 ;set graphics mode. ESCSHA: LDK A,EF_HA ;ESC-) set half intensity JR :125 ;go set flag bit ESCSUN: LDK A,EF_UN ;ESC-l set underline :125: OR B ;Reg B is ESCH Byte value :130: STO A,ESCH ;store desired value. JR VOUT97 ;Exit ESCCGR: LDK A,NOT EF_GR ;ESC-G Clear graphics mode JR :140 ;go clear ESCH bit ESCCHA: LDK A,NOT EF_HA ;ESC-( Clear half intentY :sX: ADD A,A ;double A ADD A,VFLO ;PIA A-reg magic offset constant AND 1111_1110b ;clear bit 0 => no 1/2 chr shift MOV C,A CALL OPAD ;set X coordinate CBIT 5,B ;finished screen-addressing JR :exitX space 4,10 SETXY: ;Set X-Y value for Cursor/Screen Addressing ; Entry HL= cursor_addr ; B = ESCH ; C = chr ; Exit to VOUT90; ESCH updated CALL UN_CUR LK A,-(' ') ADD C ;remove cursor bias BIT 5,B ;cursor/screen addressing? JRNZ SCREEN ;if screen addressing ;cursor addressing: ADD HL,HL ;shift HL left BIT 6,B ;X/Y coordinate? JRNZ :cX ;if X coordinate :cY: MOV H,A ;save LD A,PIABD ADD H ;offset by start-Y co-ord of video RAR ;bit0(A) -> CY, shift A right RR L ;CY -> bit7(L) OR 0F0h ;turn on upper nybl MOV H,A ;HL= new cursor addr ; JR :exitY :exitY: LK A,0100_0000b ;next addr-chr will be X-coord OR B JR :exit2 :cX: RAL ;trash 7th bit SRA H ;bit0(H) -> CY, bit7 stays 1 RAR ;... CY -> bit7(A) MOV L,A ; JR :exitX :exitX: s for COUT ; Here to store new data and to update cursor VGRAPH: VOUT80: STO A,[hl] ;This exit path stores A (new char) MOV E,L CBIT 7,E ;E = col(cursor) LD A,LLIMIT DEC A ;A = last_legal_col SUB E ;A = last_legal_col - col(cur) JRNZ VOUT85 ;if not @LLIMIT LK A,80h AND L MOV L,A ;do CR... CALL DO_LF2 ;...and LF. JR VOUT90 VOUT85: INC HL ;move cursor ; Here if NO cursor update VOUT90: LD A,[HL] ;This exit path turns on 80h bit ; Here if new data already in A VOUT95: RAL ;Make this chr cursor VOUT96: CMC ;invert cursor bit RAR STO A,[hl] STO HL,CURS ;update cursor ; Here if no change to cursor, restore reg and exit VOUT97: POP BC POP DE POP HL MOV A,C ;Exit with A=chr RET ;return, end of cout subr. space 4 :First = VOUT97 - (127 + 2) ;earliest possible JR :Last = VOUT80 + (128 - 2) ;latest possible JR page ESC_LCK: ;Lock Keyboard Proc XOR A JR :2 ESC_ULK: ;Unlock Keyboard LK A,0FFh :2: STO A,KEYLCK JR +sity JR :140 ESCCUN: LDK A,NOT EF_UN ;ESC-m Clear underline :140: AND B ;Clear bit JR :130 ;Go store ESCH byte ESCZZ: = VC_CLRS ;ESC-Z Clear screen -same as ; ;Control-Z routine. page ; Proc ;VSHFT_L: ;shift screen left ; LDK A,08 ; JR :1 ;VSHFT_R: ;shift screen right ; LDK A,0CH ; JR :1 ;VSHFT_0: ;shift to column #0 (like ^1) ; LDK A,31H ; JR :1 ;set video offset ;VSHFT_U: ;SHIFT SCREEN UP ; LD A,VRTOFF ;INCRESS VERTICAL OFFSET FLAG ; INC A ; AND 00011111B ;ONLY VIDEO BITS ; STO A,VRTOFF ; LDK A,0BH ; JR :1 ;VSHFT_D: ;SHIFT SCREEN DOWN ; LD A,VRTOFF ;DECRESS VERICAL OFFSET FLAG ; DEC A ; AND 00011111B ; STO A,VRTOFF ; LDK A,0AH ;:1: ; CALL SLIDE ;IN BMSCAN.ASM ; JMP VOUT97 page ESCRR: ;Delete Line ESCEE: ;Insert Line ; Entry HL = cursor ; C = chr ; Exit screen updated ; HL = new cursor ; ...to VOUT90 Proc CALL UN_CUR LK A,1000_0000b AND L MOV L,A ;do CR PUSH HL ;save new cursor ADD HL,HL LD A,PIABDpos ; window moved if necessary proc CALL UN_CUR ;clear cursor DO_LF2: PUSH HL ;save original cursor LK BC,VLL ;line length ADD HL,BC JRNC :nowap ;if not wrapping from LWAVM to FWAVM LK BC,FWAVM ADD HL,BC ;HL = new cursor @ top of VM :nowap: XTHL ;save new cursor, get old ADD HL,HL ;shift HL left LD A,PIABD ADD A,23 ;start + 23 = last_video_line SUB H ;A = l_line - curr_line AND 0001_1111b ;modulo 32 JRZ :vmov ;if cursor is on 24th line of screen :end: POP HL ;get new cursor RET :vmov: LD A,LLIMIT SRL L ;unshift L register SUB L ;A = LLIMIT - col(cursor) JRC :end ;if cursor is outside logical line ;cursor is on last line of screen, inside of logical line. ;must move screen to follow cursor down through video memory. POP HL PUSH HL LK A,80h AND L MOV L,A ;HL = beginning of line CALL CLRLN ;erase to EOL LD A,PIABD MOV B,A AND not 31 ;A = line zero MOV C,A ;C = housekeeping bits 5..7 LK A,31 INC B ;increment line# AND B ;A = line# E: MOV A,B ;RESTORE CHR CALL SHIFT ;SHIFT PROCESSING LDK HL,CKEY BIT 2,[HL] ;CK FOR CNTL KEY JRZ :FIN ;IF CNTL-KEY IS NOT PRESSED CALL SLIDE ;CK FOR SCREEN SLIDE KEYS JRNZ :1 ;IF NOT SLIDE CHARACTER INC A ;A=1 STO A,HKCNT ;SHORT-CIRCUIT DEBOUNCE/AUTO-REPEAT ;DELAY LOGIC JR GKEYX ;IGNORE RET-ADDR ON STK: :1: CALL CNTRL ;CNTRL KEY PROCESSING :FIN: STO A,LKEY ;MAKE CHR AVAILABLE TO CI GKEYX: JMP EXITI ;EXIT INTERRUPT GKEYAB: ;ABORT PROCESSING: SET TKEY := -2 AND RETURN. LDK A,-2 STO A,TKEY JR GKEYX PAGE SHIFT: ;SHIFT KEY PROCESSING ; ENTRY A = CHR FROM RDKEY ; EXIT A = SHIFTED VALUE FROM SHIFT AND ALPHA LOCK KEYS PROC CMP ' ' + 1 RC ;IF CNTL-CHR (<=SPACE), UNSHIFTABLE CMP 80H RNC ;IF GREATER THAN 7FH LDK HL,CKEY BIT 4,[HL] ;SHIFT KEY BIT JRNZ :SHIFT ;IF SHIFT KEY PRESSED BIT 3,[HL] ;ALPHA LOCK KEY BIT JRNZ :ALPHA ;IF ALPHA KEY PRESSED RET ;IF NO SHIFTING NECESSARY :SHIFT: CMP 'a' JRNC :ALPHA ; ADD A,24 ;A = addr(25th line) SUB H ;A = lines_to_move + 1 AND 0001_1111b ;mod 32 MOV B,A LK A,VDELL CMP C MOV A,B ;recall #lines to move JRZ :delt ;if deleting a line space 3,17 :insrt: ;Insert a line ADD H ;A = addr(25th line) MOV D,A LK E,0 RR D ! RR E ;shift right DE DEC DE ;DE = addr(lst_chr_on_lst_line) MOV A,B ;A = #lines to move LK HL,-VLL ADD HL,DE ;HL = addr(line above DE) ;DE := DE or F000h; HL := HL or F000h JR :istrt :icont: PUSH DE POP IX CALL VLDDR ;move 1 line down :istrt: CALL :vmod JRNZ :icont ;if must move more lines INC HL ;HL => 1st chr of new line ; JR :exit space 3,3 :exit: CALL CLRLN POP HL ;recover cursor JMP VOUT90 ;Main Exit space 3,11 :delt: POP DE ;recover new cursor PUSH DE LK HL,VLL ADD HL,DE ;HL = line_below_cursor JR :dstrt :dcont: PUSH DE POP IX CALL VLDIR ;move 1 line up :dstrt: CALL :vmod JRNZ :dcont EX HL,DE ;get addr of line to clear JR :exit space 3,13 ; STO A,VRTOFF ;SET VERTICAL OFFSET FOR COUT OR C ;A = new line# OR housekeeping_bits MOV C,A ;C = new value for OPBD CALL OPBD ;move video screen down 1 line in memory POP HL RET space 4,12 VLDDR: ;Video Block Move ; Entry BC, IX, HL set ; Exit LDDR on main & 9th bit memory ; Uses BC, DE, HL,IX PUSH IX POP DE PUSH BC ! PUSH DE ! PUSH HL LDDR ;main memory POP HL ! POP DE ! POP BC DI ENADIM LDDR ;9th bit memory DISDIM EI RET space 4,12 VLDIR: ;Video Block Move ; Entry BC, IX, HL set ; Exit LDIR on main & 9th bit memory ; Uses BC, DE, HL,IX PUSH IX POP DE PUSH BC ! PUSH DE ! PUSH HL LDIR ;main memory POP HL ! POP DE ! POP BC DI ENADIM LDIR ;9th bit memory DISDIM EI RET space 4,10 UN_CUR: ;Undo/Invert Cursor ; Entry HL = cursor_addr ; Exit cursor inverted ; Uses A, CY. LD A,[hl] ;get the chr RAL ;cursor_bit => CY CMC ;invert it RAR STO A,[hl] ;... RET PAGE ;KEYBOARD SCANNING & DECODE GKEY: ;KIF 'A'..'Z' CMP '[' JRC :TBLSF ;IF CHR < '[', USE SHIFT TABLE ;MUST BE '[' OR '\' JRNZ :ALPHX ;IF '\', SHIFT AS ALPHA LDK A,']' RET ;...ELSE '[' SHIFTED IS ']' :TBLSF: MOV E,A LDK D,0 ;DE = CHR LDK HL, :STBL - '''' ;TABLE FWA - APOSTROPHE ADD HL,DE ;HL => SHIFTED CHARACTER LD A,[HL] ;A = SHIFTED CHR RET :ALPHA: CMP 'a' RC ;IF <'A', IGNORED BY ALPHA LOCK :ALPHX: XOR 20H ;UPPER/LOWER CASE BIT RET ;SHIFTED "COMMA" BECOMES "LESS THAN", ;SHIFTED "HYPHEN" BECOMES "UNDERBAR", (ETC.) ; ''', ...THESE 4 ARE UNUSED :STBL: DB '"', '{', '}', '|', '~' ; ',', '-', '.', '/', '0', '1', '2', '3', '4', '5' DB '<', '_', '>', '?', ')', '!', '@', '#', '$', '%' ; '6', '7', '8', '9', (:), ';', (<), '=', (>) DB '^', '&', '*', '(', ' ', ':', ' ', '+', ' ' PAGE CNTRL: ;CONTROL KEY PROCESSING ; ENTRY A = CHR, CNTL KEY PRESSED SIMULTANEOUSLY ; EXIT A = ^CHR PROC CMP ' ' + 1 RC ;IF SPACE, TAB, ESC, RET, ETC. CMP '@' JRC :CHEAT ;IF <'@', CKHL := HL or F000h; DE := DE or F000h; ;simple mod-4096 arithmetic to keep pointers INSIDE video memory :vmod: PUSH AF ;save A = #lines to move LK A,0F0h OR H MOV H,A ;set upper nybl of H LK A,0F0h OR D MOV D,A ;modulo 4096 LK BC,VLL POP AF DEC A ;decrement line_count RET space 4,30 CLRLN: ;Clear to end of line ; Entry HL= Cursor ; Exit clear to EOL ; Uses All. proc STO ' ',[hl] ;clear cursor... DI ENADIM STO BRTBIT,[hl] ;set cursor BRIGHT DISDIM EI LD A,LLIMIT DEC A ;max_#cols => maximum_col_# MOV E,L CBIT 7,E SUB E ;A = col(EOL) - col(cursor) RZ ;if @EOL, done JRNC :2 ;if inside logical_video_line LK A,VLL SUB E ;...else clr to end of 128-chr line RZ ;if cursor @ column #127 :2: MOV C,A LK B,0 ;BC = chrs to move ; MOV E,L ; MOV D,H PUSH HL POP IX ; INC DE ;DE = HL + 1 INC IX JR VLDIR page DO_LF: ;Do Line Feed processing ; Entry HL = cursor_addr ; Exit Cursor cleared ; HL updated for current cursor EYBOARD INTERRUPT PROCESSOR ; ENTRY NONE ; EXIT KEYBOARD PROCESSING DONE, RESULT IN LDKEY. ; SYSTEM CLOCK UPDATED BY UPTIM. PROC DI STO SP,IESTK ;SAVE INTERRUPTED PROCESS STK LDK SP,ISTK ;SET TO RAM INT STK ALPUSH CALL UPTIM ;UPDATE SYSTEM CLOCK LD A,KEYLCK OR A JRZ GKEYX ;IF LOCKED KEYBOARD LD A,0EFF0H ORA A JNZ 0EFF1H :SCAN: CALL RDKEY ;SCAN KEYBOARD CMP -2 JRZ GKEYAB ;IF NO KEY BEING PRESSED ;DEBOUNCE THE KEYBOARD: LDK HL,TKEY CMP [HL] ;SAME AS LAST TIME? (SET Z FLAG) STO A,[HL] ;SET TKEY TO CURRENT VALUE MOV B,A ;SAVE CHR LDK HL,HKCNT JRNZ :1ST ;IF THIS IS FIRST SUCH KEYPRESS MOV A,[HL] CMP 0 JZ :2ND ;SECOND TIME FOR THIS KEY :AUTO: DEC [HL] JRNZ GKEYX ;IF STILL WAITING FOR REPD/REPK STO REPK,[HL] ;...ELSE SET REPK FOR NEXT CHR, JR :DCODE ;AND RETURN CHR :1ST: LD A,KBDLY ;GET # OF INTERRUPTS TO DEBOUNCE CALL DELAY XRA A ;ZERO "HKCNT" STO A,HKCNT JR :SCAN :2ND: STO REPD,[HL] ;SET "REPD" DELAY :DCOD, FOR CHEATED CHR CMP 'z'+1 JRNC GKEYAB ;IF GREATER THAN 'Z', NO CNTL-CHR AND ' ' - 1 ;KILL CNTL & LOWERCASE BITS RET :CHEAT: CMP ',' JRC GKEYAB ;IF NOT A LEGAL CHEATED CHR LDK HL,:TBL1-',' :LOOK: ADD L ;DO INDEXED LOAD FROM BASE IN HL MOV L,A JRNC :GET INC H ;IF CARRY, PROPAGATE INTO H :GET: LD A,[HL] RET SPACE 3 ; , - . / :TBL1: DB '{' , '_'-40H, '}' , '~' ; 0 1 2 3 4 DB 80H, 81H, 82H, 83H, 84H ; 5 6 7 8 9 DB 85H, 86H, 87H, 88H, 89H ; : ; DB 00H, 00H ; < = > ? :TBL2: DB ('{'), '`' , ('}'), 7FH SLIDE: ; EXIT 1) RET IF CHR NOT A SPECIAL SLIDING CHR PROC LDK DE,PIABD LDK HL,VRTOFF ;VERTICAL OFFSET SET BY COUT PUSH AF LD A,[DE] ;B=Y MOV B,A POP AF LDK C,+2 CMP LEFT ;LEFT ARROW JRZ :SLIDH LDK C,-2 CMP RIGHT ;RIGHT ARROW JRZ :SLIDH PUSH AF LD A,PIAAD ;C=X MOV C,A POP AF LDK B,+1 CMP UP ;UP ARROW JRZ :SLIDV LDK B,-1 CMP DOBOARD LDK BC, 0800H ;B := 8, C := 0 :LOOP2: RRC ;SHIFT CORRESPONDING BIT INTO CY JRNC :3 ;IF DIDN'T FIND BIT THIS TIME THRU DEC C ;...ELSE RECORD THAT A KEY WAS PRESSED ; MOV E,B ;DON'T NEED TO SAVE LOOP-INDEX LD D,[HL] ;GET CHR FROM TABLE :3: INC HL ;...ELSE TRY NEXT CHR & BIT DJNZ :LOOP2 INC C JRZ :EXIT QUIT: LDK A,-2 RET :EXIT: MOV A,D ;RETURN CHR IN A RET SPACE 4,10 T5KEY: T6KEY: DB ESC, TAB, ERC, ERC, ERC, CR, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',' DB UP, LEFT, '0', ' ', '.', 'p', 'o', '9' DB RIGHT, DOWN, '-', '/', ';', '\', 'L', '=' ; END OCCROM3?.??? LDK B,0 ;BC = OFFSET INTO TABLE LDK HL,T5KEY ;HL = FWA(TABLE) ADD HL,BC ;HL => RANK(KEY) MOV A,D ;RESTORE DATA FROM KEYid. ; Entry None. ; Exit Back to diag main loop. proc CALL DSKDI ;initialize LDK A,100 :2: STO A,TEM CALL GNRN ;get next track STO A,SAVTRK LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if disk error CALL GNRN ;get random CALL DELAY ;delay LD A,TEM DEC A JRNZ :2 ;if not done JR DERC ;display error count space 4,8 ;DDAM: ;Test data address marks ;; Entry None ;; Exit After 1000 tries and displays ; proc ; CALL DSKDI ;initialize disk ; LDK BC,1000 ;:2: PUSH BC ; CALL DRDA ;read address mark ; LDK C,' ' ; JRZ :4 ;if good xfer ; LD HL,ERCNT ; INC HL ; STO HL,ERCNT ;update error count ; LDK C,80h ;pure white space ;:4: CALL COUT ;output indicator ; POP BC ; DEC BC ; MOV A,B ; OR C ; JRNZ :2 ;if not done ; JR DERC ;display error count space 4,8 DERC: ;Display error counter. ; Entry ERCNT = current error count LDK DE,DERCMG CALL ESTR ;output error prompt LD HL,ERCNT JMP ADRD ;output number DERCMG: DBE cr,lf DCE 'ERWN ;DOWN ARROW JRZ :SLIDV ; ^[ CMP '[' RNZ ;IF NOT A SLIDING CHR LD A,[DE] ;OLD Y VALUE AND 11100000B ;SET Y TO ZERO ORA [HL] ;ADD TO HOUSEKEEPING BITS MOV B,A ;VALUE TO B LDK C, VFLO + 2*00 ;SET SCREEN TO 0TH COLUMN JR :SET :SLIDV: LD A,2 ;DELAY 4 MILLISECONS CALL DELAY LD A,[DE] ;ADD TO VIDEO BITS AND 00011111B ADD A,B ;ADD NEW TO OLD AND 00011111B MOV B,A LD A,[DE] ;LAST VALUE AND 11100000B ;CLEAR VIDIO BITS OR B ;ADD NEW VIDIO OFFSET MOV B,A JMP :SET :SLIDH: LD A,PIAAD ;OLD SCREEN OFFSET VALUE ADD A,C MOV C,A :SET: PUSH BC ;SAVE Y CALL OPAD ;MOVE THE SCREEN POP BC MOV C,B CALL OPBD ;SET Y XRA A ;ZERO REG A IF SLIDE RET PAGE RDKEY: ;SCAN KEYBOARD ; ENTRY NONE ; EXIT A = CHR (IF AVAILABLE) ; -2 (IF NO KEY PRESSED) PROC LDK HL,H.KEY + 0FFH ;CHECK ALL PORTS CALL KEYRD ;A=KEY, FLAGS SET JRZ QUIT ;NO KEY LDK HL,H.KEY + 81H ;CHECK FOR CONTROL KEYS CALL KEYRD STO A,CKEY ;SAVE CONT TITLE 'Diagnostic section.' ; This section of code is entered either via the 1st prompt ; level by entering ^d, or by using the monitor command of ; 'T' if DEBUG is assembled on. ; ; This section of code contains all of the rom resident ; diagnostics to assist production and distributors. ; ; The diagnostic section uses a menu and contain test ; for major hardware pieces. These diagnostics are NOT ; considered to be all-encompassing...... DIAG: proc LK SP,ROMSTK LDK DE,DIAMSG DIAG1: CALL ASKU ;ask user for input LDK HL,DSKSWP ;disk swap cell LDK C,0 STO C,[HL] ;SET A=A,B=B CMP 'A' JZ CBOOT ;IF BOOT A DRIVE INC [HL] ;SWAP DRIVES A=B,B=A CMP 'B' JZ CBOOT ;IF BOOT B DRIVE DEC [HL] ;A=A, B=B CMP 'K' JZ KEYBT ;if Keyboard test CMP 'M' JZ TSTMEM ;if memory test CMP 'R' JZ TSERI ;if input test program CMP 'D' JRNZ DIAG ;if illegal DSKD: ;Here to run disk diagnostic LDK DE,DSKMSG CALL ASKU ;Ask user for input SUB 'A' JRZ :2 ;ifR cnt- ' page DSKDI: ;Disk diagnostic initialize ; Entry SDISK set to disk to test(0 or 1) proc LD A,SEC6 STO A,RNDV ;set random seed CALL DDRV ;deselect drive :2: LDK DE,0 STO DE,ERCNT ;clear error count MOV C,E CALL HOMED ;select drive 0, home. JRZ :3 ;if drive ready CALL RDSKC ;reset disk controller LDK DE,DNRMSG CALL ODER ;output disk error JR :2 :3: LDK BC,HSTBUF STO BC,DMADR ;set to default dma RET page ASKU: ;Ask user for input, first displaying prompt ; Entry DE= FWA of prompt message ; Exit A= normalized input from user CALL ESTR ;prompt user CALL GETCH ;get next char CMP ESC JZ DIAG ;if abort RET page KEYBT: ;Perform reading of keyboard and echoing to screen ; Keeps running till user types in ^Z. LDK DE,KEYTM CALL ESTR ;output prompt LDK HL,4000h JMP ACMDD ;enter A command KEYTM: DBE cr,lf DCE 'Enter keys (till ^Z) : ' page TSTMEM: ;performs a test of memory validating that the ; memory is working correROL KEYS AND 11100011B ;NOT SHIFT,CNTRL & A/L LDK L,01H ;CNTRL RANK LDK BC,0700H ;LOOP SEVEN TIMES JR :MIDLE :LOOP1: SLA L CALL KEYRD :MIDLE: JRZ :2 ;IF NO KEY PRESSED IN THIS RANK DEC C ;RECORD THAT A KEY WAS PRESSED MOV E,B ;RECORD 7-RANK# OF KEY PRESSED MOV D,A ;SAVE THE DATA READ :2: DJNZ :LOOP1 ;IF NOT FINISHED READING ALL RANKS INC C ;CK FOR C = -1 JRZ :FBIT ;IF FOUND EXACTLY ONE KEY PRESS ;HERE IF FOUND 1) NO KEYS PRESSED ; 2) MANY (MORE THAN 1) KEYS PRESSED JR QUIT KEYRD: MOV A,L MOV R,A LD A,[HL] XOR 0FFH ;SET FLAGS/COMPLEMENT RET ;HERE TO FIND THE KEY PRESSED IN A PARTICULAR RANK: ;LOAD UP THE APPROPRIATE TABLE ENTRY & RETURN. ; ENTRY D = DATA READ FROM KEYBOARD ; E = 7-RANK# OF ABOVE DATA :FBIT: LDK A,7 ;#RANKS SUB E ;A = TABLE ROW TO USE )0..7) RAL ! RAL ! RAL ;A := A * 8 MOV C,A LDK B,0 ;BC = OFFSET INTO TABLE LDK HL,T5KEY ;HL = FWA(TABLE) ADD HL,BC ;HL => RANK(KEY) MOV A,D ;RESTORE DATA FROM KEY 'A' DEC A JRNZ DIAG ;if not A or B INC A :2: STO A,SDISK ;set drive CALL DRDT ;test reading entire disk CALL DSEKT ;test random seeks JMP DIAG1 ;next DIAMSG: DBE 'Z'-40h DBE ' ROM DIAGNOSTICs' DBE cr,lf,'Select Test:' DBE cr,lf,'A,B Boot Sys' DBE cr,lf,' D isk' DBE cr,lf,' K ey-vdt' DBE cr,lf,' M emory' DBE cr,lf,' R ead in test' DBE lf,cr,lf,' :' DCE ' ' DSKMSG: DBE cr,lf DCE 'Select (A,B): ' ; Disk diagnostic section. DRDT: ;Disk read test ; reads each sector on disk and reports any errors proc CALL DSKDI ;initialize disk LDK A,0 :2: STO A,SAVTRK LDK A,1 :3: STO A,SAVSEC LDK B,1 CALL DREAD ;read sector OR A CNZ DERR ;if error LD A,SAVSEC INC A CMP MSEC+1 JRNZ :3 ;if not full track LD A,SAVTRK INC A CMP MTRK JRNZ :2 ;if not full disk JR DERC ;display error count space 4,10 DSEKT: ;Disk seek test ; Routine performs random seeks followed by reads validating ; drive is aligned and data path is val-ctly. ; Fixed limits on memory test are 4000h to EF00h ; (TEM = EF00h) ; Entry none. ; Exit To error if any errors occurred during ; the testing ; Calls GETNM proc LDK DE,TSMSG CALL ESTR ;prompt user about mem test LDK DE,TEM LDK HL,4000h LDK C,0A5h ;initial test pattern ; Loop thu testing memory within limits ; HL= FWA ; DE= LWA :2: DI PUSH DE ;save LWA PUSH HL ;save FWA :3: STO C,[hl] ;data to memory INC HL ;update address CALL CDEHL JRNZ :3 ;if not all done ; Now perform test on memory reading ; what was just written and comparing ; with pattern C. POP HL ;restore FWA PUSH H :5: DI LD A,[hl] CMP C ;validate good write JRZ :7 ;If GOOD compare EI MOV B,A ;save BAD data PUSH BC CALL OCRLF ;output new line CALL ADRD ;Output Location in error CALL OSP ;Output space char POP BC PUSH BC MOV A,C CALL NMOUT ;Output good data LDK C,'=' CALL COUT MOV A,B CALL NMOUT ;Output BAD data POP BC ;restore pattern CALL BREAK :7: Iaddress JR PBBH space 4,10 BREAK: ;Check for break key. ; Entry NONE ; Exit To DIAG if char entered is ESC, else ; return to caller A= char or 0 if none ; Calls SKEY, CI ; DESTROYS: A,F/F'S CALL SKEY ;get console status RZ ;If not ready CALL CI ;get char CMP ESC JZ DIAG ;if ESC, abort RET space 4,10 GETCH: ;returns the next character in the input stream ; TO the calling program. ; Entry NONE ; Exit C - next character normalized to UPPER case. ; Calls CI,CO,NORM ; DESTROYS: A,C,F/F'S CALL CI ;Get character from terminal CALL CO ;output it JMP NORM ; END OCCROM7?.??? l] INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of  TITLE 'OSBORNE 1 UTILITY ROUTINES.' NMOUT: PBBH: ;PRINT BINARY BYTE IN HEX. ; CONVERTS THE 8 BIT, UNSIGNED INTEGER IN THE ; A REGISTER INTO 2 ASCII CHARACTERS. ; ENTRY A= 8 BIT INTEGER ; EXIT NONE ; CALLS CO,PRVAL ; DESTROYS: AF, C. PUSH AF ;SAVE ARGUMENT RRC RRC RRC RRC ;GET UPPER 4 BITS TO LOW 4 BIT POSITIONS CALL PRVAL ;CONVERT LOWER 4 BITS TO ASCII CALL CO ;SEND TO TERMINAL POP AF ;GET BACK ARGUMENT CALL PRVAL JMP CO SPACE 4,10 PRVAL: ;CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO ; THE CORRESPONDING ASCII CHARACTER, 0-9,A-F. PRVAL ; DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT. ; ENTRY A= INTEGER, RANGE 0 TO F ; EXIT A= ASCII CHARACTER. ; C= A ; CALLS NONE. ; DESTROYS: AF AND 0FH ADD A,90H ;SET UP A SO THAT A-F CAUSE A CARRY DAA ;ADJUST CONTENTS OF A REGISTER ADC A,40H ;ADD IN CARRY AND ADJUST UPPER 4 BITS DAA ;ADJUST CONTENTS OF A REGISTER AGAIN MOV C,A RET OCRLF: ;OUTPUT CR,LF ON CONSOLE SCREEN LK C,CR CALL COUT LK C,LF NC HL CALL CDEHL JRNZ :5 ;If not all done EI ;allow key entry MOV A,C RRC ;shift one position MOV C,A LDK HL,FWAVM+40 INC [hl] ;indicate running POP HL POP DE CALL BREAK JRZ :2 ;if not data MOV C,A ;next test pattern JMP :2 ;keep on looping TSMSG: DBE cr,lf,'Memory tes' DCE 't' page TSERI: ;Input test routine through serial port ; Format of input: ; 8 bit binary data, no parity ; 1st two bytes are DW (length) ; (length) following bytes are placed ; at 4000h in memory; ; Exit: JMP 4000h Proc LK DE,:lmsg ;length msg CALL ESTR CALL READER ;get chr MOV L,C ;low byte of length CALL READER MOV H,C CALL PBWH ;print out length of test routine EX HL,DE ;DE = length LK HL,4000h ;FWA of test program :loop: MOV A,D OR E JRZ :xit ;if finished with input, run prgm CALL READER STO A,[hl] ;get & deposit next byte STO A,FWAVM+40 ;indicate recieved data INC HL DEC DE JR :loop :xit: LK DE,:xmsg ;exit message CALL ESTR TITLE 'FORMAT' FORMT: ;Format one track ; in IBM 3740 format consisting of 40 tracks, with each ; track containing 10 sectors. ; Drive already selected and ready ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK LDK HL,D.TRKR ;PRESENT TRACK OR [HL] JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI REJMP COUT O2SP: ;OUTPUT 2 SPACES ON CONSOLE CALL OSP OSP: LK C,' ' JMP COUT RLWA = * ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',RLWA IF RLWA > 0FFFH .9 ERROR CODE TOO LARGE.. ENDIF ; endx BMUTIL2.asm ; END OCCROM9?.??? ALL CO ;SEND TO TERMINAL POP AF ;GET BACK ARGUMENT CALL PRVAL JMP CO SPACE 4,10 PRVAL: ;CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO ; THE CORRESPONDING ASCII CHARACTER, 0-9,A-F. PRVAL ; DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT. ; ENTRY A= INTEGER, RANGE 0 TO F ; EXIT A= ASCII CHARACTER. ; C= A ; CALLS NONE. ; DESTROYS: AF AND 0FH ADD A,90H ;SET UP A SO THAT A-F CAUSE A CARRY DAA ;ADJUST CONTENTS OF A REGISTER ADC A,40H ;ADD IN CARRY AND ADJUST UPPER 4 BITS DAA ;ADJUST CONTENTS OF A REGISTER AGAIN MOV C,A RET OCRLF: ;OUTPUT CR,LF ON CONSOLE SCREEN LK C,CR CALL COUT LK C,LF  JMP 4000h ;...to user program :lmsg: DBE cr,lf,'Start input: Len' ! DCE '=' :xmsg: DBE cr,lf,'Program begins' ! DCE ':' space 4,10 GNRN: ;Get next random number ; Exit A= new number to use (0 to MTRK-1) proc MOV A,R ;refresh register XOR [hl] AND 3Fh ;cannot exceed 28h=40d ADD A,16 CMP MTRK JC :4 ;if in range SUB MTRK :4: STO A,[hl] ;update RET space 4,10 ACMDD: ;Eotry here from Diagnostic loop HL = 4000h proc :3: CALL CI ;read char CPI EOFC JZ DIAG ;if request to quit STO A,[hl] ;into memory INC HL ;update pointer CPI CR JRNZ :5 ;If not carriage return STO LF,[hl] INC HL :5: MOV C,A CALL COUT ;back to user JR :3 ;next character space 4,10 ADRD: PBWH: ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address to be displayed ; Exit NONE ; Calls PBBH ; DESTROYS: AF, C. MOV A,H ;display First half of address CALL PBBH MOV A,L ;display second half of T ; END OCCROM8?.??? ors. ; Drive already selected and ready ; Entry BC = FWA of buffer ; BUF+0= DW length ; BUF+2= beginning of data ; SAVTRK = next track to format ; SAVSEC = 1 ; Exit track formatted proc PUSH BC ;save address LD A,SAVTRK LDK HL,D.TRKR ;PRESENT TRACK OR [HL] JZ :2 ;if already on track LDK A,D.STPI CALL PSEKC ;perform step IN :2: LDK A,D.WRTT ;request write track DI CALL FDSK ;request write POP HL ;FWA of buffer EI RNZ ;if error DI ; Load BC with length and set ; HL = FWA of data to xmit to disk LD C,[hl] ! INC HL LD B,[hl] ! INC HL ;BC = length of xfer ; Now write out data :4: CALL XDD ;xfer to disk JRNZ :11 ;if error ; Pad rest of track with FFh :10: LD A,D.STSR OR A JRZ :11 ;if all done AND DS.DRQ JRZ :10 LDK A,0FFh STO A,D.DATR ;pad JR :10 ;continue ; Exit A=0, if no error :11: EI RE. TITLE 'B o o t C P / M f r o m d i s k.' ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; ; Before any data is read in, the maximum drive step rate ; must be determined: ; 1. set slowest seek ; 2. home drive A: ; 3. seek track #12 ; 4. speed up step rate ; 5. seek 4 tracks outward (12=>8,8=>4,4=>0) ; 6. if error, slow down step rate by 1, ; load in CP/M, boot, exit, etc. ; 7. else try faster step rate ; (if not fastest, GOTO #4 above) ; 8. if stepping fastest rate, boot CP/M. ; The exit address is to the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDCPME ;if drive NOT ready LDK HL,CCP ;Set buffer address STO HL,DMADR LDK HL,0 STO HL,SAVTRK ;set track LDK A,1 STO A,SAVSEC ;set sector=1 ; Read in 1st two track LDK B,2 :4: PUSH BC LDK B,MSEC CALL DREAD ;read 1st track POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LD HL,SAVTRK INC HL STO HL,SAVTRK ;update track to read DJNZ :4 ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCPM BCPME1: PUSH DE LOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT routines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; ; Disk layout Definition ; --Note: Tracks 0, 1, and 2 are reserved for CPM.-- ; Track 0----------- ; 1 thru 8 CCP 2k ; 9 thru 10 BDOS ; Track 1----------- ; 1 thru 10 BDOS ; Track 2----------- ; 1 thru 2 BDOS 3.5k ; 3 thru 10 CBIOS 2k page CBOOT: ;Entry C= drive to boot from ; Exit A= drive Proc LDK A,6 ;read 6 sectors of trk 3 STO A,TEM MOV A,C CALL BCPM ;boot system LD A,SDISK ;use requested drive JMP BIOS ;enter CPM ; LK A,3 ; STO A,SEKDEL ;set step rate =3 (slowest) ; CALL HOMED ;send A: home ; ; LK BC,12 ; CALL SETTRK ;track 12 ; LK C,0 ; CALL SETSEC ;sector 0 ; CALL SEEK ;do (slow) seek to trk 12, sec 0 ; ;:fastr: DK A,low(256) CALL DELAY ;Delay 256 milli-seconds POP DE ;FWA of message CALL ODER ;indicate drive NOT ready JR BCPM1 ;try again ; Here on Boot READ error BRDE: LDK DE,BRDEMG JR BCPME1 ;delay output error DNRMSG: DCE 'Drive NOT ready.' BRDEMG: DCE 'Boot READ error.' ; END OCCROM2?.???  ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A ;sectors to read :8: PUSH BC LDK B,1 CALL DREAD ;read one sector POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVSEC INC [hl] ;update sector number DJNZ :8 ;if not all secs LDK HL,HSTACT LDK DE,(LOGSEC-HSTACT)+1 CALL FILLZ ;clear Host BIOS cells LDK A,0FFh STO A,UNASEC LDK A,VLL-1 STO A,LDTRK ;set other drive NOT int XRA A ;Clear error indicator RET ; Here on Drive NOT ready BCPME: LDK DE,DNRMSG ; Output error message and return to BCPM BCPME1: PUSH DE L LK HL,SAVTRK ; LK A,-4 ;seek 4 tracks out ; ADD [hl] ; STO A,[hl] ; LK HL,SEKDEL ; DEC [hl] ;speed up step rate ; CALL SEEK ;seek 4 track outwards, faster ; JRNZ :err ;if stepping too fast ; LD A,SEKDEL ; OR A ;stepping fastest possible? ; JRNZ :fastr ;try a faster seek ;; JR :end ;..else seeking fastest already ; ;:end: CALL BCPM1 ;read in cpm ; JMP BIOS ;cold start ; ;:err: LK HL,SEKDEL ; INC [hl] ;seek at previous (slower) speed ; LK A,0000_0011b ; AND [hl] ;limit seek to (slowest) 3 ; STO A,[hl] ; JR :end WBOOT: Proc LDK A,2 ;don't read CBIOS STO A,TEM ;save sectors LD A,CDISK ;Current logged in drive ; JR BCPM ;Boot CP/M space 4,10 BCPM: ;Boot CPM from disk ; Entry A = Drive to boot from. ; TEM = Number of sectors to read from ; track 3. ; A = Drive to boot or warm-boot from ; Exit A = 0, load sucessful. ; Z bit = 1, load successful. proc STO A,SDISK ;Set drive to boot from BCPM1: CALL HOMED ;home drive OR A JRNZ B/0123456789:;<=>?@ABCDEFGHIJKL