mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 09:24:19 +00:00
1317 lines
35 KiB
Plaintext
1317 lines
35 KiB
Plaintext
title 'CCP/M-86 Loader Program and BIOS'
|
|
;*****************************************************
|
|
; The Loader consists of the three modules:
|
|
; Loader BDOS (the file LBDOS.H86), the Loader
|
|
; Program and the Loader BIOS. This
|
|
; module contains both the Loader Program
|
|
; and the Loader BIOS.
|
|
;
|
|
; The Loader resides in sectors 2-8 on the first track
|
|
; of an IBM PC floppy diskette. The Loader is
|
|
; is brought into memory by the Boot Sector which
|
|
; resides in sector 1 of track 0. The Boot Sector
|
|
; is brought into memory by the IBM PC's ROM
|
|
; monitor.
|
|
;
|
|
; The Loader Program opens the file 'CCPM.SYS' using the
|
|
; Loader BDOS and Loader BIOS,
|
|
; and then reads it into memory. The DS register is set
|
|
; to the start of the CCPM DATA area, and a JMPF to the
|
|
; first byte of the CCPM code is executed.
|
|
;
|
|
; The first 128 byte record of the CCPM.SYS file is a header
|
|
; with the following format:
|
|
;
|
|
; +----+----+----+----+----+----+----+----+----+
|
|
; |TYPE| LEN | ABS | MIN | MAX |
|
|
; +----+----+----+----+----+----+----+----+----+
|
|
;
|
|
; type rb 1 ;seg type
|
|
; len rw 1 ;length
|
|
; abs dw 1 ;absolute segment address for LOADER
|
|
; min rw 1 ;minimum mem
|
|
; max rw 1 ;max mem needed
|
|
;
|
|
; The code is expected first and then the data within CCPM.SYS
|
|
; This header record is constructed automatically by the
|
|
; GENCCPM utility. See the variables declared at 'SEC1:'
|
|
; where the first sector of CCPM.SYS will be read.
|
|
;
|
|
; Loader may be read into any segment by the Boot
|
|
; Sector that does not overlap the area of memory
|
|
; the system image in CCPM.SYS will occupy.
|
|
;
|
|
;*****************************************************
|
|
|
|
false equ 0
|
|
true equ not false
|
|
|
|
cr equ 0dh
|
|
lf equ 0ah
|
|
|
|
ldbdos_offset equ 0000H ;offset of Loader BDOS
|
|
ldr_offset equ 0900h ;offset of Loader BIOS
|
|
|
|
codetype equ 1 ; code type CMD header
|
|
datatype equ 2 ; data type CMD header
|
|
|
|
; bdos function numbers
|
|
|
|
seldskf equ 14
|
|
openf equ 15
|
|
readsf equ 20
|
|
setdmaf equ 26
|
|
setuserf equ 32
|
|
setmultcntf equ 44
|
|
setdmabf equ 51
|
|
|
|
|
|
;*****************************************************
|
|
;*
|
|
;* CCPMLDR starts here
|
|
;*
|
|
;*****************************************************
|
|
|
|
cseg
|
|
org ldr_offset
|
|
|
|
jmp init
|
|
jmp entry
|
|
jmp loadp
|
|
|
|
ldusr db 0 ;load user is 0
|
|
|
|
|
|
loadp: ; loader entry from BDOS init
|
|
;-----
|
|
; entry: CH = boot user number
|
|
; CL = boot disk number
|
|
; DS,ES,SS = CS
|
|
|
|
|
|
mov dx,offset signon
|
|
call msg
|
|
|
|
mov dl,ldusr
|
|
mov cl,setuserf ! int 224 ;set user number
|
|
|
|
mov dx,offset ccpmfcb
|
|
mov cl,openf ! int 224 ;open CCPM.SYS file
|
|
cmp al,255 ! jne perr ;insure good file
|
|
mov dx,offset nofile
|
|
jmp stop
|
|
perr:
|
|
|
|
mov dx,ds
|
|
mov cl,setdmabf ! int 224 ;set DMA segment address
|
|
|
|
mov dx,offset sec1
|
|
mov cl,setdmaf ! int 224 ;set DMA offset address
|
|
|
|
mov dl,1
|
|
mov cl,setmultcntf ! int 224 ;set Multi-sector count to 1
|
|
|
|
mov dx,offset ccpmfcb
|
|
mov cl,readsf ! int 224 ; read first record
|
|
|
|
; the following
|
|
; "commented out" code
|
|
; can be used to
|
|
; perform error checking
|
|
|
|
; cmp ctype,codetype ; code should be first
|
|
; jnz badhdr
|
|
; cmp dtype,datatype ; then data
|
|
; jnz badhdr
|
|
; mov ax,cldseg ; code abs + code length
|
|
; add ax,clen ; should be = to data abs
|
|
; cmp ax,dldseg ! jnz badhdr
|
|
; add ax,dlen ! cmp ax,cldseg ; check for wrap around
|
|
; ja hdrok
|
|
;badhdr:
|
|
; mov dx,offset rerr
|
|
; jmp stop
|
|
;hdrok:
|
|
mov dx,offset csegment
|
|
call msg ; put memory map on console
|
|
mov ax,cldseg
|
|
call phex ; print base code segment
|
|
mov dx,offset dsegment
|
|
call msg ; print base data segment
|
|
mov ax,dldseg
|
|
call phex
|
|
|
|
mov dx,128
|
|
mov cl,setmultcntf ! int 224 ; set multi-sector count to 128
|
|
mov dx,0
|
|
mov cl,setdmaf ! int 224 ; set DMA offset to 0
|
|
mov dx,cldseg ; initial DMA segment
|
|
readit1:
|
|
push dx ; save dma segment
|
|
mov cl,setdmabf ! int 224 ; set DMA segment for disk IO
|
|
mov dx,offset ccpmfcb
|
|
mov cl,readsf ! int 224 ; next 128 sector read
|
|
pop dx ; restore dma segment
|
|
add dx,8*128 ; increment dma segment
|
|
cmp al,01H ! je done ; check for EOF
|
|
cmp al,0 ! je readit1 ; check for good write
|
|
mov dx,offset rerr ; print READ ERROR message
|
|
jmp stop
|
|
done:
|
|
call pcrlf ; and a crlf
|
|
|
|
mov clen,0 ; set CCPM offset to 0
|
|
|
|
mov ds,dldseg ; CCP/M data segment
|
|
jmpf cs:dword ptr clen ; leap to CCPM initialization
|
|
|
|
;*****************************
|
|
;*
|
|
;* subroutines
|
|
;*
|
|
;*****************************
|
|
|
|
stop:
|
|
;----
|
|
call msg
|
|
cli ! hlt
|
|
|
|
|
|
phex: ;print 4 hex characters from ax
|
|
;----
|
|
mov cx,0404h ; 4 in both CH and CL
|
|
lhex:
|
|
rol ax,cl ; rotate left 4
|
|
push cx ! push ax ; save crucial registers
|
|
call pnib ; print hex nibble
|
|
pop ax ! pop cx ; restore registers
|
|
dec ch ! jnz lhex ; and loop four times
|
|
ret
|
|
pnib: ;print low nibble in AL as hex char
|
|
and al,0fh ! cmp al,9
|
|
ja p10 ;above 9 ?
|
|
add al,'0' ;digit
|
|
jmps prn
|
|
p10: add al,'A'-10 ;char a-e
|
|
prn: mov dl,al
|
|
|
|
putchar:
|
|
;-------
|
|
mov cl,dl
|
|
jmp io_conout
|
|
|
|
pcrlf:
|
|
;-----
|
|
mov dx,offset crlf ;print carriage return, line feed
|
|
|
|
msg: ;print msg starting at dx until $
|
|
;---
|
|
mov bx,dx
|
|
msg1:
|
|
mov dl,[bx]
|
|
cmp dl,'$' ! je msg2
|
|
push bx
|
|
call putchar
|
|
pop bx
|
|
inc bx
|
|
jmps msg1
|
|
msg2:
|
|
ret
|
|
|
|
eject
|
|
;************************************************************************
|
|
;*
|
|
;*
|
|
;* L O A D E R
|
|
;*
|
|
;* B I O S - 8 6
|
|
;* =============
|
|
;*
|
|
;* CP/M-86 3.0 or Concurrent CP/M-86 2.0
|
|
;*
|
|
;* Boot Loader I/O System
|
|
;* for the
|
|
;* IBM Personal Computer
|
|
;*
|
|
;* Copyright (c) 1982
|
|
;* Digital Research, Inc.
|
|
;* box 579, Pacific Grove
|
|
;* California, 93950
|
|
|
|
;*
|
|
;* (Permission is hereby granted to use or
|
|
;* abstract the following program in the
|
|
;* implementation of Concurrent CP/M-86,
|
|
;* CP/M, MP/M or CP/Net for the 8086 or 8088
|
|
;* micro-processor.)
|
|
;*
|
|
;************************************************************************
|
|
;*
|
|
;* Register usage for BIOS interface routines:
|
|
;*
|
|
;* Entry: AL = function # (in entry)
|
|
;* CX = entry parameter
|
|
;* DX = entry parameter
|
|
;* DS = LDBDOS data segment
|
|
;*
|
|
;* Exit: AX = return
|
|
;* BX = AX (in exit)
|
|
;* ALL SEGMENT REGISTERS PRESERVED:
|
|
;* CS,DS,ES,SS must be preserved though call
|
|
;*
|
|
;* Notes: flag set and the far jump to the dispatcher are
|
|
;* the only legal Operating System "entry" points
|
|
;* for an interrupt routine)
|
|
;*
|
|
;* changes have been made in the
|
|
;* register conventions from
|
|
;* the CP/M-86 BIOS and the MP/M-86 BIOS.
|
|
;*
|
|
;************************************************************************
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* IBM PC SOFTWARE INTERRUPT STRUCTURE *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
tick_interrupt equ 08h
|
|
keyboard_interrupt equ 09h
|
|
disk_interrupt equ 0Eh
|
|
os_interrupt equ 224 ;Loader BDOS entry
|
|
debugger_interrupt equ 225 ;debugger entry to O.S.
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* INTERFACE TO LOADER BDOS *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
;=====
|
|
;=====
|
|
entry: ;arrive here from JMP at
|
|
;===== ;03H in BIOS code segment
|
|
;=====
|
|
|
|
; entry: AL = function number
|
|
; CX, DX parameters
|
|
; exit: AX = BX = return
|
|
; ALL SEGMENT REGISTERS PRESERVED:
|
|
; CS,DS,ES,SS must be preserved though call
|
|
|
|
; Note: no alteration of stack is allowed during entry except
|
|
; for the return address caused by the "call function_table[bx]"
|
|
; instruction.
|
|
|
|
cld ;set the direction flag
|
|
xor ah,ah
|
|
shl al,1 ;multiply by 2
|
|
mov bx,ax ;put in indirect register
|
|
call function_table[bx] ;no range checking needed
|
|
mov bx,ax ;only called by loader BDOS
|
|
retf ;return to loader BDOS
|
|
|
|
io_ret:
|
|
ret
|
|
|
|
;------
|
|
i_disk:
|
|
;------
|
|
mov al,pic_nseoi ;signal end of interrupt
|
|
out pic_even_port,al ;to 8259
|
|
iret ;note we destroyed AL
|
|
|
|
;=========
|
|
io_conout:
|
|
;=========
|
|
; entry: CL = character to output
|
|
; DL = device number
|
|
; exit: None
|
|
; ALL SEGMENT REGISTERS PRESERVED:
|
|
; CS,DS,ES,SS must be preserved though call
|
|
|
|
; Put character in screen and update cursor position
|
|
; BX = screen structure
|
|
|
|
mov bx,offset ss0
|
|
mov di,ss_cursor[bx] ;cursor offset in bytes
|
|
cmp cl,cr
|
|
je carriage_return
|
|
cmp cl,lf
|
|
je linefeed
|
|
push es
|
|
mov ax,bw_video_seg
|
|
mov es,ax ;segment of foreground screen
|
|
mov al,cl
|
|
mov ah,07h ;default attribute
|
|
stosw ;update and don't touch the attribute
|
|
pop es ;DI incremented by 2
|
|
cmp ss_column[bx],columns_per_screen - 1
|
|
jne inc_col
|
|
call carriage_return
|
|
jmp line_feed
|
|
inc_col:
|
|
inc ss_column[bx] ;DI = next data, attribute
|
|
mov ss_cursor[bx],di ;save new cursor position
|
|
ret
|
|
|
|
;---------------
|
|
carriage_return:
|
|
;---------------
|
|
; entry: BX = screen structure
|
|
; exit: BX preserved
|
|
|
|
xor dx,dx ;AX = 0
|
|
xchg dl,ss_column[bx] ;set cursor position to begining of
|
|
shl dx,1 ;times 2 for data and attribute
|
|
sub ss_cursor[bx],dx ;set new cursor position
|
|
ret
|
|
|
|
;---------
|
|
line_feed:
|
|
;---------
|
|
; entry: BX = screen structure
|
|
; exit: BX preserved
|
|
|
|
; This routine assumes the loader will never
|
|
; need to scroll the screen
|
|
|
|
inc ss_row[bx]
|
|
add ss_cursor[bx],columns_per_screen*2
|
|
ret
|
|
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* 6845 CRT CONTROLLER PORT AND COMMAND EQUATES *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
|
|
; The IBM PC's monochrome memory mapped video display begins
|
|
; at paragraph 0B000H. It represents a screen 80 X 25.
|
|
; Each video character requires a word value, the low byte
|
|
; is the ASCII code (characters codes > 128 are also displayed)
|
|
; and the high byte is an attribute byte. The 25th line
|
|
; is reserved by this BIOS as a status line.
|
|
|
|
|
|
bw_card equ 003b4h
|
|
|
|
video_on equ 00029h
|
|
video_off equ 00021h
|
|
|
|
cursor_start equ 10
|
|
cursor_end equ 11
|
|
display_start_hi equ 12
|
|
display_start_low equ 13
|
|
cursor_hi equ 14
|
|
cursor_low equ 15
|
|
light_pen_hi equ 16
|
|
light_pen_low equ 17
|
|
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* SCREEN PARAMETERS *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
rows_per_screen equ 24
|
|
columns_per_screen equ 80
|
|
screen_siz equ rows_per_screen * columns_per_screen
|
|
;in words
|
|
bw_video_seg equ 0b000h ;segment address of
|
|
;start of video ram
|
|
bw_video_status_line equ screen_siz * 2
|
|
;byte offset of status line
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* SCREEN STRUCTURES *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
; Each virtual console has a structure of the following
|
|
; format associated with it. (SS = Screen Structure)
|
|
; The data in this structure is dependent on the type of screen
|
|
; supported and any escape sequence handling in io_conout.
|
|
; Note: ss_cursor, ss_row, ss_column are relative to 0 and are
|
|
; word pointers, i.e., if ss_cursor is 1 then it refers to
|
|
; bytes 2 and 3 in the video RAM or a background screen's
|
|
; data area.
|
|
|
|
ss_cursor equ word ptr 0 ;points at data/attrib
|
|
ss_escape equ word ptr ss_cursor + word ;escape routine to return to
|
|
ss_screen_seg equ word ptr ss_escape + word ;data for screen image
|
|
ss_row equ byte ptr ss_screen_seg + word ;current row
|
|
ss_column equ byte ptr ss_row + byte ;current col
|
|
|
|
; DISK I/O
|
|
; --------
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* 8237 DIRECT MEMORY ACCESS CONTROLLER PORT AND COMMANDS *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
dma_c0_address equ 000h ;8237 channel 0 address rw
|
|
dma_c0_count equ 001h ;8237 channel 0 transfer count rw
|
|
dma_c1_address equ 002h ;8237 channel 1 address rw
|
|
dma_c1_count equ 003h ;8237 channel 1 transfer count rw
|
|
dma_c2_address equ 004h ;8237 channel 2 address rw
|
|
dma_c2_count equ 005h ;8237 channel 2 transfer count rw
|
|
dma_c3_address equ 006h ;8237 channel 3 address rw
|
|
dma_c3_count equ 007h ;8237 channel 3 transfer count rw
|
|
dma_stat_reg equ 008h ;8237 status register ro
|
|
dma_cmd_reg equ dma_stat_reg ;8237 command register wo
|
|
dma_requ_reg equ dma_stat_reg+1 ;8237 software dma request wo
|
|
dma_bmsk_reg equ dma_stat_reg+2 ;8237 binary channel mask wo
|
|
dma_mode_reg equ dma_stat_reg+3 ;8237 mode register wo
|
|
dma_cbpf equ dma_stat_reg+4 ;8237 clear byte pointer f/f wo
|
|
dma_temp_reg equ dma_stat_reg+5 ;8237 temporary register ro
|
|
dma_clear equ dma_stat_reg+5 ;8237 master clear wo
|
|
dma_mask_reg equ dma_stat_reg+7 ;8237 linear channel mask wo
|
|
|
|
dma_page_c1 equ 080h ;a16 to a20 for channel 1
|
|
|
|
dma_page_fdc equ 081h ;a16 to a20 for channel 2
|
|
dma_page_c3 equ 082h ;a16 to a20 for channel 3
|
|
|
|
|
|
; The following labels define single mode, address increment
|
|
; auto-initialization disable, read or write using channel 2
|
|
|
|
dma_mode_write_fdc equ 01001010b
|
|
dma_mode_read_fdc equ 01000110b
|
|
|
|
dma_bmsk_fdc equ 00000010b ;binary channel mask for disk
|
|
|
|
|
|
; DMA channel assignments
|
|
|
|
;channel 0 dynamic memory refresh
|
|
;channel 1
|
|
;channel 2 floppy disk controller
|
|
;channel 3
|
|
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* FLOPPY DISK DRIVER EQUATES *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
|
|
; The following equates are set to the size of a double density,
|
|
; single sided 5 & 1/4" floppy.
|
|
|
|
bytes_per_sector equ 512
|
|
sectors_per_track equ 8 ;1 to 8
|
|
bytes_per_track equ sectors_per_track * bytes_per_sector
|
|
tracks_per_disk equ 40 ;0 to 39
|
|
bytes_per_disk equ tracks_per_disk * bytes_per_track
|
|
|
|
|
|
; The following equates are for the INTEL 8272 Floppy Disk
|
|
; Controller.
|
|
|
|
fdc_stat equ 03f4h ;status port for the disk controller
|
|
fdc_data equ fdc_stat+1 ;data port for the disk controller
|
|
fdc_port equ 03f2h ;all bits clear on channel reset
|
|
|
|
;7 6 5 4 3 2 1 0
|
|
;| | | | | | \_/
|
|
;| | | | | | |
|
|
;| | | | | | drive select 00=a,01=b,10=c,11=d
|
|
;| | | | | fdc reset*
|
|
;| | | | int & dmarq enable
|
|
;d c b a motor on
|
|
|
|
fdc_on equ 00001100b ;mask to keep the 8272 unreset
|
|
fdc_no_motor equ 11111100b ;mask for no motors
|
|
fdc_read_cmd equ 01100110b ;mfm, skip deleted data, read
|
|
fdc_write_cmd equ 01000101b ;mfm, write
|
|
fdc_format_cmd equ 01001101b ;mfm, format
|
|
fdc_seek_cmd equ 00001111b ;seek
|
|
fdc_recal_cmd equ 00000111b ;home to track 0
|
|
fdc_si_cmd equ 00001000b ;sense interupt status
|
|
fdc_spec_cmd equ 00000011b ;specify
|
|
|
|
fdc_ready equ 10000000b ;mask for transfer ready
|
|
|
|
fdc_spec_1 equ 11001111b ;srt=0c, hd unload=0f first specify byte
|
|
fdc_spec_2 equ 00000011b ;hd load=1, mode=DMA second specify byte
|
|
|
|
f_bytes equ 2 ;magic number for 512 bytes per sector
|
|
f_sectors equ 8 ;sectors per track
|
|
f_gap equ 03ah ;magic number for format gap
|
|
f_filler equ 0e5h ;fill character
|
|
|
|
r_bytes equ 2 ;magic number for 512 bytes
|
|
r_sectors equ 8
|
|
|
|
r_gap equ 02ah
|
|
r_dtl equ 0ffh
|
|
|
|
; Equates for paramter passing for read and write from the
|
|
; BDOS.
|
|
|
|
; At the disk read and write function entries,
|
|
; all disk I/O parameters are on the stack.
|
|
; The stack at these entries appears as
|
|
; follows:
|
|
;
|
|
|
|
; +-------+-------+
|
|
; +14 | DRV | MCNT | Drive and Multi sector count
|
|
; +-------+-------+
|
|
; +12 | TRACK | Track number
|
|
; +-------+-------+
|
|
; +10 | SECTOR | Physical sector number
|
|
; +-------+-------+
|
|
; +8 | DMA_SEG | DMA segment
|
|
; +-------+-------+
|
|
; +6 | DMA_OFF | DMA offset
|
|
; +-------+-------+
|
|
; +4 | RET_SEG | BDOS return segment
|
|
; +-------+-------+
|
|
; +2 | RET_OFF | BDOS return offset
|
|
; +-------+-------+
|
|
; SP+0 | RET_ADR | Return address to BIOS ENTRY routine
|
|
; +-------+-------+
|
|
;
|
|
; These parameters may be indexed and modifided
|
|
; directly on the stack by the BIOS read and write rotines
|
|
; They will be removed by the BDOS when the BIOS completes
|
|
; the read/write function and returns to the BDOS.
|
|
|
|
|
|
drive equ byte ptr 14[bp]
|
|
mcnt equ byte ptr 15[bp]
|
|
track equ word ptr 12[bp]
|
|
sector equ word ptr 10[bp]
|
|
dma_seg equ word ptr 8[bp]
|
|
dma_off equ word ptr 6[bp]
|
|
|
|
|
|
; Some equtes in the Disk Parameter Header (DPH)
|
|
; and the Disk Parameter Block.
|
|
|
|
xlt equ 0 ;translation table offset in DPH
|
|
dpb equ 8 ;disk parameter block offset in DPH
|
|
|
|
spt equ 0 ;sectors per track offset in DPB
|
|
psh equ 15 ;physical shift factor offset in DPB
|
|
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* DISK DRIVER ROUTINES *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
|
|
;=========
|
|
io_seldsk: ; Function 7: Select Disk
|
|
;=========
|
|
; entry: CL = disk to be selected
|
|
; DL = 00h if disk has not been previously selected
|
|
; = 01h if disk has been previously selected
|
|
; exit: AX = 0 if illegal disk
|
|
; = offset of DPH relative from
|
|
; BIOS Data Segment
|
|
; ALL SEGMENT REGISTERS PRESERVED:
|
|
; CS,DS,ES,SS must be preserved though call
|
|
|
|
xor ax,ax ;get ready for error(s)
|
|
cmp cl,0 ;is it a A: ?
|
|
jne sel_ret ;if not just exit
|
|
mov ax,offset dph0
|
|
sel_ret:
|
|
ret
|
|
|
|
;=======
|
|
io_read: ; Function 11: Read sector
|
|
;=======
|
|
; Reads the sector on the current disk, track and
|
|
; sector into the current DMA buffer.
|
|
|
|
; entry: parameters on stack
|
|
; exit: AL = 00 if no error occured
|
|
; AL = 01 if an error occured
|
|
; AL = 0ffh if density change detected
|
|
; ALL SEGMENT REGISTERS PRESERVED:
|
|
; CS,DS,ES,SS must be preserved though call
|
|
|
|
mov bp,sp ;set BP for indexing into IOPB
|
|
; mov dma_mode_storage,dma_mode_read_fdc
|
|
; mov fdc_rw_cmd,fdc_read_cmd ;loader always reads
|
|
call flp_io
|
|
mov al,1
|
|
jnz i_read_ret ;zero flag is set with successful
|
|
dec al ;I/O
|
|
i_read_ret:
|
|
ret
|
|
|
|
flp_io:
|
|
;------
|
|
; entry: parameters on stack
|
|
; exit: zero flag set if no error
|
|
|
|
mov ax,sectors_per_track;max sectors - starting sector =
|
|
sub ax,sector ;sectors left on track
|
|
xor bh,bh
|
|
mov bl,mcnt ;multi sector count is byte variable
|
|
cmp ax,bx ;sectors left on track, sectors requested
|
|
jbe flp_track ;transfer to end of track
|
|
mov al,mcnt ;transfer to before end of track
|
|
|
|
flp_track:
|
|
sub mcnt,al ;AL = # sectors to R/W on this iteration
|
|
;through FLP_IO,
|
|
mov track_mcnt,al ;sectors to R/W on current track
|
|
|
|
;check for 64K page overlap
|
|
mov ah,al ;shl al,8 (* 256)
|
|
xor al,al
|
|
shl ah,1 ;* 512
|
|
push ax ;how many bytes to R/W on cur trk
|
|
|
|
mov ax,dma_seg ;compute new 20 bit DMA addr
|
|
mov bx,dma_off
|
|
call comp_dma ;returns AX = low 16 bits of 20 bit adr
|
|
not ax ;how many bytes left in this 64K page
|
|
|
|
pop bx ;BX=bytes to R/W on current track
|
|
cmp ax,bx ;does this transfer fit in 64K page
|
|
jb flp_end_64K
|
|
jmp flp_pg_ok
|
|
|
|
flp_end_64K:
|
|
;read to end of 64K page and then
|
|
;read spanning sector locally
|
|
mov al,ah ;how many sectors fit in this page ?
|
|
xor ah,ah ;bytes left in 64K page
|
|
shr ax,1 ;divided by 512
|
|
test ax,ax ;if 0, no sectors fit
|
|
jz flp_rwlocal ;in the rest of this 64K page
|
|
|
|
mov num_sec,al ;sectors that fit in end 64K page
|
|
sub track_mcnt,al ;track_mcnt always > AL
|
|
call flp_phys_io ;read/write them, DMA already computed
|
|
jz flp_end64k_ok
|
|
jmp flp_ret ;return if zero reset on error
|
|
|
|
flp_end64K_ok:
|
|
xor ax,ax
|
|
mov al,num_sec ;compute new DMA offset
|
|
add sector,ax ;still on the same track
|
|
xchg ah,al ;shl ax,8 (* 256)
|
|
shl ah,1 ;* bytes_per_sector (512)
|
|
add dma_off,ax ;64K wrap around is legal
|
|
|
|
flp_rwlocal: ;read into BIOS data segment the spanning
|
|
mov bx,local_buf ;sector
|
|
mov ax,ds ;compute 20 bit local DMA addr
|
|
call comp_dma
|
|
; cmp fdc_rw_cmd,fdc_read_cmd ;loader always reads
|
|
; ;only need this for writes
|
|
|
|
; ;reading or writing ?
|
|
; je flp_local
|
|
; mov si,dma_off ;get the sector to write from local
|
|
; mov di,local_buf ;buffer
|
|
; push es ! push ds ! push ds ! pop es
|
|
; mov ax,dma_seg ! mov ds,ax
|
|
; mov cx,bytes_per_sector/2
|
|
; rep movsw
|
|
; pop ds ! pop es
|
|
; mov dma_off,si ;update DMA offset
|
|
;
|
|
;flp_local:
|
|
|
|
mov num_sec,1 ;read/write one sector
|
|
call flp_phys_io
|
|
jnz flp_ret ;return zero flag reset
|
|
inc sector ! dec track_mcnt
|
|
|
|
; cmp fdc_rw_cmd,fdc_read_cmd ;loader always reads
|
|
; jne flp_local_done
|
|
|
|
mov di,dma_off ;move the sector to user's area
|
|
mov si,local_buf ;if reading
|
|
push es ! mov es,dma_seg
|
|
mov cx,bytes_per_sector/2
|
|
rep movsw
|
|
mov dma_off,di ;update DMA offset
|
|
pop es
|
|
|
|
flp_local_done:
|
|
mov ax,dma_seg ;compute new 20 bit DMA addr
|
|
mov bx,dma_off ;for next FDC read/write
|
|
call comp_dma
|
|
|
|
flp_pg_ok: ;read will not cross 64K boundary
|
|
mov al,track_mcnt ;could be 0 if we just read locally
|
|
test al,al ! jz nxt_track
|
|
mov num_sec,al ;read the rest from this track
|
|
call flp_phys_io ;DMA is already computed
|
|
jnz flp_ret ;return zero flag reset on error
|
|
xor ax,ax
|
|
mov ah,num_sec ;shl num_sec,8 (* 256)
|
|
shl ah,1 ;* 512
|
|
add dma_off,ax
|
|
|
|
nxt_track:
|
|
xor al,al
|
|
cmp mcnt,al
|
|
jz flp_ret ;return successful with zero flag set
|
|
inc track
|
|
mov sector,0
|
|
jmp flp_io
|
|
flp_ret:
|
|
ret
|
|
|
|
comp_dma: ;Compute 20 bit address from offset, segment
|
|
;--------
|
|
|
|
; entry: AX = segment
|
|
; BX = offset
|
|
; exit: AX = low 16 bits
|
|
; CH = highest 4 bits of address, always less then 16 -
|
|
; no megabyte wrap around
|
|
;
|
|
; The BIOS variables DMA_LOW16 and DMA_HIGH4 are
|
|
; set by this routine. These variables are transferred
|
|
; to the floppy disk controller by the routine DMA_SET_UP.
|
|
|
|
mov cl,4 ! rol ax,cl ;make paragraphs into bytes
|
|
mov ch,al ! and al,0f0h ;save high 4 bits, 0 low 4 bits
|
|
add ax,bx ;add byte offset
|
|
adc ch,0 ! and ch,0fh ;add in the carry, page is less than
|
|
mov dma_low16,ax ;16
|
|
mov dma_high4,ch
|
|
ret
|
|
|
|
flp_phys_io:
|
|
;-----------
|
|
; entry: num_sec = number of sectors to read in this
|
|
; operation
|
|
; disk parameters on the stack
|
|
; exit: zero flag set if ok
|
|
|
|
; Perform physical actions to read/write floppy diskette
|
|
|
|
mov d_a_number,r_bytes
|
|
mov d_a_eot,r_sectors
|
|
mov d_a_gpl,r_gap
|
|
mov d_a_dtl,r_dtl
|
|
|
|
call motor_and_recal ;make sure motor is on
|
|
mov recals,max_recals
|
|
recal_loop:
|
|
mov retries,max_retries
|
|
retry_loop:
|
|
call seek
|
|
call dma_setup
|
|
call fdc_read_write
|
|
jz phys_ret ;if errors
|
|
dec retries ;attempt retries
|
|
jnz retry_loop
|
|
call recal
|
|
dec recals
|
|
jnz recal_loop
|
|
or al,1 ;reset zero flag
|
|
phys_ret: ;and return error
|
|
ret
|
|
|
|
motor_and_recal:
|
|
;---------------
|
|
; entry: none
|
|
; exit: none
|
|
|
|
; Turn on the motor if off. Also do RECAL operation if
|
|
; motor is off. Note: loader does not turn off the motor.
|
|
|
|
mov al,010h ;pick up a bit for motor a
|
|
mov cl,drive ;fetch the binary drive code
|
|
shl al,cl ;make it a bit for motor x
|
|
mov ah,motor_flags ;fetch the motor bits
|
|
test ah,al ;check to see if its on
|
|
jnz motor_on_done ;yes then leap
|
|
or al,fdc_on ;mask in the no reset,enable interupt
|
|
or al,drive ;mask in the drive
|
|
mov motor_flags,al ;save for later
|
|
mov dx,fdc_port ;point to the port number
|
|
out dx,al ;select & motor on
|
|
call recal ;back to track zero
|
|
motor_on_done: ;when we first turn on the motor
|
|
ret
|
|
|
|
recal:
|
|
;-----
|
|
; entry: none
|
|
; exit: none
|
|
|
|
; Move the head to home on the selected disk drive.
|
|
|
|
mov disk_arguments,2 ;specify number of arguments
|
|
mov d_a_command,fdc_recal_cmd
|
|
mov al,drive ;get current disk
|
|
mov d_a_drive,al ;set up the command block
|
|
call fdc_command_put ;go send the command block
|
|
hlt ;wait for FDC interrupt
|
|
jmp sense_interrupt ;required after RECAL command
|
|
;ret
|
|
|
|
seek:
|
|
;----
|
|
; entry: TRACK to seek to on the stack relative to BP
|
|
; exit: none
|
|
|
|
mov disk_arguments,3 ;request 3 byte command transfer
|
|
mov d_a_command,fdc_seek_cmd
|
|
xor bl,bl ;select head 0
|
|
mov ax,track ;get track off stack
|
|
cmp al,40 ;test for off side 1
|
|
jb side_ok ;if single sided then leap
|
|
mov bl,1 ;else get a head 1
|
|
mov ah,79 ;else get back track bias
|
|
sub ah,al ;compute new track number
|
|
xchg ah,al ;and get it into al
|
|
side_ok:
|
|
mov d_a_head,bl ;set up the head
|
|
add bl,bl ;multiply by 2
|
|
add bl,bl ;multiply by 4
|
|
mov d_a_cylinder,al ;set up the track number
|
|
or bl,drive ;bits 0,1 are drive number
|
|
mov d_a_drive,bl ;set up disk number
|
|
mov ax,sector ;get sector off stack
|
|
inc ax ;sectors are relative to 1
|
|
mov d_a_record,al ;and set it up
|
|
add al,num_sec ;compute new end of track
|
|
dec al
|
|
mov d_a_eot,al ;save it
|
|
call fdc_command_put ;send the command block
|
|
hlt ;wait for FDC interrupt
|
|
jmp sense_interrupt ;required after SEEK command
|
|
;ret
|
|
|
|
dma_setup:
|
|
;---------
|
|
; entry: DMA_MODE_STORAGE, DMA_LOW16, DMA_HIGH4 set up
|
|
; exit: none
|
|
|
|
; Set the DMA device up for a read/write operation.
|
|
; The current DMA command word must in DMA_MODE_STORAGE.
|
|
; DMA_LOW16 and DMA_HIGH4 are the twenty bit starting address.
|
|
; The read/write operation cannot cross a physical 64K boundary.
|
|
|
|
out dma_cbpf,al ;reset the byte pointer
|
|
|
|
mov al,dma_mode_storage ;get the mode byte
|
|
out dma_mode_reg,al ;set the mode
|
|
mov ax,dma_low16 ;low 16 bits of 20 bit DMA address
|
|
out dma_c2_address,al ;send low 8 bits
|
|
mov al,ah
|
|
out dma_c2_address,al ;send next 8 bits
|
|
mov al,dma_high4 ;high 4 bits of 20 bit DMA address
|
|
out dma_page_fdc,al
|
|
xor ax,ax
|
|
mov ah,num_sec ;shl num_sec,8 (* 256)
|
|
shl ah,1 ;*512
|
|
dec ax ;0 relative
|
|
out dma_c2_count,al ;set up the low byte
|
|
mov al,ah ;get the low byte
|
|
out dma_c2_count,al ;and the high byte
|
|
mov al,dma_bmsk_fdc ;get the binary channel mask
|
|
out dma_bmsk_reg,al ;enable the disk channel
|
|
ret
|
|
|
|
fdc_read_write:
|
|
;--------------
|
|
|
|
; entry: DMA device set up, head positioned on correct
|
|
; track
|
|
; exit: zero flag set if successful
|
|
|
|
; Send read or write command to 8272 FDC
|
|
|
|
mov disk_arguments,9 ;9 byte command for read or write
|
|
mov al,fdc_rw_cmd ;get read or write command
|
|
mov d_a_command,al ;put it in the command string
|
|
call fdc_command_put ;send the command to the FDC
|
|
hlt ;wait for FDC interrupt
|
|
mov disk_results,7 ;7 byte result transfer
|
|
call fdc_status_get ;get the result bytes
|
|
test d_r_st0,0C0H ;test status register 0
|
|
ret ;return zero flag set on success
|
|
|
|
sense_interrupt:
|
|
;---------------
|
|
; Sense interrupt command on the FDC. It is called
|
|
; after a recal or a seek to test for seek complete.
|
|
|
|
mov disk_arguments,1 ;only one byte of command
|
|
mov d_a_command,fdc_si_cmd ;sense interrupt commmand
|
|
call fdc_command_put ;send the command to the FDC
|
|
mov disk_results,2 ;2 bytes are returned
|
|
call fdc_status_get ;get the 2 result bytes
|
|
ret
|
|
|
|
fdc_command_put:
|
|
;---------------
|
|
; entry: DISK_ARGUMENT array set up
|
|
; exit: none
|
|
|
|
; Send the command block in the DISK_ARGUMENTS table to
|
|
; the 8272 FDC.
|
|
; The number of commands to write to the FDC is the
|
|
; first item in the table.
|
|
|
|
|
|
mov dx,fdc_stat ;point to the i/o port
|
|
mov si,offset disk_arguments ;point to the table of arguments
|
|
cld ;make sure we go forward
|
|
lodsb ;get the length of the arguments table
|
|
mov cl,al ;get it into the count register
|
|
sub ch,ch ;zero the high byte
|
|
|
|
fdc_command_loop:
|
|
in al,dx ;get the current control byte
|
|
test al,fdc_ready ;if not ok to send next byte
|
|
jz fdc_command_loop ;then loop waiting
|
|
inc dx ;point at the data port
|
|
lodsb ;else get the byte to send
|
|
out dx,al ;send it
|
|
dec dx ;point back at the status port
|
|
loop fdc_command_loop ;if not last byte then loop
|
|
ret ;else were all done
|
|
|
|
fdc_status_get:
|
|
;--------------
|
|
; entry: number of results in 1st byte of DISK_RESULTS array
|
|
; exit: none
|
|
|
|
; Get the status information from the 8272
|
|
; FDC and place them in the table at DISK_RESULTS.
|
|
; The first byte in the table is the number of results
|
|
; to read from the FDC
|
|
|
|
push es ;save UDA
|
|
mov dx,fdc_stat ;point at the status port
|
|
mov ax,ds ;get our data segment
|
|
mov es,ax ;into the extra segment
|
|
mov di,offset disk_results + 1 ;point to where to put the data
|
|
cld ;make sure we go forward
|
|
mov cl,disk_results ;fetch the number of expected results
|
|
sub ch,ch ;zero the high byte
|
|
|
|
fdc_status_loop:
|
|
in al,dx ;get the current control byte
|
|
test al,fdc_ready ;if not ok to read next byte
|
|
jz fdc_status_loop ;then loop waiting
|
|
inc dx ;point at the data port
|
|
in al,dx ;get the byte
|
|
stosb ;put it in the structure
|
|
dec dx ;point back at the status port
|
|
loop fdc_status_loop ;if not last then loop
|
|
pop es ;restore UDA
|
|
ret ;else return
|
|
|
|
|
|
|
|
; INIT ROUTINE
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* 8259 PROGRAMMABLE INTERRUPT CONTROLLER COMMANDS *
|
|
;* AND PORTS *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
pic_even_port equ 020h ;port 0
|
|
pic_odd_port equ 021h ;bit 0 is A0 of 8259 instructions
|
|
|
|
pic_nseoi equ 020h ;non specific end of interupt
|
|
|
|
;************************************************************************
|
|
;* *
|
|
;* BIOS INITIALIZATION ROUTINE *
|
|
;* *
|
|
;************************************************************************
|
|
|
|
;track buffer
|
|
memory_size equ 12h ;ROM interrupt to get memory size
|
|
equipment equ 11h ;ROM interrupt to get equipment word
|
|
|
|
; The following routine is used to initialize any required
|
|
; data areas and alter any peripheral chip programming when
|
|
; starting up CCP/M-86. This code is called once from the
|
|
; SUP(ERVISOR) after calling the SUP has called the RTM,
|
|
; RTM, CIO, MEM, BDOS initialization routines and before the
|
|
; SUP has created the RSP processes.
|
|
; This code can be placed in an BIOS data area if the BIOS is
|
|
; 8080 model (mixed code and data). Usually, overlaying the
|
|
; initialization code with a data area is done after the BIOS
|
|
; has been debugged.
|
|
|
|
|
|
;====
|
|
;====
|
|
init: ;arrive here from the JMP
|
|
;==== ;at 0 in BIOS code segment
|
|
;====
|
|
|
|
cli ! cld ;Supervisor restores DS,ES and int
|
|
;224 after on INIT call
|
|
|
|
; Disk I/O initialization
|
|
|
|
|
|
set_up_interrupts:
|
|
mov al,10111101b ;enable diskette and keyboard
|
|
out pic_odd_port,al ;interrupts only
|
|
;and mask off the rest
|
|
|
|
; mov disk_arguments,3 ;send specify command to the
|
|
; mov d_a_command,fdc_spec_cmd ;FDC (Intel 8272 or NEC 765)
|
|
; mov d_a_drive,0d0h ;step rate=3ms, head unload=0ms
|
|
; mov d_a_cylinder,20h ;head load=2ms, DMA mode true
|
|
; call fdc_command_put ;head unload and head load times
|
|
;are meaningless on mini floppies
|
|
;where the head is loaded
|
|
;when the motor is turned on
|
|
|
|
mov ax,ds
|
|
add data_buf_seg,ax ;fix up data buffer segment
|
|
|
|
push es ! xor ax,ax
|
|
mov es,ax
|
|
mov di,disk_interrupt*4 ;point at vector location
|
|
mov ax,offset i_disk
|
|
stosw ;save and inc DI
|
|
mov ax,cs
|
|
stosw
|
|
pop es
|
|
|
|
set_up_video:
|
|
mov dx,bw_card ;get the video chip port
|
|
mov si,offset bw_table ;initialization commands
|
|
mov cx,length bw_table ;how many commands
|
|
call video_init ;send commands to port
|
|
;color board is similar ...
|
|
push es
|
|
mov di,bw_video_seg ;clear the video RAM
|
|
mov es,di
|
|
xor di,di
|
|
mov cx,screen_siz + columns_per_screen
|
|
;screen length in words plus
|
|
;status line
|
|
mov ax,0720h ;7 = default attribute
|
|
;20 = ASCII space
|
|
rep stosw
|
|
pop es
|
|
|
|
sti
|
|
retf ;initializaiton done
|
|
|
|
;----------
|
|
video_init:
|
|
;----------
|
|
xor bl,bl
|
|
video_init_l:
|
|
mov al,bl ! inc bl
|
|
out dx,al ! inc dx
|
|
lodsb ! out dx,al
|
|
dec dx !
|
|
loop video_init_l
|
|
add dx,4
|
|
mov al,video_on
|
|
out dx,al
|
|
ret
|
|
|
|
|
|
last_code_offset equ offset $
|
|
DSEG
|
|
ORG last_code_offset
|
|
|
|
; Loader BIOS data
|
|
|
|
bw_table db 61h,50h,52h,0fh,19h,06h,19h,19h,02h,0dh,0bh,0ch,0,0,0,0
|
|
|
|
function_table:
|
|
dw io_ret ; 0 console status
|
|
dw io_ret ; 1 console input
|
|
dw io_conout ; 2 console output
|
|
dw io_ret ; 3 list status
|
|
dw io_ret ; 4 list output
|
|
dw io_ret ; 5 auxillary input
|
|
dw io_ret ; 6 auxillary out
|
|
dw io_ret ; 7 switch screen
|
|
dw io_ret ; 8 update or print new status
|
|
dw io_seldsk ; 9 select disk
|
|
dw io_read ;10 read logical sector
|
|
dw io_ret ;11 write logical sector
|
|
dw io_ret ;12 flush buffers
|
|
dw io_ret ;13 poll device
|
|
|
|
|
|
;short screen structure
|
|
;for IO_CONOUT
|
|
|
|
ss0 dw 0,0,0 ;cursor, escape, screen_seg
|
|
db 0,0 ;row,column
|
|
|
|
|
|
; Floppy Disk Driver data
|
|
|
|
|
|
max_retries equ 3
|
|
retries db 0 ;retry counter
|
|
max_recals equ 5
|
|
|
|
recals db 0
|
|
|
|
; The following 2 tables are used to issue commands to,
|
|
; and read results from the 8272 FDC. The first entry
|
|
; in each table is the number of bytes to send or receive
|
|
; from the device
|
|
|
|
disk_arguments db 0 ;number of arguments to send
|
|
d_a_command db 0 ;command read/write
|
|
d_a_drive db 0 ;drive select & head select
|
|
d_a_cylinder db 0 ;cylinder to read/write
|
|
d_a_head db 0 ;head
|
|
d_a_record db 0 ;sector
|
|
d_a_number db 2 ;magic number for 512 bytes/sector
|
|
d_a_eot db sectors_per_track ;end of track sector number
|
|
d_a_gpl db 02ah ;inter sector gap length
|
|
d_a_dtl db 0ffh ;data length
|
|
|
|
disk_results db 0 ;number of bytes to read
|
|
d_r_st0 db 0 ;status byte 0
|
|
d_r_st1 db 0 ;status byte 1
|
|
d_r_st2 db 0 ;status byte 2
|
|
d_r_cylinder db 0 ;cylinder we are on now
|
|
d_r_head db 0
|
|
d_r_record db 0
|
|
d_r_number db 0 ;number of sectors read
|
|
|
|
f_a_bytes db 0
|
|
f_a_sectors db 0
|
|
f_a_gap db 0
|
|
f_a_filler db 0
|
|
|
|
fdc_rw_cmd db fdc_read_cmd ;read or write command
|
|
dma_mode_storage db dma_mode_read_fdc
|
|
|
|
num_sec db 1 ;num sectors to read/write
|
|
;in one call to controller
|
|
|
|
track_mcnt rb 1 ;multi sector count on
|
|
;current track
|
|
dma_low16 rw 1 ;20 bit address storage
|
|
dma_high4 rb 1
|
|
|
|
motor_flags db 0 ;last state of the motor bits
|
|
|
|
; Disk Parameter Header
|
|
|
|
dph0 dw 0 ;translate table
|
|
dw 0,0,0 ;scratch area
|
|
dw dpb0 ;dsk parm block
|
|
dw 0 ;check
|
|
dw 0 ;alloc vectors
|
|
dw dir_bcb_hdr ;dir buff cntrl blk
|
|
dw data_bcb_hdr ;data buff cntrl blk
|
|
dw 0 ;hash table segment
|
|
|
|
; Disk Parameter Block
|
|
|
|
dpb0 dw 8 ;sectors per track
|
|
db 3 ;block shift
|
|
db 7 ;block mask
|
|
db 0 ;extnt mask
|
|
dw 155 ;disk size in 1k blocks
|
|
;less offset track(s)
|
|
dw 63 ;directory max
|
|
db 11000000b ;alloc0
|
|
db 0 ;alloc1
|
|
dw 16 ;check size
|
|
dw 1 ;offset
|
|
db 2 ;phys sec shift
|
|
db 3 ;phys sec mask
|
|
|
|
dir_bcb_hdr dw dir_bcb
|
|
db 1
|
|
|
|
dir_bcb db 0ffh ;drive
|
|
db 0,0,0 ;record
|
|
db 0,0 ;wflg,seg
|
|
dw 0,0 ;track,sector
|
|
dir_buf_off dw dir_buf ;buffer offset
|
|
dw 0,0 ;link,pdadr
|
|
|
|
data_bcb_hdr dw data_bcb
|
|
db 1
|
|
|
|
data_bcb db 0ffh ;drive
|
|
db 0,0,0 ;record
|
|
db 0,0 ;wflg,seg
|
|
dw 0,0 ;track,sector
|
|
data_buf_seg dw data_buf;buffer segment, fixed up by LBIOS init:
|
|
dw 0,0 ;link,pdadr
|
|
|
|
|
|
; Loader Program data
|
|
|
|
signon db 'CCP/M-86 Loader 2.0$'
|
|
nofile db cr,lf,'No CCPM.SYS File On Disk$'
|
|
rerr db cr,lf,'Error Reading CCPM.SYS$'
|
|
csegment db cr,lf,'Code Paragraph = $'
|
|
dsegment db cr,lf,'Data Paragraph = $'
|
|
crlf db cr,lf,'$'
|
|
|
|
ccpmfcb db 1,'CCPM ','SYS',0,0,0,0
|
|
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
|
|
db 0
|
|
|
|
|
|
; Note the Loader Program and Loader BIOS uninitialized
|
|
; data areas are combined to save space.
|
|
|
|
; Unitialized data for Loader Program
|
|
|
|
;read first CMD header of
|
|
;CCPM.SYS file here
|
|
ctype rb 1 ;type
|
|
clen rw 1 ;length
|
|
cldseg rw 1 ;abs
|
|
cmin rw 1 ;minimum
|
|
cmax rw 1 ;maximum
|
|
dtype rb 1
|
|
dlen rw 1
|
|
dldseg rw 1
|
|
dmin rw 1
|
|
dmax rw 1
|
|
|
|
org offset ctype
|
|
sec1 rb 128 ;reserve space for the sector
|
|
|
|
|
|
; Unitialized data for Loader BIOS
|
|
|
|
|
|
dir_buf equ ((offset $) + 15) and 0fff0h
|
|
|
|
; Sector for reads that span 64K boundaries;
|
|
; this sector can not cross a 64K boundary
|
|
|
|
local_buf equ dir_buf + 512
|
|
|
|
data_buf equ (local_buf + 512)/16
|