		if2
		%out	Pass 2.
		endif
		.286c
		page	60,132
		name	core
		title	Slicer Concurrnet BIOS Version 1.0A
;--------------------------------------------------------------------------------
;	      Concurrent BIOS for the Slicer. (C) Slicer Computers Inc.,1985
;
;             Version 1.0A                April 4, 1985 
;	      By David Daney 1985
;
;
;--------------------------------------------------------------------------------
		subttl	Equates
		page
;----------------------------------------------------------------
;      E Q U A T E S
;----------------------------------------------------------------
b		equ	byte ptr  
w		equ	word ptr 
;
;		byte definition
;		disk type
uninitialized	equ	10000000b
mini		equ	00010000b
double_density	equ	00100000b
double_track	equ	01000000b
sector_size_m	equ	00001100b
step_rate_m	equ	00000011b
;----------------------------------------------------------------
;		disk_flags
;----------------------------------------------------------------
disk_in_service	equ	00000001b
fop_waiting	equ	00000010b	;floppy done
f_nest		equ	00000100b
write_status	equ	00001000b
interuptable	equ	00010000b
sop_waiting	equ	00100000b	;sasi done
sasi_nest	equ	01000000b
sasi_in_service	equ	10000000b
;----------------------------------------------------------------
;              com_flags
;----------------------------------------------------------------
com1_waiting	equ	00000001b
com2_waiting	equ	00000010b
com3_waiting	equ	00000100b
com4_waiting	equ	00001000b
com5_waiting	equ	00010000b
com6_waiting	equ	00100000b
;----------------------------------------------------------------
;		Hardware I/O port definition
;----------------------------------------------------------------
keyboard_port	equ	300h		;CAN BE 60 WITH BOARD CHANGES
aux_timer_int	equ	01ch
ibm_timer0_int	equ	08h
concurrent_int	equ	0f9h
aux_int13_int	equ	0fch
mini_sel	equ	010ch
dbl_den_sel	equ	010eh
sasi_reset_port	equ	102h
sasi_sel_port	equ	100h
sasi_data_port	equ	180h
sasi_stat_port	equ	184h
sasi_reset_port	equ	102h
sasi_sel_port	equ	100h
;----------------------------------------------------------------
; sasi status port definitions
;----------------------------------------------------------------
status_mask	equ	1011100000000000b
selected	equ	0000100000000000b
request		equ	0100000000000000b
command_block1	equ	0010100000000000b
data_block_fro	equ	0000100000000000b
data_block_to	equ	1000100000000000b
status_byte	equ	1010100000000000b
message_byte	equ	1011100000000000b


;
;
;  2681 EQUATES
;
;
uart_base2	equ	200h
uart_base	equ	80h
mode_rega	equ	uart_base
stat_reg	equ	2
stat_rega	equ	uart_base+stat_reg
clock_reg	equ	2
command_reg	equ	4
command_rega	equ	uart_base+command_reg
clock_rega	equ	uart_base+clock_reg
tx_rega		equ	6+uart_base
rx_rega		equ	6+uart_base
aux_cr		equ	8+uart_base
int_reg		equ	0ah+uart_base
mode_regb	equ	mode_rega+10h
stat_regb	equ	stat_rega+10h
command_regb	equ	command_rega+10h
clock_regb	equ	clock_rega+10h
tx_regb		equ	tx_rega+10h
rx_regb		equ	rx_rega+10h
out_cr		equ	uart_base+1ah
in_reg		equ	uart_base+1ah
sio_out_set	equ	uart_base+1ch
sio_out_clr	equ	uart_base+1eh
;
reset_rx	equ	00100000b
reset_tx	equ	00110000b
disable_channel	equ	00001010b
enable_channel	equ	00000101b
reset_mr_ptr	equ	00010000b
mode1		equ	10010011b
mode2		equ	00011111b
auxa		equ	10000000b
enable_all	equ	00100010b
enable_1	equ	00000010b
enable_2	equ	00100000b
rx_rdy		equ	1b
tx_rdy		equ	100b
enable_ctsa	equ	1b
enable_ctsb	equ	10b
enable_dtra	equ	100b
enable_dtrb	equ	1000b
out_config	equ	0
xoff		equ	13h
jump96		equ	40h

baudb		equ	66h		;1200 baud
;
;	8250	EQUATES
;
;
com_port		equ	3f0h
line_control		equ	com_port+0bh
divisor_latchl		equ	com_port+08h	;dlab = 1
divisor_latchm		equ	com_port+09h	;dlab = 1
line_status		equ	com_port+0dh
interrupt_id		equ	com_port+0ah
interrupt_enable	equ	com_port+09h	;dlab	= 0
modem_control		equ	com_port+0ch
modem_status		equ	com_port+0eh
receiver_buffer		equ	com_port+08h	; dlab = 0 READ
transmitter_holding	equ	com_port+08h	; dlab = 0 WRITE
;
;
; Z8530 EQUATES
;
;
scc_base	equ	240h
port4_control	equ	scc_base
port3_control	equ	scc_base+4
port4_data	equ	scc_base+2
port3_data	equ	scc_base+6
reset3		equ	080h
reset4		equ	040h
reset_scc	equ	0c0h
mie		equ	08h
wr1		equ	12h
wr11		equ	01010101b
wr14d		equ	2
wr14e		equ	3
wr15		equ	0
reset_txip	equ	00101000b
channela_txip	equ	00010000b
channela_rxip	equ	00100000b
channelb_txip	equ	00000010b
channelb_rxip	equ	00000100b
;----------------------------------------------------------------
;  Meg board equates
;----------------------------------------------------------------
switch_port	equ	261h
smem_mask	equ	4
vmem_mask	equ	2
meg_mask	equ	00001001b
switch_mask	equ	11111001b
uart2_base	equ	200h
mode_reg2a	equ	uart2_base
stat_reg2a	equ	uart2_base+stat_reg
command_reg2a	equ	uart2_base+command_reg
clock_reg2a	equ	uart2_base+clock_reg
tx_reg2a	equ	6+uart2_base
rx_reg2a	equ	6+uart2_base
aux_cr2		equ	8+uart2_base
int_reg2	equ	0ah+uart2_base
mode_reg2b	equ	mode_reg2a+10h
stat_reg2b	equ	stat_reg2a+10h
command_reg2b	equ	command_reg2a+10h
clock_reg2b	equ	clock_reg2a+10h
tx_reg2b	equ	tx_reg2a+10h
rx_reg2b	equ	rx_reg2a+10h
out_cr2		equ	uart2_base+1ah
sio2_out_set	equ	uart2_base+1ch
sio2_out_clr	equ	uart2_base+1eh
;
;
;
;
fdc_status	equ	0h
fdc_command	equ	0h
fdc_track	equ	2h
fdc_sector	equ	4h
fdc_data	equ	6h
dma_cr0		equ	0ffcah
dma_sl0		equ	0ffc0h
dma_sh0		equ	0ffc2h
dma_dl0		equ	0ffc4h
dma_dh0		equ	0ffc6h
dma_tc0		equ	0ffc8h
dma_cr1		equ	0ffdah
dma_sl1		equ	0ffd0h
dma_sh1		equ	0ffd2h
dma_dl1		equ	0ffd4h
dma_dh1		equ	0ffd6h
dma_tc1		equ	0ffd8h

timer0_control	equ	0ff56h
timer1_control	equ	0ff5eh
timer2_control	equ	0ff66h
timer2_max_ct	equ	0ff62h
timer2cw	equ	1110000000000001b	;enable timer2 continous counting
						;generating interupts
timer1cw	equ	0100000000000000b	;disabled
timer0cw	equ	0100000000000000b	;disabled
timer2_divisor	equ	40000			;50 times a sec at 8mHz.

;----------------------------------------------------------------
; Interupt registers
;----------------------------------------------------------------
int0_int_cr	equ	0ff38h
int1_int_cr	equ	0ff3ah
int2_int_cr	equ	0ff3ch
int3_int_cr	equ	0ff3eh
dma0_int_cr	equ	0ff34h
dma1_int_cr	equ	0ff36h
timer_int_cr	equ	0ff32h
is_reg		equ	0ff2ch
priority_maskr	equ	0ff2ah
int_maskr	equ	0ff28h
eoi_reg		equ	0ff22h
;----------------------------------------------------------------
; Interupt priorities     These priorities should be observed when
;   0-dma0                using external service routines
;   1-fdc
;   2-dma1(if used)
;   3-onboard serial ports
;   4-offboard serial ports(if installed)
;   5-IBM keyboard(if installed)
;   6-timer
;   7-unused interupts
;----------------------------------------------------------------
timer_int_cw	equ	6
dma0_int_cw	equ	0
dma1_int_cw	equ	2
int0_int_cw	equ	0fh
int1_int_cw	equ	1		;edge triggered (fdc)
int2_int_cw	equ	0fh
int3_int_cw	equ	0fh
com_int_cw	equ	13h		;level triggered
com2_int_cw	equ	14h		;level triggered
priority_mask	equ	6
int_is_mask	equ	11111101b	;mask out non inservice bits
;
eoi_cmd		equ	8000h
dma0_int_mask	equ	00000100b
dma1_int_mask	equ	00001000b
int0_int_mask	equ	00010000b
int1_int_mask	equ	00100000b
int2_int_mask	equ	01000000b
int3_int_mask	equ	10000000b
timer_int_mask	equ	00000001b

