	title	'Track Buffered BIOS - SBC204'

;  5 Jan 82  -jrp


;	Copyright (C) 1980,1981
;	Digital Research, Inc.
;	Box 579, Pacific Grove
;	California, 93950
;
;	(Permission is hereby granted to use
;	or abstract the following program in
;	the implementation of CP/M, MP/M or
;	CP/NET for the 8086 or 8088 Micro-
;	processor)


true		equ -1
false		equ not true

;	Track buffering equates...

host_sectsiz	equ	128
host_spt	equ	26
host_fsn	equ	1

bdos_int	equ 224
bios_code	equ 2500h
ccp_offset	equ 0000h
bdos_ofst	equ 0B06h ;BDOS entry point

csts		equ 0DAh  ;i8251 status port
cdata		equ 0D8h  ;   "  data port

lsts		equ 41h ;2651 No. 0 on BLC8538 status port
ldata		equ 40h	; "   "   "  "    "    data port
blc_reset	equ 60h	;reset selected USARTS on BLC8538


;*********************************************
;*                                           *
;*    Intel iSBC 204 Disk Controller Ports   *
;*                                           *
;*********************************************

base204		equ 0a0h	;SBC204 assigned address

fdc_com		equ base204+0	;8271 FDC out command
fdc_stat	equ base204+0	;8271 in status
fdc_parm	equ base204+1	;8271 out parameter
fdc_rslt	equ base204+1	;8271 in result
fdc_rst		equ base204+2	;8271 out reset
dmac_adr	equ base204+4	;8257 DMA base address out
dmac_cont	equ base204+5	;8257 out control
dmac_scan	equ base204+6	;8257 out scan control
dmac_sadr	equ base204+7	;8257 out scan address
dmac_mode	equ base204+8	;8257 out mode
dmac_stat	equ base204+8	;8257 in status
fdc_sel		equ base204+9	;FDC select port (not used)
fdc_segment	equ base204+10	;segment address register 
reset_204	equ base204+15	;reset entire interface

max_retries	equ 10		;max retries on disk i/o 
				;before perm error
cr		equ 0dh		;carriage return
lf		equ 0ah		;line feed

	cseg
	org	ccpoffset
ccp:
	org	bios_code

;*********************************************
;*                                           *
;* BIOS Jump Vector for Individual Routines  *
;*                                           *
;*********************************************

 jmp INIT	;Enter from BOOT ROM or LOADER
 jmp WBOOT	;Arrive here from BDOS call 0  
 jmp CONST	;return console keyboard status
 jmp CONIN	;return console keyboard char
 jmp CONOUT  	;write char to console device
 jmp LISTOUT	;write character to list device
 jmp PUNCH	;write character to punch device
 jmp READER  	;return char from reader device 
 jmp HOME	;move to trk 00 on cur sel drive
 jmp SELDSK  	;select disk for next rd/write
 jmp SETTRK  	;set track for next rd/write
 jmp SETSEC  	;set sector for next rd/write
 jmp SETDMA  	;set offset for user buff (DMA)
 jmp READ	;read a 128 byte sector
 jmp WRITE	;write a 128 byte sector
 jmp LISTST  	;return list status 
 jmp SECTRAN 	;xlate logical->physical sector 
 jmp SETDMAB 	;set seg base for buff (DMA)
 jmp GETSEGT 	;return offset of Mem Desc Table
 jmp GETIOBF	;return I/O map byte (IOBYTE)
 jmp SETIOBF	;set I/O map byte (IOBYTE) 



		;print signon message and initialize hardware
INIT:
	mov ax,cs	;we entered with a JMPF so use
	mov ds,ax	; CS: as the initial value of DS:,
	mov es,ax	;	and ES:
	mov ss,ax	; use local stack during initialization
	mov sp,offset stkbase
	cld		;set forward direction
	push ds		;save the DS register
	mov ax,0
	mov ds,ax
	mov es,ax 	;set ES and DS to zero
	;setup interrupt 0 to address trap routine
	mov int0_offset,offset int_trap
	mov int0_segment,CS
	mov di,4
	mov si,0	;then propagate
	mov cx,510	;trap vector to
	rep movs ax,ax	;all 256 interrupts
	;BDOS offset to proper interrupt
	mov bdos_offset,bdos_ofst
	pop ds		;restore the DS register

