IMD 1.16: 13/08/2007 18:27:57 rom 1.3, cbios .3 osborne source 12/16/81  ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċOCCROM13ASM*OCCROM23ASM!OCCROM33ASM€ OCCROM33ASM~OCCROM43ASM_OCCROM53ASMOCCROM63ASMZ !"#$OCCROM73ASM7%&'(OCCROM83ASM )OCCROM93ASM *OCCROM03ASM+OCCBIO23ASM,OCCBIO13ASM,-./OCCBIO63ASM 01OCCBIO83ASM€23456789OCCBIO83ASM:OCCBIO33ASM ;OCCBIO43ASM<=OCCBIO03ASM >OCCBIO53ASM?@OCCBIO73ASMAċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċNOT 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 ; Intialize IEEE port ldk c,1 call ie.co ; 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 romjp1: ldk de,1633h ;offset in bios jump table jr biojp romjp2: ldk de,1636h ;offset in bios jump taple biojp: ld hl,ccpadr add hl,de ;form address jmp [hl] COPYR: DB 'c. 1981 OCC' page ORG 100h ; Jump vector for debugger and CP/M RVEC: JMP CBOOċ 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 ;continueT ;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 romjp1 JMP romjp2 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] JMP XDD ;DMA from memory to disk JMP DMARD ;DMA from disk to memory PAGE OSTR: ;OUTPUT STRING TO CONSOLE ;ENTċ 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 RY ;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 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 ' MONITOR 1.3 ' DB ESC,'(' DB ' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'Z'-40h DB 07Fh,unction ; 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,MSEC ;read 10 sectors of trk 3 STO A,TEM MOV A,C EX AF,AF' ;SET "CCPADR" CALL HOMED ;HOME DRIVE ORA A JRNZ :2 ;IF ERROR LDK HL,0D000H STO HL,DMADR ;SET DMA STO A,SAVTRK ;set track INC A STO A,SAVSEC ;set sectoR MOV B,A CALL RDTRY ;READ SECTOR ONE JRZ :1 ;IF GOOD :2: LDK DE,BRDEMG ;REPORT BOOT READ ERROR CALL ODER BRDEMG: DCE 'READ ERR' ; END OCCROM2?.???  DJNZ :TLOOP ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A CALL RDTRY ;read requested number of sectors JRNZ BRDE ;if read error 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 PAGE RDTRY: ;READ AND RETRY ROUTINE ;ENTRY ;B = NUMBER OF SECTORS TO READ ;EXIT ;ZBIT = SET IF NO ERROR PROC LDK C,5 :1: PUSH BC CALL DREAD POP BC RZ ;IF GOOD DEC C JRNZ :1 ;LOOP ORA A ;SET FLAGS FOR A REG RET PAGE BCPME: ;HERE ON DRIVE NOT READY LDK DE,DNRMSG BCPME1: ;Output error message and return to BCPM CALL ODER JR BCPM1 ;try again BRDE: ;HERE ON BOOT READ ERROR LDK DE,BRDEMG JR BCPME1 ;output error DNRMSG: DCE 'HOME ERR'  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?.???  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 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 ' MONITOR 1.3 ' DB ESC,'(' DB ' ' DB 'D'-40h DB ESC,VEGH DB cr,lf DB ESC,VSGH DB 'Z'-40h DB 07Fh, JR CBOOT ;try again :1: LD A,0D002H ;get ccp address/100h + 3 sub 3 LDK L,0 mov h,a ;BOOT SYSTEM EX AF,AF' ;RECOVER DRIVE TO BOOT FROM PUSH HL CALL BCPM ;boot system POP HL ld a,sdisk STO HL,CCPADR ldk de,1600h ;offset for bios add hl,de ;address of bios in hl jmp [hl] ;enter cpm PAGE WBOOT: Proc LDK A,2 ;don't read CBIOS STO A,TEM ;save sectors LD A,CDISK ;Current logged in drive LD HL,CCPADR PAGE BCPM: ;Boot CPM from disk ;ENTRY ;A = DRIVE TO BOOT FROM ;HL = DMA ADDR FOR CCP ;TEM = Number of sectors to read from track 3. ;EXIT ;A = 0 IF NO ERROR ;ZBIT = SET IF NO ERROR proc STO A,SDISK ;Set drive to boot from STO HL,DMADR ;SET DMA BCPM1: LDK B,5 ;RETRY :HLOOP: PUSH BC CALL HOMED ;home drive POP BC OR A JRZ :1 ;IF GOOD DJNZ :HLOOP ;LOOP JR BCPME ;if drive NOT ready :1: STO A,SAVTRK ;set track INC A STO A,SAVSEC ;set sector=1 ; Read in 1st two tracks LDK B,2 :TLOOP: PUSH BC LDK B,MSEC CALL RDTRċ 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 BDOS (fY ;read 1st track POP BC JRNZ BRDE ;if read error STO HL,DMADR ;update DMA LDK HL,SAVTRK INC [HL] ;SAVTRK=SAVTRK+1 DJNZ :TLOOP ;if not all tracks ; Now read in requested number of sectors ; from track 3. LD A,TEM MOV B,A CALL RDTRY ;read requested number of sectors JRNZ BRDE ;if read error 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 PAGE RDTRY: ;READ AND RETRY ROUTINE ;ENTRY ;B = NUMBER OF SECTORS TO READ ;EXIT ;ZBIT = SET IF NO ERROR PROC LDK C,5 :1: PUSH BC CALL DREAD POP BC RZ ;IF GOOD DEC C JRNZ :1 ;LOOP ORA A ;SET FLAGS FOR A REG RET PAGE BCPME: ;HERE ON DRIVE NOT READY LDK DE,DNRMSG BCPME1: ;Output error message and return to BCPM CALL ODER JR BCPM1 ;try again BRDE: ;HERE ON BOOT READ ERROR LDK DE,BRDEMG JR BCPME1 ;output error DNRMSG: DCE 'HOME ERR'  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 perZ 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 retu 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 braD 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 ;HOUSEnch 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: ;Insline 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 VÈA_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 = 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 ;Control 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_A-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. ; Bytpace 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 ; e 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 Z ;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 withservice 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 ; LDK L,1 ; CALL RDROW ; PUSH psw ; LDK l,80h ; CALL rdrown. ; input: ; Reg A = Keynumber ; output: ; Z ind clr = Key is off. ; Z ind set = Key is on. CHKEY: 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 MOV A,L MOV R,A ld a,[hl] xor 0ffh ;invert values ret PAGE ;** ; sbrt: KBSERV - services the key ; input: ; reg A = keynumber ; [SP]-4 = poinar 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 ;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,  ; ANI 08h ; MOV B,A ; POP PSW ; OR B and 11100011b ;remove ctl/shift and alpha lock LDK b,tot_row ; 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 ter 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 8ch 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,1 ;row 0 adrs call rdrow ;get row containing ctl,shift and alpha key ; PUSH AF LDK L,80H CALL RDROW ANI 8 MOV E,A POP AF OR E ; 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' jrncerc 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', '=' 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, 00H, 60H ; END OCCROM3?.??? o ;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, entry is used then and krow_m+kcol_m cmp c ;check with current key jrz :27 ;exit if 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 o :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 codes 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 BIT shft_ky,e ;test for cntl shift jrz :52 ;if not cmp '/' ;is it ? jrnz :52 ;if not '?' ldk a,07fh ;deleat key jr :12 :52: cmp '@' jrc :54 ;goto translate chars from table cmp 'z'+1 jrnc :12 and 1fh jr :12 :54: cmp ',' jrc :12 ;no translation if ch 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 ndac/nrfd CBIT 1,[HL] SBIT 1,[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 PARAME 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 CTERS 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 ,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 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 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 ;: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 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?.??? D 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  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 ACCE 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,PTOR 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 ċ 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 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.BSY,A JRZ :1 BIT BS.DRQ,A JZ :LOOP ;if no data LD A,[HL] STO A,D.DATR ;send to controller INC HL DEC BC MOV A,B OR C JNZ :LOOP ;if not done RET :1: ORI 80H 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 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 DACTVOV 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 bc,lsecb call dmard jrnz rwex ;if error ; 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 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 RWE 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 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  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: EX1 ;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 PAGE DMARD: ;TRANSFER DATA FROM CONTROLER TO MEMORY ;ENTRY ;BC = LENGTH ;HL = FWA OF BUFFER ;EXIT ;HL = NEXT ADDRESS ;A = 80 IF BUSY DROPPED BEFORE BC=0 PROC LDK DE,D.STSR :LOOP: LD A,[DE] BIT BS.BSY,A JRZ :1 ;DROPPED BUSY BEFORE BC = 0 BIT BS.DRQ,A JZ :LOOP ;if no data LD A,D.DATR STO A,[HL] ;TO MEMORY INC HL DEC BC MOV A,B OR C JNZ :LOOP ;if not done RET :1: ORI 080H RET PAGE XDD: ;Xfer data from memory to disk ;ENTRY ;BC = LEANTH ;HL = FWA ;EXIT ;HL = NEXT ADDR ;A = 80 IF BUSY DROPPED BEFORE BC=0 PROC LDK DE,D.STSR :LOOP: LD A,[DE] BIT BS = 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 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: ;...s '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 DIAG ;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): ' PAGE ; Disk diagnostic section. DRDT: ;Disk read test ;reads each sector on disk and reports any errors proc CALL DSKDI ;initialize disk :2: STO A,SAVTRK LDK B,1 MOV A,B STO A,SAVSEC ;SECTOR = 1 CALL DREAD ;read sector CNZ DERR ;if error LD A,SAVTRK INC A CMP MTRK JRNZ :2 ;if not full disk ret PAGE DSEKT: ;Disk seek test ; Routine performs random seeks followed by reads validating ; drive is aligned and data path is valid. ; Entry None. ; Exit Back to diag main loop. proc CALL DSKDI ;initialize LDK B,100 :2: PU 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: 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 aves 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 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 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: ;...sSH BC CALL GNRN ;get next track STO A,SAVTRK LDK B,1 MOV A,B STO A,SAVSEC ;SECTOR = 1 CALL DREAD ;read sector CNZ DERR ;if disk error CALL GNRN ;get random CALL DELAY ;delay POP BC DJNZ :2 ;if not done RET 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 LDK B,5 ;RETRY :2: PUSH BC CALL HOMED ;select drive 0, home. POP BC JRZ :3 ;if drive ready DJNZ :2 ;RETRY FIVE TIMES LDK DE,DNRMSG ;DRIVE NOT READY JMP DIAG1 :3: LDK HL,04000H STO HL,DMADR ;SET 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 coA,[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 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 t 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 LDK DE,DIAMSG DIAG1: LK SP,ROMSTK 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 ;ifmmand KEYTM: DBE cr,lf DCE 'Enter keys (till ^Z) : ' page TSTMEM: ;performs a test of memory validating that the ; memory is working 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  o 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 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?.???  ;Print Binary Word in Hex. ; PBWH outputs to the console the address ; contained in the H,L registers. ; Entry HL= address tT ; 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 'Osborne-One Monitor for Model 1 system.' ; +-------------------------------+ ; | | ; | Osborne-One Monitor | ; | | ; +-------------------------------+ ;VER = REV 3 ;DATE = 349 ;Developed for use with the new cbios CCP = 0 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 OCCROM13.ASM ;ROM STANDARDS LINK OCCROM23.ASM ;CPM BOOT LINK OCCROM33.ASM ;CONSOL ROUTINES LINK OCCROM43.ASM ;PIA ROUTINES LINK OCCROM53.ASM ;SIA ROUTINES LINK OCCROM63.ASM ;DISK ROUTINES LINK OCCROM73.ASM ;DIAGNOSIC ROUTINES LINK OCCROM83.ASM ;FORMAT ROUTINE LINK OCCROM93.ASM ;UTILITES LINK OCCRAM2.ASM ;RAM LOCATIONS ; Endx ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ 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 ċ 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 = *-1 ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',RLWA IF RLWA > 0FFCH .9 ERROR CODE TOO LARGE.. ENDIF org 0ffdh SERNO: ds 3 ; ; 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  ; Sector Translation Tables. org BIOS+256 XLTS: ;Translation table 2 to 1 DB 0, 1, 4, 5, 8, 9, 12,13, 16,17 DB 2, 3, 6, 7, 10,11, 14,15, 18,19 ; Translation 3 to 1 ; DB 0, 1, 6, 7, 12,13, 18,19 ; DB 2, 3, 8, 9, 14,15 ; DB 4, 5, 10,11, 16,17 ; Translation 4 to 1 ; DB 0, 1, 8, 9, 16,17 ; DB 2, 3, 10, 11, 18,19 ; DB 4, 5, 12, 13 ; DB 6, 7, 14, 15 IF (*-XLTS) <> (MSEC*2) MSG 'Translation table error',ERROR ENDIF space 4,10 ; Control Blocks for disk drives DPBASE: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive A: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive B: space 4,10 ; Disk type definition blocks for each particular mode. DPBS1: ;Single density, single sided. DPBGEN DSKS1,2*MSEC,4,15,1,S1DSM,64,1000000000000000b,3 .AL IF ALVSZ <> ALVS MSG 'Allocation problems ALVS<> ALVSZ, ALVSZ= ',ALVSZ .9 ERROR .AL ENDIF ; endx OSBBIOS2 ro for generating Control Blocks for disk drives ; The format of these disk control blocks are as follows: ; 16 bits = -> translation table. ; 48 bits = Work area for CP/M. ; 16 bits = -> DIRBUF. ; 16 bits = -> Parameter block. ; 16 bits = -> check vector. ; 16 bits = -> allocation vector. NDSK: SET 0 ;Number of disk drives NOFDD: SET 0 ;Number of floppy disk drives ALVSZ: SET 0 ;Allocation vector size CSVSZ: SET 0 ;Check vector size LIST D,G,M DPHGEN MACRO TYPE,XLATE,DIRBUF,DPBADR NDSK: SET NDSK+1 DW %2 DW 0,0,0 DW %3 DW %4 DW CSV+CSVSZ DW ALV+ALVSZ NOFDD: SET NOFDD+1 CSVSZ: SET CSVSZ+(64/4) ALVSZ: SET ALVSZ+((S1DSM+7)/8) ENDM ; Make sure Systext agrees with assembled size space 4,10 ; Macro for generating the Disk Parameter Blocks. ; ; Disk type definition blocks for each particular mode. ; The format of these areas are as follow: ; 8 bit = disk type code ; 16 bit = Sectors per track ; 8 bit = Block shift ; 8 bit = BS mask ; 8 bit = Extent mask ; 1; iobite: db 40h ;default to serial printer=40h ; parallel printer=80h ; IEEE printer=c0h prnter: db 00h ;default to standard serial=0 ;Qume ETX/ACK =1 ;Diablo XON/XOFF =2 ahsenb: db TRUE ;auto horizontal scroll enable brate: db si.120 ;default baud rate = 1200 scrsze: db 128 ;default screen size = 128 ; xltbl: dw cntrl0 ;Fixed length table dw cntrl1 ;contains pointers dw cntrl2 ;to strings dw cntrl3 ;to decode dw cntrl4 ;function keys dw cntrl5 dw cntrl6 dw cntrl7 dw cntrl8 dw cntrl9 dw up dw right dw down dw left dw eotbl ;end of table address ; acmd: db 1 ;auto command = 0 ignore auto boot ; = 1 auto on cold boot ; = 2 auto on warm boot ; = 3 auto on both cauto: db cautol ;length of auto command here db 'AUTOST ' ;auto command goes here cautol: = *-cauto-1 ; cntrl0: db '0' ;Variable length table cntrl1: db '1' ;is placed here by set-up cntrl2: db '2' ;program, with xlttbl cnċ6 bit = Disk size/1024 - 1. ; 16 bit = Directory size. ; 16 bit = Allocation for directory. ; 16 bit = check area size. ; 16 bit = offset to first track. DPBGEN MACRO TYPE,SPT,BSH,BSM,EXM,DSM,DIRSIZ,ALVMSK,OFFSET DB %1 DW %2 DB %3,%4,%5 DW %6-1,%7-1,REV (%8) DW (%7+3)/4 DW %9 ENDM page ; The following jump table defines the entry points ; into the CBIOS for use by CP/M and other external ; routines; therfore the order of these jump cannot ; be modified. The location of these jumps can only ; be modified by 400h locations, which is a restriction ; of MOVCPM. ORG BIOS jmp CBOOT ;Cold boot jmp WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: trl3: db '3' ;pointing to the entries cntrl4: db '4' ; cntrl5: db '5' ;Default values for the cntrl6: db '6' ;control numerics cntrl7: db '7' ;are the numbers on the keys cntrl8: db '8' cntrl9: db '9' ; up: db 'K'-40h ;Default values right: db 'L'-40h ;for the cusor down: db 'J'-40h ;keys are standard left: db 'H'-40h ;values for CP/M eotbl: = * ; ;space reseverd for full function ;key decoding and 16 byte auto ;boot command 5 dw cntrl6 dw cntrl7 dw cntrl8 dw cntrl9 dw up dw right dw down dw left dw eotbl ;end of table address ; acmd: db 1 ;auto command = 0 ignore auto boot ; = 1 auto on cold boot ; = 2 auto on warm boot ; = 3 auto on both cauto: db cautol ;length of auto command here db 'AUTOST ' ;auto command goes here cautol: = *-cauto-1 ; cntrl0: db '0' ;Variable length table cntrl1: db '1' ;is placed here by set-up cntrl2: db '2' ;program, with xlttbl cn page ;***** ; Revisions: ; YNS 18AUG81 change bios jump vector to call new routines ; RWC 05OCT81 standardize cpm jump table (change calls to jumps) ; RWC 16OCT81 added function key table and user defined switches ; ;***** MRTRY: = 5 ;Maximum number of retries. msize: = 60 ;ccp: = (msize-8)*1024 ;location of ccp CCP: = 100H bios: = ccp+1600h bdos: = ccp+806h MSG 'Assemblying BIOS for LWA of ', LWAMEM,'h.' ; CP/M to host disk constants HSTSIZ: = 256 ;Blocking/Deblocking buffer size FPYSIB: = 2048/128 ;Sectors in floppy disk block ; CP/M disk control block equates which define the ; disk types and maximum storage capability of each ; disk type. DSKS1: = 0 ;Single density, single sided. S1DSM: = ((40-3)*2*10)/FPYSIB ; BDOS constants on entry to write WRALL: = 0 ;write to allocated WRDIR: = 1 ;write to directory WRUAL: = 2 ;write to unallocated space 4,10 ; ROM equates. ENROM: = 0 ;Port to enable ROM DIROM: = 1 ;Port to disable ROM page ; MacJMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident call SBAUD: CALL ROMCDE ; IEEE-488 vectors ieb1c: CALL ROMCDE ;Control Out ieb2c: CALL ROMCDE ;Status In ieb3c: CALL ROMCDE ;Go To Standby ieb4c: CALL ROMCDE ;Take Control ieb5c: CALL ROMCDE ;Output Interface Message ieb6c: CALL ROMCDE ;Output Device Message ieb7c: CALL ROMCDE ;Input Device Message ieb8c: CALL ROMCDE ;Parallel Poll call romcde ;extensions call romcde ; for call romcde ; memory-mapped video jmp acictl ;hook for serial command port write jmp acistat ;hook for serial status port read ; ;;;;;;;;;;;;;;;;;;;;;;; ; ; This area is reserved data storage area for ; the set-up program to install printer drivers, ; function keys, auto boot command, iobyte value, ; and auto horizontal scroll flag ; RWC ;;;;;;;;;;;;;;;;;;;;;;;  page READ: ;a CP/M 128 byte sector. ; ; EXIT A = 0, successful read operation. ; A = 1, unsucessful read operation. ; Z bit = 1, successful read operation. ; Z bit = 0, unsuccessful read operation. CALL MVINFO ;Move information for transfer XRA A ;Set flag to force a read STO A,UNACNT ;Clear sector counter CALL FILL ;Fill buffer with data POP HL POP DE LDK BC,128 ;Move 128 bytes LDIR LD A,ERFLAG ORA A RZ ;If no error XRA A STO A,HSTACT ;Clear host active ORI 001h ;Set error flag RET space 4,20 WRITE: ;the selected 128 byte CP/M sector. ; ; ENTRY C = 0, write to a previously allocated block. ; C = 1, write to the directory. ; C = 2, write to the first sector of unallocated ; data block. ; ; EXIT A = 0, write was successful. ; A = 1, write was unsucessful. ; Z bit = 1, write was successful. ; Z bit = 0, write was unsucessful. CALL MVINFO ;Move information for transfer MOV A,C ;Write type in c STO A,WRTYPE CPI WRUAL JRNZ WRIT2 ;Ik. FLUSH: LDK HL,HSTWRT LD A,[hl] ORA A RZ ;If host buffer already on disk STO 0,[hl] LD A,HSTDSK ;Move disk and type STO A,ACTDSK LD HL,HSTTRK STO HL,ACTTRK LD A,HSTSEC STO A,ACTSEC LDK A,3 ;Write flag ; JMP FINAL space 4,10 FINAL: ;Preform final transfer processing. ; ; ENTRY A = 0 .. read disk. ; = 3 .. write disk. ; Calls: Rom resident routine to read/write ONE ; sector only. MOV E,A LDK D,0 LDK HL,ROMVEC+3*13 ADD HL,DE STO HL,SAVADR LDK HL,ACTSEC INC [hl] ;update sector+1 LDK A,MRTRY ;Set retry count FNL1: STO A,RTRY ;Clear retry count LD HL,SAVADR EX DE,HL LDK B,1 ;indicate one sector xfer CALL ROMJMP ;process read or write STO A,ERFLAG ;set possible error flag RZ ;If no errors LD A,RTRY ;Get retry counter DEC A JRNZ FNL1 ;If not permanent error ORI 01h STO A,ERFLAG ;Set error flag RET ; endx OSBBIOS6.asm  crt. (always ready) ; =1: status of serial printer ; =2: status of parallel printer ; =3: status of ieee port (always ready) ; LSTST: proc mvi b,4 ;number of left shifts thru carry ;to align LIST field of IOBYTE ldk hl,ptr_lst ;list status routines jmp dispch page dispch: proc ; on entry here reg B contains the left shift count ; required to align the iobyte field to bit 1 position. ; and reg HL contains address of select table lda iobyte dspch1: ral djnz dspch1 ani 6 ;get select field*2 mov e,a ldk d,0 ; de = iobyte field * 2 dad de mov e,m inx hl mov h,m ; get the routine address mov l,e ; into hl and xchange with pc pchl ; ; addresses of routines ; ptr_cstat: dw const ; keyboard status dw sistat ; serial port input status dw pistat ; parallel input status dw ieinstat ; status of input device on IEEE port ptr_rdr: ptr_cinp: dw keyinp ; get input from keyboard dw spinp ; serial port input dw parinp ; parallel input f write to allocated LDK A,2048/128 STO A,UNACNT LD HL,SEKTRK STO HL,UNATRK ;UNATRK = SEKTRK LD A,LOGSEC INC A JR WRIT3 WRIT2: LDK HL,UNACNT LD A,[hl] ORA A JZ WRIT4 ;If no unallocated records DEC [hl] ;dec unalloc record count LD A,UNASEC ;Increment logical sector INC A CPI 2*10 JRNZ WRIT3 ;If not end of track LD HL,UNATRK INC HL STO HL,UNATRK XRA A WRIT3: STO A,UNASEC LDK A,0FFh WRIT4: CALL FILL POP DE POP HL LDK BC,128 LDIR LDK A,1 STO A,HSTWRT ;HSTWRT = 1 LD A,ERFLAG ORA A RNZ ;If any errors occurred LD A,WRTYPE ;write type CPI WRDIR ;to directory? CZ FLUSH ;Force write of directory LD A,ERFLAG ORA A RET page ; FILL - fill host buffer with approprite host sector. ; ; ENTRY A = 0, Read required if not in buffer. ; 0therwise read not required. ; ; EXIT On exit the stack will contain the following ; values: ; POP x ;x = host record address. ; POP y ;y = caller's buffer address.  page ;***** ; ; Revisions: ; YNS 20AUG81 Initial release ; YNS 29AUG81 Expanded trans. table to include ctl/numerics ; YNS 01SEP81 Added parallel port support ; YNS 05SEP81 Invert data to/from parallel port ; YNS 06SEP81 Return character in C as well as A from ; all input routines. ; YNS 08SEP81 Fixed "some" ieee bugs ; YNS 20SEP81 Recode ieee drivers to send untalk and ; unlisten commands after each char xfr. ; YNS 29SEP81 Add auto horiz. scroll ; RWC 14OCT81 Reassignment in dispatch table ; Redefinition of iobyte assignments ; Printer protocols added to serial list device ; Function key decoding added ; RWC 20OCT81 Horizontal scroll toggle added ; RWC 24OCT81 Horizontal scroll modified ; ;***** ; ; the following routines will use the IOBYTE to transfer ; control to the appropriate device driver ; ;-------------- ; return console status ; CNSTA: proc ldk hl,ptr_cstat ; status table jr godispch ; call appropriate rtn ;------------ ; read idw ieinp ; ieee port input ptr_pnch: ptr_cout: dw crtout ; output character to crt dw spout ; serial port output dw parout ; parallel output dw ieout ; ieee port output ptr_lst: dw crstat dw sostat ; serial output status dw postat ; parallel output status dw ieostat ; ieee output status ptr_list: dw crtout dw prtout dw parout dw ieout ; page ; C O N S O L S T A T U S ; ; This routine samples the Console status and returns the ; following values in the A register. ; ; EXIT A = 0 (zero), means no character ; currently ready to read. ; ; A = FFh (255), means character ; currently ready to read. nokey equ 00h ;indicates key not present CONST: proc ; check if any translated keys are pending ld a,count ora a jrnz const5 ; if no xlated keys pending, check keyhit flag LD A,LKEY ;Get Key hit flag xri nokey RZ ;If data not available const5: ORI 0FFh RET page ;** ; Routine name: KEYINP - gets keystroke from rom kbd driver. Trans FILL: STO A,RDFLAG ;Save read flag LDK DE,HSTBUF ;initial offset LDK HL,128 ;128 byte records LD A,SEKSEC ;Get logical sector EX DE,HL RRC JRNC FILL3 ;If low bit not set ADD HL,DE ;Add bias to offset FILL3: EX DE,HL ADD HL,HL ANI 07Fh ;Mask sector STO A,SEKSEC LD HL,DMAADR XTHL ;Set return parameters PUSH DE PUSH HL ;Set return address LDK HL,HSTACT ;host active flag LD A,[hl] STO 1,[hl] ;always becomes 1 ORA A JRZ FILL6 ;If host buffer inactive LDK HL,HSTSEC LDK DE,SEKSEC LDK B,SEKDSK-SEKSEC+1 FILL4: LD A,[de] CMP [hl] JRNZ FILL5 ;If mis-match INC HL INC DE DJNZ FILL4 ;If all bytes not checked RET FILL5: CALL FLUSH ;Flush host buffer FILL6: LD A,SEKDSK ;Move disk and type STO A,HSTDSK STO A,ACTDSK LD HL,SEKTRK STO HL,HSTTRK STO HL,ACTTRK LD A,SEKSEC STO A,HSTSEC STO A,ACTSEC LD A,RDFLAG ORA A RNZ ;If no read required LDK A,0 ;Read JR FINAL space 4,10 ; FLUSH - Write out active host buffer onto disnput character from device ; CNIN: proc ldk hl,ptr_cinp ; table of input rtns jr godispch ;------------- ; put output character to device ; c contains output character ; CNOUT: proc ldk hl,ptr_cout ; table of output rtns godispch: mvi b,1 ;number of shifts required to align ;CONSOLE field jmp dispch ;--------------- ; list device character output ; LST: proc mvi b,4 ldk hl,ptr_list ;table of list routines jmp dispch ;--------------- ; output to punch ; PNCH: proc mvi b,6 ldk hl,ptr_pnch ; punch routines jmp dispch ;---------------- ; reader input ; RDR: proc mvi b,8 ldk hl,ptr_rdr ; reader routines jmp dispch space 4,10 ; L i s t S t a t u s. ; ; Return the ready status for the list device. ; ; EXIT A = 0 (zero), list device is not ready to ; accept another character. ; A = FFh (255), list device is ready to accept ; a character. ; The list status is returned depending upon the iobyte fields ; LIST field (bits 6,7) ; =0: status oflates ; the codes 80h to 8fh as per table. ; ; Outputs: A = translated code in ASCII ; All registers are destroyed ; basvl0 equ 80h ;lowest value of translatable keys xltkey ds 2 ; KEYINP: proc ; if there are no xlated keys waiting then ; call the keyboard driver in rom call ahscrl ldk hl,count ld a,[hl] ;get number of xlated keys ora a jrz kin10 ;if keys pending then ld ix,xltkey ;get base address in IX reg db 0DDh,7Eh ;simulate LD A,(IX+COUNT) count: db 0 ;to get next key from table inc [hl] ;increment count ret kin10: ldk e,low(conin) call romcd1 ; When console has returned this code will check ; for function key and preform some translation cpi 80h ;function keys have value rc ;80h-8dh cpi 8Eh ;do a shift to make pointer rnc ;into table and return if not function key sla a ; mov e,a ; ldk d,0 ; ldk ix,xltbl ; add ix,de ; ld l,[ix+0] ld h,[ix+1] ld e,[ix+2] ld d,[ix+3] sto de,xltkey sbc hl,de mov a,lt ;** ; routine: SISTAT ; gets status of input device attached to serial port SISTAT: proc call acistat ani si.rrdy rz ;return with not ready status ori true ret ;** ; routine: SPINP ; Inputs a character from the serial port ; Uses the reader (sp) driver in ROM ; SPINP: proc ldk e,low(reader) jmp romcd1 ;** ; routine: SPOUT ; Outputs character in reg c to the serial port (list device) ; calls the list (sp) driver in ROM ; SPOUT: proc ldk e,low(list) call romcd1 ret ;** ; routine does serial i/o and does printer protocols ; xon: = 11h xoff: = 13h etx: = 3 ack: = 6 ; prtout: call spout ld a,prnter ora a rz ani 2 jrnz xonxof mvi a,0dh cmp c rnz ldk c,etx call spout prt10: call spinp cpi ack jrnz prt10 ret xonxof: call sistat ora a rz call spinp cpi xoff rnz prt20: call spinp cpi xon jrnz prt20 ret ;** ; routine: ACICTL ; outputs character in c to the ACIA CTL port. ; ACICTL: proc callead the device ; if char read then ; store in bfr ; endif ; make untalk ; return with status of buffer ; endif IEINSTAT: proc lda ie_char ora a jz iei10 ;if char present then ori 0ffh ;return with true status ret iei10: ;endif ;make talker lda ie_adrs adi ie_talk ;get primary address mov c,a ldk e,low(ieb5c) call romcd1 ;output interface message ora a jrnz iei10 ;try again if error ; ; ***secondary address output may be added here*** iei20: ;read a char. ldk e,low(ieb7c) call romcd1 bit 7,l jrz iei30 ;if error then xra a ;inicate no char recvd iei30: sta ie_char ;stor the char ; ; iei40: ;make untalk mvi c,ie_utlk ldk e,low(ieb5c) call romcd1 ora a jrnz iei40 ; return with status of the char lda ie_char ora a rz ori 0ffh ret ;** ; routine: IEINP ; Reads a character from IEEE port IEINP: proc call ieinstat jrz ieinp ;wait till char avail ldk hl,ie_c sto a,count ; jr keyinp ; ; ; page ;** ; routine: CRSTAT ; returns status of crt. ; crt is always ready ; IEOSTAT returns status of ieee ; ieee always appears to be ready ieostat: CRSTAT: proc ori 0FFh ret ;** ; routine name: CRTOUT ; ; inputs: C: output character EF_ESC: = 8 ;escape flag bit definitions EF_GR: = 1 ; CRTOUT: proc lda esch and ef_esc+ef_gr ; push af jrnz crt10 mov a,c cpi 14h jrnz crt10 ld a,ahsenb cma sto a,ahsenb ; pop af ret crt10: ; call outch ; pop af ; rnz ; mvi a,cr ; cmp c ; cz ahscrl ; ret ; sbrt: outch - calls rom cout routine outch: ldk e,low(conout) ;output to crt jmp romcd1 ; sbrt: ahscrl - does auto horizontal scroll if required. ahscrl: proc ld a,ahsenb or a rz ld hl,curs ;get cursor add hl,hl ; check for cursor in home window ldk a,100 cmp l jrc rhc ;jump if cursor not in home window ld a,piaad ;check for screen at home sub vflo rz ;screen at home  sw2rom mov a,c sta h.sctrl jmp sw2ram ;** ; routine: acistat ; returns usart status in A ; The ringin signal is read from the pia at address 2c00 ; and merged in at the overrun error bit of the acia status riport equ h.vio+1 ribit equ 040h ormask equ 020h acistat: proc call sw2rom lda riport ;read in ringin signal rrc ;shift ring in to overrun err ;position ani ormask ;get ring in mov c,a lda h.ssts ani 0ffh-ormask ;remove overrun error bit ora c ;merge ring in bit jmp sw2ram page ;*** ; IEEE drivers: ; ; The routines IEINSTAT, IEINP and IEOUT are used to ; transfer characters to and from an IEEE device attached to the ; OSBORNE IEEE port. The address of the device is specified in ; the cell IE_ADRS. No facility is provided at present to allow a ; transient programme to specify the device address. Thus the device ; attached must be addressable as 0 (zero). ; The function IEINSTAT returns the status of the input device. ; Unfohar ld a,[hl] sto 0,[hl] ;clear the buffer ret ;** ; routine: IEOUT ; Outputs the character in reg C to IEEE port ; Uses ROM resident primitives. ; IEOUT: proc push bc ;save the char ;make listener ieo05: lda ie_adrs adi ie_lstn ;get primary address mov c,a ldk e,low(ieb5c) call romcd1 ;output interface message ora a jrnz ieo05 ;try again if error ; ; ***secondary address output may be added here*** ; ieo20: ; mvi b,0 ;do not send eoi pop b ieo22: push b ;save char again in case of retry ldk e,low(ieb6c) call romcd1 pop b ora a jrnz ieo22 ;try again if error ; ; ;make unlisten ieo40: mvi c,ie_ulstn ldk e,low(ieb5c) call romcd1 ora a jrnz ieo40 ret page ;*** ; The Parallel port is actually the IEEE port driven with the centronix ; protocol. The bit assignements of the PIA and PIB are as follows: ; PIA0-7 = data bus ; PIB0 = 0, data bus is output. 1, data bus is input ; PIB1 = set to 1. ; Pxra a ;home screen jr scrl rhc: ; check right-hand margin ld a,piaad ;a=horizontal screen position sub vflo add a,100 ;window size*2 (49) cmp l jc :30 ;move screen when cursor about to go off ;the right hand margin ; check left hand margin sub 90 cmp l ;check left margin rc ;cursor in window return mov a,l sub 10 rz ;return if cusor at column 2 jr scrl :30: mov a,l sub 100 scrl: rar add a,' ' lk hl,escsq+3 sto a,[hl] ld a,piabd and 1fh add a,' ' dec hl sto a,[hl] ;escsq+2 = vert. coords dec hl dec hl ;point to start of esc seq lk b,4 :50: push bc push hl ld c,[hl] call outch pop hl pop bc inc hl djnz :50 ret escsq db esc ;set screen coord escape sequence db 'S' db 0 ;** y coord db 0 ;** x coord page ;** ; routine: SOSTAT ; gets status of output device attached to serial port SOSTAT: proc call acistat ;get 6850 status ani si.trdy rz ;return with not ready status ori true rertunately there is no standard way by which an IEEE device ; indicates that it has a character. In order to determine this, one ; has to read the character device. As a CP/M transient can call ; IEINSTAT many times before calling IEINP to read a char, and IEINSTAT ; has to read the char to determine the status, the character read has to ; be buffered till call to IEINP is made. IEINSTAT reads the device ; only when the buffer is empty. As zeros are used to indicate ; that the bfr is empty, a null character can not be read from the ; IEEE device. ; IEEE control codes ie_talk equ 40h ;make talker ie_utlk equ 5fh ;make untalk ie_lstn equ 20h ;make listener ie_ulstn equ 3fh ;make unlisten ie_adrs db 0 ;device address (can be moved to ;BMRAM) ie_char db 0 ;ie inp char buffer ;** ; routine: IEINSTAT ; gets status of the input device attached to ieee port ; ; if a char is present in ie_char then ; return with true status ; else ; make device talker ; rIB2 = set to 0. ; PIB3 = 0 output, 1 Input ; PIB4 = not used ; PIB5 = output strobe. Active = 1. ; PIB6 = 0, printer busy. 1, printer is ready. ; PIB7 = not used. ; ; CA2 = going low indicates to device that we are busy. ; CA1 = low to high transition gates input data to port a. ; ; The port is bidirectional but only one direction ; can be active at any time. The direction of port is determined ; by which routines are called. If postat or parout are ; called, it is made an output port and an input port if ; pistat or parinp are called. ; port registers pa.dta equ h.ieee+0 pa.dir equ pa.dta pa.ctl equ h.ieee+1 pb.dta equ h.ieee+2 pb.dir equ pb.dta pb.ctl equ h.ieee+3 ; port ctl register constants. pa.cdr equ 00101010b ;to address port a direction pa.cdt equ 00101110b ;to address port a data and set ;port a in input program handshake mode. pb.cdr equ 00000000b ;to address port b direction pb.cdt equ 00000100b ;to address port b data ; direction register constants pa.droroutine: PISTAT ; gets status of the input device attached to the ; parallel port ; piactl db 0 PISTAT: proc call sw2rom call cv2ip lda piactl ani pp.irdy jrnz pis20 ;if saved status indicates there is a char ;in the PIA lda pa.ctl sta piactl ;this is saved as reading the ;pia clears the status ani pp.irdy jrz pis30 pis20: ori true pis30: jmp sw2ram ;** ; routine: PARINP ; inputs a character from parallel port. PARINP: proc call pistat jrz parinp ;wait till char in pia call sw2rom xra a sta piactl ;clear saved status lda pa.dta cma ;invert data mov c,a ;also in c jmp sw2ram ;** ; routine: PAROUT ; outputs the character in c to the IEEE port treating the ; port as a parallel port. PAROUT: proc call postat jrz parout call sw2rom mov a,c cma ;invert data sta pa.dta lk a,pb.dto+strb sta pb.dta ;set strobe lk a,pb.dto sta pb.dta ;clear strobe jmp sw2ram page ;*** ; sbrt: SW2ROM  page ;***** ; Revisions: ; YNS 18AUG81 added iobyte function to listst ; modified romcde routine ; YNS 30AUG81 moved const and listst to osbbios9.asm ; YNS 23SEP81 saved hl in ROMCDE routine when returning ; to RAM as IEEE routines return status in ; HL ; RWC 09NOV81 Preserved value of HL when calling ROM ; routines, HL used in VLDDR, VLDIR, & STODIM ; preserved HL & DE on exit ; ;***** SETRRM: ;Set ROM-RAM flag ; Entry A= port to output (setting ROM or RAM enable) ; Exit none. ; Uses A DI PUSH BC MOV C,A OT,C A STO A,ROMRAM POP BC EI ! RET space 4,10 ROMRI: ;Exit ROM resident Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at equ 0ffh ;port a output mode pa.dri equ 00h ;port a input mode pb.dr equ 0bfh ;port b direction pb.dto equ 00000010b ;port b data for output pb.dti equ 00001011b ;port b data for input pp.ordy equ 01000000b ;output rdy bit in pib pp.irdy equ 10000000b ;input rdy bit in pia ctl reg strb equ 00100000b ;strobe bit in port b ; port modes pp.undef equ 0 pp.out equ 1 pp.in equ 2 pp.mode db pp.undef ;*** ; sbrt: CV2OP. initializes the port to a parallel output ; port. cv2op: proc lda pp.mode cpi pp.out rz ;return when in output mode ; set port a to output on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dro sta pa.dir ;output constant to dir. reg to put ; a port in output mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.d; switches to rom ; saves all registers SW2ROM: proc di push af enarom pop af ei ret ;*** ; sbrt: SW2RAM ; switches to ram ; preserves all registers SW2RAM: proc di push af disrom pop af ei ret xxx: = * if xxx>MRAMEX .9 error CODE TOO LARGE.. endif ORG BIOS+770H ;This is location ED70h in 60K system DW CCP ;This location needed by ROM for ;relocating boot loader ;last sector read bombs out part ;of BMRAM in 60K system ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC) ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC, HL, IX = any parameters sto hl,stohl DI LDK HL,0 ADD HL,SP ;Old stack to HL LDK SP,BIOSTK PUSH HL ;Save old stack pointer ld hl,stohl ;get user hl ENAROM push de ;ROM jump address to IY pop IY CALL GOROM DI PUSH AF ;save status returned DISROM POP AF pop iy ;Restore old stack pointer MOV SP,iy EI ! RET GOROM: EI JMP [IY] STOHL: DS 2 nt Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry atto sta pb.dta ;initialize port b data lk a,pp.out sta pp.mode ret ;*** ; sbrt: CV2IP. initializes the port to a parallel input ; port. cv2ip: proc lda pp.mode cpi pp.in rz ;return when in input mode ; set port a to input on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dri sta pa.dir ;output constant to dir. reg to put ; a port in input mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.dti sta pb.dta ;initialize port b data lk a,pp.in sta pp.mode ret ;** ; routine: POSTAT ; gets status of the parallel (centronix) printer ; attached to the ieee port ; POSTAT: proc call sw2rom call cv2op ;convert to output lda pb.dta ;get port b data ani pp.ordy jrz pos10 ori true pos10: jmp sw2ram ;** ; ċ page ; H O M E ; ; Return disk to home. This routine sets the track number ; to zero. The current host disk buffer is flushed to the ; disk. HOME: CALL FLUSH ;Flush host buffer XRA A STO A,HSTACT ;Clear host active flag STO A,UNACNT ;Clear sector count STO A,SEKTRK STO A,SEKTRK+1 RET space 4,10 SELDSK: ;Select disk drive for next transfer. ; ; ENTRY C = disk selection value (0..15). ; DE and 1 = 0, first call for this disk. ; ; EXIT HL = 0, if drive not selectable. ; HL = DPH address if drive is selected. MOV A,C CPI NDSK JNC SELD1 ;If invalid drive number STO A,SEKDSK MOV L,C MVI H,0 ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 MOV B,E ;save initial bit LDK DE,DPBASE ADD HL,DE ;HL = DPH address PUSH HL LDK DE,100h + (low RSELDK) MOV A,B AND 1 CZ ROMJMP ;Select the disk in reg C POP HL RET SELD1: LDK HL,0 LDA CDISK SUB C RNZ ;If default drive not in error STO A,CDISK RET space 4,10 ; S E T ċ page ;***** ; Revisions: ; RWC 20OCT81 warm boot makes dir 2 files across ; RWC 19OCT81 included baud rate and screen size initalization ; RWC 14OCT81 change iobyte to variable ; modified auto start feature ; YNS 20AUG81 change iobyte defaults ; ;***** ; 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. ; 40-41: Points to where Date and Time are kept ; ; Register C must contain the selected drive, which is ; zero to select the A drive. 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 BDOS (funct T R A C K. ; ; Set track number. The track number is saved for later ; use during a disk transfer operation. ; ; ENTRY BC = track number. SETTRK: STO BC,SEKTRK ;Set track LHLD UNATRK MOV A,L XRA C MOV C,A MOV A,H XRA B ORA C RZ ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a;OCCBIO03.ASM TITLE 'Osborne CP/M 2.2 CBIOS.' *NOTE* FOR USE WITH OCCTXT6.AST ONLY * 4D2007-00 MASTER .ASM * 2D2007-00 ASSY .ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ; Copyright 1981, Osborne. ; This product is a copyright program product of ; Osborne and is supplied for use with the Osborne. ;REV = 1.2 ;DATE = OCT 18 1981 ;DEB ; Revisions: ; 1. Extensions to CBIOS added by: ; Microcode Corporation. ; Fremont, Ca ; Y. N. Sahae ; August 1981 ; ; 2. Programmable function keys added by: ; Roger W. Chapman ; October 1981 ; ; 3. Printer protocols added by: ; Roger W. Chapman ; October 1981 ; ; 4. Extensions added to BIOS and jump table standardized by: ; Roger W. Chapman ; October 1981 ; VERS: = 22 space 4,10 LINK OCCBIO13.ASM ;Jump Table LINK OCCBIO23.ASM ;CP/M disk definitions LINK OCCBIO33.ASM ;Unit record I/O LINK Oion ; 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. ; CBOOT: ;Entry A= drive to boot off of. MOV B,A ;save requested drive DISROM MOV A,B ;restore requested drive STO A,CDISK ;force requested drive LDK SP,CCP ;********************** ld a,iobite ;get iobyte value STO A,IOBYTE ;Set I/O byte to default ld a,brate mov c,a call sbaud ;set baud rate lda scrsze sta llimit ;set screen size ldk a,1 JR BCCP ;Do CP/M WBOOT: ;Warm boot LDK SP,CCP CALL HOME ;flush any buffer BCPM: LDK DE,ROMVEC+3*1 ;Set ROM vector address LDK BC,CCP CALL ROMJMP ORA A JRNZ BCPM ;If error in read mvi a,2 ;indicate warm boot BCCP: ;Entry A = 01, if cold boot ; A = 02, if warm boot PUSH AF ;Save flags ddress. ; BC = sector number to translate. ; ; EXIT HL = translated sector. SECTRN: LDA UNASEC CMP C CNZ CUNACT ;If sectors do not match MOV A,C STO A,LOGSEC MOV L,C MOV H,B ADD HL,DE MOV L,M MVI H,0 RET  ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table aCCBIO43.ASM ;Non data transfer disk LINK OCCBIO53.ASM ;cold and warm boot LINK OCCBIO63.ASM ;Disk data transfer I/O LINK OCCBIO73.ASM ;Utility routines LINK OCCBIO83.ASM ;Utility routines LINK OCCRAM2.ASM ;Commom ram definitions ; END OCCBIO03.ASM ct of ; Osborne and is supplied for use with the Osborne. ;REV = 1.2 ;DATE = OCT 18 1981 ;DEB ; Revisions: ; 1. Extensions to CBIOS added by: ; Microcode Corporation. ; Fremont, Ca ; Y. N. Sahae ; August 1981 ; ; 2. Programmable function keys added by: ; Roger W. Chapman ; October 1981 ; ; 3. Printer protocols added by: ; Roger W. Chapman ; October 1981 ; ; 4. Extensions added to BIOS and jump table standardized by: ; Roger W. Chapman ; October 1981 ; VERS: = 22 space 4,10 LINK OCCBIO13.ASM ;Jump Table LINK OCCBIO23.ASM ;CP/M disk definitions LINK OCCBIO33.ASM ;Unit record I/O LINK OLDK BC,DBUF ;Set default data transfer address CALL SETDMA LDK HL,HSTBUF STO HL,DMADR ;set ROM DMA address ; Clear console control ESC cell XRA A STO A,ESCH ;clear ESC inc a ;a=1 make directory list two files across sto a,ccp+04b2h ;change to ccp ; Set-up low core pointer cells LDK A,0C3h ;Store jumps in low memory STO A,0 STO A,5 LDK HL,BIOS+3 STO HL,1 LDK HL,BDOS STO HL,6 LDK HL,IDAY STO HL,TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. pop bc ;cold/warm indicator in b ld a,acmd and b jrz done ld a,[hl] ORA A JRZ DONE LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer ldk de,0 jr done1 SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K ċċCP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 done: mvi a,2 cmp b jrz done0 ldk hl,signon call print done0: ldk de,3 done1: ldk hl,ccp add hl,de ld a,cdisk mov c,a jmp [hl] ; Endx OSBBIOS5.asm ange to ccp ; Set-up low core pointer cells LDK A,0C3h ;Store jumps in low memory STO A,0 STO A,5 LDK HL,BIOS+3 STO HL,1 LDK HL,BDOS STO HL,6 LDK HL,IDAY STO HL,TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. pop bc ;cold/warm indicator in b ld a,acmd and b jrz done ld a,[hl] ORA A JRZ DONE LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer ldk de,0 jr done1 SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K ċċ page ; MVINFO Move information necessary for transfer. MVINFO: XRA A STO A,ERFLAG ;Clear error flag LD A,TEMSEC STO A,SEKSEC RET space 4,10 ; Print message terminated by zero byte. ; ; ENTRY HL -> message buffer, terminated by zero. ; ; EXIT HL -> zero byte + 1. ; A = 0. ; Z bit set. ; ; Destroys only HL, Flags, and A registers. PRINT: LD A,[hl] ;Get a character ORA A INC HL RZ ;If zero the terminate PUSH HL MOV C,A CALL CONOUT ;Output to the console POP HL JR PRINT SAVADR: DS 2 ;Disk transfer routine vector OCCBIO73$$$ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ ċċċċċċċċ!ċċċċċċċċ"ċċċċċċċċ#ċċċċċċċċ$ċċċċċċċċ%ċċċċċċċċ&ċċċċċċċċ'ċċċċċċċċ(ċċċċċċċċ)ċċċċċċċċ*ċċċċċċċċ+ċċċċċċċċ,ċċċċċċċċ-ċċċċċċċċ.ċċċċċċċċ/ċċċċċċċċ0ċċċċċċċċ1ċċċċċċċċ2ċċċċċċċċ3ċċċċċċċċ4ċċċċċċċċ5ċċċċċċċċ6ċċċċċċċċ7ċċċċċċċċ8ċċċċċċċċ9ċċċċċċċċ:ċċċċċċċċ;ċċċċċċċċ<ċċċċċċċċ=ċċċċċċċċ>ċċċċċċċċ?ċċċċċċċċ@ċċċċċċċċAċċċċċċċċBċċċċċċċċCċċċċċċċċDċċċċċċċċEċċċċċċċċFċċċċċċċċGċċċċċċċċHċċċċċċċċIċċċċċċċċJċċċċċċċċKċċċċċċċċLċċċċċċċċ