;----------------------------------------------------------------
; Chip select registers
;----------------------------------------------------------------
umcsr		equ	0ffa0h
lmcsr		equ	0ffa2h
pacsr		equ	0ffa4h
mmcsr		equ	0ffa6h
mpcsr		equ	0ffa8h

umcsv		equ	0f838h			;32k no wait states
lmcsv		equ	03ff8h			;256k no wait states
pacsv		equ	03ah			;i/o starts at 0, 2 wait states
mpcsv		equ	090bbh			;io io space 7pcs lines 3 waits 32k wide mcs
mmcsv		equ	0c1fbh			;mcs lines start at c0000h
;----------------------------------------------------------------
;		Command and status definitions
;----------------------------------------------------------------
motor_ctl	equ	080h
terminate_ni	equ	11010000b
terminate_wi	equ	11011000b

restore_cmd	equ	00001000b
seek_cmd	equ	00011000b
fatal_error	equ	2
non_fatal_error	equ	1
time_out	equ	80h
not_ready_error	equ	80h
bad_seek	equ	40h
bad_crc		equ	10h
record_not_fnd	equ	04h
write_protect	equ	03h
bad_addr_mark	equ	02h
bad_cmd		equ	01h
sasi_time_out	equ	0ffh
disable_dma	equ	0110111000000101b   ;stop channel no int.

dma_read	equ	1010111101100110b	;dest inc, source nochg, stop on tc
						;int on tc high priority no timer int
						;start channel byte transfers
dma_write	equ	0111011110100110b	;dest nochg,source inc, stop on tc
						;int on tc high priority no timer int
						;start channel byte transfers
sasi_dma	equ	1111111110100110b	;used only to generate an interupt
						;after 1 transfer

dma1_int	equ	0bh
run_monitor	equ	4

;
		subttl	Data Areas
		page	+
		include	biosdata.asm
		include 8087mac.asm

		subttl	Externals and Publics
		page	+
;----------------------------------------------------------------
; Externals and Publics
;----------------------------------------------------------------
		extrn	new_call_init:near
		extrn	old_call_init:near
		extrn	ibm_call_init:near
		extrn	video_init:near
		extrn	keyboard_init:near
		extrn	bootstrap:near
;		extrn	memory_debug:near
		extrn	bomb_init:near
		extrn	bomb_c:near
		extrn	memtest:near

		extrn	moninit:near

;ADDED FOR MAP
		public	timer,cal_address,disk_op,int_dma0
		public	disk_pseudo_int,check_8087
		public	disk_read,disk_read1
		public	disk_write,disk_write1
		public	disk_reset
		public	port1_write,port2_write,port3_write,port4_write
		public	port1_status,port2_status,port3_status,port4_status
		public  set_up_port1,set_up_port2,set_up_port3,set_up_port4
		public	ibm_serial
		public	initialize
		public	drive_mask
		public	sasi_io,sasi_io1

		subttl	Initialization Code
		page	+
;----------------------------------------------------------------
;  Setup all internal and external peripheral registers, and low
;   memory locations.
;----------------------------------------------------------------

cgroup		group	code

code		segment byte public 'code'
		assume	cs:cgroup,ds:data
		org	0h
initialize	proc	far
		cli
		mov	dx,lmcsr
		mov	ax,lmcsv
		out	dx,ax
		mov	dx,pacsr
		mov	ax,pacsv
		out	dx,ax
		mov	dx,mpcsr
		mov	ax,mpcsv
		out	dx,ax
		mov	dx,mmcsr
		mov	ax,mmcsv
		out	dx,ax			;activate mmcs lines
		mov	dx,out_cr
		mov	al,out_config
		out	dx,al
		mov	al,motor_ctl
		out	sio_out_set,al		;turn off floppy motors
		mov	ax,data
		mov	ds,ax
		mov	ax,stack		
		mov	ss,ax
		assume	ss:stack
		mov	sp,offset stack_top
		cmp	reset_location,1234h
		jne	i17
		jmp	i13			;warm start skip baud rate
i17:

;----------------------------------------------------------------
		mov	dx,command_rega
		mov	al,reset_rx+disable_channel
		out	dx,al
		mov	al,reset_tx
		out	dx,al
		mov	al,reset_mr_ptr
		out	dx,al
		mov	al,enable_ctsa+enable_ctsb+enable_dtra+enable_dtrb
		mov	dx,sio_out_set
		out	dx,al

BAUD:
	MOV	AL,10010011B	;8 bits
				;   no parity
				;   Rx controls RTS
	OUT	mode_rega,AL
	MOV	AL,00011111B	;CTS controls XMTR
				;   2 stops
	OUT	mode_rega,AL
	IN	AL,in_reg	;Jumper decides whether
	TEST	AL,JUMP96	;baud rate is set by
	JNZ	GETBAUD		;CR typed at console
	MOV	AL,0BBH		;or just set to 9600
	OUT	clock_rega,AL
	JMP	i13
GETBAUD:
	MOV	CX,3		;Retries
BAUD0:	JCXZ	ECHO
	DEC	CX		;Try again
	MOV	BX,-1
BAUD1:	INC	BX		;Count breaks
	MOV	AX,0CC00H	;38.4K
	MOV	DI,OFFSET BAUD2	;Set baud
	JMP	BAUD6		;and get char
BAUD2:	OR	AL,AL		;Break?
	JZ	BAUD1		;Get another char
	CMP	AL,0dh		;If CR then 38.4K baud
	JZ	BAUD9		;is correct
	CMP	BL,0		;First char?
	JZ	BAUD3
	MOV	AL,BL		;If not use break count.
BAUD3:	MOV	BX,OFFSET BAUDTABLE
BAUD4:	MOV	DX,cs:[BX]	;Search table
	CMP	DH,0		;Error?
	JZ	BAUD0
	CMP	DL,0		;End of table?
	JZ	BAUD5		;Use default baud
	ADD	BX,2
	CMP	AL,DL		;Test.
	JNZ	BAUD4
BAUD5:	MOV	AH,DH		;Have it. Set baud
	MOV	DI,OFFSET BAUD9
	MOV	AL,80H

BAUD6:	MOV	BP,AX
	OUT	aux_cr,AL
	MOV	AL,00100001B	;Reset
	OUT	command_rega,AL
	MOV	AL,AH		;Set baud
	OUT	clock_rega,AL
	MOV	AL,00010101B	;Tx enable
				;   Rx enable
	OUT	command_rega,AL
BAUD7:	IN	AL,stat_rega	;Get a char.
	TEST	AL,rx_rdy
	JZ	BAUD7
	IN	AL,rx_rega
	JMP	DI		;RAMless return

BAUD9:
	JMP	i13

;Couldn't determine baud rate. Set baud to 1200 and go
;into continuous echo mode.

ECHO:
	MOV	AL,66H
	OUT	clock_rega,AL
ECHO0:
	MOV	AL,AH
	OUT	tx_rega,AL
ECHO1:	IN	AL,stat_rega
	TEST	AL,tx_rdy
	JNZ	ECHO0
	TEST	AL,rx_rdy
	JZ	ECHO1
	IN	AL,rx_rega
	MOV	AH,AL
	JMP	ECHO1

BAUDTABLE:
	DB	0E6H,0CCH	;19.2K
	DB	78H,0BBH	;9600
	DB	80H,99H		;4800
	DB	1,88H		;2400
	DB	3,66H		;1200
	DB	6,55H,7,55H	;600
	DB	12,44H,13,44H,14,44H	;300
	DB	0,0		;Put default baud here.

;----------------------------------------------------------------

i13:
		mov	equip_flag,40cdh		;1 printer ,no game,no rs232
						;4 disk drives, 64k ram
		call	ibm_call_init
		call	video_init		;initialize video to get bomb messages
		call	memory_check
		mov	ax,vectors
		mov	es,ax
		assume	es:vectors
		call	bomb_init		;WILD INTERRUPT
		call	old_call_init		;MONITOR

set		macro	num,val
		mov	w num,offset val
		mov	w num+2,seg val
		endm
		set	vector_3,dummy_int		;break use by PD
		set	vector_1c,dummy_int
		set	vector_8,dummy_int 		;ibm timer
		set	vector_f9,flag_int
		set	vector_33,dummy_int	       ;microsoft mouse int
		set 	vector_67,dummy_int
;

init_int:
		mov	dx,priority_maskr
		mov	ax,priority_mask
		out	dx,ax
		mov	dx,is_reg
		mov	ax,0			;clear all in service bits
		out	dx,ax
		mov	dx,int_maskr		;mask all interupts. they will be
		mov	ax,0ffh			;unmasked as they are initialized
		out	dx,ax
		mov	dx,int0_int_cr
		mov	ax,int0_int_cw
		out	dx,ax
 		mov	dx,int2_int_cr
 		mov	ax,int2_int_cw
		out	dx,ax
		mov	dx,int3_int_cr
		mov	ax,int3_int_cw
		out	dx,ax
;
		mov	dx,sasi_stat_port+1
		in	al,dx
		and	al,3
		cmp	al,2			;checks for rev E board
		mov	bl,al			;save in bl also
		mov	ax,com_int_cw
		jnz	init_int0
		set	vector_f,com_int
		mov	dx,int3_int_cr
		out	dx,ax
		jmp	i2
init_int0:	set	vector_c,com_int
		mov	dx,int0_int_cr
		out	dx,ax