; Initialize the BLC 8538 printer port
	mov al,0FFh
	out blc_reset,al ;reset all usarts on 8538
	mov al,4Eh
	out ldata+2,al	;set usart 0 in async 8 bit mode
	mov al,3Eh
	out ldata+2,al	;set usart 0 to 9600 baud
	mov al,37h
	out ldata+3,al	;enable Tx/Rx, and set up RTS,DTR
	mov bx,offset signon
	call pmsg	;print signon message

	call clear_flags ; initialize track buffering

	mov cl,0	;default to dr A: on coldstart
	jmp ccp		;jump to cold start entry of CCP

WBOOT:	jmp ccp+6	;direct entry to CCP at command level


int_trap:
	cli		;block interrupts
	mov ax,cs
	mov ds,ax	;get our data segment
	mov bx,offset int_trp
	call pmsg
	hlt		;hardstop


;*********************************************
;*                                           *
;*   CP/M Character I/O Interface Routines   *
;*   Console is Usart (i8251a) on iSBC 86/12 *
;*   at ports D8/DA                          *
;*                                           *
;*********************************************

CONST:		;console status
	in al,csts
	and al,2
	jz const_ret
	or al,255	;return non-zero if RDA
const_ret:
	ret		;Receiver Data Available

CONIN:			;console input
	call const
	jz CONIN	;wait for RDA
	in al,cdata
	and al,7fh 	;read data and remove parity bit
	ret

CONOUT:		;console output
	in al,csts
	and al,1	;get console status
	jz CONOUT 	;wait for TBE
	mov al,cl
	out cdata,al	;Transmitter Buffer Empty
	ret		;then return data

LISTOUT:		;list device output

	call LISTST
	jz LISTOUT	;wait for printer not busy
	mov al,cl
	out ldata,al	;send char to TI 810
	ret

LISTST:			;poll list status

	in al,lsts
	and al,81h	;look at both TxRDY and DTR
	cmp al,81h
	jnz zero_ret	;either false, printer is busy
	or al,255	;both true, LPT is ready
	ret

PUNCH:	;not implemented in this configuration
READER:
	mov al,1ah
	ret		;return EOF for now

GETIOBF:
	mov al,0	;TTY: for consistency
	ret		;IOBYTE not implemented

SETIOBF:
	ret		;iobyte not implemented

zero_ret:
	and al,0
	ret		;return zero in AL and flags

; Routine to get and echo a console character
;	and shift it to upper case

uconecho:
	call CONIN	;get a console character
	push ax
	mov cl,al	;save and
	call CONOUT
	pop ax		;echo to console
	cmp al,'a'
	jb uret		;less than 'a' is ok
	cmp al,'z'
	ja uret		;greater than 'z' is ok
	sub al,'a'-'A'	;else shift to caps
uret:
	ret

;	utility subroutine to print messages

pmsg:
	mov al,[BX] 	;get next char from message
	test al,al
	jz return	;if zero return
	mov CL,AL
	call CONOUT  	;print it
	inc BX
	jmps pmsg	;next character and loop



;*********************************************
;*                                           *
;*          Disk Input/Output Routines       *
;*                                           *
;*********************************************

SELDSK:		;select disk given by register CL
	mov cpm_disk,cl			; save the selected drive
	mov bx,0000h
	cmp cl,2	;this BIOS only supports 2 disks
	jnb return	;return w/ 0000 in BX if bad drive
			;now, we need disk parameter address
	mov ch,0
	mov bx,cx	;BX = word(CL)
	mov cl,4
	shl bx,cl	;multiply drive code * 16
	add bx,offset dp_base	;create offset from Disk Parameter Base
return:
	ret

home:
	test wr_flag,1 ! jnz home1 ; if the buffer is clean,
	mov	cur_disk,-1	; insure we read the directory by invalidating
				;  the track buffer
home1:
	mov	cx,0		; home is a settrk zero

settrk:
	mov	cpm_track,cx	; save track number for next operation
	ret

setsec:
	mov	cpm_sec,cx	; save sector number for next operation
	ret



setdma:
	mov	dma_offset,cx		; save DMA offset address
	ret
setdmab:
	mov	dma_segment,cx		; save DMA segment address
	ret

sectran:
	mov	bx,cx		; Put logical sector into dest. reg.
	test	dx,dx		; see if table address is zero
	jz	sectran_exit	; yeah, logical = physical
	add	bx,dx		; else, we need to fetch the
	mov	bl,[BX]		;  actual sector number from the table
	mov	bh,0		; zero high byte for good luck
