Early partition table support

Adding infrastructure for partition table support.  Backward compatible.  Not ready for end user usage yet.

Bumped version to 3.1.1 to demarcate this change.
This commit is contained in:
Wayne Warthen
2020-05-03 19:05:44 -07:00
parent 74e79a6c59
commit ee0fac37f9
26 changed files with 2243 additions and 1075 deletions

View File

@@ -10,8 +10,8 @@
; 1) STACK LOCATION DURING BOOT OR WBOOT???
; 2) REVIEW USE OF DI/EI IN INIT
;
FALSE .EQU 0
TRUE .EQU ~FALSE
FALSE .EQU 0
TRUE .EQU ~FALSE
;
BDOS .EQU 5 ; BDOS FUNC INVOCATION VECTOR
;
@@ -56,8 +56,8 @@ DEV_NUL .EQU $FF ; NUL:
;
; MEMORY LAYOUT
;
IOBYTE .EQU 3 ; LOC IN PAGE 0 OF I/O DEFINITION BYTE
CDISK .EQU 4 ; LOC IN PAGE 0 OF CURRENT DISK NUMBER 0=A,...,15=P
IOBYTE .EQU 3 ; LOC IN PAGE 0 OF I/O DEFINITION BYTE
CDISK .EQU 4 ; LOC IN PAGE 0 OF CURRENT DISK NUMBER 0=A,...,15=P
;
CCP_LOC .EQU CPM_LOC
CCP_SIZ .EQU $800
@@ -78,7 +78,7 @@ MEMTOP .EQU $10000
#INCLUDE "../UBIOS/ubios.inc"
#ENDIF
;
.ORG CBIOS_LOC ; DEFINED IN STD.ASM
.ORG CBIOS_LOC ; DEFINED IN STD.ASM
;
STACK .EQU CBIOS_END ; USE SLACK SPACE FOR STACK AS NEEDED
;
@@ -112,7 +112,7 @@ WBOOTE JP WBOOT ; #1 - WARM START
;
; RomWBW CBIOS places the following stamp data into page zero
; at address $40. The address range $40-$4F is reserved by CP/M
; as a scratch area for CBIOS. This data below is copied there at
; as a scratch area for CBIOS. This data below is copied there at
; every warm start. It allows applications to identify RomWBW CBIOS.
; Additionally, it contains a pointer to additional CBIOS extension
; data (CBX) specific to RomWBW CBIOS.
@@ -130,7 +130,7 @@ STPIMG: .DB 'W',~'W' ; MARKER
STPSIZ .EQU $ - STPIMG
;
; The following section contains key information and addresses for the
; RomWBW CBIOS. A pointer to the start of this section is stored with
; RomWBW CBIOS. A pointer to the start of this section is stored with
; with the CBX data in page zero at $44 (see above).
;
CBX:
@@ -152,15 +152,15 @@ CBXSIZ .EQU $ - CBX
; IOBYTE (0003H)
; ==============
;
; Device LST: PUN: RDR: CON:
; Bit positions 7 6 5 4 3 2 1 0
; Device LST: PUN: RDR: CON:
; Bit positions 7 6 5 4 3 2 1 0
;
; Dec Binary
; Dec Binary
;
; 0 00 TTY: TTY: TTY: TTY:
; 1 01 CRT: PTP: PTR: CRT:
; 2 10 LPT: UP1: UR1: BAT:
; 3 11 UL1: UP2: UR2: UC1:
; 0 00 TTY: TTY: TTY: TTY:
; 1 01 CRT: PTP: PTR: CRT:
; 2 10 LPT: UP1: UR1: BAT:
; 3 11 UL1: UP2: UR2: UC1:
;
; TTY: Teletype device (slow speed console)
; CRT: Cathode ray tube device (high speed console)
@@ -235,7 +235,7 @@ DEVMAP:
;==================================================================================================
;
; Disk mapping is done using a drive map table (DRVMAP) which is built
; dynamically at cold boot. See the DRV_INIT routine. This table is
; dynamically at cold boot. See the DRV_INIT routine. This table is
; made up of entries as documented below. The table is prefixed with one
; byte indicating the number of entries. The position of the entry indicates
; the drive letter, so the first entry is A:, the second entry is B:, etc.
@@ -245,24 +245,24 @@ DEVMAP:
; DPH: DPH ADDRESS OF DRIVE (WORD)
;
; DRVMAP --+
; | DRIVE A | DRIVE B | | DRIVE N |
; +-----V------+-------+-----+--------------------+ +--------------------+
; | N | UNIT | SLICE | DPH | UNIT | SLICE | DPH | ... | UNIT | SLICE | DPH |
; +----8+-----8+------8+-+-16+-----8+------8+-+-16+ +-----8+------8+-+-16+
; | | |
; +--------------------+ +-> [DPH] +-> [DPH]
; | DRIVE A | DRIVE B | | DRIVE N |
; +-----V------+-------+-----+--------------------+ +--------------------+
; | N | UNIT | SLICE | DPH | UNIT | SLICE | DPH | ... | UNIT | SLICE | DPH |
; +----8+-----8+------8+-+-16+-----8+------8+-+-16+ +-----8+------8+-+-16+
; | | |
; +--------------------+ +-> [DPH] +-> [DPH]
; |
; V-----+-------+-------+-------+--------+-----+-----+-----+
; DPH: | XLT | 0000H | 0000H | 0000H | DIRBUF | DPB | CSV | ALV |
; +---16+-----16+-----16+-----16+------16+-+-16+-+-16+-+-16+
; (ONE DPH PER DRIVE) | | |
; | | +----------+
; | | |
; +----------------------+ V-------------+ V-------------+
; | | CSV BUF | | ALV BUF |
; | +-------------+ +-------------+
; | (CSZ BYTES) (ASZ BYTES)
; |
; V-----+-------+-------+-------+--------+-----+-----+-----+--------+
; DPH: | XLT | 0000H | 0000H | 0000H | DIRBUF | DPB | CSV | ALV | LBAOFF |
; +---16+-----16+-----16+-----16+------16+-+-16+-+-16+-+-16+------32+
; (ONE DPH PER DRIVE) | | |
; | | +----------+
; | | |
; +----------------------+ V-------------+ V-------------+
; | | CSV BUF | | ALV BUF |
; | +-------------+ +-------------+
; | (CSZ BYTES) (ASZ BYTES)
; |
; +-----+-----+-----V-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
; DPB: | CSZ | ASZ | BLS | SPT | BSH | BLM | EXM | DSM | DRM | AL0 | AL1 | CKS | OFF |
; +---16+---16+----8+---16+----8+----8+----8+---16+---16+----8+----8+---16+---16+
@@ -289,6 +289,7 @@ DPBMAP:
.DW DPB_FD360 ; MID_FD360
.DW DPB_FD120 ; MID_FD120
.DW DPB_FD111 ; MID_FD111
.DW DPB_HDNEW ; MID_HDNEW (1024 DIR ENTRIES)
;
DPBCNT .EQU ($ - DPBMAP) / 2
;
@@ -1199,6 +1200,7 @@ DSK_GETINF1: ; ERROR RETURN
DSK_SELECT:
LD B,E ; SAVE E IN B FOR NOW
CALL DSK_GETINF ; GET D=UNIT, E=SLICE, HL=DPH ADDRESS
CALL NZ,PANIC ; *DEBUG*
RET NZ ; RETURN IF INVALID DRIVE (A=1, NZ SET, HL=0)
PUSH BC ; WE NEED B LATER, SAVE ON STACK
;
@@ -1209,13 +1211,15 @@ DSK_SELECT:
LD (SEKUNIT),A ; SAVE UNIT
LD (SEKDPH),HL ; SAVE DPH ADDRESS
;
; UPDATE OFFSET FOR ACTIVE SLICE
; A TRACK IS ASSUMED TO BE 16 SECTORS
; THE OFFSET REPRESENTS THE NUMBER OF BLOCKS * 256
; TO USE AS THE OFFSET
LD H,65 ; H = TRACKS PER SLICE, E = SLICE NO
CALL MULT8 ; HL := H * E (TOTAL TRACK OFFSET)
LD (SEKOFF),HL ; SAVE NEW TRACK OFFSET
LD A,E ; A := SLICE
LD (SLICE),A ; SAVE IT
; UPDATE LBAOFF FROM DPH
LD HL,(SEKDPH)
LD A,16
CALL ADDHLA
LD DE,SEKLBA
LD BC,4
LDIR
;
; RESTORE DE TO BC (FOR ACCESS TO DRIVE LOGIN BIT)
POP BC ; GET ORIGINAL E INTO B
@@ -1234,11 +1238,24 @@ DSK_SELECT:
LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY
RST 08 ; DO IT
LD A,E ; RESULTANT MEDIA ID TO ACCUM
LD (MEDID),A ; SAVE IT
OR A ; SET FLAGS
LD HL,0 ; ASSUME FAILURE
RET Z ; BAIL OUT IF NO MEDIA
;
; A HAS MEDIA ID, SET HL TO CORRESPONDING DPBMAP ENTRY
; CLEAR LBA OFFSET (DWORD)
LD HL,0 ; ZERO
LD (SEKLBA),HL ; CLEAR FIRST WORD
LD (SEKLBA+2),HL ; CLEAR SECOND WORD
;
; CHECK MBR OF PHYSICAL DISK BEING SELECTED
; WILL UPDATE MEDID AND LBAOFF IF VALID CP/M PARTITION EXISTS
CALL DSK_MBR ; UPDATE MEDIA FROM MBR
LD HL,0 ; ASSUME FAILURE
RET NZ ; ABORT ON I/O ERROR
;
; SET HL TO DPBMAP ENTRY CORRESPONDING TO MEDIA ID
LD A,(MEDID) ; GET MEDIA ID
LD HL,DPBMAP ; HL = DPBMAP
RLCA ; DPBMAP ENTRIES ARE 2 BYTES EACH
CALL ADDHLA ; ADD OFFSET TO HL
@@ -1249,12 +1266,22 @@ DSK_SELECT:
LD D,(HL) ; DE = ADDRESS OF DESIRED DPB
;
; PLUG DPB INTO THE ACTIVE DPH
LD HL,(SEKDPH)
LD HL,(SEKDPH) ; POINT TO START OF DPH
LD BC,10 ; OFFSET OF DPB IN DPH
ADD HL,BC ; HL := DPH.DPB
LD (HL),E ; SET LSB OF DPB IN DPH
INC HL ; BUMP TO MSB
LD (HL),D ; SET MSB OF DPB IN DPH
;
; ; PLUG LBA OFFSET INTO ACTIVE DPH
LD HL,(SEKDPH) ; POINT TO START OF DPH
LD BC,16 ; OFFSET OF LBA OFFSET IN DPH
ADD HL,BC ; HL := DPH.LBAOFF PTR
EX DE,HL ; DEST IS DPH.LBAOFF PTR
LD HL,SEKLBA ; SOURCE IS LBAOFF
LD BC,4 ; 4 BYTES
LDIR ; DO IT
;
#ENDIF
;
DSK_SELECT2:
@@ -1262,6 +1289,131 @@ DSK_SELECT2:
XOR A ; FLAG SUCCESS
RET ; NORMAL RETURN
;
; CHECK MBR OF DISK TO SEE IF IT HAS A PARTITION TABLE.
; IF SO, LOOK FOR A CP/M PARTITION. IF FOUND, GET
; UPDATE THE PARTITION OFFSET (LBAOFF) AND UPDATE
; THE MEDIA ID (MEDID).
;
#IFDEF PLTWBW
;
DSK_MBR:
; CHECK MEDIA TYPE, ONLY HARD DISK IS APPLICABLE
LD A,(MEDID) ; GET MEDIA ID
CP MID_HD ; HARD DISK?
JR Z,DSK_MBR1 ; IF SO, CONTINUE
XOR A ; ELSE, N/A, SIGNAL SUCCESS
RET ; AND RETURN
;
DSK_MBR1:
; FLUSH DSKBUF TO MAKE SURE IT IS SAFE TO USE IT.
CALL BLKFLSH ; MAKE SURE DISK BUFFER IS NOT DIRTY
XOR A ; CLEAR ACCUM
LD (HSTACT),A ; CLEAR HOST BUFFER ACTIVE FLAG
;
; READ SECTOR ZERO (MBR)
LD B,BF_DIOREAD ; READ FUNCTION
LD A,(SEKUNIT) ; GET UNIT
LD C,A ; PUT IN C
LD DE,0 ; LBA SECTOR ZERO
LD HL,0 ; ...
CALL DSK_IO2 ; DO IT
RET NZ ; ABORT ON ERROR
;
; SWITCH TO BIOS BANK TO ACCESS DISK BUFFER
LD A,(HB_CURBNK) ; GET CUR BANK
PUSH AF ; SAVE CUR BANK
LD A,(BNKBIOS) ; BIOS BANK
CALL HB_BNKSEL ; DO IT
;
; CHECK SIGNATURE
LD HL,(DSKBUF) ; DSKBUF ADR
LD DE,$1FE ; OFFSET TO SIGNATURE
ADD HL,DE ; POINT TO SIGNATURE
LD A,(HL) ; GET FIRST BYTE
CP $55 ; CHECK FIRST BYTE
JR NZ,DSK_MBR4 ; NO MATCH, NO PART TABLE
INC HL ; NEXT BYTE
LD A,(HL) ; GET SECOND BYTE
CP $AA ; CHECK SECOND BYTE
JR NZ,DSK_MBR4 ; NO MATCH, NO PART TABLE, ABORT
;
; TRY TO FIND OUR ENTRY IN PART TABLE AND CAPTURE LBA OFFSET
LD B,4 ; FOUR ENTRIES IN PART TABLE
LD HL,(DSKBUF) ; DSKBUF ADR
LD DE,$1BE+4 ; OFFSET OF FIRST ENTRY PART TYPE
ADD HL,DE ; POINT TO IT
DSK_MBR2:
LD A,(HL) ; GET PART TYPE
CP $52 ; CP/M PARTITION?
JR Z,DSK_MBR3 ; COOL, GRAB THE LBA OFFSET
LD DE,16 ; PART TABLE ENTRY SIZE
ADD HL,DE ; BUMP TO NEXT ENTRY PART TYPE
DJNZ DSK_MBR2 ; LOOP THRU TABLE
JR DSK_MBR4 ; TOO BAD, NO CP/M PARTITION
;
DSK_MBR3:
; WE HAVE LOCATED A VALID CP/M PARTITION
; HL POINTS TO PART TYPE FIELD OF PART ENTRY
; UPDATE MEDIA ID
LD A,MID_HDNEW ; NEW MEDIA ID
LD (MEDID),A ; SAVE IT
;
; CAPTURE THE LBA OFFSET
LD DE,4 ; LBA IS 4 BYTES AFTER PART TYPE
ADD HL,DE ; POINT TO IT
LD DE,SEKLBA ; LOC TO STORE LBA OFFSET
LD BC,4 ; 4 BYTES (32 BITS)
LDIR ; COPY IT
;
DSK_MBR4:
; RESTORE BANK
POP AF ; GET PREV BANK
CALL HB_BNKSEL ; SELECT IT
;
DSK_MBR5:
;
; DIFFERENT ALGORITHM FOR NEW HD FORMAT
LD A,(MEDID) ; GET MEDIA ID
CP MID_HDNEW ; NEW FORMAT?
JR Z,DSK_MBR6 ; IF SO, GO THERE
;
; OLD HD FORMAT, 65 TRACKS PER SLICE
LD A,(SLICE) ; GET SLICE
LD E,A ; E = SLICE NO
LD H,65 ; H = TRACKS PER SLICE
CALL MULT8 ; HL := H * E (TOTAL TRACK OFFSET)
LD DE,0 ; CLEAR HI WORD
LD B,8 ; 16 SPT, SHIFT 4 BITS
CALL RL32 ; DO IT
JR DSK_MBR7 ; DONE
;
DSK_MBR6:
; NEW HD FORMAT, MULTIPLY SLICE BY 8MB
LD DE,0 ; CLEAR HIWORD
LD H,0 ; CLEAR HI BYTE OR LOWORD
LD A,(SLICE) ; GET SLICE
LD L,A ; PUT SLICE IN LOW BYTE
LD B,14
CALL RL32 ; MULTIPLY BY 16384 SECTORS (8MB)
;
DSK_MBR7:
; ADD IN LBA OFFSET
LD BC,(SEKLBA) ; LBA OFFSET LOWORD
ADD HL,BC
EX DE,HL
LD BC,(SEKLBA+2) ; LBA OFFSET HIWORD
ADC HL,BC
EX DE,HL
SET 7,D ; SET LBA ACCESS BIT
; RESAVE IT
LD (SEKLBA),HL ; LOWORD
LD (SEKLBA+2),DE ; HIWORD
; SUCCESSFUL FINISH
XOR A ; SUCCESS
RET ; DONE
;
#ENDIF
;
;
;
DSK_STATUS:
@@ -1297,7 +1449,7 @@ DSK_WRITE:
;
;
#IFDEF PLTUNA
;
DSK_IO:
PUSH BC
LD DE,(HSTTRK) ; GET TRACK INTO HL
@@ -1338,15 +1490,10 @@ DSK_IO1:
RST 08
OR A ; SET FLAGS BASED ON RESULT
RET
;
#ELSE
;
DSK_IO:
;
; TRANSLATE CP/M TRACK/SECTOR -> HBIOS TRACK/HEAD/SECTOR
; NEEDS TO HANDLE FLOPPY SEPARATE FROM HARD DISK
;
CHS:
LD A,(HSTUNIT) ; GET UNIT
LD C,A ; UNIT -> C
PUSH BC ; SAVE FUNC/UNIT
@@ -1356,7 +1503,7 @@ CHS:
LD A,D ; DEVICE TYPE -> A
AND $F0 ; ISOLATE HIGH BITS
CP DIODEV_FD ; FLOPPY?
JR NZ,CHSHD ; IF NOT, DO HD CHS XLAT
JR NZ,LBA_IO ; IF NOT, DO LBA IO
;
; FLOPPY SPECIFIC TRANSLATION ASSUMES FLOPPY IS DOUBLE-SIDED AND
; USES LOW ORDER BIT OF TRACK AS HEAD VALUE
@@ -1368,53 +1515,51 @@ CHS:
SRL H ; SHIFT HEAD BIT OUT OF HL
RR L ; ... AND INTO CARRY
RL D ; CARRY BIT (HEAD) INTO D
JR CHS2
JR DSK_IO2 ; DO THE DISK I/O
;
; HARD DISK SPECIFIC TRANSLATION
; ASSUMES 16 HEADS PER CYLINDER AND 16 SECTORS PER TRACK
;
CHSHD:
LD HL,(HSTTRK) ; GET TRACK VALUE
LD A,L ; LSB OF TRACK TO A
AND $0F ; ISOLATE HEAD IN LOW 4 BITS
LD D,A ; STUFF IT IN D
LBA_IO:
LD A,(HSTUNIT) ; GET THE UNIT VALUE
LD C,A ; PUT IT IN C
PUSH BC ; SAVE FUNC/UNIT
; GET TRACK AND SHIFT TO MAKE ROOM FOR 4 BIT SECTOR VALUE
LD HL,(HSTTRK) ; GET TRACK
LD DE,0 ; CLEAR HIWORD
LD B,4 ; X16 (16 SPT ASSUMED)
CALL RL32 ; DO IT
; COMBINE WITH SECTOR
LD A,(HSTSEC) ; GET SECTOR
LD E,A ; STUFF IT IN E
LD A,B ; SAVE B (HBIOS FUNC)
LD B,4 ; PREPARE TO SHIFT OUT 4 BIT HEAD VALUE
CHSHD1:
SRL H ; SHIFT ONE BIT OUT
RR L ; ... OF HL
DJNZ CHSHD1 ; DO ALL 4 BITS
LD B,A ; RESTORE B (HBIOS FUNC)
; FALL THRU TO CHS2
;
; ALL TYPES OF TRANSLATION WIND UP HERE TO
; MAKE THE ACTUAL HBIOS CALL
;
CHS2:
PUSH DE ; SAVE HEAD/SECTOR + COULD MOVE
LD DE,(HSTOFF) ; NOW GET SLICE OFFSET | TO CHSHD,
ADD HL,DE ; ADD IT TO TRACK VALUE | NO SLICES
POP DE ; RECOVER HEAD/SECTOR + FOR FLOPPY
OR L
LD L,A
; ADD IN LBA OFFSET FOR PARTITION AND/OR SLICE
LD BC,(HSTLBA) ; LBA OFFSET LOWORD
ADD HL,BC
EX DE,HL
LD BC,(HSTLBA+2) ; LBA OFFSET HIWORD
ADC HL,BC
EX DE,HL
SET 7,D ; MAKE SURE LBA ACCESS BIT SET
POP BC ; RESTORE FUNC/UNIT
;JR DSK_IO2 ; DO THE DISK I/O (FALL THRU)
;
; MAKE HBIOS CALL
; HBIOS FUNC SHOULD STILL BE IN B
; UNIT SHOULD STILL BE IN C
;
DSK_IO2:
PUSH BC ; SAVE INCOMING FUNCTION, DEVICE/UNIT
LD B,BF_DIOSEEK ; SETUP FOR NEW SEEK CALL
LD B,BF_DIOSEEK ; SETUP FOR NEW SEEK CALL
RST 08 ; DO IT
POP BC ; RESTORE INCOMING FUNCTION, DEVICE/UNIT
RET NZ ; ABORT IF SEEK RETURNED AN ERROR W/ ERROR IN A
LD HL,(DSKBUF) ; GET BUFFER ADDRESS
POP BC ; RESTORE INCOMING FUNCTION, DEVICE/UNIT
RET NZ ; ABORT IF SEEK RETURNED AN ERROR W/ ERROR IN A
LD HL,(DSKBUF) ; GET BUFFER ADDRESS
LD A,(BNKBIOS) ; GET BIOS BANK
LD D,A ; TRANSFER TO/FROM BIOS BANK
LD E,1 ; TRANSFER ONE SECTOR
LD E,1 ; TRANSFER ONE SECTOR
;CALL PC_ASTERISK ; *DEBUG*
RST 08 ; DO IT
OR A ; SET FLAGS
RET ; DONE
;
#ENDIF
;
;==================================================================================================
@@ -1501,12 +1646,14 @@ STR_SEC .DB " SEC=$"
; DATA
;==================================================================================================
;
;STR_READONLY .DB "\r\nCBIOS Err: Read Only Drive$"
;STR_STALE .DB "\r\nCBIOS Err: Stale Drive$"
;STR_READONLY .DB "\r\nCBIOS Err: Read Only Drive$"
;STR_STALE .DB "\r\nCBIOS Err: Stale Drive$"
;
SECADR .DW 0 ; ADDRESS OF SECTOR IN ROM/RAM PAGE
;SECADR .DW 0 ; ADDRESS OF SECTOR IN ROM/RAM PAGE
DEFDRIVE .DB 0 ; DEFAULT DRIVE
CCPBUF .DW 0 ; ADDRESS OF CCP BUF IN BIOS BANK
MEDID .DB 0 ; TEMP STORAGE FOR MEDIA ID
SLICE .DB 0 ; CURRENT SLICE
;
#IFDEF PLTWBW
BNKBIOS .DB 0 ; BIOS BANK ID
@@ -1521,21 +1668,22 @@ BNKUSER .DW 0 ; USER BANK ID
; DOS DISK VARIABLES
;
DSKOP .DB 0 ; DISK OPERATION (DOP_READ/DOP_WRITE)
WRTYPE .DB 0 ; WRITE TYPE (0=NORMAL, 1=DIR (FORCE), 2=FIRST RECORD OF BLOCK)
DMAADR .DW 0 ; DIRECT MEMORY ADDRESS
WRTYPE .DB 0 ; WRITE TYPE (0=NORMAL, 1=DIR (FORCE), 2=FIRST RECORD OF BLOCK)
DMAADR .DW 0 ; DIRECT MEMORY ADDRESS
HSTWRT .DB 0 ; TRUE = BUFFER IS DIRTY
DSKBUF .DW 0 ; ADDRESS OF PHYSICAL SECTOR BUFFER
;
; LOGICAL DISK I/O REQUEST PENDING
;
SEK:
SEKDSK .DB 0 ; DISK NUMBER 0-15
SEKTRK .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL)
SEKSEC .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL)
SEKUNIT .DB 0 ; DISK UNIT
SEKDSK .DB 0 ; DISK NUMBER 0-15
SEKTRK .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL)
SEKSEC .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL)
SEKUNIT .DB 0 ; DISK UNIT
SEKDPH .DW 0 ; ADDRESS OF ACTIVE (SELECTED) DPH
SEKOFF .DW 0 ; TRACK OFFSET IN EFFECT FOR SLICE
SEKACT .DB TRUE ; ALWAYS TRUE!
SEKLBA .FILL 4,0 ; LBA OFFSET
;
; RESULT OF CPM TO PHYSICAL TRANSLATION
;
@@ -1547,6 +1695,7 @@ XLTUNIT .DB 0
XLTDPH .DW 0
XLTOFF .DW 0
XLTACT .DB TRUE ; ALWAYS TRUE!
XLTLBA .FILL 4,0 ; LBA OFFSET
;
XLTSIZ .EQU $ - XLT
;
@@ -1560,13 +1709,14 @@ HSTUNIT .DB 0 ; DISK UNIT IN BUFFER
HSTDPH .DW 0 ; CURRENT DPH ADDRESS
HSTOFF .DW 0 ; TRACK OFFSET IN EFFECT FOR SLICE
HSTACT .DB 0 ; TRUE = BUFFER HAS VALID DATA
HSTLBA .FILL 4,0 ; LBA OFFSET
;
; SEQUENTIAL WRITE TRACKING FOR (UNA)LLOCATED BLOCK
;
UNA:
UNADSK .DB 0 ; DISK NUMBER 0-15
UNATRK .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL)
UNASEC .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL)
UNADSK .DB 0 ; DISK NUMBER 0-15
UNATRK .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL)
UNASEC .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL)
;
UNASIZ .EQU $ - UNA
;
@@ -1595,13 +1745,13 @@ ALS_HD .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP)
; BLS BSH BLM EXM (DSM<256) EXM (DSM>255)
; ---------- --- --- ------------- -------------
; 1,024 3 7 0 N/A
; 2,048 4 15 1 0
; 4,096 5 31 3 1
; 8,192 6 63 7 3
; 16,384 7 127 15 7
; 2,048 4 15 1 0
; 4,096 5 31 3 1
; 8,192 6 63 7 3
; 16,384 7 127 15 7
;
; AL0/1: EACH BIT SET ALLOCATES A BLOCK OF DIR ENTRIES. EACH DIR ENTRY
; IS 32 BYTES. BIT COUNT = (((DRM + 1) * 32) / BLS)
; AL0/1: EACH BIT SET ALLOCATES A BLOCK OF DIR ENTRIES. EACH DIR ENTRY
; IS 32 BYTES. BIT COUNT = (((DRM + 1) * 32) / BLS)
;
; CKS = (DIR ENT / 4), ZERO FOR NON-REMOVABLE MEDIA
;
@@ -1623,16 +1773,16 @@ ALS_HD .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP)
.DW ALS_ROM ; ALS: BLKS / 8
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_ROM:
.DW 64 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DW 64 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 1 ; EXM: (BLKS <= 256) ? 1 : 0
.DW 192 - 1 ; DSM: TOTAL STORAGE IN BLOCKS - 1
.DW 255 ; DRM: DIR ENTRIES - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW 0 ; OFF: ROM DISK HAS NO SYSTEM AREA
.DW 255 ; DRM: DIR ENTRIES - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW 0 ; OFF: ROM DISK HAS NO SYSTEM AREA
;__________________________________________________________________________________________________
;
; RAM DISK: 64 SECS/TRK, 128 BYTES/SEC
@@ -1650,16 +1800,16 @@ DPB_ROM:
.DW ALS_RAM ; ALS: BLKS / 8
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_RAM:
.DW 64 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DW 64 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 1 ; EXM: (BLKS <= 256) ? 1 : 0
.DW 192 - 1 ; DSM: TOTAL STORAGE IN BLOCKS - 1
.DW 255 ; DRM: DIR ENTRIES - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW 0 ; OFF: RESERVED TRACKS = 0 TRK
.DW 255 ; DRM: DIR ENTRIES - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW 0 ; OFF: RESERVED TRACKS = 0 TRK
;__________________________________________________________________________________________________
;
; 4MB RAM FLOPPY DRIVE, 32 TRKS, 1024 SECS/TRK, 128 BYTES/SEC
@@ -1669,16 +1819,16 @@ DPB_RAM:
.DW ALS_HD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_RF:
.DW 64 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = (4MB / 2K BLS) - 1 = 2047
.DW 511 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11111111B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW 0 ; OFF: RESERVED TRACKS = 0 TRK
.DW 64 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = (4MB / 2K BLS) - 1 = 2047
.DW 511 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11111111B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA
.DW 0 ; OFF: RESERVED TRACKS = 0 TRK
;__________________________________________________________________________________________________
;
; GENERIC HARD DISK DRIVE (8MB DATA SPACE + 128K RESERVED SPACE)
@@ -1690,16 +1840,33 @@ DPB_RF:
.DW ALS_HD
.DB (4096 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_HD:
.DW 64 ; SPT: SECTORS PER TRACK
.DB 5 ; BSH: BLOCK SHIFT FACTOR
.DB 31 ; BLM: BLOCK MASK
.DB 1 ; EXM: EXTENT MASK
.DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 = (8MB / 4K BLS) - 1 = 2047
.DW 511 ; DRM: DIR ENTRIES - 1 = 512 - 1 = 511
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 16 ; OFF: RESERVED TRACKS = 16 TRKS * (16 TRKS * 16 HEADS * 16 SECS * 512 BYTES) = 128K
.DW 64 ; SPT: SECTORS PER TRACK
.DB 5 ; BSH: BLOCK SHIFT FACTOR
.DB 31 ; BLM: BLOCK MASK
.DB 1 ; EXM: EXTENT MASK
.DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 = (8MB / 4K BLS) - 1 = 2047
.DW 512 - 1 ; DRM: DIR ENTRIES - 1
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 16 ; OFF: RESERVED TRACKS
;
; BLOCKSIZE (BLS) = 4K, DIRECTORY ENTRIES = 1024
;
.DW CKS_HD
.DW ALS_HD
.DB (4096 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_HDNEW:
.DW 64 ; SPT: SECTORS PER TRACK
.DB 5 ; BSH: BLOCK SHIFT FACTOR
.DB 31 ; BLM: BLOCK MASK
.DB 1 ; EXM: EXTENT MASK
.DW 2048 - 1 - 4 ; DSM: STORAGE BLOCKS - 1 - RES TRKS
.DW 1024 - 1 ; DRM: DIR ENTRIES - 1
.DB 11111111B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 0 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS
;__________________________________________________________________________________________________
;
; IBM 720KB 3.5" FLOPPY DRIVE, 80 TRKS, 36 SECS/TRK, 512 BYTES/SEC
@@ -1709,16 +1876,16 @@ DPB_HD:
.DW ALS_FD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_FD720:
.DW 36 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 350 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((720K - 18K OFF) / 2K BLS) - 1 = 350
.DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127
.DB 11000000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4
.DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K
.DW 36 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 350 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((720K - 18K OFF) / 2K BLS) - 1 = 350
.DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127
.DB 11000000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4
.DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K
;__________________________________________________________________________________________________
;
; IBM 1.44MB 3.5" FLOPPY DRIVE, 80 TRKS, 72 SECS/TRK, 512 BYTES/SEC
@@ -1728,16 +1895,16 @@ DPB_FD720:
.DW ALS_FD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_FD144:
.DW 72 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 710 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,440K - 18K OFF) / 2K BLS) - 1 = 710
.DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 72 SEC/TRK) = 18K
.DW 72 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 710 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,440K - 18K OFF) / 2K BLS) - 1 = 710
.DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 72 SEC/TRK) = 18K
;__________________________________________________________________________________________________
;
; IBM 360KB 5.25" FLOPPY DRIVE, 40 TRKS, 9 SECS/TRK, 512 BYTES/SEC
@@ -1747,16 +1914,16 @@ DPB_FD144:
.DW ALS_FD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_FD360:
.DW 36 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 1 ; EXM: EXTENT MASK
.DW 170 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((360K - 18K OFF) / 2K BLS) - 1 = 170
.DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4
.DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K
.DW 36 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 1 ; EXM: EXTENT MASK
.DW 170 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((360K - 18K OFF) / 2K BLS) - 1 = 170
.DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4
.DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K
;__________________________________________________________________________________________________
;
; IBM 1.20MB 5.25" FLOPPY DRIVE, 80 TRKS, 15 SECS/TRK, 512 BYTES/SEC
@@ -1766,16 +1933,16 @@ DPB_FD360:
.DW ALS_FD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_FD120:
.DW 60 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 591 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,200K - 15K OFF) / 2K BLS) - 1 = 591
.DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K
.DW 60 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 591 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,200K - 15K OFF) / 2K BLS) - 1 = 591
.DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K
;__________________________________________________________________________________________________
;
; IBM 1.11MB 8" FLOPPY DRIVE, 77 TRKS, 15 SECS/TRK, 512 BYTES/SEC
@@ -1785,16 +1952,16 @@ DPB_FD120:
.DW ALS_FD
.DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128)
DPB_FD111:
.DW 60 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 569 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,155K - 15K OFF) / 2K BLS) - 1 = 569
.DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K
.DW 60 ; SPT: SECTORS PER TRACK
.DB 4 ; BSH: BLOCK SHIFT FACTOR
.DB 15 ; BLM: BLOCK MASK
.DB 0 ; EXM: EXTENT MASK
.DW 569 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,155K - 15K OFF) / 2K BLS) - 1 = 569
.DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255
.DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE
.DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE
.DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4
.DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K
;
#IFDEF PLTUNA
SECBUF .FILL 512,0 ; PHYSICAL DISK SECTOR BUFFER
@@ -2086,7 +2253,7 @@ DEV_INIT0:
;POP BC ; RESTORE LOOP CONTROL
;LD A,C ; UNIT INDEX TO ACCUM
;;CALL C,JPHL ; DO IT IF DEVICE TYPE < VDU
LD A,(HCB + HCB_CONDEV) ; CURRENT CONSOLE UNIT
CP C ; IS CURRENT CONSOLE?
LD A,C ; UNIT INDEX TO ACCUM
@@ -2650,7 +2817,8 @@ DPH_INIT:
LD H,0 ; ... INTO HL
ADD HL,HL ; MULTIPLY
ADD HL,HL ; ... BY SIZE
ADD HL,HL ; ... OF DPH (16)
CALL ADDHLA ; ...
ADD HL,HL ; ... OF DPH (20)
ADD HL,HL ; ... FOR TOTAL SIZE
CALL ALLOC ; ALLOCATE THE SPACE
CALL C,PANIC ; SHOULD NEVER ERROR
@@ -2707,7 +2875,8 @@ DPH_INIT2:
LD (HL),D ; ... DRIVE MAP
INC HL ; AND BUMP TO START OF NEXT ENTRY
; UPDATE DPH ALLOCATION TOP
LD A,16 ; SIZE OF A DPH ENTRY
;LD A,16 ; SIZE OF A DPH ENTRY
LD A,20 ; SIZE OF A DPH ENTRY
EX DE,HL ; HL := DPH POINTER
CALL ADDHLA ; CALC NEW DPHTOP
LD (DPHTOP),HL ; SAVE IT
@@ -3011,7 +3180,7 @@ CMD .DB CMDLEN - 2
CMDLEN .EQU $ - CMD
;
FCB_SUB .DB '?' ; DRIVE CODE, 0 = CURRENT DRIVE
.DB "SUBMIT " ; FILE NAME, 8 CHARS
.DB "SUBMIT " ; FILE NAME, 8 CHARS
.DB "COM" ; FILE TYPE, 3 CHARS
.FILL 36-($-FCB_SUB),0 ; ZERO FILL REMAINDER OF FCB
;
@@ -3023,7 +3192,7 @@ FCB_PRO .DB '?' ; DRIVE CODE, 0 = CURRENT DRIVE
STR_BANNER .DB "CBIOS v", BIOSVER, " [", PLTSTR, "]$"
STR_INITRAMDISK .DB "Formatting RAMDISK...$"
STR_LDR2 .DB "\r\n"
STR_LDR .DB "\r\n $"
STR_LDR .DB "\r\n $"
STR_DPHINIT .DB "Configuring Drives...$"
STR_HEAPOVF .DB " *** Insufficient Memory ***$"
STR_INVMED .DB " *** Invalid Device ID ***$"

View File

@@ -430,3 +430,15 @@ PRTHEXBUF1:
INC DE
DJNZ PRTHEXBUF1
RET
;
; LEFT SHIFT DE:HL BY B BITS (B > 0)
;
RL32:
OR A ; CLEAR CARRY
RL L
RL H
RL E
RL D
DJNZ RL32
RET