i2:
		mov	dx,command_reg2a	;check for expansion board ports
		mov	al,reset_mr_ptr
		out	dx,al
		mov	al,055h
		mov	dx,mode_reg2a
		out	dx,al
		mov	dx,command_reg2a
		mov	al,reset_mr_ptr
		out	dx,al
		mov	dx,mode_reg2a
		in	al,dx
		cmp	al,055h
		je	i5
		jmp	i3			;no expansion ports
i5:
		cmp	bl,2			;checks for rev E board
		mov	ax,com2_int_cw
		jnz	init_int2

				
		set	vector_c,com2_int
		mov	dx,int0_int_cr
		out	dx,ax
		jmp	i4
init_int2:	set	vector_f,com2_int
		mov	dx,int3_int_cr
		out	dx,ax
i4:
		mov	dx,command_reg2a
		mov	al,reset_rx+disable_channel
		out	dx,al
		mov	al,reset_tx
		out	dx,al
		mov	al,reset_mr_ptr
		out	dx,al

		mov	dx,mode_reg2a
		mov	al,mode1
		out	dx,al
		mov	al,mode2
		out	dx,al
		mov	al,baudb
		mov	dx,clock_reg2a
		out	dx,al
		mov	dx,aux_cr2
		mov	al,0
		out	dx,al
		mov	al,enable_all
		mov	com2_int_status,al
		mov	dx,int_reg2
		out	dx,al
		mov	dx,out_cr2
		mov	al,out_config
		out	dx,al
		mov	al,enable_ctsa+enable_ctsb+enable_dtra+enable_dtrb
		mov	dx,sio2_out_set
		out	dx,al
		mov	dx,command_reg2a
		mov	al,enable_channel
		out	dx,al

		mov	dx,command_reg2b
		mov	al,reset_rx+disable_channel
		out	dx,al
		mov	al,reset_tx
		out	dx,al
		mov	al,reset_mr_ptr
		out	dx,al

		mov	dx,mode_reg2b
		mov	al,mode1
		out	dx,al
		mov	al,mode2
		out	dx,al
		mov	al,baudb
		mov	dx,clock_reg2b
		out	dx,al
		mov	dx,command_reg2b
		mov	al,enable_channel
		out	dx,al

i3:		mov	dx,command_rega
		mov	al,reset_rx+disable_channel
		out	dx,al
		mov	al,reset_tx
		out	dx,al
		mov	al,reset_mr_ptr
		out	dx,al
		mov	dx,mode_rega
		mov	al,mode1
		out	dx,al
		mov	al,mode2
		out	dx,al
		mov	al,enable_all
		mov	com1_int_status,al
		mov	dx,int_reg
		out	dx,al
		mov	dx,out_cr
		mov	al,out_config
		out	dx,al
		mov	al,enable_ctsa+enable_ctsb+enable_dtra+enable_dtrb
		mov	dx,sio_out_set
		out	dx,al
		mov	dx,command_rega
		mov	al,enable_channel
		out	dx,al

		mov	dx,command_regb
		mov	al,reset_rx+disable_channel
		out	dx,al
		mov	al,reset_tx
		out	dx,al
		mov	al,reset_mr_ptr
		out	dx,al

		mov	dx,mode_regb
		mov	al,mode1
		out	dx,al
		mov	al,mode2
		out	dx,al
		mov	al,baudb
		mov	dx,clock_regb
		out	dx,al
		mov	dx,command_regb
		mov	al,enable_channel
		out	dx,al

init_dma:	mov	dx,dma_cr0
		mov	ax,disable_dma
		out	dx,ax
		mov	dx,dma_cr1
		out	dx,ax
		mov	dx,dma0_int_cr
		mov	ax,dma0_int_cw
		out	dx,ax
		mov	dx,dma1_int_cr
		mov	ax,dma1_int_cw
		out	dx,ax
		set	vector_a,int_dma0
		set	vector_b,int_dma1

init_timers:	mov	dx,timer0_control
		mov	ax,timer0cw		;turn off timers 0,1
		out	dx,ax			;turn on timer 2
		mov	ax,timer1cw
		mov	dx,timer1_control
		out	dx,ax
		mov	dx,timer2_control
		mov	ax,timer2cw
		out	dx,ax
		mov	dx,timer2_max_ct
		mov	ax,timer2_divisor
		out	dx,ax
		mov	dx,timer_int_cr
		mov	ax,timer_int_cw
		out	dx,ax
		set	vector_13,timer
		set	vector_fd,disk_pseudo_int	;Jonathan 10-8-86
		mov	motor_count,500
		mov	select_count,100
;****************************************************************
		mov	disk_time_out,25		;
		mov	hdisk_time_out,0ffffh
;****************************************************************
		mov	motor_count1,0
		mov	select_count1,0
		mov	disk_time_out1,0


init_fdc:	mov	dx,fdc_command
		mov	al,terminate_ni
		out	dx,al
		mov	dx,int1_int_cr
		mov	ax,(int1_int_cw or 8)
		out	dx,ax
		set	vector_d,int_fdc
		and	disk_flags,not disk_in_service
		xor	bx,bx
		mov	cx,4
		xor	ax,ax
ifloop:		mov	w wait_flags[bx],ax
		add	bx,2
		loop	ifloop
		call	disk_reset
		call	ibm_call_init
		mov	al,0ffh
		mov	dx,keyboard_port
		out	dx,al			;set video to text display
		
						;initialize video to get bomb messages
		call	ibm_com1_init
		call	new_call_init
		call	keyboard_init
		call	keyboard_init		;do it twice to make sure we find keyboard
		call	video_init
						;initialize ibm com1 if present
		call	check_8087
		sti
;
		cmp	reset_location,4321h	;monitor start code
		jne	i15
		jmp	moninit			;goto monitor
i15:
		mov	al,79h		 	;BIT IN FLOPPY CONTROLLER FOR HEAD DEBOUNCE
		mov	bx,1			;turn on head settle
		mov	cx,0ffffh		;spin up time in biosdata.asm            
		mov	ah,0
		int	0f8h			;floppy control
		mov	printer_stat,0		;used to initialize ack signal
		mov	dsknum,0			       
		jmp	bootstrap

initialize	endp
;----------------------------------------------------------------
; Misc. functions
;----------------------------------------------------------------
memory_check	proc	near
;
;
		cmp	reset_location,1234h
		jne	mc13
		mov	reset_location,4321h	;goto monitor code
		jmp	short mc14
mc13:		mov	reset_location,0	;cold boot on next reset
mc14:
		mov	dx,sio2_out_set	;signal is inverted
		mov	al,0ffh
		out	dx,al		;set meg board to map 0
		xor	ax,ax		;ax has current memory size in k-bytes
mc1:		mov	bx,ax
		shl	bx,6		;move to bx and convert to segment
		mov	es,bx
		xor	bx,bx
mc2:		mov	cx,es:[bx]
		mov	dx,es:[bx+2]
		mov	es:[bx],05555h
		mov	es:[bx+2],0ffffh
		cmp	es:[bx],05555h
		mov	es:[bx],cx
		jne	mc3
		mov	es:[bx],0aaaah
		mov	es:[bx+2],0ffffh
		cmp	es:[bx],0aaaah
		mov	es:[bx+2],dx
		mov	es:[bx],cx
		jne	mc3
		add	bx,2
		cmp	bx,400h
		jl	mc2
		inc	ax
		jmp	mc1
mc3:		cmp	ax,64
		jae	mc4
		jmp	memtest
mc4:		mov	bx,ax			;save value in bx
		mov	dx,switch_port
		in	al,dx			;check for meg board and adjust size 
		mov	dl,al
		and	dl,switch_mask		;mask out 3 high bits
		cmp	dl,meg_mask
		jne	mc5
		test	al,smem_mask
		jnz	mc6
		cmp	bx,832
		jle	mc6
		mov	bx,832
mc6:		test	al,vmem_mask
		jnz	mc5
		cmp	bx,640
		jle	mc5
		mov	bx,640

mc5:		mov	memory_size,bx		;ibm monitor size
		mov	memsize,bx		;old monitor size
		cmp	reset_location,4321h	;goto monitor code
		je	mc15
		mov	reset_location,1234h	;warm boot on next reset
mc15:		ret
memory_check	endp
		subttl	Concurrent Flags
		page	+
;----------------------------------------------------------------
;  Flag Int
;   ah=function
;     0=wait until flag set then clear flag and return
;     1=set flag
;     2=clear flag         (used only for initialization)
;     3=pop ax and return
;   al=flag number (0-63)
;     functions 0-2 destroy ax,and bx
;----------------------------------------------------------------
flag_int	proc	far
		sti
		or	ah,ah
		jz	wait_flag
		dec	ah
		jz	set_flag
		dec	ah
		jz	clear_flag
		add	sp,6		;pop off callers return address and flags
		pop	ax		;pop ax
		iret
set_flag:	push	ds
		mov	bx,data
		xor	ah,ah
		mov	ds,bx
		mov	bl,8
		div	bl
		xchg	ah,al
		mov	bx,offset drive_mask
		xlat	cs:drive_mask
		mov	bl,ah
		xor	bh,bh
		or	wait_flags[bx],al
		pop	ds
		iret
clear_flag:	push	ds
		mov	bx,data
		mov	ds,bx
		xor	ah,ah
		mov	bl,8
		div	bl
		xchg	ah,al
		mov	bx,offset drive_mask
		xlat	cs:drive_mask
		mov	bl,ah
		xor	bh,bh
		not	al
		and	wait_flags[bx],al
		pop	ds
		iret