sectran_exit:
	ret


GETSEGT:  ;return address of physical memory table
	mov bx,offset seg_table
	ret



read:
	call	track_setup
	push	es			; save the extra segment register
	mov	si,offset track_buffer	; source segment is systems DS:
	add	si,ax			; gives the offset into the buffer
	les	di,dma_longword		; point ES:DI at the users sector
	rep movsw			; doit
	pop	es			; restore the extra segment
	sub	ax,ax			; make a zero return code
	ret

write:
	push	cx			; save the write mode from the BDOS
	call	track_setup
	push	ax			; save buffer offset
	push	ds			; save the data segment
	push	es			; save the extra segment
	mov bx,ds ! mov es,bx		; destination is our data segment
	mov	di,offset track_buffer	; destination is in track buffer
	add	di,ax			; plus appropriate offset
	lds	si,dma_longword		; source is users DMA address
	rep movsw			; move that sector
	pop	es			; restore the extra segment
	pop	ds			; and the data segment registers
	pop	ax			; recover buffer offset
	mov	cx,host_sectsiz		; setup to divide by host sector size
	sub	dx,dx			; extend ax to 32 bits
	div	cx			; find out which host sector we changed
	mov	bx,ax			; put into index [BX]
	mov	sec_flags[BX],1		; set the update flag for that sector
	mov	wr_flag,1		; also set the dirty buffer flag
	pop	cx			; recover BDOS write code
	cmp	cl,1			; is this a directory update ?
	jne	write_return		; no, we may leave dirty records
					;	in the buffer
	call	flush_buffer		; we have a directory write, need to
					; flush the buffer to insure the
					; disks integrity
write_return:
	sub	ax,ax			; never return BAD SECTOR code
	ret


track_setup:			; common code for setting up reads and writes

	mov	al,cpm_disk		; see if selected disk is
	cmp	al,cur_disk		;	the same as last time
	jne	wrong_track		; no, we have wrong track

	mov	ax,cpm_track		; see if desired track is same as
	cmp	ax,cur_track		;	the track in the buffer
	je	correct_track		; same drive and track, we don't need to read

;	Desired operation is on a different track then is in our buffer,
;	So it will be nessecary to read in the desired track.  First, we
;	must check to see if any sectors of the current buffer are dirty.

wrong_track:
	call	flush_buffer		; write any old records, if nessecary

	mov	ax,cpm_track		; get desired track number
	mov	cur_track,ax		; make in new track
	mov	al,cpm_disk		; get desired disk number
	mov	cur_disk,al		; make it current drive
	mov	cur_dma_adr,offset track_buffer
					; point dma offset at track buffer
	mov	cur_sec,host_fsn	; starting from first sector
	call	track_read		; load the track

correct_track:
	mov	ax,cpm_sec		; get the cp/m sector number
  if (host_fsn ne 0)
	sub	ax,host_fsn		; correct if we start with sector one
    endif
	mov	cl,7			; log2(128)
	shl	ax,cl			; sector times 128 gives offset
	mov cx,64 ! cld			; move 64 words forward
	ret


flush_buffer:
	test	wr_flag,1		; see if we have anything to write
	jz	no_flush		; no, skip scanning for dirty sectors
	mov	bx,host_fsn		; start at first host sector
	mov	cx,host_spt		; for host_spt sectors...
next_sect:
	test	sec_flags-host_fsn[BX],1 ; see if this sector has been changed
	jz	not_updated		 ; no, leave it alone
	mov	sec_flags-host_fsn[BX],0 ; zero the flag for next time
	push	bx			 ; save the registers
	push	cx
	mov	cur_sec,bx		; save host sector number
	mov	ax,host_sectsiz
  if (host_fsn ne 0)
	sub	bx,host_fsn
  endif
	mul	bx			; make track buffer offset
	add	ax,offset track_buffer	; make direct pointer
	mov	cur_dma_adr,ax		; save for write routine
	call	sector_write
	pop	cx
	pop	bx
not_updated:
	inc	bx
	loop	next_sect
no_flush:
	mov	wr_flag,0		; clear the dirty buffer flag
	ret

