Title MD-HD Bios for CP/M 3.x Copyright 1984 Morrow Designs, Inc. (13_Aug_84) ; ; Copyright (c), 1983, 1984 ; Morrow Designs, Inc. ; 600 McCormick ; San Leandro, Ca. 94577 ; Bill Smith ; .z80 ;This file is assembled using Zilog nmenonics ;---------------------------------------------------------------------- ; Index (19_Jul_84) ;------------------ ; ; Banked Bios: ; Include Files, External Declarations and Equates ; Datá Areá (Characteò Tables) ; Data Area (Virtual Drive Message) ; Data Area (Local Data Area) ; Data Area (Drive Tables/Dph's and Dpb's) ; Data Area (System RamDatY and Apif) ; Data Area (System Mtab's) ; Data Area (Free Space Pool) ; Cold Boot Routine ; Jump Table Entry Points ; Extended Bios Functions ; Console Input Translation Routines ; Console Output Translation Routines ; Character I/O (List Device Drivers) ; Character I/O (Physical Level) ; ; Resident Bios: ; Banking Considerations and Bios Jump Table ; Jump Table ; Bank Crossing Routines ; Non Bank Crossing Routines ; InterBank Utilities ; Interrupt Handling Routines ; Interrupt Handling Routines ; Local Data Area, Stacks and Interrupt Vectors ; ;credits ; The MD-11 Design Team included (alphabetically) ; David Block Len Edmondson Howard Fullmer ; Pearl Ledbetter George Morrow Bill Smith ; Mike Stolowitz Steve Tai John Zalabak Subttl Banked Bios -- Include Files, External Declarations and Equates page 60 ;---------------------------------------------------------------------- ; Include Files ;-------------- ; .sall ;Suppress all Macro Expansions .xlist ;Don't List any of the Include Files include HD22DEF.MAC ;General Definitions File include DRIVES.MAC ;Drive Definitions (Dpb, Dph and Mtabs) include DEFINE.MAC ;Drive Type and Organization Definitions .list ;Resume Listing ;---------------------------------------------------------------------- ; External Declarations ;---------------------- ; External @civec ;Console Input Vector External @covec ;Console Output Vector External @aivec ;Aux Input Vector External @aovec ;Aux Output Vector External @lovec ;List Output Vector External @bnkbf ;Bank Buffer for Booting External @crdma ;Last Error Current Dma Address External @erdsk ; " " Current Disk External @fx ; " " Bdos Function Number External @usrcd ; " " User Code External @crdsk ;Current Default Disk Drive External @vinfo ;Valid Fcb Address (only if @ReSel = 0FFh) External @resel ;If = 0FFh then VinFo is valid External @mltio ;Current Multi-Sector Count External @ermde ;Error Mode External @media ;If = 0FFh then drive door has been opened External @bflgs ;Error Message Type (bit7=Set=Long Error Msg) External @date ;Number of days since 1_Jan_78 External @hour ;Clock - Hours External @min ; " - Minutes External @sec ; " - Seconds External ?erjmp ;Bdos Error Vector External @mxtpa ;Address of the Top of the Tpa page ;---------------------------------------------------------------------- ; Local Equates (20_Jul_84) ;-------------------------- ; BioRev equ 19h ;Current Bios Revision Clevel equ 1 ;Compatibility Level ; Rom Entry Points Rom equ 0 ;Base of This Table MsgRm equ rom+3 ;Print signon message routine RdHsRm equ rom+9 ;Read disk routine WrHsRm equ rom+0Ch ;Write disk routine BtERm equ rom+18h ;Print boot err routine FmtHst equ rom+26h ;Format single track ; Default Baud Rate Settings Dflt1 equ 0FFh ;Console (9600 jumper OUT; 19200 jumper IN) Dflt2 equ 3 ;List 1200 Baud Dflt3 equ 6 ;Sio 9600 Buad ; Misc Definitions $Auto_Enables equ 00100000b ;Enables Cts and Dcd Status Inputs BootRam equ 0 Tpa equ 100h ;Start of the TPA Media_Offset equ 11 ;offset into dph for media flag PhysOff equ 15 ;offset from spt to psh in dpb Dpb_Length equ 17 DpbOff equ 12 ;offset from spt to dpb in dbh DsktLn equ 25 DskTb equ dskbuf+80h+dsktln ;address of end of table+1 DskTdb equ dskbuf+80h+9 Edv equ 40h ;bad drive from format entry @Primary equ 0 ;Primary Disk Select Flag @Parity equ 7 ;Parity bit Cr equ 0Dh ;Carriage Return Esc equ 1Bh ;Escape Character Leadin equ 1Ch ;Leadin code for function keys Fast equ 9Fh ;Ims Status Response Fast Slow equ 9Dh ; " " " Slow ; SFlag Bit Defintions @PcStat equ 0 ;1=Physical Console Status Active @FunSeq equ 6 ;1=Last key part of function key seq @FunCode equ 7 ;1=Last key was a function key code Subttì Bankeä Bioó -- Datá Areá (Characteò Tables) page dseg ;Begin the Code Section of Banked Bios ;---------------------------------------------------------------------- ; Boot Entry ;----------- ; 1) This entry has been placed here so that it may be used by external ; programs to size the system when examining the CPM3.SYS file. ; Boot: jp Boot2 ;Jump Past the Data Areas ;---------------------------------------------------------------------- ; Character Table (18_Jul_84) ;---------------------------- ; 1) These tables are provided for external programs ; 2) This section MUST follow the boot jump above ; Char_Tables: ; Default Serial Baud Rates ;-------------------------- ; Ser1Baud: db Dflt1 Ser2Baud: db Dflt2 Ser3Baud: db Dflt3 ; Misc Data ;---------- ; If Auto ;If (Auto Load is Enabled) Default_CFlag: db 11100011b ; Ims On,Translate-On,Cent-List Else ;Else Default_CFlag: db 00100011b ; Translations On,Centronics List EndIf VNumb: db Drives ;Number of physical drives TLev: db 4 ;Terminal level (default = MT60/MT70) Con_Stat_3: db 11000001b ;Console Format 8 bits, Rx_Enabled Lst_Stat_3: db 11000001b ;List Format 8 bits, Rx_Enabled Aux_Stat_3: db 11000001b ;Aux Format 8 bits, Rx_Enabled db BioRev ;Bios Revision Number db CLevel ;Compatibility Level dw APIF ;Pointer to Application Interface Area dw RamDatY ;Pointer to RamDatY dw Mtab ;Pointer to the base of the first MTAB dw Pool ;Pointer to free space page ; Console Translation Pointers ;----------------------------- ; ETblPtr: dw EscTbl ;Pointer to the Escape Character Table CTblPtr: dw CtrlTbl ; " " " Control " " EVctPtr: dw EscVect ; " " " Escape Vector Table CVctPtr: dw CtVect ; " " " Control " " dw DcaStrt ; " " " Start of the Dca Struct ; Direct Cursor Addressing Area ;------------------------------ ; DcaStrt: db Esc,'=',0FFh ;Dca Prefix String ds 3,0FFh DcaMid: ds 6,0FFh ;Dca Seperator DcaEnd: ds 6,0FFh ;Dca Terminator String Esc_Lvl: db 0 ;Indicates Escape Sequence Level Offset1: db 0 ;First Character Offset Offset2: db 0 ;Second Character Offset Order: db 0 ;bit 0 = 0 --> Row, then Column, ; = 1 --> Column, then Row ;bit 1 = 0 --> Binary Cursor Adresses ; 1 --> Ascii Cursor Addresses First: db 0 ;Temporary Storage of First Second: db 0 ;Temporary Storage of Second Char_Table_Length equ $-Char_Tables Subttl Banked Bios -- Data Area (Virtual Drive Message) page ;---------------------------------------------------------------------- ; Virtual Drive Messages ;----------------------- ; VMsg: db Cr,Lf,'Your floppy drive is being re-assigned as drive ' VDrv: db 'a.',Cr,Lf,'Exchange diskettes and press [return]',0 ds 96 - ($ - VMsg),0 VMsg_Length equ $-VMsg Subttl Banked Bios -- Data Area (Local Data Area) page ;---------------------------------------------------------------------- ; Other Local Data Definitions (10_Jul_84) ;----------------------------------------- ; Before_After: db 2 ;Default = pre-reads on Sector_Length: dw 0 ;Initialized by seldsk Dma_Bank: db 0 ;Current Dma Bank SCount: db 0 ;Counter used in Get_Character SFlag: db 0 ;Status flag in Character Input Routines Ims_Length: db 0 ;Storage Used in Bank Inject Ims LstFlg: db 0FFh ;X-On X-Off (initial value = 0FF) BaudTbl: dw 1136 *2 ;0 110 dw 417 *2 ;1 300 dw 208 *2 ;2 600 dw 104 *2 ;3 1200 dw 52 *2 ;4 2400 dw 26 *2 ;5 4800 dw 13 *2 ;6 9600 dw 13 ;7 19,200 dw 1 ;8 Reserved dw 1 ;9 Reserved dw 1 ;10 Reserved Subttl Banked Bios -- Data Area (Drive Tables/Dph's and Dpb's) page ;---------------------------------------------------------------------- ; Drive Tables and System DPH's (9_Jul_84) ;----------------------------------------- ; drive_table: table_gen dph ds (16-drives)*2,0 dpbase: struct_gen dph dphlen equ dphb-dpha dph_struct_len equ $-drive_table ;---------------------------------------------------------------------- ; System DPB's ;------------- ; table defines logical to physical mapping of dpb's. ; structure is same as drive_table, all dph point at same dpb_buf ; in common. dpb_table: table_gen dpb dw 0 ;terminator struct_gen dpb dpb_table_leng equ $-dpb_table ;default single-sided disk dpb, not part of table sdpb: dw 40 db 4 db 15 db 1 dw 94 dw 127 db 0c0h db 0 dw 32 dw 2 db 3,7 Subttl Banked Bios -- Data Area (System RamDatY and Apif) page ;---------------------------------------------------------------------- ; General Disk Operations Data Area (1_Sept_83) ;---------------------------------------------- ; RamDatY: db 0 ;(SEKDSK) BDOS disk number dw 0 ;(SEKTRK) BDOS track number ; dw 0 ;(SEKSEC) BDOS sector number ; dw 0 ;(SEKHST) Actual sector number on the disk ; db 0 ;(UNACNT) Unallocated record count db 0 ;(UNADSK) Unallocated disk number dw 0 ;(UNATRK) Unallocated track number ; dw 0 ;(UNASEC) Unallocated sector number ; db 0 ;(UNAMAX) Sectors per Unallocated block dw 0 ;(SECTRK) Logical Sectors per track ; db 0 ;(PHYSPT) Physical sectors per track db 0 ;(WRTYPE) Write type db 0 ;(CFLAG) Flag Byte (initialized from chr_tbl db 0 ;(DFLAG) Flag Byte db 0 ;(TRSEC) Offset to logical sector within physical sector dw VMsg ;(VMSGP) Pointer to virtual drive message ; dw VDrv ;(VDRVP) Pointer to virtual drive in message ; db 0FFh ;(CDSK) Current drive db CVDsk ;(VDSK) Current virtual drive dw 2800h ;(DMAADR) disk DMA address ; dw jcono ;(CONOUT) Pointer to Current console output routine ; dw jconi ;(CONIN) Pointer to Current console input routine ; dw jcons ;(CONSTS) Pointer to Current console status routine db $CNTRST ;(CPYBNK) Copy of bank strobe (printer restore = false) ;rom is on, bank 1 (system) is on, used only by rom, ;see system_bank_bits page ;---------------------------------------------------------------------- ; Default Application Interface area (13_Oct_83) ;----------------------------------------------- ; APIF: db 0 ;(HSTDSK) BDOS Drive Number (1st floppy) dw 0000 ;(HSTTRK) Desired Cylinder (lo) ; Desired Cylinder (hi) dw 1 ;(HSTSEC) Desired Sector (lo) ; Desired Sector (hi) db 1 ;(SECCNT) Number of sectors to transfer db 10 ;(RETRY) Retry Count dw DskBuf ;(HSTBUF) Buffer Address (lo) ; Buffer Address (hi) db 0 ;(ERFLAG) Error Code db 0 ;(OPFLAG) Options Flag dw 0 ;(PHYTRK) Physical track number (lo) ; Physical track number (hi) db 0 ;(PHYSEC) Physical sector number db 0 ;(PHYHD) Desired Head db 2 ;(PHYDRV) Physical Drive Number dw 0 ;(IOADD) Execution Address (lo) ; Execution Address (hi) Subttl Banked Bios -- Data Area (System Mtab's) page ;---------------------------------------------------------------------- ; System Mtabs ;------------- ; Mtab: struct_gen mt Subttl Banked Bios -- Data Area (Free Space Pool) page ;---------------------------------------------------------------------- ; Free Space Pool (27_Jun_84) ;---------------------------- ; Pool: ;beginning of managed space ; Disk Translation Table ;----------------------- ; XlTab: db 0 ;Standard Disk Tranlation Table Header dw 5 ; " " " " Length XlT1k: db 1,4,2,5,3 ; Console Translation Table ;--------------------------- ; db 0FEh ;Console Translation Table Header dw CLen ; " " " Length EscTbl: db 0FFh ;Escape Table (Null) CtrlTbl:db 0FFh ;Control Table (Null) EscVect:dw 0 ;Escape Vector Table (Null) CtVect: dw 0 ;Control Vector Table (Null) ; translation strings for the terminal go here CLen equ $-esctbl ;Define the Length of the Console Xlt ; Free Space Pointer ;------------------- ; db 0FFh ;Free Space Header dw 870 ; " " Length ; Sign On Message and Free Space Storage Allocation Definitions ;-------------------------------------------------------------- ; ds 400,0 Sign_On_Start: db cr, lf, 'CP/M Plus -- Ver 3.0 Rev ' db ((BioRev and 0f0h) shr 4) + '0','.',(BioRev and 0Fh) + '0' db cr,lf,'Copyright 1982, 1983 Digital Research, Inc.' db cr,lf,'Copyright 1983, 1984 Morrow Designs, Inc.' db cr,lf,0 Sol equ $ - Sign_On_Start ds (470 - Sol), 0 ; Ims Buffer Header ;------------------ ; db 0FDh ;Ims Buffer Header If Auto ;If (Auto Command Load is Enabled) dw 4 ; Save Space for the HDL String db 'HDL',Cr ; Startup with HDL Else ;Else dw 0 ; Ims Length:= 0 (No Ims) EndIf ; Function Key Translation Header ;-------------------------------- ; db 0FCh ;Function Table Header dw function_table_length ; " " Length translation_table: db 23 ;# entries db 4Ah,1,2 db 6Ah,1,17h db 0Ah,1,17h ;up arrow db 4Bh,0 db 6Bh,0 db 0Bh,0 ;down arrow db 4Ch,1,8 db 6Ch,1,1 db 0Ch,1,8 ;left arrow db 4Dh,1,20h db 6Dh,1,6h db 0Dh,1,7h ;right arrow db 4Fh,5,'HELP',Cr db 6Fh,5,'HELP',Cr db 0Fh,5,'HELP',Cr ;Help Key db 4Eh,1,18h db 6Eh,1,18h db 0Eh,1,18h ;Home/Clear db 49h,1,18h db 69h,1,0Bh db 09h,1,0Bh ;Erase db 1Ah,1,9h db 1Bh,1,9h ;Tab function_table_length equ $-translation_table pool_length equ $-pool Subttl Banked Bios -- Cold Boot Routine page ;---------------------------------------------------------------------- ; Cold Boot Routine (18_Jul_84) ;------------------------------ ; Boot2: ;enter here from loader, rom is on, system bank is on call Init_Uarts ;Initialize the Uarts ld hl,services ld (bios+1),hl ;point cold at services ld hl,dpb_buffer ;init dph.dpb -> dpb_buffer (gencpm needs 'em real) ld (dpbase+dpboff+dphlen*0),hl ld (dpbase+dpboff+dphlen*1),hl ld (dpbase+dpboff+dphlen*2),hl ld (dpbase+dpboff+dphlen*3),hl ld (dpbase+dpboff+dphlen*4),hl ld a,$cntrst ld (system_bank_bits),a out (bnkstb),a ;Turn on the rom and bank 0 ld iy,RamDatY ;IY:= Ram Data ld sp,System_Stack ;Stack:= Initialized ld de,Sign_On_Start call MsgRm ;Print the Sign On message ld a,$cntrst + 1 ld (system_bank_bits),a jp wboot ;read ccp and go Subttl Banked Bios -- Jump Table Entry Points page ;---------------------------------------------------------------------- ; Warm Boot Routine (10_Aug_84) ;------------------------------ ; Banked_WBoot: ld c,Esc ;ConOut:= Escape call conout ld c,'(' ;ConOut:= Open Paren. call conout ;[Brightness Now ReSet to HIGH] ld hl,RamDatY+CFlag res @FstSlw,(hl) ;Set Console Mode to Slow set @ImsAct,(hl) ;Set Ims to Active ld a,(RamDatY+OpFlag) res @SerD,a ;Clear the Suppress Error Display flag res @SerUR,a ;Clear the Suppress Error Response flag ld (RamDatY+OpFlag),a ld a,10 ;retry count ld (RamDatY+retry),a ;set retry count ld c,0 ;drive a: call seldsk If Floppy ld hl,1 ld (RamDatY+hsttrk),hl ;track 1 ld (RamDatY+hstsec),hl ;sector 1 Else ld hl,6 ld (RamDatY+hstsec),hl ;sector 6 ld l,h ;[hl]=0 ld (RamDatY+hsttrk),hl ;track 0 EndIf ld a,1 ld (Dma_Bank),a ;moves to tpa bank ld hl,tpa ld (RamDatY+dmaadr),hl ;transfer to tpa ld b,4 ;4k to move ld iy,RamDatY BwLp1: push bc ;save sector count call read ;read a sector to dma jr nz,BwSk2 ;if no error, ld (RamDatY+dmaadr),hl ;dma ++ inc (iy+hstsec) ;sector ++, no track moves pop bc djnz BwLp1 ld hl,(@mxtpa) ld (lo_mem_copy+6),hl ;set bdos address ld bc,100h ;destination tpa call xmove ld hl,0 ;destination lo-mem ld de,lo_mem_copy ld bc,lo_mem_length call move jp WBoot_Return ;transfer control thru common ;Error has ocurred BwSk2: call rom_on jp bterm ;exit to rom "press reset" Lo_Mem_Copy: jp warmpt nop nop jp warmpt Lo_Mem_Length equ $-Lo_Mem_Copy ;---------------------------------------------------------------------- ; Home the Disk Heads ;-------------------- ; Home: ld bc,0 ;track 0 ld (RamDatY+hsttrk),bc ;set track in RamDatY ret page ;---------------------------------------------------------------------- ; Select a Disk (13_Jul_84) ;-------------------------- ; 1) Register Usage ; C -> enter equal to number of drive to select ; HL -> exit equal to dph, or equal to 0 If Bad Drive ; SelDsk: ld a,Drives-1 ;If (Drive is Non-Existant) cp c jp c,BDrv ; Goto Bad Drive Return ld a,c ;new drive ld (RamDatY+HstDsk),a ;set drive as current ld (RamDatY+SekDsk),a ;set drive as current ld hl,RamDatY ;pointer to RamDatY push de ;save primary/secondsry select call GDskHL ;get mtab pointer in [HL] pop de ;restore primary/secondary select bit @Primary,e jr nz,skpset ; if first time, bit @frgn,(hl) jr nz,skpset ; then if native morrow format, bit @hrddsk,(hl) jr nz,skpset ; then if floppy, (read disk id) ; Prepare to read ID info from media push hl ;save dskdef pointer call getab ;read config table from diskette or a ;see if error jp nz,ubdrv ;back to drive a: if error jr dskchk fmtlog: ;format enters here with disk info copied to buffer push hl ;format enters with system mtab ; Check ID info for correctness (checksum) dskchk: ld hl,dsktb ;pointer to end of table+1 ld b,dsktln ;count must be odd! for field of E5 xor a ;init check byte ld e,a ;init 0-check byte chklp: dec hl ;dec pointer xor (hl) ;x-or table value into parity check byte ld d,a ;save parity check byte or e ;or in 0-check byte ld e,a ;save 0-check byte ld a,d ;restore pariy check byte djnz chklp ;dec table length & loop til done inc hl ;hl=>dskdef1, access to sided-ness or a ;a=0 if table ok ld a,e ;a = 0-check byte jr nz,sside ;assume s.s. if invalid table or a ;check 0-check byte jr nz,dskdpb ;invalid table if zero sside: ld de,sdpb ;pointer to s.s. dpb from ram pop hl ;restore ram mtab jr setsgl ;now we know that the media really is native morrow format dskdpb: ld de,dsktdb ;pointer to dpb in boot ;set ram MTAB according to disk MTAB bit @dblmed,(hl) ;check disk MTAB for d.s. media pop hl ;restore pointer to ram MTAB set @dblmed,(hl) ;presume double sided jr nz,dside ;but if single sided, setsgl: res @dblmed,(hl) ;set for s.s. media dside: xor a ;set z flag ;enter with z=1 if disk contains dpb to copy, pointed to by [DE] ;also, [HL] -> current MTAB skpset: push hl ;save current MTAB (in common) push af ;save z-boolean for ldir below push de ;save pointer to dpb from disk ld a,(RamDatY+hstdsk) ;get drive ld hl,drive_table call get_indexed ex (sp),hl ;put DPH on stack push hl ;under disk DPB address ld a,(RamDatY+hstdsk) ;get drive ld hl,dpb_table call get_indexed ex de,hl ;[de] -> dpb space in ram pop hl ;restore disk dpb pointer pop bc ;dph address pop af ;restore boolean push bc ;dph address push de ;current dpb (common) jr nz,notab ;skip if no dpb update ld bc,15 ;length of dpb on drive media ldir ;update dpb ; Figure the number of physical sectors per track = SPT / 2^secsiz ; Figure the transfer length for sector moves = 128 * secsiz ; Figure physical record shift mask (DPB.psm) = (2^secsiz)-1 ; Initialize physical record shift factor (DPB.psh) = secsiz notab: pop de ;DPB in common pop hl ;current DPH ex (sp),hl ;restore current MTAB inc hl ;dskdef1, for sizmsk ld a,(hl) and $sizmsk ;get size push af ;save size ld b,a ;set as a count inc b ;count +1 for djnz bit @hasbad,(hl) ;set-up bad-map ld hl,RamDatY+dflag res @curbad,(hl) jr z,notab1 set @curbad,(hl) ;dflag @curbad reflects diskdef1 @hasbad notab1: ld c,70h ;for psm calculation ld a,(de) ;read records per track add a,a ;*2 ld hl,40h ;128/2 pspt: add hl,hl ;transfer length * 2 rlc c ;shift mask * 2 circular srl a ;records per track / 2 djnz pspt ld (RamDatY+physpt),a ;set physical sectors per track ld (sector_length),hl ;set transfer length ld hl,physoff ;offset from SPT to PSH add hl,de ;[hl] -> DPB.psh pop af ;size ld (hl),a ;set DPB.psh inc hl ;[hl -> DPB.psm ld a,c and 7 ;delete remaining high order bits ld (hl),a ;set DPB.psm ex de,hl ;[hl] -> dpb ld de,dpb_buffer ;buffer in common ld bc,dpb_length ldir ;copy current dpb to common pop hl ;restore dph address ret ret ubdrv: pop hl ;drop bdrv: ld hl,0 ret page ;---------------------------------------------------------------------- ; Set the HL equal to HL indexed by the Accm ;------------------------------------------- ; get_indexed: add a,a ;*2 add a,l ld l,a jr nc,GiSk1 inc h ;HL:= HL + (2 * A) GiSk1: ld a,(hl) ;dph lo inc hl ld h,(hl) ld l,a ;[hl] -> dph ret ;------------------------------------------------------------------ ; Read the Boot Sector ;--------------------- ; 1) read boot sector of currently selected disk ; getab: ld hl,0 ld (RamDatY+hsttrk),hl ;set track 0 inc hl ld (RamDatY+hstsec),hl ;set sector 1 ld hl,RamDatY+opflag res @inmap,(hl) res @bufok,(hl) jp read2 ;read without move ;---------------------------------------------------------------------- ; Set the Current Track ;---------------------- ; SetTrk: ld (RamDatY+hsttrk),bc ;set track in RamDatY ret ;---------------------------------------------------------------------- ; Set the Current Sector ;----------------------- ; SetSec: ld (RamDatY+hstsec),bc ;set sector in RamDatY ret ;---------------------------------------------------------------------- ; Set the Dma Address ;-------------------- ; SetDma: ld (RamDatY+dmaadr),bc ;set dma address in RamDatY ret page ;---------------------------------------------------------------------- ; Read a Sector (13_Jul_84) ;-------------------------- ; Read: ld a,(RamDatY+SekDsk) ld (RamDatY+HstDsk),a ;Insure that HstDsk is Valid ld hl,RamDatY+opflag res @inmap,(hl) ;don't pre-read bad map res @bufok,(hl) ;errors are not re-mapable call read2 push af call rwmove pop af ret read2: push ix ;save ix & iy push iy ld iy,RamDatY ;set-up iy -> RamDatY set @ReadOp,(iy+DFlag) ;indicate read call Rom_On ;turn rom on call RdHsRm ;read from disk or a ;set flags for error call Rom_Off ;turn the Rom Off (AF preserved) pop iy pop ix ld d,a ;[d]=physical error ret z ;if error, ld a,1 ; say so ret ;endif page ;---------------------------------------------------------------------- ; Write a Sector (13_Jul_84) ;--------------------------- ; Write: ld a,(RamDatY+SekDsk) ld (RamDatY+HstDsk),a ;Insure that HstDsk is Valid ld hl,RamDatY+OpFlag ;HL:= Pointer to RamDatY ld a,(Before_After) ;check read before enabled res @inmap,(hl) ;do not pre-read bad map res @bufok,(hl) ;not mapable if no data pre-read bit 1,a jr z,write1 ;if pre-read enabled, ld a,(RamDatY+DFlag) bit @curbad,a jr z,write1 ;if drive has bad map set @bufok,(hl) ;errors are re-mapable call read2 ;do pre-read, don't move data ret nz ;exit on non=remap error write1: call write2 jr z,r_a_w_check ;if error, ld d,a ;[d]=physical error cp ERwp ;is it write protected? ld a,2 ;write protect error jr z,WrSk2 ;if write protected, say so ld a,1 ;error is permanent WrSk2: or a ;set flags = error ret r_a_w_check: ;no apparent error, ld a,(Before_After) ;check user enabled read-after-write bit 0,a ld a,0 ;if not enabled, no error ret z ;if enabled, ld hl,RamDatY+opflag res @inmap,(hl) set @bufok,(hl) ;same as pre-read call read2 ;read the stuff, don't move data ret z ;exit if no error call write2 ;try writing again ld a,1 ;in case error, return permanent ret nz ;exit if error on second write jp read2 ;if written, check again, return read's error write2: push ix ;save ix & iy push iy ld iy,RamDatY ;set-up iy -> RamDatY res @readop,(iy+dflag) ;indicate write call rwmove ;make transfer call Rom_On ;turn rom on call WrHsRm ;write to disk or a ;set flags for error call Rom_Off ;turn the Rom Off pop iy pop ix ret ;---------------------------------------------------------------------- ; Read/Write Move Routine ;------------------------ ; RwMove: ld hl,(RamDatY+dmaadr) ;destination address, (presuming read) ld de,dskbuf ;source address ld bc,0100h ;presume destination is tpa ld a,(RamDatY+dflag) bit @readop,a ;test for write jr nz,rwmov0 ;if write, ex de,hl ; reverse direction of transfer ld bc,0001h ; reverse banks too rwmov0: ld a,(bnkmsk) push af ld a,(Dma_Bank) ;see if dma to/from tpa bank (2) or a call nz,xmove ;set-up for inter-bank transfer ld bc,(sector_length) ;number of bytes to transfer call move ;make transfer pop af ld (bnkmsk),a ret ;---------------------------------------------------------------------- ; Sector Translation ;------------------- ; 1) This routine provides Logical to Physical Sector Translation. ; 2) Register Usage: ; A -> General Purpose ; BC -> Enter equal to the Logical Sector ; DE -> Pointer to the Translation Table (0 if No Translation) ; HL -> Exit equal to the Physical Sector ; SecTrn: ld l,c ld h,b ;HL:= BC (logical Sector Number) inc hl ;(start sectors at 1) ld a,d ;If (there's No Translation Table) or e ret z ; Return (HL:= Physical Sector) ex de,hl ;HL:= Translation Table Address add hl,bc ;HL:= Pointer into Translation Table ld l,(hl) ld h,0 ;HL:= Translated (Physical) Sector ret ;Return page ;---------------------------------------------------------------------- ; Return the Address of the System Drive Tables ;---------------------------------------------- ; DrvTbl: ld hl,Drive_Table ret ;---------------------------------------------------------------------- ; Multiple Sector Read/Write ;--------------------------- ; Multio: ret ;multi-sector count NOT implemented ;---------------------------------------------------------------------- ; Flush the Disk Buffers ;----------------------- ; Flush: xor a ;no error ret ;not needed ;---------------------------------------------------------------------- ; Set the Current Bank ;--------------------- ; SetBnk: ld (Dma_Bank),a ret ;---------------------------------------------------------------------- ; Setup for an Inter-Bank Move ;----------------------------- ; 1) build memory mask modifying $xfer, $bank2, $_rmenb. ; 2) result is always non-zero ; XMove: ld a,c ;source bank cp b ;same as dest? ld b,$_RMENB ;presume no xfer, rom off jr z,XmSk1 ld b,$XFER or $_RMENB ;set xfer, rom off XmSk1: add a,a ;bank *2 for hardware or b ;add bits set above ld b,a ld a,(system_bank_bits) ;include centronics controls and not ($xfer + $bank2 + $_rmenb) or b ld (bnkmsk),a ;set for xmove ret page ;---------------------------------------------------------------------- ; Turn the Rom On/Off (13_Aug_84) ;-------------------------------- ; 1) the rom is turned on by inter_bank to facilitate migration of code ; from here to rom. all usage of read, write, and format must pass ; through this code so we can perform interrupt management in later ; releases. ; ; Turn the Rom ON ;---------------- ; Rom_On: di push af ld a,(RamDatY+CFlag) ld (Save_Ims_Status),a ;Save the Current Value of CFlag res @ImsAct,a ld (RamDatY+CFlag),a ;DeActivate Ims Buffering ld a,(System_Bank_Bits) and not $_RmEnb ;rom on jr RofSkp ; Turn the Rom OFF ;----------------- ; Rom_Off: di push af ld a,(Save_Ims_Status) ld (RamDatY+CFlag),a ;Restore the Previous Value of CFlag ld a,(System_Bank_Bits) or $_RmEnb ;rom off ; Rom On/Off Common Code ;----------------------- ; RofSkp: ld (System_Bank_Bits),a ;update out (BnkStb),a pop af ei ret Subttl Banked Bios -- Extended Bios Functions page ;---------------------------------------------------------------------- ; Bank Inter-Bank Execution ;-------------------------- ; 1) This is a continuation of inter_bank located in the Resident ; part of the bios. ; ; Begin Execution of a Bank Crossing Routine ;------------------------------------------- ; Bnk_Inter_Bank: ld (Save_User_Stack),sp ld sp,System_Stack ld a,(System_Bank_Bits) push af ;save for restore and Not ($Bank2 + $_RmEnb) ;indicate rom and sys are on ld (System_Bank_Bits),a ;now reflects system state ei push hl ld hl,Bnk_Return ;force return to here ex (sp),hl ;by placing on stack jp (hl) ;execute desired function ;Return from Executing a Bank Crossing Routine ;--------------------------------------------- ; Bnk_Return: ;prepare to exit system bank ex (sp),hl ;get saved bank bits in [h] push af ;preserve returned value ld a,h di ;DisAble Irq while bits ld (System_Bank_Bits),a ;don't reflect system state jp Res_Bnk_Return ;continue above page ;---------------------------------------------------------------------- ; Extended Bios Functions (18_Jul_84) ;------------------------------------ ; 1) entry parameters ; bc = function number, 0 -> n (b=0) ; de,ix = parameters if needed ; hl_entry and bc_entry are also available ; 2) exit parameters vary ; Bnk_Services: ld hl,-max_func add hl,bc jp c,wboot ;kill program if making illegal call ld hl,Function_Table add hl,bc add hl,bc ld a,(hl) inc hl ld h,(hl) ld l,a jp (hl) ;do function Function_Table: dw func0 ;Read from System Memory dw func1 ;Write to System Memory dw func2 ;Copy RamDatY and Apif to Tpa dw func3 ;Copy System Mtabs to Tpa dw func4 ;Copy DrvTbl and Dph's to Tpa dw func5 ;Copy Dpb_Table and Dpb's to Tpa dw func6 ;Copy Character Table to Tpa dw func7 ;Copy Virtual Drive Message to Tpa dw func8 ;Copys Free Space to Tpa dw Bnk_Format ;Format a Track dw Init_Uarts ;Initialize the CTC dw Bnk_Inject_Ims ;Inject into the Ims Buffer dw func12 ;EnAble/DisAble Centronics Irq dw func13 ;EnAble/DisAble Read after/before write dw func14 ;Execute in System Bank dw func15 ;Verify Track (With Re:Mapping) dw func16 ;Verify Track (With-out Re:Mapping) dw func17 ;Alter CFlag dw func18 ;Copy System ID Frame to Tpa dw Init_Baud_Rates ;Initialize the Uart's Baud Rates dw Read_Host ;Read a Physical Sector dw Write_Host ;Write a Physical Sector Max_Func equ ($-Function_Table)/2 page ;---------------------------------------------------------------------- ; System/Tpa Move Routines (12_Jul_84) ;------------------------------------- ; ; Move a Block from the Tpa Bank to the System Bank ;-------------------------------------------------- ; Sys_Move: push bc ld bc,1 ;dest = system jr Mskp1 ; Move a Block from the System Bank to the Tpa Bank ;-------------------------------------------------- ; Tpa_Move: push bc ld bc,100h ;dest = tpa ;Common Code for Sys_Move and Tpa_Move Mskp1: call xmove ;Set the Source and Destination Banks pop bc ;(Restore the Entry Value of BC) push bc ;(Save all register pairs) push de push hl ex de,hl ;reverse source & destination for move call move ;Move the Block pop hl pop de pop bc ;(Restore all register pairs) ret ;Return ; OverLay the System's Apif with a User's Apif ;--------------------------------------------- ; 1) Enter with the IX pointing at the Apif in the Tpa ; Install_Apif: push ix pop hl ;Source is the User's Apif ld de,Apif ;DE:= Destination (System Apif) ld bc,AiLeng ;BC:= Length (Length of Apif) call Sys_Move ;Copy User's Apif to the System's ret ; Restore a User's Apif from the System's Apif ;--------------------------------------------- ; 1) Enter with the DE pointing at the User's Apif (in the Tpa Bank) ; Restore_Apif: push af push de ld hl,Apif ;HL:= Source (System's Apif) ld bc,Aileng ;BC:= Length (Length of Apif) call Tpa_Move ;Copy System's Apif to the User's pop ix ;Restore (User's pointer to Apif) pop af ret page ;---------------------------------------------------------------------- ; 0 - Read from System Memory ;---------------------------- ; 1) Register Usage: ; BC -> Length in bytes ; DE -> Destination in Tpa ; HL -> Source in System bank ; func0: ld hl,(HL_Entry) ;HL:= User Source ld bc,(BC_Entry) ;DE:= User Length jr Tpa_Move ;---------------------------------------------------------------------- ; 1 - Write to System Memory ;--------------------------- ; 1) Register Usage ; BC -> Length in bytes ; DE -> Destination in System bank ; HL -> Source in Tpa ; func1: ld hl,(HL_Entry) ;HL:= User Source ld bc,(BC_Entry) ;BC:= User Length jr Sys_Move ;---------------------------------------------------------------------- ; 2 - Copy RamDatY and Apif to Tpa ;--------------------------------- ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func2: ld hl,RamDatY ;HL:= Pointer to start of RamDatY ld bc,MtOff ;BC:= Length of RamDatY and APIF jr Tpa_Move ;---------------------------------------------------------------------- ; 3 - Copy Mtabs to Tpa (10_Jul_84) ;---------------------------------- ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func3: ld hl,Mtab ;HL:= Pointer to start of Mtabs ld bc,Drives*16 ;BC:= Length (Drives * length of 1 mtab) jr Tpa_Move page ;---------------------------------------------------------------------- ; 4 - Copy DrvTbl and all DPH's to Tpa ;------------------------------------- ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func4: ld hl,Drive_Table ld bc,32 + (Drives * DphLen) jr Tpa_Move ;---------------------------------------------------------------------- ; 5 - Copy Dpb_Table and all DPB's to Tpa ;---------------------------------------- ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func5: ld hl,Dpb_Table ld bc,Dpb_Table_Leng jr Tpa_Move ;---------------------------------------------------------------------- ; 6 - Copy the Character Table to Tpa ;------------------------------------ ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func6: ld hl,Char_Tables ld bc,Char_Table_Length jr Tpa_Move ;---------------------------------------------------------------------- ; 7 - Copy Virtual Drive Message to Tpa ;-------------------------------------- ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func7: ld hl,VMsg ld bc,VMsg_Length jr Tpa_Move page ;---------------------------------------------------------------------- ; 8 - Copy Free Space to Tpa ;--------------------------- ; 1) Register Usage ; BC -> Returned equal to number of bytes moved ; DE -> Destination in Tpa ; HL -> Returned equal to Source in System bank ; func8: ld hl,Pool ld bc,Pool_Length jr Tpa_Move ;---------------------------------------------------------------------- ; 9 - Format a Track (18_Jul_84) ;------------------------------- ; 2) Register Usage ; DE -> Enter equal old micro decision mtab/dpb pair, as on media ; IX -> Pointer to user's APIF area ; apif.hstdsk = logical drive to format ; apif.hsttrk = track for format ; apif.hstsec -> sector table (in reverse order) ; Bnk_Format: push iy ld iy,RamDatY push ix ;save for exit push de ;save mtab call Install_Apif ;Overlay the System's Apif with User's ld a,(iy+HstDsk) ;apif.drive from user ld (iy+SekDsk),a call GDskIY ;get its mtab bit @HrdDsk,(hl) ;see if harddsk pop de ;restore user's mtab jr z,BfSk1 ;If (This is a hard disk) ld e,1 ; secondary select ld c,(iy+HstDsk) call SelDsk ; secondary select jr BfSk2 BfSk1: push de ;Else DE:= Pointer to new MTAB (source) ex (sp),hl ; save system mtab ld de,DskBuf+80h ; ID area is destination ld bc,DskTLn ; length call Sys_Move ; copy to system pop hl ; restore system mtab call FmtLog ; format logon for floppy BfSk2: ld l,(iy+HstSec) ld h,(iy+HstSec+1) ;HL:= Source (Pointer to Gap Table) ld de,FmtBuf ;DE:= Destination (Format Buffer) ld bc,3 ;BC:= Length (3 bytes for gap table) call Sys_Move ;Move Gap Table from Tpa to System add hl,bc ;HL:= Pointer to Start of Sector Table push hl ld a,(RamDatY+HstDsk) call GDskIY ;(HL:= Disk's Mtab DskDef0) bit @HrdDsk,(hl) ;(test for hard disk) ld hl,FmtBuf+3 ;HL:= Start hard disk Sector Table ld de,0 ;DE:= Hard Disk Offset to Sector Table jp nz,BfSk3 ;If (This is a Floppy Disk) ld de,12-3 ; DE:= Floppy Offset Sector Table BfSk3: add hl,de ex de,hl ;DE:= Destination (Start Sector Table) pop hl ;HL:= Source (User Sector Table) ld c,(iy+PhySpt) ld b,0 ;BC:= Number of Physical Sectors/Track call Sys_Move ;Install Sector Table call Rom_On ;rom is on, but chario needs to know call FmtHst ;Format the Track pop de ;DE:= Destination (User's Apif) call Rom_Off ;Turn Off the Rom call Restore_Apif ;Update the User's Apif ld d,a ;D:= Returned Status pop iy ret ;Return ; Get a Disk's Mtab ;------------------ ; 1) Enter: A:=Drive and IY:=RamDatY (GDskIY) or HL:=RamDatY (GDskHL) ; 2) Return: HL:= Start of Drive's Mtab ; GDskIY: push iy pop hl ;HL:= IY GDskHL: ld de,MToff ;calc. mtab pointer add hl,de rlca ;multiply drive by 16 rlca rlca rlca ld e,a ;add (16 * drive) to pointer add hl,de ret page ;---------------------------------------------------------------------- ; 10 -Initialize the Uart Characteristics (4_Sept_84) ;---------------------------------------------------- ; Init_Uarts: ld a,(system_bank_bits) and not $cntrst ;Restore Centronics out (bnkstb),a ;(exiting this bank lifts restore) ld hl,RamDatY+CFlag ;HL:= Pointer to CFlag in RamDatY ld a,(Default_CFlag) ;defaults from SETUP.COM ld (hl),a ;Re:Initialize CFlag ;Setup Console Reciever Format ld a,3 out (s1stat),a ;Select Write Register 3 ld a,(Con_Stat_3) out (s1stat),a ;Console Format 8 bits, Rx_Enabled in a,(s1stat) ;Read status register once to clear it ;Setup List Reciever Format/Handshaking ld a,0FFh ld (LstFlg),a ;Enable X-On/X-Off ld a,3 out (s2stat),a ;Select Write Register 3 ld a,(Lst_Stat_3) ;Lst Format 8 bits, Rx_Enabled bit @hwsync,(hl) jr z,IntCt1 ;If (Hardware Handshake eq Enabled) or $Auto_Enables ; Set Auto_Enables Bit IntCt1: out (s2stat),a ;8bits/char, auto, rx on in a,(s2stat) ;Read status register once to clear it ;Setup Aux Reciever Format/Handshaking ld a,3 out (s3stat),a ;Select Write Register 3 ld a,(Aux_Stat_3) ;Aux Format 8 bits, Rx_Enabled bit @SioSyn,(hl) ;If (Hardware Handshaking eq Enabled) jr z,IntCt2 or $Auto_Enables ; Set Auto_Enables Bit IntCt2: out (s3stat),a ;8bits/char, auto, rx on in a,(s3stat) ;Read status register once to clear it call Init_Baud_Rates ;Initialize the Uart's Baud Rates ret ;Return page ;---------------------------------------------------------------------- ; 11 - Bank Ims Injection Routine (9_Jul_84) ;------------------------------------------- ; Bnk_Inject_Ims: ex de,hl ;source is [de] on entry ld bc,1 ;1 byte ld de,Ims_Length ;destination call sys_move ;read length byte ex de,hl ;point at user's string ld bc,1 ;destination is sys for move below call xmove ld a,(hl) ;get length byte from Ims_Length jp inject_ims2 ;[de] -> input string in tpa ;---------------------------------------------------------------------- ; 12 - enable/disable centronics interrupts [e]=0=disable ;-------------------------------------------------------- ; stack currently contains (0) return to bnk_return, (+2) bank bits ; warning, this code is not intended to update centronics bits in ; iy.cpybnk this discipline will cause centronics interrupts to be ; disabled automatically during rom execution. ; func12: pop hl pop af ;get the bits ld d,a ;previous state res 7,a ;centronics interrupts off bit 0,e ;was this an enable? jr z,F12Sk1 set 7,a F12Sk1: push af ;back on stack jp (hl) ;and exit page ;---------------------------------------------------------------------- ; 13 - Enable/Disable Disk Read After/Before Write ;------------------------------------------------- ; 1) Register Usage: ; E -> Bit Mask ; bit 0 Read after Write 0=Disable, 1=Enable ; bit 1 Read before Write 0=Disable, 1=Enable ; func13: ld hl,Before_After ld d,(hl) ;return what it was before ld (hl),e ret ;---------------------------------------------------------------------- ; 14 - Execute a Routine in the System Bank (29_Aug_84) ;------------------------------------------------------ ; 1) This routine executes a routine in the System Bank. Notice that ; the Rom is considered part of the system bank too. ; 2) Register Usage: ; BC -> User's Entry Parameters ; DE -> User's Entry Parameters ; HL -> Execution Address ; IY -> Set to RamDatY ; func14: ld iy,RamDatY ld hl,(hl_entry) ld bc,(bc_entry) jp (hl) page ;---------------------------------------------------------------------- ; 15 - verify track, destructive ;------------------------------- ; 1) This routine Verifies one track on the selected disk. ; 2) If an error is encountered then the bad sector is remapped if ; possible. ; func15: ld iy,RamDatY set @BufOk,(iy+OpFlag) jr Verify ;---------------------------------------------------------------------- ; 16 - verify track, non-destructive ;----------------------------------- ; 1) This routine Verifies one track on the selected disk. ; 2) Bad Sectors are reported but nothing is done about them. ; func16: ld iy,RamDatY res @BufOk,(iy+OpFlag) jr Verify ;---------------------------------------------------------------------- ; Verify a Track -- Common Code (9_Jul_84) ;----------------------------------------- ; 1) md11 hard disk sectors are formatted 1,8,6,4,2,9,7,5,3, physically ; interleave for verify makes sequence 1,6,2,7,3,8,4,9,5, every other ; one set ; 2) Register Usage ; B -> sector_count ; C -> interleave_increment ; D -> sectors_track+1 ; E -> remaps ; Verify: ld bc,0905h ;9 sectors interleaved ld de,0A00h ;10 is illegal sector bit @hrddsk,(iy+phydrv) jr nz,VrSk1 ;if floppy ld b,(iy+PhySpt) ; Number of Sectors to Physical Sectors ld c,01h ; No interleave VrSk1: ld (iy+hstsec),1 ;begin at sector 1 VrLp1: push de ;Repeat push bc res @inmap,(iy+opflag) ; reset @inmap call read2 ; Read a Sector pop bc pop de jr z,VrSk2 ld d,a ; D:= error code; E:= remapped sectors ret ; user abort error VrSk2: bit @inmap,(iy+opflag) ; If (Sector is now in Bad Map) jr z,VrSk3 inc e ; Inc remap count VrSk3: ld a,(iy+hstsec) add a,c ; interleave cp d jr c,VrSk4 dec d sub d ; - sectors per track inc d VrSk4: ld (iy+hstsec),a djnz VrLp1 ;Until (all Sectors have been Checked) ld d,0 ;no errors ret ;normal exit ;------------------------------------------------------------------------- ; 17 - Modify Contents of CFlag ;------------------------------ ; 1) The value of CFlag is set to the entry value of the E register. ; 2) The previous value of CFlag is returned in the D register. ; func17: ld hl,RamDatY+CFlag ld d,(hl) ld (hl),e ret ;---------------------------------------------------------------------- ; 18 - Read the System ID Frame (13_Jul_84) ;------------------------------------------ ; 1) This routine moves the system ID Frame into the Tpa address ; specified by the user. ; 2) The ID Frame has the following format ; 1 Rom Revision number ; 1 Compatibility Level ; 8 Reserved for second source ID Information ; 2 Starting address of checksummed block ; 2 Length of checksummed block ; 1 Ram Checksum ; 1 Rom Checksum ; func18: ld hl,50h ;Starting Location of Rom ID Block ld bc,10h ;Length of Rom ID Block ld a,(system_bank_bits) ;include centronics controls push af and 0FCh ;Enable Rom And Bank 1 or $Xfer ;Set the transfer bit out (BnkStb),a ldir ;Move the Rom ID Block into the Tpa pop af out (BnkStb),a ;Restore the Bank Strobe ret page ;---------------------------------------------------------------------- ; 19 - Initialize the Uart's Baud Rates (18_Jul_84) ;-------------------------------------------------- ; Init_Baud_Rates: ld a,(Ser1Baud) ;A:= Index for Console Baud Rate cp 0FFh ;If (Value is not Specified) jr nz,IntSk1 in a,(DrvSts) ; If (Baud Rate Jumper is IN) and $JBAUD ld a,6 ; (A:= default 9600 baud) jr z,IntSk1 ; Else inc a ; A:= 19200 baud IntSk1: ld (Ser1Baud),a ;A:= Baud Rate Index (Update for Setup) ld b,0BEh ;B:= Select Channel_2 - Mode 3 ld c,baud0 ;C:= Port Select call SetVal ;Initialize the Console Baud Rate (Dart) ld a,(ser2baud) ;A:= Aux Baud Rate Index ld b,07Eh ;B:= Select Channel_1 - Mode 3 ld c,baud1 ;C:= Port Select call SetVal ;Initialize the Aux Baud Rate (Dart) ld a,(ser3baud) ;A:= List Baud Rate Index ld b,03Eh ;B:= Select Channel_0 - Mode 3 ld c,baud2 ;C:= Port Select call SetVal ;Initialize the List Port (Sio) ret ;Set the Baud Rate (A=Baud_Rate_Index B=Channel_Select C=Port_Select) SetVal: push bc ld hl,BaudTbl ;HL:= Base of Bit Rate Table add a,a ld c,a ld b,0 ;BC:= Index * 2 add hl,bc ;HL:= Pointer into Bit Rate Table pop bc ld a,b out (BaudSet),a ;Select the Channel ld a,(hl) out (c),a ;(Set Baud Rate Lo) inc hl ld a,(hl) out (c),a ;(Set Baud Rate Hi) ret ;Return page ;---------------------------------------------------------------------- ; 20 - Read a Physical Sector (18_Jul_84) ;---------------------------------------- ; 1) Enter with the ix set to an Apif Structure. ; Read_Host: push iy ld iy,RamDatY push ix call Install_Apif ;Install the User's Apif res @InMap,(iy+OpFlag) ;don't pre-read bad map res @BufOk,(iy+OpFlag) ;errors are not re-mapable set @ReadOp,(iy+DFlag) ;indicate read call Rom_On ;turn rom on call RdHsRm ;read from disk call Rom_Off ;turn the Rom Off (AF preserved) pop de ;DE:= Destination (User's Apif) call Restore_Apif ;Update the User's Apif pop iy ret ;Return ;---------------------------------------------------------------------- ; 21 - Write a Physical Sector (18_Jul_84) ;----------------------------------------- ; 1) Enter with the ix set to an Apif Structure. ; 2) It is up to the User to Set @InMap Properly (Jam it or PreRead). ; Write_Host: push iy ld iy,RamDatY push ix call Install_Apif ;Install the User's Apif set @BufOk,(iy+OpFlag) ;same as pre-read res @ReadOp,(iy+DFlag) ;indicate write call Rom_On ;turn rom on call WrHsRm ;write to disk call Rom_Off ;turn the Rom Off pop de ;DE:= Destination (User's Apif) call Restore_Apif ;Update the User's Apif pop iy ret ;Return Subttl Banked Bios -- Console Input Translation Routines page ;---------------------------------------------------------------------- ; Logical Console Input Status (11_Jul_84) ;----------------------------------------- ; 1) This routine returns the Logical Console Input Status. If the ; Ims buffer is Inactive or it is empty then the Physical status ; is returned. If the Ims buffer is active and Has characters then ; the Flag @FstSlw (in CFlag) is tested. If @FstSlw is 0 then the ; physical console status is returned; Otherwise, the logical or ; of the Ims status and Physical status is returned (always = 0FFh). ; 2) Register Usage: ; AF -> Status Returned from CPhy (0=No_Char; 0FFh=Char_Ready) ; HL -> Pointer to CFlag ; Banked_ConSt: call CPhy ;Get the Physical Console Status ld hl,RamDatY + CFlag ;HL:= Pointer to CFlag bit @ImsAct,(hl) ;If (Ims InActive) ret z ; Return bit @ImsWet,(hl) ;If (Ims Buffer Has NO Characters) ret z ; Return bit @FstSlw,(hl) ;If (this is Physical Status) ret z ; Return (Physical Status) ld a,0FFh ;Else ret ; Return (Active) ;---------------------------------------------------------------------- ; Get the Physical Console Status (10_Jul_84) ;-------------------------------------------- ; 1) This routine checks the physical console status. If the console ; status port shows that a character is ready then the Flag @PcStat ; (in SFlag) is returned set and the accm is returned equal to 0FFh ; else @PcStat is Cleared and the accm returned equal to 0. ; 2) Register Usage: ; A -> Returned 0=No_Character; 0FFh=Character_Ready ; HL -> Returned Pointing to SFlag ; CPhy: ld hl,SFlag ;HL:= Pointer to Status Flag res @PcStat,(hl) ;Clear Physical Console Status Flag in a,(S1Stat) ;A:= Console input status port and $RcvRdy ;If (Status eq NOT ready) ret z ; Return (Accm:= 0) set @PcStat,(hl) ;Else Set Physical Console Status Flag ld a,0FFh ; Accm:= 0FFh ret ; Return page ;---------------------------------------------------------------------- ; Console Input with Function Key Translation (13_Jul_84) ;-------------------------------------------------------- ; 1) This routine returns the next character. This character can come ; from the Console I/O port, the ims buffer of from a function key. ; 2) If a character is the START of a function key sequence then it is ; thrown away and the next character of the sequence is read. If this ; character is in the function key lookup table then the string ; associated with it is placed in the ims buffer and the first ; character of that string is returned. If it isn't found then it's ; returned with it's parity bit set. ; Banked_ConIn: ld a,(RamDatY+CFlag) bit @Xl_In,a ;If (Console Input Translation eq OFF) jp z,Ser1_Input ; Goto Physical I/O CiLp1: call getchr ;get a character from current source CiLp2: push af ;While (There was a Character) And jr z,No_Char bit @FunSeq,(hl) ; (Start Funct Key Seq) jr z,No_Char pop af call PConIn ; Wait for Next Character jr CiLp2 No_Char:ld a,(RamDatY + CFlag) ;[*=> Re:Enter Here from Submt <=*] and 11000000b ;(remove all but @ImsAct and @ImsWet) cp 11000000b ;If (Ims eq Active AND Ims Buffer Active) jp z,Submt ; Goto Submit pop af ;If (there was really NO Character) jr z,CiLp1 ; Goto Start of ConIn bit @FunCode,(hl) ;If (Not 2nd Char of Funct Key Seq) ret z ; Return push af ld a,0FCh call Find ;Find the Function Key Struct inc hl ;HL:= Start of Function Key Struct pop af call Scan ;Look for the Function Key set @Parity,a ;If (Key NOT Found) ret c ; Return (Char has Parity Set) ld a,(hl) ;A:= Length Funct Key Tranlation String or a ;If (String Length ne 0) ex de,hl ; (DE:= Pointer to String Length) call nz,Inject_Ims ; Inject String into the Ims Buf jr CiLp1 ;Goto Start of ConIn page ;---------------------------------------------------------------------- ; Pause for Console Input (11_Jul_84) ;------------------------------------ ; PConIn: call GetChr ;Repeat jr z,PConIn ;Until (a Character is Available) ret ;---------------------------------------------------------------------- ; Get a Character from the Console or the Submit Buffer (11_Jul_84) ;------------------------------------------------------------------ ; GetChr: ld hl,SFlag ;HL:= Pointer to SFlag ld e,(hl) ;E:= Contents of SFlag res @PcStat,e ;Clear Physical Console Status Active in a,(S1Stat) and $RcvRdy ;If (There's No Character Ready) ret z ; Return in a,(S1Data) res @Parity,a ;A:= Char from Console without parity push af push hl ld hl,SCount ;HL:= Pointer to Time-out Counter inc (hl) ;If (Time-out Counter eq 0) jr nz,GcSk1 dec (hl) ; Reset Counter to 0FFh GcSk1: ld a,(hl) ld d,a ;D:= Current Time-Out Counter Value pop hl ;(restore HL pointing to SFlag) bit @FunCode,(hl) ;If (Last Char ne Funct Key Code) And res @FunCode,(hl) ; (Clear Funct Key Code Flag) jr nz,GcLp1 bit @FunSeq,(hl) ; (Last Char part of Funct Key Seq) jr z,GcLp1 set @FunCode,(hl) ; Set Funct Key Code Flag res @FunSeq,(hl) ; Clear Funct Key Sequence Flag cp 0Dh ; If (No Time-Out Error) jr nc,GcSk2 ; Skip Leadin Check GcLp1: pop af ;Repeat push af cp Leadin ; If (Char eq Funct Key Leadin Char) jr nz,GcSk2 set @FunSeq,(hl) ; Set Funct Key Seq Flag res @FunCode,(hl) ; Clear Funct Key Code Flag GcSk2: ld a,1 out (S1Stat),a ; Select Register 1 of Sio/Dart in a,(S1Stat) ; Read Register 1 of Sio/Dart and 00100000b ; If (there was NO OverRun Error) jr nz,GcSk3 pop af ; Restore the Accm ret ; Return GcSk3: xor a ld (SCount),a ; Clear SCount ld a,00110000b out (S1Stat),a ; Clear the OverRun Error ld a,1100000b ; (@ImsAct and @ImsWet) and e ; If (Not a Funct Key Seq) jr nz,GcSk5 ld a,0Ch cp d jr nc,GcSk4 ; If (Time_Out Error) pop af ; (fix Stack) ld a,0 ; Accm:= 0 ret ; Return GcSk4: pop af ; Else Restore Char ret ; Return GcSk5: pop af push af cp Leadin jr z,GcLp1 ;Until (Char ne Function Key Leadin) res @FunSeq,(hl) set @FunCode,(hl) pop af ;Restore Character ret ;Return page ;---------------------------------------------------------------------- ; Inject an IMS String into the Free Space (11_Jul_84) ;----------------------------------------------------- ; 1) This routine injects an Ims String into the free space pool. ; 2) If there was insufficient room then the carry is returned set, else ; its returned cleared. ; 3) If there was already an Ims String in the buffer but it was inactive ; then the last character of the new string will have its parity set ; to turn off the Ims buffer at the end of the new string. ; 4) Both the @ImsAct (Ims Active) and @ImsWet (Ims Buffer has Chars) ; flags are returned set if the Ims String was successfully installed. ; 5) Register Usage ; BC -> Used in Length Calculations ; DE -> On Entry Points to an Ims string with length byte first ; HL -> Used as general purpose pointer ; Inject_Ims: ld a,(de) ;get length byte Inject_Ims2: ld c,a ld b,0 ;BC:= Length of Ims String inc de ;DE:= Start of Ims String push de ;Find the Free Space Length ld a,0FFh ;A:= Free Space Block Header call find ;Find the Free Space Block push hl ld h,d ld l,e ;HL:= Free Space Length ;See If there's enough space for the new Ims String or a ;(clear carry) sbc hl,bc ;If (there's insufficient Free Space) jr nc,IiSk1 pop de ; (remove Free Space Length) pop de ; (remove Pointer to Ims Start) ret ; Return (Carry = Set) ;Update the Free Space Length IiSk1: ex de,hl ;DE:= New Free Space Length ex (sp),hl ;HL:= Free Space Address (save old length) ld (hl),d dec hl ld (hl),e ;Update Free Space Length ;Calculate the New Ims Buffer Length and Starting Address inc hl inc hl ;(adj HL to point to free data area) pop de ;DE:= old Free Space Length add hl,de ;(HL:= pointer to Ims Code (FD)) inc hl ;HL:= Pointer to Ims Buffer Length ld e,(hl) ;read ims.len inc hl ld d,(hl) ex de,hl ;HL:= Ims Length (DE:= Pointer to Ims Length) add hl,bc ;(HL:= current ims len + string len) ex de,hl ;HL:= Pointer to Ims Length sbc hl,bc ;HL:= New Ims Starting Address ;Install the New Ims Header (Id code and Length word) ld (hl),d ;write new ims header, ims.len(hi) dec hl ld (hl),e ;Install New Ims Length dec hl ld (hl),0FDh ;Install Ims header ;Move the New Ims String Into Place inc hl inc hl inc hl ;HL:= Destination (Ims Buffer) pop de ;DE:= Source (new Ims String) call move ;copy string, may be from tpa or sys ex de,hl ;DE:= 1st Char of Previous Ims (if any) ;Deal with an Ims Buffer that has chars and is inactive ld hl,RamDatY + CFlag bit @ImsWet,(hl) jr z,IiSk2 ;If ((Ims Buffer Already has Chars) And biô @ImsAct,(hl© jr nz,IiSk2 ; (Ims Buffer eq InActive)) dec de ; DE:= Last Char of New String ld a,(de) set @Parity,a ; Set Flag to turn-off Ims after ld (de),a ; processing this new Ims string IiSk2: set @ImsWet,(hl) ;Set the Ims Buffer has Char Flag set @ImsAct,(hl) ;Set the Ims Active Flag xor a ;(clear the carry) ret ;Return page ;---------------------------------------------------------------------- ; Search for a Function key (10_Jul_84) ;-------------------------------------- ; 1) This routine searches any table with the same structure as ; the Function Key Table. ; 2) The Function Key Table Structure starts with one byte giving ; the number of entries. Each entry consists of 1) a function Key ; Code followed by 2) the length of the Function Key Translation ; String followed by 3) the Fuction Key Translation String. ; 3) If the Key is found then the carry is returned Clear else it is Set ; 4) Register Usage: ; A -> Key to Search for ; B -> used as a Counter ; HL -> Pointer to the Base of the Table ; Scan: ld d,0 ;(set hi-order byte of DE to 0) ld b,(hl) ;B:= Number of Entries inc b ;(Make sure there's a count of .ge. 1) inc hl ;HL:= Start of First Entry jr ScSk1 ScLp1: cp (hl) ;Repeat If (Entry Matches Desired Key) inc hl ; (HL:= string.length) ret z ; Return (carry clear) ld e,(hl) ; E:= Length of Entry inc e ; adjust add hl,de ; HL:= Start of Next Entry ScSk1: djnz ScLp1 ;Until (Whole Table has been Checked) scf ;Set the NOT Found Flag ret ;Return ;---------------------------------------------------------------------- ; Get the Next Character from the Submit Buffer (11_Jul_84) ;---------------------------------------------------------- ; 1) The next character from the Ims buffer is returned to the calling ; routine after updating the Free and Submit String Block pointers. ; 2) If the character is the last in the buffer then the @ImsWet flag ; in CFlag is Cleared. ; 3) If the character has the Parity bit Set (bit 7) then the @ImsAct ; flag in CFlag is Cleared which deactivates the Ims Buffer until ; the next warm boot. ; AF -> Valid Character if Z-Flag is Cleared ; HL -> Pointing at CFlag ; Submt: pop af ;If ((There's a Char in the Accm) And jr z,SuSk2 bit @FunCode,(hl) ; (Last Key wasn't Funct Key Code)) jr nz,SuSk2 cp 3 ; If (Char eq Control C) jr nz,SuSk1 call Drop_Ims ; DeActive Ims ret ; Return SuSk1: ld hl, RamDatY + CFlag ; HL:= Pointer to CFlag bit @FstSlw,(hl) ; If ((Ims ConSt eq Inactive) And jr nz,SuSk2 bit @PcStat,e ; (Physical ConSt eq Active)) jr z,SuSk2 cp 13h ; If (Char eq Control S) ret z ; Return ld a,11h ; Else A:= Control Q ret ; Return SuSk2: ld a,0FFh ;A:= Free Space Header Code call Find ;Find the Free Space Block inc de ld (hl),d dec hl ld (hl),e ;Update the Free Space Pointer add hl,de ;HL:= Pointer to the Ims Buffer inc hl inc hl ld e,(hl) ld (hl),0FDh ;Write the Ims Header Code inc hl ld d,(hl) dec de ;(adjust the Ims Length) ld (hl),e ;Write the New Ims Length Byte (Lo) inc hl ld a,e or d ;(Test for the last char in the Buffer) ld a,(SFlag) ld e,a ;E:= SFlag ld a,(hl) ;A:= Current Character from Buffer ld (hl),d ;Write the New Ims Length Byte (Hi) ld hl,RamDatY + CFlag ;HL:= Pointer to CFlag jr nz,SuSk3 ;If (This was the last char in Buffer) res @ImsWet,(hl) ; Clear Ims Buffer has Char Flag SuSk3: bit @Parity,a ;check parity bit of char. res @Parity,a ;If (we're clear to Continue) ret z ; Return cp Slow-80h ;If (Character eq Slow) jr nz,SuSk4 res @FstSlw,(hl) ; Clear Ims ConSt Flag jr SuSk6 SuSk4: cp Fast-80h ;Else If (Character ne Fast) jr z,SuSk5 res @ImsAct,(hl) ; DeActivate the Ims Buffer ret ; Return SuSk5: set @FstSlw,(hl) ;Else Set Ims ConSt Flag SuSk6: ld a,e ld (SFlag),a ;Update SFlag xor a ;(Set the Z-Flag) push af ;(fix the Stack) jp No_Char ;Goto Banked_ConIn's No_Char entry page ;---------------------------------------------------------------------- ; DeActivate the Ims Buffer (10_Jul_84) ;-------------------------------------- ; drop_ims: ;empty the ims buffer ld a,0FDh ;ims call find ;get count push de ;save length ld a,0FFh ;free call find ex de,hl ;[hl]=free.len pop bc ;[bc]=ims.len add hl,bc ;[hl]=total space ex de,hl ;[hl]=free.len(hi) ld (hl),d dec hl ld (hl),e ;reset free length inc hl inc hl ;[hl] -> free.data space add hl,de ;[hl] -> end of free space ld (hl),0FDh ;ims header inc hl ld (hl),0 inc hl ld (hl),0 ;reset ims.len ld a,(RamDatY+CFlag) ;de-activate ims res @ImsAct,a res @ImsWet,a ld (RamDatY+CFlag),a ld a,18h ret page ;---------------------------------------------------------------------- ; Locate a Header in the Free Space Pool ;--------------------------------------- ; 1) This routine searches the free space pool for the header ID ; passed in the accm. ; 2) Register Usage: ; A -> Header ID ; DE -> Returned equal to the Length of the block if Found ; HL -> Returned equal to the start of the block if Found ; Find: ld hl,pool ;HL:= Start of Free Space Pool FiLp1: cp (hl) ;Loop inc hl ld e,(hl) inc hl ; DE:= Length of this block ld d,(hl) ; If (ID matches desired ID) ret z ; Return inc hl add hl,de ; HL:= Pointer to start next block jr FiLp1 Subttl Banked Bios -- Console Output Translation Routines page ;---------------------------------------------------------------------- ; Console Output with escape sequence translation ;------------------------------------------------ ; on entry to xlate, register c contains the character to be output. ; a test is made to see if the system is in the process of outputing ; a multiple character escape sequence, or if the character is a ; morrow standars control code. if neither test is true, than the ; character is output. ; if the character is part of a multiple character escape sequence, ; then the character is passed to the escape routine. if the ; character is a mscc, then it is converted to the appropriate ; sequence, and output. ; Banked_ConOut: ld a,(RamDatY+cflag) bit @xl_out,a jp z,ser1_output ;if translation is enabled, ld a,(esc_lvl) ; test escape flag or a ; check if flag is set jr nz,escape ; if escape sequence, jump ld a,1fh ; test if mscc cp c jp c,ser1_output ; if not, then xmit it ld a,Esc ; check if esc char cp c jp nz,notesc ; if not, jump ld a,1 ; otherwise, set escape ld (esc_lvl),a ; level to 1st stage ret ; and return notesc: ld hl,(ctblptr) ; set to search control table call lookup ; and lookup character in table or a ; see if char found jp z,ser1_output ; if not, output char ld hl,(cvctptr) ; calculate string location page ; Output a string of characters to the console ;--------------------------------------------- ; this routine outputs a string of characters to the console. ; it is used by the translate program to output a terminal ; specific string in order to implement a control sequence. ; when entered, the hl register pair points to the base of ; the string table, and the bc register pair is the offset ; to the string. characters are output starting with the ; first character until a byte value of ffh is detected. ; outstr: add hl,bc ; add offset to base ld e,(hl) ; get location of string inc hl ld d,(hl) ex de,hl ; move address of string to hl loop: ld a,(hl) ; get a char cp 0ffh ; see if done ( ffh==>done) ret z ld c,a ; if not, get char call ser1_output ; xmit it inc hl jr loop ; until end of string page ; Cursor/Escape_Sequence Translation ;----------------------------------- ; 1) This routine is used to create a string for direct cursor ; addressing, or to translate character codes. upon receipt of an ; escape code from a program, the esc_lvl is set to indicate an ; escape sequence is being output. when the next character is ; received, it is tested to see if it is an equals sign (=). If it ; is not, than an escape character is output, followed by the ; character received. if the character is the equal sign, then two ; more characters (row and column addresses) will be accepted, ; after-which a string will be output for positioning the cursor. ; Escape: ld a,(esc_lvl) ; get current escape level cp 1 ; level 1? jr z,seq1 ; then process 1st part cp 2 ; level 2? jr z,seq2 ; then process 2nd level jr seq3 ; it must be level 3 seq1: ld a,'=' ; equal sign? cp c ; if char is =, then dca started jr z,set ; else, could be character to xlate xor a ; clear escape level ld (esc_lvl),a ld hl,(etblptr) ; point to xlate table call lookup ; lookup character or a ; see if char found jr nz,down ; if found, jump to output push bc ld c,Esc ; else, send escape, then char call ser1_output ; send escape pop bc ; get original character jp ser1_output ; send it down: ld hl,(evctptr) ; calculate string location jr outstr ; output the string set: ld a,2 ; otherwise, set for level 2 ld (esc_lvl),a ; processing ret ; and return seq2: ld a,c ld (first),a ; this is the first char ld a,3 ; set for level 3 ld (esc_lvl),a ret seq3: ld a,(offset2) ; get offset for 2nd char add a,c ; add to 2nd char ld (second),a ; save 2nd char ld a,0 ld (esc_lvl),a ; clear escape sequence ld de,first ; pointer to 1st char ld a,(de) ; get 1st char ld c,a ; save in c ld a,(offset1) ; get offset for 1st char add a,c ; add to 1st char ld (de),a ; save 1st char ld a,(order) push af rra sbc a,a ; 0==>1-2 : ff==>2-1 ld b,a ; save order in b ld a,e ; use order to adjust de sub b ld e,a ; de points to 1st char to output ld hl,dcastrt ; pointer to dca prefix sting call loop ; output string ld a,(de) ; get 1st char to output ld c,a pop af bit 1,a ; see if ascii push af call nz,ascout ; call ascii if nz call ser1_output ; output char ld hl,dcamid ; pointer to seperator string call loop ; output string ld a,e ; use order to adjust de add a,b inc b add a,b ld e,a ; de points to 2nd char to output ld a,(de) ; get char to output ld c,a pop af call nz,ascout ; call ascii if flag set call ser1_output ; output char outend: ld hl,dcaend ; point to dca terminator jp loop page ;---------------------------------------------------------------------- ; ASCOUT - Output a byte in decimal ascii ;---------------------------------------- ; 1) ascout takes a binary value in c and output its decimal ascii ; equivalent. ; AscOut: push bc ld a,c ld c,'0' ;init to ascii 0 Tens: sub 10 ;subtract 10 from value jr c,Ones ;jmp if underflow inc c ;inc ascii tens value jr Tens ;loop Ones: ld b,a ;save intermediate value ld a,'0' ;a = ascii 0 cp c ;see if tens value is 0 call nz,Ser1_Output ;output tens value if not 0 ld a,3ah ;ascii 0 plus 10 add a,b ;add to produce ones value pop bc ld c,a ;get ready for output ret page ;---------------------------------------------------------------------- ; Lookup a Character in Escape/Control table (10_Jul_84) ;------------------------------------------------------- ; 1) This routine can search any table with the same structure as ; the ecsape or control tables. ; 2) The structure of these tables is as follows: ; - There is a list of Characters (which is searched by this routine) ; - There is a second list of Vectors (not actually referenced in ; this routine) that is positionally related to the character list ; (i.e. the Vector associated with a character is offset from its ; table base by 2 * character offset from its table base). ; - There are some number of strings pointed to by the Vectors. ; 2) Register Usage: ; A -> Returned 0=Not_Found; 0FFh=Found ; BC -> Enter w/C = Character to Search for; Exit = Vector Offset ; HL -> Pointer to base of table to search ; Lookup: ld b,0 ;Offset:= 0 LuLp1: ld a,(hl) ;Loop cp 0FFh ; If (Character eq End_Of_Table) jr z,LuSk2 ; Goto No Character Exit cp c ; If (Character Matches Table) jr z,LuSk1 ; Goto Match Exit inc hl ; Table_Pointer:= Table_Pointer+1 inc b ; Offset:= Offset = 2 inc b jr LuLp1 ;Character has been Found LuSk1: ld c,b ld b,0 ;BC:= Offset ld a,0FFh ;A:= Returned Status is Found ret ;Return ;Character has NOT been Found LuSk2: xor a ;A:= Returned Status is NOT Found ret ;Return Subttl Banked Bios -- Character I/O (List Device Drivers) page ;---------------------------------------------------------------------- ; List Device Drivers (20_Aug_84) ;-------------------------------- ; Banked_List: ld a,(RamDatY+CFlag) bit @CenLst,a ;If (Serial Device eq List Device) jr nz,BlLp2 BlLp1: call Banked_ListSt ; Repeat (get serial status) jr z,BlLp1 ; Until (List Device eq Ready) jp Ser2_Output ; do Serial Output BlLp2: call Cent_Status ;Else Repeat (Get Parallel Status) jr z,BlLp2 ; Until (Parallel Device eq Ready) jp Cent_Output ; Do Parallel Output Banked_ListSt: ld a,(RamDatY+CFlag) bit @CenLst,a ;If (List Device eq Centronics) jp nz,Cent_Status ; Goto Centronics List Status bit @hwsync,a ;If (handshake mode eq Xon/Xoff) jr nz,BlSk3 call ser2_input_status ; If (Character is Ready) call nz,ser2_input ; Read the Character and 01111111b ; (Strip the Parity) cp 13h ; if (Char eq xoff) jr nz,BlSk1 ld a,0 ld (lstflg),a ; Flag:= not rdy ret ; Return not rdy BlSk1: cp 11h ; Else If (Char eq Xon) jr nz,BlSk2 ld a,0FFh ld (lstflg),a ; Flag:= rdy BlSk2: ld a,(lstflg) ; get status flag or a ; set flags ret z ; if zero, then xoff pending BlSk3: jp ser2_output_status ;Check Output Status Subttl Banked Bios -- Character I/O (Physical Level) page ;---------------------------------------------------------------------- ; Centronics Parallel Device Driver (11_Jul_84) ;---------------------------------------------- ; Cent_Status: in a,(cstat) and $CntRdy ;If (Centronics Status ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Cent_Output: ld a,c ;get char out (CData),a ;write data di ld a,(system_bank_bits) or $CNTSTB out (bnkstb),a ;strobe on ld b,10 cntdly: djnz cntdly ;delay and not $CNTSTB out (bnkstb),a ;strobe off ei ret page ;---------------------------------------------------------------------- ; Serial Port 1 - (Default Console Device) Drivers (11_Jul_84) ;------------------------------------------------------------ ; Ser1_Input_Status: in a,(S1Stat) and $RcvRdy ;If (Reciever Status ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser1_Input: call Ser1_Input_Status ;Repeat jr z,Ser1_Input ;Until (Input Port is Active) in a,(S1Data) ;A:= Input Character ret Ser1_Output_Status: in a,(S1Stat) and $TxRdy ;If (Transmitter Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser1_Output: call Ser1_Output_Status ;Repeat jr z,Ser1_Output ;Until (Transmitter Buffer eq Ready) ld a,c ;(move character to output to Accm) out (s1data),a ;Output the Character ret ;Return page ;---------------------------------------------------------------------- ; Serial Port 2 - (Default List Device) Drivers (11_Jul_84) ;---------------------------------------------------------- ; Ser2_Input_Status: in a,(S2Stat) and $RcvRdy ;If (Reciever Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser2_Input: call Ser2_Input_Status ;Repeat jr z,Ser2_Input ;Until (Reciever Buffer eq Ready) in a,(S2Data) ;A:= Input Character ret ;Return Ser2_Output_Status: in a,(S2Stat) and $TxRdy ;If (Transmitter Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser2_Output: call Ser2_Output_Status ;Repeat jr z,Ser2_Output ;Until (Transmitter Buffer eq Ready) ld a,c ;(move character to output into Accm) out (S2Data),a ;Output the Character ret ;Return page ;---------------------------------------------------------------------- ; Serial Port 3 (Default Auxilary Device) Drivers (11_Jul_84) ;------------------------------------------------------------ ; Ser3_Input_Status: in a,(S3Stat) and $RcvRdy ;If (Reciever Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser3_Input: call Ser3_Input_Status ;Repeat jr z,Ser3_Input ;Until (Reciever Buffer eq Ready) in a,(s3data) ;A:= Input Character ret ;Return Ser3_Output_Status: in a,(S3Stat) and $TxRdy ;If (Transmitter Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser3_Output: call Ser3_Output_Status ;Repeat jr z,Ser3_Output ;Until (Transmitter Buffer eq Ready) ld a,c ;(move character to output into Accm) out (S3Data),a ;Output the Character ret ;Return page Subttl Resident Bios -- Banking Considerations and Bios Jump Table page ;====================================================================== ; Resident Bios - Banking Considerations ;======================================= ; We all live by rules, the following shall be observed: ; 1) The routines SELMEM and MOVE shall always reside in common. ; 2) Interrupt entry points shall always reside in common. ; 3) The interrupt save/restore routines, and the sytem stack ; shall always reside in common. ; 4) The system_stack save/restore routines shall reside in common. ; 5) The call_bank/restore_bank routines shall reside in common. ; 6) Access to rom code shall never be made from common, only ; from the banked part of the bios (except for error exits) ; 7) Routines may be freely moved from the banked part to rom ; when doing so does not require co-binding of rom and bios. ; ; observing the above will make life more pleasant and will prevent ; brutalizations of our personal joules. ; ;---------------------------------------------------------------------- ; External Declarations ;---------------------- ; Public devtbl Public time Public devini Public userf Public services Public wboot Public const Public conin Public conost Public auxin Public auxist Public auxost Public auxout Public listst Public list Public conout Public selmem ;select memory now, [a]=desired bank, 0 or 1 Public move Subttl Resident Bios -- Jump Table page ;---------------------------------------------------------------------- ; Resident Bios - Jump Table ;--------------------------- ; cseg ;Begin the Resident Bios Module Code bios: jp boot ;arrive here from cold start load warmpt: jp wboot ;arrive here for warm start jcons: jp const ;return console input status jconi: jp conin ;read console character jcono: jp conout ;write conlole character jp list ;write list character jp auxout ;write aux character jp auxin ;read aux character jp home ;move to track zero on selected drive jp seldsk ;select disk drive jp settrk ;set track number jp setsec ;set sector number jp setdma ;set DMA address jp read ;read selected sector jp write ;write selected sector jp listst ;return list device status jp sectrn ;translate logical to physical sector number jp conost ;return console output status jp auxist ;return aux device input status jp auxost ;return aux device output status jp devtbl ;return address of character i/o table jp devini ;init character i/o devices jp drvtbl ;return address of disk drive table jp multio ;set number of consec. sec. to read/write jp flush ;flush user [de]blocking buffers jp move ;copy memory to memory jp time ;clock support jp selmem ;select memory bank jp setbnk ;set bank for next DMA jp xmove ;set banks for next move jp userf ;reserved for me. jp wboot ;reserved for DRI jp wboot ;reserved for DRI Subttl Resident Bios -- Bank Crossing Routines page ;---------------------------------------------------------------------- ; Bank Crossing Routines (14_Jul_84) ;----------------------------------- ; Services: ;Cold Boot (Access to bios extensions) ld (HL_Entry),hl ;Save Entry Value of HL ld (BC_Entry),bc ;Save Entry Value of DE ld b,0 ld c,a ;BC:= Entry Value of A ld hl,Bnk_Services ;HL:= Vector to Banked Services jr Inter_Bank WBoot: ld hl,Banked_WBoot ;Warm Boot jr Inter_Bank ;(-Does NOT return via Res_Bnk_Return-) WBoot_Return: ;Return from Warm Boot ld hl,(VNumb) ;(get drive & terminal level) ld a,1 call SelMem ;Set Current Bank to Tpa ld (8),hl ;Save drive & terminal level in page 0 jp Tpa ConSt: ld hl,Banked_ConSt ;Console Input Status jr Inter_Bank ConIn: ld hl,Banked_ConIn ;Console Input jr Inter_Bank ConOut: ld hl,Banked_ConOut ;Console Output jr Inter_Bank List: ld hl,Banked_List ;List Output jr Inter_Bank AuxOut: ld hl,ser3_output ;Aux Output jr Inter_Bank AuxIn: ld hl,ser3_input ;Aux Input jr Inter_Bank ListSt: ld hl,Banked_ListSt ;List Status jr Inter_Bank ConOSt: ld hl,ser1_output_status ;Console Output Status jr Inter_Bank AuxISt: ld hl,ser3_input_status ;Aux Input Status jr Inter_Bank AuxOSt: ld hl,ser3_output_status ;Aux Output Status jr Inter_Bank Subttl Resident Bios -- InterBank Control Transfer page ;---------------------------------------------------------------------- ; Control Transfer to and from the System Bank (14_Jul_84) ;--------------------------------------------------------- ; 1) These two routines prvide access to the System Bank and the Rom ; for the Bank Crossing Routines. ; 2) The rom is turned on here because any or all of these routines ; may be moved into the rom (although none of them are in there now). ; 3) Note that res_bdos can request the system bank, then pass control ; to bnk_bdos, and bnk_bdos can request character io while the system ; bank is already on; Thus, the rom control bit is tested to prevent ; double execution. ; 4) The last half of Inter_Bank and the first half of Res_Bnk_Return ; are located in the Banked portion of the Bios in the Extended Bios ; Functions Block under the banner 'Bank Inter-Bank Execution'. ; Inter_Bank: ld a,(System_Bank_Bits) ;If (The Rom eq Active) bit 0,a jr nz,IbSk1 jp (hl) ; Goto the Routine via HL IbSk1: and Not ($Bank2 + $_RmEnb) ;Select System Bank and Enable the Rom di ;IRQ Off while system_bank_bits Invalid out (BnkStb),a jp Bnk_Inter_Bank ;do more below ;*=> inter_bank continues in sys_bank ;*=> res_bnk_return begins in sys_bank Res_Bnk_Return: ;return control to bank 2 (tpa) out (BnkStb),a ;restore bank 2 (tpa) ei pop af ;restore pop hl ld sp,(Save_User_Stack) ret Subttl Resident Bios -- Non Bank Crossing Routines page ;---------------------------------------------------------------------- ; InterBank Move ;--------------- ; 1) Register Usage ; BC -> Enter = Count Exit = 0 ; DE -> Enter = Source Exit = Source + Count ; HL -> Enter = Destination Exit = Destination + Count ; move: ld a,(bnkmsk) ;see if xmove or a ;test jr z,move1 ;if xmove, di ;no interrupts during interbank xfer out (bnkstb),a ;select desired bank, rom off xor a ld (bnkmsk),a ;clear bank mask move1: ex de,hl ldir ;move ex de,hl ld a,(system_bank_bits) out (bnkstb),a ei ret ;---------------------------------------------------------------------- ; Select Memory ;-------------- ; 1) select memory now, [a]=desired bank, 0 or 1 ; selmem: push hl ld hl,system_bank_bits di res 1,(hl) ;presume bank 0 add a,a ;*2 for bnkstb or (hl) ;switch to bank 1 ld (hl),a ;update pop hl out (bnkstb),a ;set hardware ei ret ;---------------------------------------------------------------------- ; Misc Null Routines ;------------------- ; devtbl: ld hl,0 ;no table time: devini: userf: ld a,-1 ret Subttl Resident Bios -- Interrupt Handling Routines page ;---------------------------------------------------------------------- ; Interrupt Handling Rotuines ;---------------------------- ; Interrupt_Save: ;routine is called by interrupt entry ex (sp),hl ;save hl, get return ld (Save_Int_Stack),sp ;save stack ld sp,Interrupt_Stack push af ;save [af] push hl ld hl,Interrupt_Exit ex (sp),hl ;save a return to exit jp (hl) ;ret ;*=> Interrupt service routines are responsible for saving [bc],[de] if used Interrupt_Exit: pop af ld sp,(Save_Int_Stack) pop hl ei reti Centronics_Isr: call Interrupt_Save ld a,(System_Bank_Bits) push af ;save res 0,a ;rom off set 1,a ;bank 2 (tpa) on out (BnkStb),a ld hl,Centronics_Exit push hl ld hl,(0FFFAh) ;redirection vector jp (hl) Centronics_Exit: ;restore system pop af out (BnkStb),a ret Subttl Resident Bios -- Local Data Area, Stacks and Interrupt Vectors page ;---------------------------------------------------------------------- ; Local Data Area (19_Jul_84) ;---------------------------- ; 1) The system_bank_bits are used by the bios to control bank switching ; and the centronics port. RamDatY.CPYBNK is not used because it does ; not reside in common. This byte is initialized in boot2 ; System_Bank_Bits: db 0 ;Setup in Boot2 ($cntrst ! rom-off) Save_Ims_Status: db 0 ;Save Location for CFlag for Rom_On/Off BnkMsk: db 0 ;desired bank bits set in xmove HL_Entry: ds 2,0 BC_Entry: ds 2,0 Dpb_Buffer: ds Dpb_Length,0 ;current dpb must be in common ;---------------------------------------------------------------------- ; Stacks and Interrupt Vectors (14_Jul_84) ;----------------------------------------- ; 1) high ram definitions, not much space, be sparse ; 2) note, the interrupt stack is overwritten by the system stack ; (which is small) during warm boot. This is the only time the ; rom uses the system stack. It goes as low as 0FFAAh; But, ; Character interrupts are off by then. ; ; Stack Definitions ;------------------ ; Interrupt_Stack equ 0FFA6h Save_Int_Stack equ 0FFA6h System_Stack equ 0FFD6h Save_User_Stack equ 0FFD6h ;Reserved Space for Interupt Vectors ;----------------------------------- ; ; FFD8-FFDF 4 vectors for sio/9 ; FFE0-FFEF 8 vectors for dart ; FFF0-FFF9 5 vectors for disk system and centronics ; FFFA-FFFB redirection vector reserved for spool rsx ; FFFC-FFFD redirection vector available ; FFFE-FFFF redirection vector reserved for minimon break (rst 30h) end