wait_flag:	push	ds
		mov	bx,data
		mov	ds,bx
		xor	ah,ah
		mov	bl,8
		div	bl
		xchg	ah,al
		mov	bx,offset drive_mask
		xlat	cs:drive_mask
		mov	bl,ah
		xor	bh,bh
wf_loop:	test	wait_flags[bx],al
		jz	wf_loop
		not	al
		and	wait_flags[bx],al
		pop	ds
		iret

flag_int	endp
		subttl	Serial Ports
		page	+
;----------------------------------------------------------------
;  Serial port write functions.
;    Reads will just access the buffers
;----------------------------------------------------------------
port1_write	proc	near		;char in al to port1
		push	ax		;wait for transmitter ready
;
;
		test	com_hold_enable,1
		jz	p1w3
p1w4:		test	com_hold,1
		jnz	p1w4		;wait for hold to clear
p1w3:		mov	dx,stat_rega
p1w1:		in	al,dx
		test	al,tx_rdy
		jz	p1w1
;
;
		pop	ax
		mov	dx,tx_rega	;output byte
		out	dx,al
		ret
port1_status:
		test	com_hold_enable,1
		jz	p1w5
		test	com_hold,1
		jnz	p1w6		;hold
p1w5:
		mov	dx,stat_rega
		in	al,dx
		test	al,tx_rdy
		mov	al,0
		jnz	p1w2
p1w6:		mov	al,not_ready_error
p1w2:		ret
port1_write	endp
port2_write	proc	near		;char in al to port1
		push	ax		;wait for transmitter ready
;
;
		test	com_hold_enable,10b
		jz	p2w3
p2w4:		test	com_hold,10b
		jnz	p2w4		;wait for hold to clear
p2w3:		mov	dx,stat_regb
p2w1:		in	al,dx
		test	al,tx_rdy
		jz	p2w1
;
;
		pop	ax
		mov	dx,tx_regb	;output byte
		out	dx,al
		ret
port2_status:
		test	com_hold_enable,10b
		jz	p2w5
		test	com_hold,10b
		jnz	p2w6		;hold
p2w5:
		mov	dx,stat_regb
		in	al,dx
		test	al,tx_rdy
		mov	al,0
		jnz	p2w2
p2w6:		mov	al,not_ready_error
p2w2:		ret
port2_write	endp
port3_write	proc	near		;char in al to port1
		push	ax		;wait for transmitter ready
;
;
		test	com_hold_enable,100b
		jz	p3w3
p3w4:		test	com_hold,100b
		jnz	p3w4		;wait for hold to clear
p3w3:		mov	dx,stat_reg2a
p3w1:		in	al,dx
		test	al,tx_rdy
		jz	p3w1
;
;
		pop	ax
		mov	dx,tx_reg2a	;output byte
		out	dx,al
		ret
port3_status:
		test	com_hold_enable,100b
		jz	p3w5
		test	com_hold,100b
		jnz	p3w6		;hold
p3w5:
		mov	dx,stat_reg2a
		in	al,dx
		test	al,tx_rdy
		mov	al,0
		jnz	p3w2
p3w6:		mov	al,not_ready_error
p3w2:		ret
port3_write	endp
port4_write	proc	near		;char in al to port1
		push	ax		;wait for transmitter ready
;
;
		test	com_hold_enable,1000b
		jz	p4w3
p4w4:		test	com_hold,1000b
		jnz	p4w4		;wait for hold to clear
p4w3:		mov	dx,stat_reg2b
p4w1:		in	al,dx
		test	al,tx_rdy
		jz	p4w1
;
;
		pop	ax
		mov	dx,tx_reg2b	;output byte
		out	dx,al
		ret
port4_status:
		test	com_hold_enable,1000b
		jz	p4w5
		test	com_hold,1000b
		jnz	p4w6		;hold
p4w5:
		mov	dx,stat_reg2b
		in	al,dx
		test	al,tx_rdy
		mov	al,0
		jnz	p4w2
p4w6:		mov	al,not_ready_error
p4w2:		ret
port4_write	endp

set_up_port1	proc	near
		mov	duart_base,uart_base		;porta on slicer
		call	set_up_port
		ret
set_up_port1	endp
set_up_port2	proc	near
		mov	duart_base,uart_base+10h      ;port b on slicer
		call	set_up_port
		ret
set_up_port2	endp
set_up_port3	proc	near
		mov	duart_base,uart_base2	      ;porta expansion
		call	set_up_port
		ret
set_up_port3	endp
set_up_port4	proc	near
		mov	duart_base,uart_base2+10h	;portb expansion
		call	set_up_port
		ret
set_up_port4	endp
;
; bl contains setup info as given in newcall.asm
; routine called from there

set_up_port	proc	near

		mov	dx,duart_base
		add	dx,4
		mov	al,1ah
		out	dx,al		;reset mr pointer disable rx tx
		mov	al,2ah
		out	dx,al
		mov	al,3ah
		out	dx,al		;port now reset & disabled

;set mr1 character length and parity

		mov	bh,bl
		and	bh,03	;number of bits per char correct
		test	bl,8
		jz	no_parity   	
		or	bh,8			;force parity
		jmp	set_parity
no_parity:	or	bh,10h	 		;no parity
		jmp	setmr1	  
set_parity:	test	bl,10h
		jnz	setmr1			;even leave bit set to 0
		or	bh,4		       ;set odd parity bit
setmr1:		       
		mov	dx,duart_base
		in	al,dx
		and	al,0e0h			;save rx control, rx int, err mode
		or	bh,al
		mov	al,10h
		mov	dx,duart_base
		add	dx,4
		out	dx,al			;reset mr pointer
		mov	al,bh			; new mr1
		mov	dx,duart_base
		out	dx,al			;set new mr1

;now set stop bits

		test	bl,4
		jz	one_stop
		mov	bh,0fh		;two stop bits
		jmp	setmr2
one_stop:	mov	bh,7
setmr2:		in	al,dx
		and	al,0f0h
		or	al,bh
		out	dx,al
	 
;set baud rate		       
		xor	bh,bh
		shr	bl,5
		push    ds
		mov	ax,cs
		mov	ds,ax
		mov	si,offset baud_table
		add	bx,si
		mov	bl,[bx]
		pop	ds
	      	mov	dx,duart_base
		add	dx,2
		mov	al,bl
		out	dx,al		;set baud rate

;enable communications 			     

		mov	dx,duart_base
		add	dx,4
		mov	al,15h
		out	dx,al 
		ret
baud_table	db	11h,22h,44h,55h,66h,88h,99h,0bbh
set_up_port	endp

ibm_com1_init	proc	near 
		push	bx	 
		push	cx
	     	mov	bx,offset ser_addr
		mov	cx,8
com1_init1:	mov	word ptr [bx],0			;init 40:0-40:f
		add	bx,2				;as IBM would
		loop	com1_init1
		mov	dx,modem_control		;modem control reg
		mov	al,0Bh 				
		out	dx,al
		mov	dx,line_control			;7bits/word no parity dlab=1
		mov	al,82h		
		out	dx,al		     
		mov	dx,modem_control		
		in	al,dx
		cmp	al,0Bh
		jz	tst_com1
		jmp	no_com1
tst_com1:	mov	dx,line_control
		in	al,dx
		cmp	al,82h
		jnz	no_com1
					;THERE IS A IBM SERIAL CARD INITIALIZE 
		or	equip_flag,200h				;com1 is present
	   	mov	ser_addr,3f8h	
		mov	ax,0ch
		mov	dx,divisor_latchl		;divisor latch
		out	dx,al				;9600 baud
		mov	al,0
		mov	dx,divisor_latchm
		out	dx,al
		mov	dx,line_control
		mov	al,3			;8 bits/char no parity dlab=0
		out	dx,al
		mov	dx,interrupt_enable
		mov	al,0	       		; no interrupts 
		out	dx,al			       	     
		
		mov	dx,sasi_stat_port+1
		in	al,dx			;REV D BOARD 
		and	al,3			;INTERRUPT NOT SUPPORTED
		cmp	al,2
		jnz	no_com1			;don't steal interrupt

		mov	dx,0ff3eh			;disable int3
		mov	ax,0fh
		out	dx,ax

		mov	dx,88h		      ;acr & IPCR register on 2681
		in	al,dx
		in	al,dx
		or	al,4
		out	dx,al
		mov	dx,8ah		    ; INTERRUPT MASK ON 2681
		mov	al,0a2h
		out	dx,al					    
		push	es
		mov	ax,0
		mov	es,ax
		
		push	si
		mov	si,offset bomb_c
		mov	bx,30h
		mov	ax,es:[bx]
		cmp	ax,si
		jnz	ex_present
	   	mov	es:[bx],7ffdh		;IRET INSTUCTION	
ex_present:	pop	si
		mov	bx,3ch			;int3 vector
		mov	dx,offset ibm_com_int
		mov	ax,cs			;reset vector for int3
		mov	es:[bx],dx
		mov	es:[bx+2],ax
		pop	es
		mov	dx,0ff3eh
		mov	ax,14h			 ;enable int3
		out	dx,ax      
no_com1:	pop	cx
		pop	bx
		ret
ibm_com1_init	endp	    	     

ibmb_table		dw	417h	;110
		dw	300h	;150
		dw	180h	;300
		dw	0c0h	;600
		dw	60h	;1200
		dw	30h	;2400
		dw	18h	;4800
		dw	0ch	;9600

command		dw	receive
		dw	send
		dw	in_status
		dw	out_status
		dw	bad_command
		dw	init_ibm_port