clear_flags:	; Clear all variables associated with the track buffer,
		; so next operation will have to read a track.
		;  This is involves clearing all write flags and setting
		;  the old drive code to the invalid -1.

	push es				; save extra segment
	mov cur_disk,-1 		; insure initial pre-read
	sub ax,ax			; make a zero
	mov wr_flag,al			; clear the dirty buffer flag
	mov di,offset sec_flags		; point to the update flag list
	mov bx,ds ! mov es,bx		; ES <- DS
	mov cx,host_spt ! cld		; set length and direction
	rep stosb			; zero the sector update flags
	mov cur_dma_seg,ds		; get our segment address
	pop es				; recover extra segment
	ret



track_READ:
	mov io_com,4		; read track takes 4 byte command
	mov io_com+1,13h	; special read track command
	jmps r_w_common

sector_WRITE:
	mov io_com,3		; write sector takes 3 byte command
	mov io_com+1,0ah 	; basic write sector command

r_w_common:
	cmp cur_disk,1 ! jne not_first_b	; see if drive B
	test b_first_flag,-1 ! jz not_first_b	; and first reference to B
	call restore				; then restore drive B
	mov b_first_flag,0			; and clear flag
not_first_b:
	mov bx,offset io_com ;point to command string
	mov ax,cur_sec	; put sector in
	mov sect,al	; iopb as 8 bits
	mov ax,cur_track ; same with
	mov trk,al	;    track . . 

;	fall into execute and return

execute:  ;execute command string.
	;[BX] points to length,
	;	followed by Command byte,
	;	followed by length-1 parameter bytes

	mov last_com,BX	;save command address for retries
outer_retry:
	;allow some retrying
	mov rtry_cnt,max_retries
retry:
	mov BX,last_com
	call send_com	;transmit command to i8271
;	check status poll

	mov BX,last_com
	mov al,1[bx]	;get command op code
	mov cx,0800h	;mask if it will be "int req"
	cmp al,2ch
	jb exec_poll	;ok if it is an interrupt type 
	mov cx,8080h	;else we use "not command busy"
	and al,0fh
	cmp al,0ch	;unless there isn't
	mov al,0
	ja exec_exit	;	any result
			;poll for bits in CH,
exec_poll:		;  toggled with bits in CL

	in al,fdc_stat	;read status
	and al,ch
	xor al,cl	;  isolate what we want to poll
	jz exec_poll	;and loop until it is done

			;Operation complete,
	in al,fdc_rslt	; see if result code indicates error
	and al,1eh
	jz exec_exit	;no error, then exit
			;some type of error occurred . . .
	cmp al,10h
	je dr_nrdy	;was it a not ready drive ?
			;no,
dr_rdy:	; then we just retry read or write
	push ax		; save error code
	call restore	; after physically homing this disk
	pop ax		; recover error code
	dec rtry_cnt
	jnz retry	;  up to 10 times

;	retries do not recover from the
;	hard error

	mov ah,0
	mov bx,ax	;make error code 16 bits
	mov bx,errtbl[BX]
	call pmsg	;print appropriate message
	in al,cdata	;flush usart receiver buffer
	call uconecho	;read upper case console character
	cmp al,'C'
	je wboot_l	;cancel
	cmp al,'R'
	je outer_retry	;retry 10 more times
	cmp al,'I'
	je z_ret	;ignore error
	or al,255	;set code for permanent error
exec_exit:
	ret

dr_nrdy:	;here to wait for drive ready
	call test_ready
	jnz retry	;if it's ready now we are done
	call test_ready
	jnz retry	;if not ready twice in row,
	mov bx,offset nrdymsg
	call pmsg 	;"Drive Not Ready"
nrdy01:
	call test_ready
	jz nrdy01 	;now loop until drive ready
	jmps retry	;then go retry without decrement
zret:
	and al,0
	ret		;return with no error code

wboot_l:		;can't make it w/ a short leap
	jmp WBOOT

;*********************************************
;*                                           *
;*  The i8271 requires a read status command *
;*  to reset a drive-not-ready after the     *
;*  drive becomes ready                      *
;*                                           *
;*********************************************

test_ready:
	mov dh, 40h  	;proper mask if dr 1
	test sel_mask,80h
	jnz nrdy2
	mov dh, 04h  	;mask for dr 0 status bit
nrdy2:
	mov bx,offset rds_com
	call send_com
