mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-24 08:54:17 +00:00
1308 lines
35 KiB
Plaintext
1308 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
|
||
|