ibm_serial	proc	far
		push	ds
		push	ax
		mov	ax,cs
		mov	ds,ax
		pop	ax				   
		cmp	al,5					   
		ja	bad_command				   
		push	cx
		mov	di,offset command
		push	bx  
		mov	bl,al
		xor	bh,bh
		shl	bx,1
		add	di,bx
		jmp	word ptr [di]
exit:		pop	bx
		sub	bx,cx
		mov	cx,bx			;characters sent al last char sent
		xor	bl,bl			;for printer status
bad_command:   pop	ds
		ret
ibm_serial	endp
init_ibm_port:  pop	bx
		mov	cl,bl
		mov	al,cl
		and	cl,0e0h
		shr	cl,4
		xor	ch,ch
		and	al,1fh
		or	al,80h			;set dlab = 1
		mov	dx,line_control
		out	dx,al			;set parity and word length
		mov	bx,offset ibmb_table
		add	bx,cx
		mov	ax,[bx]
		mov	dx,divisor_latchl
		out	dx,ax			;set baud rate
		
		mov	dx,line_control
		in	al,dx
		and	al,7fh
		out	dx,al			;set dlab = 0
		mov	dx,interrupt_enable
		xor	al,al
		out	dx,al
		pop	cx
		push	cx
		jmp	exit

send: 		pop	bx	
send1:		mov	dx,modem_control
		mov	al,1
		out	dx,al
		mov	dx,modem_status
		mov	bl,10h
		mov	di,offset cts
		push	di
		jmp	t_out
cts:
		mov	dx,line_status
		mov	bl,20h
		mov	di,offset trans_ready
		push	di
		jmp	t_out
trans_ready:
		mov	dx,transmitter_holding
		lods	byte ptr es:[si]
		out	dx,al
	       	loop	send1
		jmp	exit		

receive:	pop	bx  
receive1:	mov	dx,modem_control
		mov	al,3
		out	dx,al
		mov	dx,line_status
		in	al,dx
		test	al,1
		jnz	get_char
		jmp	receive1
get_char:
		mov	dx,receiver_buffer
		in	al,dx
		mov	es:[si],al
		inc	si
		loop	receive1
		xor	al,al			;status on charatcer writes
		jmp	exit	

out_status:	pop	bx
		mov	dx,line_status
		in	al,dx
		test	al,20h			;test trans holding 1 = empty
		jz	not_r
		xor	al,al
not_r:		jmp	exit

in_status:	pop	bx
		mov	dx,line_status
		in	al,dx
		test	al,1
		jnz	rdy
		mov	al,80h
		jmp	exit
rdy:		mov	al,0
		jmp	exit

t_out		proc	near
		push	cx
		xor	cx,cx
wait1:		in	al,dx
		test	al,bl
		jnz	got_it
		loop	wait1
		pop	cx
		pop	bx
		mov	al,80
		jmp	exit
got_it:		pop	cx
		ret
t_out 		endp


check_8087	proc	near			 
		push	bx
		mov	bx,offset area
		mov	w [bx],0		;set resslt of test to zero
		mov	w [bx+2],0
		mov	bx,offset radius
		mov	w [bx],56419
		mov	w [bx+2],0
		mov	bx,offset scale
		mov	w [bx],10000
		mov	w [bx+2],0
		finit			;initialize 8087
	  	fldpi			;load pi on stack
		fild	scale		;scale factor
		fild	radius
		fdiv	1		;radius/scale
		fmul	0		;square it
		fmul	2		;multiply by pi
		fst	area		;store it in test result area
		mov	bx,area
		or	bx,bx
		jz	no_8087
		or	equip_flag,2	;8087 present
		cmp	bx,13h
		jz	good1
		call	bad8087
		jmp	short no_8087
good1:		mov	bx,area+2
		cmp	bx,42c8h
		jz	good2
		call	bad8087
		jmp	short	no_8087
good2:		call	g8087
no_8087:        pop	bx
		ret
check_8087	endp
			     
badmess		db	'8087 gave bad answer',0dh,0ah
		db	'     '
goodmess	db	'8087 present and working',0dh,0ah
		db	'bring her up to warp speed Scotty',0dh,0ah
		db	'     '

bad8087		proc	near
		pusha
		push	es
		mov	si,offset badmess
		mov	ax,cs
		mov	es,ax
		mov	cx,23
		mov	ax,601h
		int	0f8h
		pop	es
		popa
		ret
bad8087		endp

g8087		proc	near
		pusha
		push	es
		set	vector_2,dummy_int		;NMI
		mov	ax,0
		mov	es,ax
		mov	dx,0a0h				;NMI mask register
		mov	al,80h
		out	dx,al 				;enable NMI interrupts

		mov	si,offset goodmess
		mov	ax,cs
		mov	es,ax
		mov	cx,62
		mov	ax,601h
		int	0f8h
		pop	es
		popa
		ret
g8087		endp


;----------------------------------------------------------------
;  Serial port interupt
;     Gets charecter from uart and puts it in the appropriate buffer.
;----------------------------------------------------------------
;SLICER BOARD INTERRUPT SERVICE ROUTINE
ibm_com_int	proc	far
		push	dx
		push	ax
		mov	dx,88h		;change port register on port 1
		in	al,dx
		test	al,4		;check input pin ip2
		jz	not_ibm_com
		pop	ax		;it is ibm com 1 interrupt
		pop	dx
		sti
		int	0ch		;do ibm com 1 interrupt
		push	dx
		push	ax
		mov	dx,3fch
		in	al,dx
		or	al,8 
		out	dx,al
		mov	dx,0ff22h
		mov	ax,8000h
		out	dx,ax
		pop	ax
		pop	dx
		iret
not_ibm_com:
		pop	ax
		pop	dx
ibm_com_int	endp
		
com_int		proc	far
		sti
		push	ax
		push	bx
		push	dx
		push	ds
		mov	ax,data
		mov	ds,ax
		mov	dx,stat_rega
		in	al,dx
		test	al,rx_rdy		;was it porta on slicer
		jz	com_int_8		;if not check portb
;
		
		mov	dx,rx_rega
		in	al,dx	  		;input char from porta		
		test	com_hold,1		;was last char xoff
		jz	com_int_7		;if not jump
		and	com_hold,not 1		;if so clear hold this int
		jmp	com_int_8		;go check portb
com_int_7:	test	com_hold_enable,1	;are we looking for xoff on this port
		jz	com_int_6		;jump if not
		cmp	al,xoff			;was char xoff
		jne	com_int_6
		or	com_hold,1		;yes set hold this port
		jmp	com_int_8		;go check portb
com_int_6:	mov	bl,port1_head		;not xoff save char in buffer
		xor	bh,bh
		mov	port1_buf[bx],al
		inc	bl
		and	bl,0fh
		mov	port1_head,bl		 ;update buffer pointer
com_int_9:	test	com_flags,com1_waiting
		jz	com_int_8
		mov	ax,102h				;set flag 2
		int	concurrent_int
		and	com_flags,not com1_waiting
com_int_8:
		mov	dx,stat_regb		    ;same as port a
		in	al,dx
		test	al,rx_rdy
		jz	com_int_91
;
		
		mov	dx,rx_regb
		in	al,dx
;
		test	com_hold,10b
		jz	com_int_17
		and	com_hold,not 10b
		jmp	com_int_91
com_int_17:	test	com_hold_enable,10b
		jz	com_int_16
		cmp	al,xoff
		jne	com_int_16
		or	com_hold,10b
		jmp	com_int_91
com_int_16:	mov	bl,port2_head
		xor	bh,bh
		mov	port2_buf[bx],al
		inc	bl
		and	bl,0fh
		mov	port2_head,bl
com_int_19:	test	com_flags,com2_waiting
		jz	com_int_91
		mov	ax,103h			;set flag 3;
		int	concurrent_int
		and	com_flags,not com2_waiting
com_int_91:	mov	dx,eoi_reg
		mov	ax,eoi_cmd
		cli
		out	dx,ax
		mov	dx,is_reg
		in	ax,dx
		and	ax,int_is_mask
		or	ax,ax
		jz	com_int_92
;
		pop	ds
		pop	dx
		pop	bx
		pop	ax		   
		iret
com_int_92:	pop	ds
		pop	dx
		pop	bx
		mov	ax,300h
		int	concurrent_int		;pop ax/iret
com_int		endp

; EXPANSION BOARD SERIAL INTERRUPT SERVIVE ROUTINE

com2_int	proc	far
		sti
		push	ax
		push	bx
		push	dx
		push	ds
		mov	ax,data
		mov	ds,ax
		mov	dx,stat_reg2a
		in	al,dx
		test	al,rx_rdy
		jz	com2_int_8		  ;go check port b on 2681
;
		
		mov	dx,rx_reg2a
		in	al,dx			  ;input char from port a 2681
		test	com_hold,100b		  ;was last char xoff
		jz	com2_int_7
		and	com_hold,not 100b	  ;it was xoff disasble hold
		jmp	com2_int_8		  ;go check next port
com2_int_7:	test	com_hold_enable,100b	  ;are we looking for xoff on this port
		jz	com2_int_6		
		cmp	al,xoff			  ;is character xoff
		jne	com2_int_6
    		or	com_hold,100b		  ;yes set hold this port
		jmp	com2_int_8		;go check next port
com2_int_6:	mov	bl,port3_head		;put char in port 3 buffer
		xor	bh,bh
		mov	port3_buf[bx],al
		inc	bl
		and	bl,0fh
		mov	port3_head,bl		 ;adjust circular buffer