dr_poll:
	in al,fdc_stat	;get status word
	test al,80h
	jnz dr_poll 	;wait for not command busy
	in al,fdc_rslt	;get "special result"
	test al,dh	;look at bit for this drive
	ret		;return status of ready


restore:	;move selected disk to home position (Track 0)
	mov bx,offset hom_com
	call execute
	jz restore_exit	;home drive and return if OK
	mov bx,offset bad_hom	;else print 
	call pmsg	;"Home Error"
	jmps restore	;and retry
restore_exit:
	ret

;*********************************************
;*                                           *
;*  Send_com sends a command and parameters  *
;*  to the i8271:  BX addresses parameters.  *
;*  The DMA controller is also initialized   *
;*  if this is a read or write               *
;*                                           *
;*********************************************

send_com:
	in al,fdc_stat
	test al,80h	;insure command not busy
	jnz send_com	;loop until ready

	;see if we have to initialize for a DMA operation

	mov al,1[bx]	;get command byte
	cmp al,13h
	jne write_maybe	;if not a read it could be write
	mov cl,40h
	jmps init_dma	;is a read command, go set DMA
write_maybe:
	cmp al,0ah
	jne dma_exit	;leave DMA alone if not read or write
	mov cl,80h  	;we have write, not read
init_dma:
;we have a read or write operation, setup DMA controller
;	(CL contains proper direction bit)
	mov al,04h
	out dmac_mode,al    ;enable dmac
	mov al,00
	out dmac_cont,al    ;send first byte to control port
	mov al,cl
	out dmac_cont,al   ;load direction register
	mov ax,cur_dma_adr
	out dmac_adr,al    ;send low byte of DMA
	mov al,ah
	out dmac_adr,al	   ;send high byte
	mov ax,cur_dma_seg
	out fdc_segment,al ;send low byte of segment address
	mov al,ah
	out fdc_segment,al ;then high segment address
dma_exit:
	mov cl,[BX]	;get count
	inc BX
	mov al, 80h
	cmp cur_disk,0
	jne sel1 	;drive 1 if not zero
	mov al, 40h	;else drive is 0
sel1:	mov sel_mask,al	; save select mask
	or al,[BX]	;merge command and drive code
	out fdc_com,al 	;send command byte
parm_loop:
	dec cl
	jz parm_exit	;no (more) parameters, return
	inc BX		;point to (next) parameter
parm_poll:
	in al,fdc_stat
	test al,20h	;test "parameter register full" bit
	jnz parm_poll	;idle until parm reg not full
	mov al,[BX]
	out fdc_parm,al	;send next parameter
	jmps parm_loop	;go see if there are more parameters
parm_exit:
	ret

;*********************************************
;*                                           *
;*               Data Areas                  *
;*                                           *
;*********************************************
data_offset	equ offset $

	dseg
	org	data_offset	;contiguous with code segment


signon	db	cr,lf,cr,lf
	db	'  CP/M-86, 1 Feb 82 ',cr,lf,0

bad_hom	db	cr,lf,'Home Error',cr,lf,0
int_trp	db	cr,lf,'Interrupt Trap Halt',cr,lf,0

errtbl  dw er0,er1,er2,er3
	dw er4,er5,er6,er7
	dw er8,er9,erA,erB
	dw erC,erD,erE,erF

er0 	db  cr,lf,'Error Code 0 :',0
er1 	db  cr,lf,'Error Code 1 :',0
er2 	db  cr,lf,'Error Code 2 :',0
er3 	db  cr,lf,'Error Code 3 :',0
er4 	db  cr,lf,'Clock Error :',0
er5 	db  cr,lf,'Late DMA :',0
er6 	db  cr,lf,'ID CRC Error :',0
er7 	db  cr,lf,'Data CRC Error :',0
er8 	db  cr,lf,'Drive Not Ready :',0
er9 	db  cr,lf,'Write Protect :',0
erA 	db  cr,lf,'Track 00 Not Found :',0
erB 	db  cr,lf,'Write Fault :',0
erC 	db  cr,lf,'Sector Not Found :',0
erD 	db  cr,lf,'Error Code D :',0
erE 	db  cr,lf,'Error Code E :',0
erF 	db  cr,lf,'Error Code F :',0

nrdymsg	equ er8

b_first_flag	db	-1