com2_int_9:	test	com_flags,com3_waiting
		jz	com2_int_8
		mov	ax,104h			;set flag 4;
		int	concurrent_int
		and	com_flags,not com3_waiting
com2_int_8:
		mov	dx,stat_reg2b
		in	al,dx
		test	al,rx_rdy
		jz	com2_int_93		;go check sio chip
;
		
		mov	dx,rx_reg2b
		in	al,dx			 ;get char port b 2681
;
		test	com_hold,1000b
		jz	com2_int_17
		and	com_hold,not 1000b
		jmp	com2_int_91
com2_int_17:	test	com_hold_enable,1000b
		jz	com2_int_16
		cmp	al,xoff
		jne	com2_int_16
		or	com_hold,1000b
		jmp	com2_int_91
com2_int_16:	mov	bl,port4_head		 ;put char in buffer
		xor	bh,bh
		mov	port4_buf[bx],al
		inc	bl
		and	bl,0fh
		mov	port4_head,bl		 ; move head to next byte in buffer
com2_int_19:	test	com_flags,com4_waiting
		jz	com2_int_91
		mov	ax,105h			;set flag 5;
		int	concurrent_int
		and	com_flags,not com4_waiting
		
com2_int_91:	  					    ;check for Z8530 ready


com2_int_93:	mov	dx,eoi_reg		    ;END OF INTERRUPT
		mov	ax,eoi_cmd
		cli
		out	dx,ax
		mov	dx,is_reg
		in	ax,dx
		and	ax,int_is_mask
		or	ax,ax
		jz	com2_int_92
;
		pop	ds
		pop	dx
		pop	bx
		pop	ax		   
		iret
com2_int_92:	pop	ds
		pop	dx
		pop	bx
		mov	ax,300h
		int	concurrent_int		;pop ax/iret
com2_int	endp


		subttl	Timer
		page	+
;----------------------------------------------------------------
; Timer interupt
;   Increments time of day counters.  Decrements time_out counters.
;   Turns off disk Drives
;----------------------------------------------------------------
timer		proc	far
		sti
		push	ax
		push	dx
		mov	dx,is_reg		;check if interupt came from the
		in	ax,dx			;timer if it didn't pass it to an
		test	ax,timer_int_mask	;auxiliary handler.
		jnz	t1
		pop	dx
		pop	ax
		int	aux_int13_int
		ret	2
t1:		push	ds
		mov	ax,data
		mov	ds,ax
		add	hundredth,2  
		inc	ibm_timer_cnt
		cmp	ibm_timer_cnt,3
		jl	t5
		mov	ibm_timer_cnt,0
		int	ibm_timer0_int
t5:		cmp	hundredth,100
		jl	timer_cont17
		mov	hundredth,0
		inc	seconds
		cmp	seconds,60
		jl	timer_cont17
		mov	seconds,0
		inc	min
		cmp	min,60
		jl	timer_cont17
		mov	min,0
		inc	hours
		cmp	hours,24
		jl	timer_cont17
		mov	hours,0
		inc	day

timer_cont17:
		test	disk_flags,disk_in_service
		jnz	timer_cont19
		cmp	motor_count1,0
		je	timer_cont18
		dec	motor_count1
		jnz	timer_cont18
		call	motor_off
		call	deselect
timer_cont18:
		cmp	select_count1,0
		jz	t2
		dec	select_count1
		jnz	t2
		call	deselect
		jmp	t2
timer_cont19:
		cmp	disk_time_out1,0
		je	t2
		dec	disk_time_out1
		jnz	t2
		inc	disk_time_out1		;so we can try again if disk can't
		cli		      		;be interupted
		test	disk_flags,interuptable	;terminate disk operation if ok
		jz	not_interuptable	;set proper termination address
		mov	disk_time_out1,0
		cmp	f_state,offset disk_op_end
		je	t3
		mov	f_state,offset disk_op_22
t3:
		or	diskette_status,time_out
		mov	dx,fdc_command
		mov	al,terminate_wi
		out	dx,al
not_interuptable:
		sti


t2:		test	disk_flags,sasi_in_service
		jz	timer_end
		cli
		cmp	hdisk_time_out1,0
		je	timer_end
		dec	hdisk_time_out1
		jnz	timer_end
		or	sasi_status,sasi_time_out
		int	dma1_int			;interupt process

timer_end:	int	aux_timer_int
		mov	dx,eoi_reg
		mov	ax,eoi_cmd
		cli
		out	dx,ax
		mov	dx,is_reg
		in	ax,dx
		and	ax,int_is_mask
		or	ax,ax
		jz	t4			;interupts not nested
		
		pop	ds
		pop	dx
		pop	ax
dummy_int:	iret
t4:		pop	ds
		pop	dx
		mov	ax,300h
		int	concurrent_int		;pop ax/ iret
timer		endp


		subttl	Floppy Disk I/O
		page	+
;----------------------------------------------------------------
; Floppy disk I/O
;    destroys ax, bx, cx, and dx all others unchanged.
;    interupt driven to run concurrently with other programs
;
;----------------------------------------------------------------

ds0		dw	010ah		;drive select addresses
ds1		dw	0108h
ds2		dw	0106h
ds3    		dw	0104h
drive_mask	db	001h
		db	002h
		db	004h
		db	008h
		db	010h
		db	020h
		db	040h
		db	080h

disk_pseudo_int	proc	far			;so disk opperations can
		sti   
		cmp	al,0c0h
		jz	pseudo_int1
		test	al,20h			;be intercepted by MS-DOS 3.2
		jz	pseudo_int1		;in the print command this is
		call	disk_write		;interrupt 0fdh Jonathan 10-8-86
		jmp	short pseudo_intout
pseudo_int1:	call	disk_read
pseudo_intout:	ret	2
disk_pseudo_int	endp
		    


cal_address	proc	near         ;es:bx -> ax = high 4 bits bx = low 16 bits
		mov	ax,es
		mov	dx,ax
		shl	dx,4
		shr	ax,12
		add	bx,dx
		adc	ax,0
		ret
cal_address	endp
;
disk_reset	proc	near
		and	disk_flags,not fop_waiting
disk_reset1:	mov	recal_required,0ffh
		mov	dx,fdc_command
		mov	al,terminate_ni
		out	dx,al
		mov	diskette_status,0
		ret
disk_reset	endp
;
disk_read	proc	near			;general pourpose read.
		pop	f_return		;command in al es:bx->data
						;save return address
		and	disk_flags,not f_nest
disk_read1:	mov	fdc_cmd,al		;entry point for composite commands
		mov	al,head_number
		and	al,1
		shl	al,1
		or	fdc_cmd,al
		call	cal_address
		mov	dx,dma_dh0
		out	dx,ax
		mov	dx,dma_dl0
		mov	ax,bx
		out	dx,ax
		xor	ax,ax
		mov	dx,dma_sh0
		out	dx,ax
		mov	ax,fdc_data
		mov	dx,dma_sl0
		out	dx,ax
		mov	f_dma_cmd,dma_read
		and	disk_flags,not write_status
		jmp	disk_op
disk_read	endp
disk_write	proc	near			;general pourpose write command
		pop	f_return		;command in al es:bx->data
						;save return address
		and	disk_flags,not f_nest
disk_write1:	mov	fdc_cmd,al		;entry point for composite commands
		mov	al,head_number
		and	al,1
		shl	al,1
		or	fdc_cmd,al
		call	cal_address
		mov	dx,dma_sh0
		out	dx,ax
		mov	dx,dma_sl0
		mov	ax,bx
		out	dx,ax
		xor	ax,ax
		mov	dx,dma_dh0
		out	dx,ax
		mov	ax,fdc_data
		mov	dx,dma_dl0
		out	dx,ax
		mov	f_dma_cmd,dma_write
		or	disk_flags,write_status
;		jmp	disk_op
disk_write	endp
;
disk_op		proc	near
		mov	dx,fdc_command
		mov	al,terminate_ni
		out	dx,al
		mov	cx,10			;must delay 10us before reading status reg
do13:		loop	do13
		mov	dx,fdc_status
		in	al,dx			;reset fdc

		mov	dx,int1_int_cr		;enable fdc interupts disable others
		mov	ax,int1_int_cw
		out	dx,ax	      
;		mov	dx,0ff2ah		; mask 
;		mov	ax,1	    
;		out	dx,ax


;----------------------------------------------------------------
;preform command in bl at specified location. DMA cmd in di
;----------------------------------------------------------------
		cli					;has to run with out interuption
		or	disk_flags,disk_in_service	;until first wait so it will not
		and	disk_flags,not interuptable
		mov	ax,disk_time_out		;time out if it is prempted
		mov	disk_time_out1,ax
		mov	diskette_status,0
		cmp	num_of_sectors,0
		jnz	disk_op_15
		jmp	disk_op_end
disk_op_15:
		call	motor_on
		mov	bl,drive_number	       ;recal if needed
		xor	bh,bh
		call	drive_select
		mov	al,disk_track
		test	d_type_0[bx],double_track
		jz	disk_op_16
		shl	al,1
disk_op_16:	mov	drive_track,al
		mov	al,drive_mask[bx]
		test	recal_required,al
		jz	no_recal
		jmp	restore
;----------------------------------------------------------------
;	seek to current track
;----------------------------------------------------------------	
no_recal:
		mov	bl,drive_number
		xor	bh,bh
		mov	al,track_0[bx]
		mov	dx,fdc_track
		out	dx,al
		cmp	al,drive_track		;already there ?
		je	no_seek
		mov	al,drive_track		;save where we will be.
		mov	track_0[bx],al
		jmp	seek			;seek to new track only
						;if needed
;----------------------------------------------------------------
;	ok, now we are over the right track.
;	perform desired operations.
;----------------------------------------------------------------
no_seek:	mov	f_state,offset disk_op_done
		mov	bl,drive_number
		xor	bh,bh
		mov	dx,mini_sel           ;switch to 5" or 8" mode
		mov	al,1
		test	d_type_0[bx],mini
		jnz	is_mini
		mov	al,0
is_mini:	out	dx,al
		mov	dx,dbl_den_sel
		mov	al,1
		test	d_type_0[bx],double_density
		jz	not_dbl_den
		mov	al,0
not_dbl_den:	out	dx,al

		mov	cl,d_type_0[bx]
		and	cl,sector_size_m
		shr	cl,2
		mov	ax,80h
		shl	ax,cl
		mov	sector_size,ax

		call	wait_fdc_ready
		mov	dx,fdc_track
		mov	al,disk_track
		out	dx,al
		mov	dx,fdc_sector
		mov	al,sector_number
		out	dx,al
		mov	al,num_of_sectors
		xor	ah,ah
		mul	sector_size
		mov	dx,dma_tc0
		out	dx,ax
		mov	ax,f_dma_cmd
		mov	dx,dma_cr0
		out	dx,ax
		mov	al,fdc_cmd
		mov    	dx,fdc_command
		cli
		out	dx,al
		jmp	wait_done		;wait for operation to finish

disk_op_done:	mov	dx,dma_tc0		;compleation entry point
		in	ax,dx
		xor	dx,dx
		div	sector_size
		or	dx,dx
		jz	disk_op_21
		inc	al
disk_op_21:
		sub	num_of_sectors,al	;number of sectors transfered
		jmp	short disk_op_23

;----------------------------------------------------------------
;	test error codes
;----------------------------------------------------------------
disk_op_22:	mov	num_of_sectors,0	;alternate compleation entry point
disk_op_23:	mov	al,temp			;fdc status into al
		test	disk_flags,write_status
		jz	j9			;only set for write operations
		test	al,40h
		jz	j9
		or	diskette_status,write_protect
j9:		test	al,001000b
		jz	j6
		or	diskette_status,bad_crc
j6:		test	al,80h
		jz	j8
		or	diskette_status,time_out
j8:		test	al,10h
		jz	disk_op_end
		or	diskette_status,record_not_fnd
disk_op_end:	and	disk_flags,not disk_in_service
		mov	disk_time_out1,0
		mov	dx,int1_int_cr
		mov	ax,(int1_int_cw or 8)		;disable fdc interupts
		out	dx,ax					
;		mov	dx,0ff2ah			;unmask keyboard if present
;		mov	ax,6h			;interrupts
;		out	dx,ax
;no_keyboard:
		jmp	[f_return]
disk_op		endp
;----------------------------------------------------------------
; DMA interupt handler.
;    Disables DMA transfers, interupts FDC, and returns
;----------------------------------------------------------------
int_dma0	proc	far
		push	ax
		push	dx
		push	ds
		mov	ax,data
		mov	ds,ax
		mov	dx,dma_cr0
		mov	ax,disable_dma
		out	dx,ax
;delay added 7/12/84 00:54:23 JPS
		push	cx		;delay insures 192 us. delay so crc bytes
		mov	cx,90		;can be written
self:		loop	self
		pop	cx
;
		mov	dx,fdc_command
		mov	al,terminate_wi
		out	dx,al
		mov	dx,eoi_reg
		mov	ax,eoi_cmd
		out	dx,ax
		pop	ds
		pop	dx
		pop	ax
		iret
int_dma0	endp
;----------------------------------------------------------------
;FDC interupt handler.
;   Gets status into temp, enables FDC, disables DMA, and starts
;   the next phase of the disk operation.  If the operation is finished
;   does a set flag call and return through the flag wait return.
;----------------------------------------------------------------
int_fdc		proc	far
		push	ax
		push	bx
		push	cx
		push	dx
		push	ds
		mov	dx,fdc_status
		in	al,dx
		mov	cl,al			;save status in cl
		mov	dx,fdc_command
		mov	al,terminate_ni
		out	dx,al
		mov	ax,data
		mov	ds,ax			;must read status again to clear interrupt
		mov	temp,cl			;save original status in temp
		mov	cx,29			;must delay 56us before reading status reg
if13:		loop	if13
		mov	dx,fdc_status
		in	al,dx
		mov	dx,dma_cr0
		mov	ax,disable_dma
		out	dx,ax
		mov	dx,eoi_reg
		mov	ax,eoi_cmd
		out	dx,ax
		and	disk_flags,not interuptable
simulate_fdc_int:
		test	disk_flags,f_nest
		jnz	if1
		cmp	f_state,offset disk_op_done
		je	if2
		cmp	f_state,offset disk_op_22
		jne	if1


if2:		and	disk_flags,not fop_waiting
		mov	ax,100h
		int	concurrent_int		;set flag 0

		mov	dx,is_reg
		in	ax,dx
		and	ax,int_is_mask
		or	ax,ax
		jz	wd1			;interupts not nested

		pop	ds
		pop	dx
		pop	cx
		pop	bx
		mov	ax,300h
		int	concurrent_int		;pop ax iret
;
if1:
		sti
		jmp	[f_state]		;start next phase of disk op
;
wd1:		pop	ds
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		iret
int_fdc		endp
;----------------------------------------------------------------
; Wait done checks to see if a floppy operation is in progress.
; If it is it does a return from interupt sequence.  If it is not
; it does a wait flag call.
;----------------------------------------------------------------
wait_done	proc	near			;interupts disabled on entry
		or	disk_flags,interuptable	;allow disk time out to happen
		test	disk_flags,fop_waiting
		jnz	wd1			;wd1 is in int_fdc
		or	disk_flags,fop_waiting
		sti
		mov	ax,0			;wait for flag 0
		int	concurrent_int
		jmp	[f_state]		;has termination address
wait_done	endp

wait_fdc_ready	proc	near
		mov	dx,fdc_status
busy_loop:	in	al,dx
		test	al,1
		jnz	busy_loop
		ret
wait_fdc_ready	endp
		
;----------------------------------------------------------------
; Restore R/W head to track 0
;----------------------------------------------------------------
restore		proc	near			;si has drive #
		mov	f_state,offset r1
		call	wait_fdc_ready
		mov	dx,mini_sel		;switch to 8" mode to enable 3ms
		mov	al,0			;step time.
		out	dx,al
;
		mov	dx,fdc_command
		mov	al,d_type_0[bx]
		and	al,step_rate_m
		or	al,restore_cmd
		cli
		out	dx,al
		jmp	wait_done
;
r1:		mov	al,temp
		test	al,0100b
		jnz	r2
		or	diskette_status,bad_seek
		mov	f_state,offset disk_op_22
		jmp	simulate_fdc_int
r2:							;CHANGED BY JONATHAN 5/21/86
		mov	bl,drive_number
		xor	bh,bh
		mov	al,drive_mask[bx]
		not	al
		and	recal_required,bl
		mov	track_0[bx],0			;current track number.
		jmp	no_recal

restore		endp
;----------------------------------------------------------------
; Seeks R/W heads to track in al
;----------------------------------------------------------------
seek		proc	near                  ;al has new track # si has drive
		mov	f_state,offset no_seek
		push	ax
		call	wait_fdc_ready
		mov	dx,mini_sel           ;switch to 8" mode to enable 3ms
		mov	al,0                  ;step time.
		out	dx,al
;
		mov	dx,fdc_data
		pop	ax
		out	dx,al
		mov	dx,fdc_command
		mov	al,d_type_0[bx]
		and	al,step_rate_m
		or	al,seek_cmd
		cli
		out	dx,al
		jmp	wait_done
seek		endp
;----------------------------------------------------------------
; Turn on disk motors.
;----------------------------------------------------------------
motor_on	proc	near	  
		mov	ax,motor_count
		mov	motor_count1,ax
		mov	al,motor_ctl
		out	sio_out_clr,al
		test	settle,80h          ;is motor on
		jnz	motor_go            ;jump if on
		push	cx
		mov	cx,spin_up
motor_lp: 	nop		       ;about 4 tenth of a second
		nop		       ; if cx = ffff like on boot
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		loop	motor_lp	;might want concourent interrupt
		or	settle,80h	;no spin up until after motor off
		pop	cx
motor_go:	ret
motor_on	endp
;----------------------------------------------------------------
; Turn off disk motors.
;----------------------------------------------------------------
motor_off	proc	near
		mov	al,motor_ctl
		out	sio_out_set,al
		and	settle,7fh 	;reset to spin up next time
		ret
motor_off	endp
;----------------------------------------------------------------
; Select disk drive (disk number in bx).
;----------------------------------------------------------------
drive_select	proc	near
		mov	ax,select_count
		mov	select_count1,ax
		call	deselect
		shl	bx,1
		mov	dx,ds0[bx]
		shr	bx,1
		mov	al,1
		out	dx,al
		ret
drive_select	endp
;----------------------------------------------------------------
; Deselect all disk drives.
;----------------------------------------------------------------
deselect	proc	near
		mov	al,0
		mov	dx,ds0
		out	dx,al
		mov	dx,ds1
		out	dx,al
		mov	dx,ds2
		out	dx,al
		mov	dx,ds3
		out	dx,al
		ret