rtry_cnt db 0 	;disk error retry counter
last_com dw 0 	;address of last command string
cur_dma_adr  dw 0 	;dma offset stored here
cur_dma_seg  dw 0 	;dma segment stored here
sel_mask db 40h ;select mask, 40h or 80h

;	Various command strings for i8271

io_com	db 3	;length (changed to 4 to read a track)
rd_wr	db 0	;read/write function code
trk	db 0	;track #
sect	db 0	;sector #
sec_len	db 26	;transfer 26 sectors on a track read

hom_com	db 2,29h,0	;home drive command
rds_com	db 1,2ch	;read status command

;	Track buffering variables

cpm_disk	rb	1
cpm_track	rw	1
cpm_sec		rw	1

cur_disk	rb	1
cur_track	rw	1
cur_sec		rw	1

dma_offset	rw	1
dma_segment	rw	1
dma_longword	equ	dword ptr dma_offset

bdos_wr_code	rb	1
wr_flag		rb	1

;	System Memory Segment Table

segtable db 2	;2 segments
	dw tpa_seg	;1st seg starts after BIOS
	dw tpa_len	;and extends to 08000
	dw 1000h	;second is 10000 -
	dw 1000h	;1FFFF (64k)

;	include singles.lib ;read in disk definitions
;	        DISKS 2
dpbase	equ	$		;Base of Disk Parameter Blocks
dpe0	dw	xlt0,0000h	;Translate Table
	dw	0000h,0000h	;Scratch Area
	dw	dirbuf,dpb0	;Dir Buff, Parm Block
	dw	csv0,alv0	;Check, Alloc Vectors
dpe1	dw	xlt1,0000h	;Translate Table
	dw	0000h,0000h	;Scratch Area
	dw	dirbuf,dpb1	;Dir Buff, Parm Block
	dw	csv1,alv1	;Check, Alloc Vectors
;	        DISKDEF 0,1,26,6,1024,243,64,64,2
;
;	 1944:	128 Byte Record Capacity
;	  243:	Kilobyte Drive  Capacity
;	   64:	32 Byte Directory Entries
;	   64:	Checked Directory Entries
;	  128:	Records / Extent
;	    8:	Records / Block
;	   26:	Sectors / Track
;	    2:	Reserved  Tracks
;	    6:	Sector Skew Factor
;
dpb0	equ	offset $	;Disk Parameter Block
	dw	26		;Sectors Per Track
	db	3		;Block Shift
	db	7		;Block Mask
	db	0		;Extnt Mask
	dw	242		;Disk Size - 1
	dw	63		;Directory Max
	db	192		;Alloc0
	db	0		;Alloc1
	dw	16		;Check Size
	dw	2		;Offset
xlt0	equ	offset $	;Translate Table
	db	1,7,13,19
	db	25,5,11,17
	db	23,3,9,15
	db	21,2,8,14
	db	20,26,6,12
	db	18,24,4,10
	db	16,22
als0	equ	(243+7)/8	;Allocation Vector Size
css0	equ	16		;Check Vector Size
;	        DISKDEF 1,0
;
;	Disk 1 is the same as Disk 0
;
dpb1	equ	dpb0		;Equivalent Parameters
als1	equ	als0		;Same Allocation Vector Size
css1	equ	css0		;Same Checksum Vector Size
xlt1	equ	xlt0		;Same Translate Table
;	        ENDEF
;
;	Uninitialized Scratch Memory Follows:
;
dirbuf	rs	128		;Directory Buffer
alv0	rs	als0		;Alloc Vector
csv0	rs	css0		;Check Vector
alv1	rs	als1		;Alloc Vector
csv1	rs	css1		;Check Vector


sec_flags	rb	host_spt

track_buffer	rb	host_spt*host_sectsiz


loc_stk	rw  32	;local stack for initialization

stkbase	equ offset $

lastoff	equ offset $

tpa_seg	equ ((lastoff+07FFh)/0400h)*40h		; round off to 1K boundary
tpa_len	equ 0800h - tpa_seg

	db 0	;fill last address for GENCMD

;*********************************************
;*                                           *
;* Dummy Data Section for Interrupt Vectors  *
;*                                           *
;*********************************************

	dseg	0	;absolute low memory
	org 	0	;(interrupt vectors)

int0_offset	rw	1
int0_segment	rw	1

;	pad to system call vector
	org	bdos_int * 4

bdos_offset	rw	1
bdos_segment	rw	1

	END