deselect	endp
		subttl	Hard Disk I/O
		page	+
;-------------------------------------------------------------
;    Sasi I/O
;    ah=0     reset system
;    ah=1     read blocks into memory
;    ah=2     write blocks from memory
;       bp:si=command block
;       es:bx=data blocks
;       cx=block count
;       dx=block size
;
;**************************************************************
;        RETURNS
;
;        al=status
;          0=no error
;          1=op error (error occoured during operation)
;          2=fatal error (controler out of sync)
;          ff=time out
;        cx=number of blocks xfered
;
;
;
;------------------------------------------------------------
sasi_io		proc	near
		pop	sasi_return		;save return address
		and	disk_flags,not sasi_nest
sasi_io1:
		mov	sasi_xfer_count,cx
		mov	sasi_xfer_count1,cx
		mov	sasi_cmd,ah
		or	ah,ah
		jnz	sio1
		call	hd_reset
		and	disk_flags,not sop_waiting
		jmp	sio_end1
sio1:		call	hd_select
		or	al,al
		jz	sio2
		mov	al,0ffh			;time out has occoured
		or	sasi_status,time_out
		xor	cx,cx
		jmp	sio_end1
sio2:		mov	sasi_status,0
		mov	sasi_block_size,dx
		mov	ax,es			;adjusts es:bx for no wraparound
		mov	dx,bx
		and	bx,0fh
		shr	dx,4
		add	ax,dx
		mov	sasi_es_temp,ax
		mov	sasi_bx_temp,bx
		mov	sasi_bp_temp,bp
		mov	sasi_si_temp,si
		mov	ax,0ffffh		;dummy address
		mov	dx,dma_dh1
		out	dx,ax
		mov	dx,dma_dl1
		out	dx,ax
		mov	dx,dma_sh1
		out	dx,ax
		mov	dx,dma_sl1
		out	dx,ax
		mov	dx,dma_tc1
		mov	ax,1
		cli
		out	dx,ax			;count of 1 to interupt on first
						;request
		mov	dx,dma_cr1
		mov	s_state,offset send_command
		mov	ax,hdisk_time_out
		mov	hdisk_time_out1,ax
		mov	ax,sasi_dma
		or	disk_flags,sasi_in_service
		out	dx,ax
		test	disk_flags,sop_waiting
		jz	sio4
		jmp	si2			;already waiting must be nested operation
						;restore registers and iret
sio4:		or	disk_flags,sop_waiting
		mov	ax,1
		int	concurrent_int		;wait for flag 1
		jmp	sio16			;exit sio


send_command:	cld
		mov	es,sasi_bp_temp			;setup segment from bp
		mov	si,sasi_si_temp
		mov	cx,6
sc_loop:
		mov	dx,sasi_stat_port
		in	ax,dx
		test	ax,request
		jz	sc_loop			;wait for request
		and	ax,status_mask
		cmp	ax,command_block1
		je	sc1
		or	sasi_status,fatal_error
		jmp	sc_end
sc1:		lods	b es:[si]
		mov	dx,sasi_data_port
		out	dx,al
		loop	sc_loop
sc_end:
		cmp	sasi_xfer_count1,0
		jne	sio13			;no transfers
		jmp	sio5
sio13:
		mov	al,sasi_cmd
		dec	al
		jz	sasi_read
		dec	al
		jz	sasi_write
		mov	sasi_xfer_count1,0
		mov	sasi_xfer_count,0
		or	sasi_status,fatal_error
		jmp	sio_end1
sasi_read:
		mov	dx,dma_tc1
		mov	ax,1
		cli
		out	dx,ax			;count of 1 to interupt on first
						;request
		mov	dx,dma_cr1
		mov	s_state,offset sio6
		mov	ax,sasi_dma
		out	dx,ax
		jmp	si2			;wait for interupt

sio6:		mov	di,sasi_bx_temp		;interupt activated 
		mov	es,sasi_es_temp
		mov	cx,sasi_block_size
sasi_read_loop:	mov	dx,sasi_stat_port
		in	ax,dx
		test	ax,request
		jz	sasi_read_loop
		and	ax,status_mask
		cmp	ax,data_block_to
		jne	sio5
		mov	dx,sasi_data_port
		ins	b [di],dx
		loop	sasi_read_loop
		mov	sasi_bx_temp,di
		dec	sasi_xfer_count
		jz	sio5
		jmp	sasi_read
				 

sasi_write:

		mov	dx,dma_tc1
		mov	ax,1
		cli
		out	dx,ax			;count of 1 to interupt on first
						;request
		mov	dx,dma_cr1
		mov	s_state,offset sio66
		mov	ax,sasi_dma
		out	dx,ax
		jmp	si2			;wait for interupt

sio66:		mov	si,sasi_bx_temp		;interupt activated 
		mov	es,sasi_es_temp
		mov	cx,sasi_block_size
sasi_write_loop:
		mov	dx,sasi_stat_port
		in	ax,dx
		test	ax,request
		jz	sasi_write_loop
		and	ax,status_mask
		cmp	ax,data_block_fro
		jne	sio5
		mov	dx,sasi_data_port
		outs	dx,b es:[si]
		loop	sasi_write_loop
		mov	sasi_bx_temp,si
		dec	sasi_xfer_count
		jz	sio5
		jmp	sasi_write

sio5:
		mov	dx,dma_tc1
		mov	ax,1
		cli
		out	dx,ax			;count of 1 to interupt on first
						;request
		mov	dx,dma_cr1
		mov	s_state,offset sio55
		mov	ax,sasi_dma
		out	dx,ax
		jmp	si2			;wait for interupt

sio55:		call	hd_wait_req		;finish hand shaking
		and	ax,status_mask
		cmp 	ax,status_byte
		je	sio11
		or	sasi_status,fatal_error
		jmp	short sio_end
sio11:		mov	dx,sasi_data_port
		in	al,dx
		test	al,010b
		jz	sio12
		or	sasi_status,non_fatal_error
sio12:		
		mov	dx,dma_tc1
		mov	ax,1
		cli
		out	dx,ax			;count of 1 to interupt on first
						;request
		mov	dx,dma_cr1
		mov	s_state,offset sio122
		mov	ax,sasi_dma
		out	dx,ax
		jmp	si2			;wait for interupt
sio122:		call	hd_wait_req
		and	ax,status_mask
		cmp	ax,message_byte
		je	sio14
		or	sasi_status,fatal_error
		jmp	short sio_end
sio14:		mov	dx,sasi_data_port
		in	al,dx
sio_end:	call	hd_deselect
		test	disk_flags,sasi_nest
		jnz	sio16
		and	disk_flags,not sop_waiting
		mov	ax,101h
		int	concurrent_int		;set flag 1
		jmp	si5

sio16:
		mov	cx,sasi_xfer_count1
		sub	cx,sasi_xfer_count
sio_end1:	and	disk_flags,not sasi_in_service
		mov	al,sasi_status
		jmp	[sasi_return]
sasi_io		endp
;----------------------------------------------------------------
;  DMA1 Interupt
;   disables dma1 sets sop_waiting
;----------------------------------------------------------------
int_dma1	proc	far
		sti
		cld
		push	ax
		push	bx
		push	cx
		push	dx
		push	si
		push	bp
		push	es
		push	ds
		mov	ax,data
		mov	ds,ax
		mov	dx,dma_cr1
		mov	ax,disable_dma
		out	dx,ax
		mov	dx,is_reg
		in	ax,dx
		test	ax,dma1_int_mask
		jz	simulate_sasi_int	;must have timed out
		mov	dx,eoi_reg
		mov	ax,eoi_cmd
		out	dx,ax

simulate_sasi_int:
		cmp	sasi_status,0ffh
		jne	si6
		call	hd_reset
		jmp	sio16
si6:		jmp	s_state
;
;
si5:		mov	dx,is_reg
		in	ax,dx
		and	ax,int_is_mask
		or	ax,ax
		jnz	si2			;nested int just do an iret
		pop	ds
		pop	es
		pop	bp
		pop	si
		pop	dx
		pop	cx
		pop	bx
		mov	ax,300h
		int	concurrent_int		;pop ax iret
;
si2:		pop	ds
		pop	es
		pop	bp
		pop	si
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		iret
int_dma1	endp



hd_reset	proc	near
		call	hd_deselect
		mov	dx,sasi_reset_port
		mov	al,0
		out	dx,al
		mov	al,0ffh
		out	dx,al
		mov	dx,dma_cr1
		mov	ax,disable_dma
		out	dx,ax
		ret
hd_reset	endp		

hd_wait_req	proc	near
		mov	dx,sasi_stat_port
		in	ax,dx
		test	ax,request
		jz	hd_wait_req
		ret
hd_wait_req	endp
hd_select	proc	near
		push	dx
		push	cx
		push	ax
		mov	ax,0001h
		mov	dx,sasi_stat_port
		out	dx,ax
		mov	al,0
		mov	dx,sasi_sel_port
		out	dx,al
		mov	dx,sasi_stat_port
		mov	cx,1000
sel_loop:	in	ax,dx
		test	ax,selected
		loopz	sel_loop
		pop	ax
		xor	al,al
		or	cx,cx
		jnz	hds1
		mov	al,sasi_time_out
		
hds1:
		pop	cx
		pop	dx
		ret
hd_select	endp
hd_deselect	proc	near
		mov	al,0ffh
		mov	dx,sasi_sel_port
		out	dx,al
		ret
hd_deselect	endp

code		ends
		end


