$title(Bootstrap First Stage)
$genonly
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;	TITLE:		bs1.inc
;			Bootstrap first stage code and configuration macros
;
;	DATE:		25 Sept 1985
;
;	ABSTRACT:	Include file to generate bootstrap first stage.
;			Generates code for setup and to call options,
;			and generates device table.
;
;	Set tabs = 8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
stacksize	equ	256

		extrn	bserror: far		; bootstrap error routine

NULL		EQU	0

code		segment	public 'CODE'

code		ends

boot		segment	public 'BOOT'

second_stage	label	far

boot		ends

stack		segment	stack 'STACK'
		db	stacksize dup (?)

stack		ends

data		segment	public 'DATA'

dummy_file_name		label	byte
second_stage_ptr	label	dword
second_stage_o	dw	?
second_stage_s	dw	?

		public	inhibit_co
inhibit_co	db	?

data		ends

		assume cs:code, ss:stack, ds:data

code		segment	
			;
%SET(is_cico, 0)
%*DEFINE(cico) (
    %SET(is_cico, -1)
)

%SET(sdm_base,0F000H)
%DEFINE(cpu_type) (8086)
%DEFINE(delay) (0F00H)
%*DEFINE(cpu(ctype)) (
	%DEFINE(cpu_type) (%ctype)
	%IF (%EQS(%cpu_type,8086))  THEN (%DEFINE(delay) (0800H)) 
	ELSE (%IF (%EQS(%cpu_type,8088))  THEN (%DEFINE(delay) (0600H)) 
	ELSE (%IF (%EQS(%cpu_type,80186)) THEN (%DEFINE(delay) (0D00H)) 
	ELSE (%IF (%EQS(%cpu_type,80188)) THEN (%DEFINE(delay) (0600H)) 
	ELSE (%IF (%EQS(%cpu_type,80286)) THEN (%DEFINE(delay) (0F00H))
	ELSE (%IF (%EQS(%cpu_type,80386)) THEN (%DEFINE(delay) (3C00H))
	ELSE (%IF (%EQS(%cpu_type,80486)) THEN (%DEFINE(delay) (3F00H))
	FI) FI )FI )FI )FI )FI )FI
)

%SET(clear_ext, 0)	;set to false
%*DEFINE(clear_sdm_extensions) (
	%SET(clear_ext, -1)	%'set to true'
)

%'	TRIM and ARG are utility macros
%'
%'  TRIM(a) - returns the input parameter trimmed of leading and
%'	 trailing blanks.
%*DEFINE(TRIM(a)) LOCAL x y (%MATCH( x y)(%a)%x)%'
%' 
%'   ARG -  gets the next comma-delimited arg from variable named TAIL,
%'	stripped and trimmed.  Any macro that has a valid type of NONE
%'	uses this macro so that the other parameters are not needed.
%*DEFINE(ARG) LOCAL a (%MATCH(a,tail)(%tail)%TRIM(%a))%'
%' 
%'
%DEFINE(extrn_list) ()
%'
%*DEFINE(external(target,extrn_type)) LOCAL a b (%'
%MATCH(a,b)(%extrn_list)%'
%'
%SET(result,-1)%'
%WHILE(%LEN(%a) NE 0) (%'
%'	'%IF(%EQS(%target,%a)) THEN(%'
%'		'%SET(result,0)%'
%'	')FI %'
%'
%'	'%MATCH(a,b)(%b)%'
)%'
%'
%IF(%result) THEN(%'
%'	'%DEFINE(extrn_list) (%target,%extrn_list) %'
%'	'%IF(%EQS(%extrn_type,far)) THEN(%'
code	ends
	extrn	%target	: %extrn_type
code	segment
%'	') ELSE(%'
	extrn	%target	: %extrn_type
%'	')FI %'
)FI %'
%'
)
%'
%' TITLE: system_120_init
%' INPUTS: None
%' OUTPUTS: System 120 initialization code.
%' ABSTRACT: This macro sets up the initialization code for the System 120.
%' *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
%*DEFINE(system_120_INIT)(%'
%SET(sdm_base, 0E000H)
SDM_OFFSET		equ	0FFF0H
INIT_POLLTIMES		equ	0FFFFH
ENTER_SDM_FLAG		equ	00H
ENTER_FIRSTSTAGE_FLAG	equ	01H
RET_TO_BIOS_FLAG	equ	02H
%'
code	ends
system_120_seg	segment	AT 0E000H

	dw	0AA55H
	db	0FFH

; at 0e000:0003 - entrypoint for 120 initialization code from ROM BIOS
	jmp	far ptr boot_init_120

; at 0e000:0008 - entrypoint for boot command from SDM
	jmp	far ptr bootstrap_entry

system_120_seg	ends

code	segment

	public	boot_init_120
boot_init_120	proc	far

;int 3

	pushf
	cli
	push	ax			; save regs in case we must return to
	push	bx			; ROM BIOS
	push	cx
	push	dx
	push	si
	push	di
	push	bp
	push	ds	
	push	es
	mov	ax,data
	mov	ds,ax			;set up BSL data segment

	mov	polltimes, INIT_POLLTIMES
	sub	sp, 4

	%external(auto_device_select,near)
	call	auto_device_select	; call auto procedure
	add	sp, 4
	or	ax, ax			; device found?
	jz	ret_to_BIOS

	cmp	dl, RET_TO_BIOS_FLAG
	je	ret_to_BIOS

	cmp	dl, ENTER_SDM_FLAG
	jne	enter_firststage

	mov	ax, %sdm_base
	push	ax
	mov	ax, SDM_OFFSET
	push	ax

;jmp firststage

	ret

ret_to_BIOS:
	pop	es			;restore all saved registers
	pop	ds
	pop	bp
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	popf
	ret

enter_firststage:
	lea	bx, dummy_file_name
	mov	byte ptr [bx], CR
	mov	ax, bx
	mov	dl, 0FFH		; load inhibit_co flag
	jmp	s120_begin

boot_init_120	endp
)%'
%'
%'
%' TITLE: iAPX_186_init
%' INPUTS: RELO - a boolean for whether to put the 186 PIC into RMX mode
%'	 and the register values for UMCS,LMCS,MPCS,MMCS,and PACS
%' OUTPUTS: public variables for the chip select registers
%' ABSTRACT: This macro sets up the public variables for programming
%' 	the 5 iAPX_186 chip select registers.  Assumes Relo Reg will
%'	not be moved.
%' *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
%*DEFINE(iAPX_186_INIT(parameters))(%DEFINE(tail)(%parameters)%'
%'
%IF ((%NES(%cpu_type,80186)) AND (%NES(%cpu_type,80188))) THEN (%'
ERROR -- CPU type is not 80186 or 80188
) ELSE (%'
;
;	This procedure sets up the chip select registers for
;	the 80186/8.  It must be executed before the execution leaves 
;	the top 1K of memory.
;
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

boot_186_init	segment	at 0fff0h

	assume	cs:boot_186_init,ds:boot_186_init
	public	firststage_186

firststage_186	proc far
	cli

%IF (%is_bist) THEN (%'Initialize the 186 before and after the bist runs
	mov	bx,boot_186_init

	mov	es,bx			; the segment value is still in bx
	mov	bx,offset init186_table	; point to the init table

init_loop_1:
	mov	dx,es:[bx]		; set up the port
	cmp	dx,NULL			; a null port will terminate the loop.
	je	init_finished_1
	mov	ax,es:[bx+2]		; get the programming value
	out	dx,ax			; initialize the register
	add	bx,4			; point to the next table entry.
	jmp	init_loop_1		; do the next output

init_finished_1:
$include(:F1:bbist.inc)
) FI
	mov	bx,boot_186_init

	mov	es,bx			; the segment value is still in bx
	mov	bx,offset init186_table	; point to the init table

init_loop_2:
	mov	dx,es:[bx]		; set up the port
	cmp	dx,NULL			; a null port will terminate the loop.
	je	init_finished_2
	mov	ax,es:[bx+2]		; get the programming value
	out	dx,ax			; initialize the register
	add	bx,4			; point to the next table entry.
	jmp	init_loop_2		; do the next output

init_finished_2:
	jmp	far ptr continue_186		; enter the firststage

firststage_186	endp

init186_table:
%DEFINE(rmx_v)(%ARG)%'
%IF ((%EQS(%rmx_v,Y)) OR (%EQS(%rmx_v,y)) OR (%EQS(%rmx_v,YES)) OR (%EQS(%rmx_v,yes)) ) THEN (%'
	DW	0fffeh
	DW	40ffh
)FI%'
%DEFINE(umcs_v)(%ARG)%'
%IF ((%NES(%umcs_v,NONE)) AND (%NES(%umcs_v,none))) THEN (%'
	DW	0ffa0h
	DW	%umcs_v
)FI%'
%DEFINE(lmcs_v)(%ARG)%'
%IF ((%NES(%lmcs_v,NONE)) AND (%NES(%lmcs_v,none))) THEN (%'
	DW	0ffa2h
	DW	%lmcs_v
)FI%'
%DEFINE(mpcs_v)(%ARG)%'
%IF ((%EQS(%mpcs_v,NONE)) OR (%EQS(%mpcs_v,none))) THEN (%'
%'	'%SET(mpcs_v,0)%'
)FI%'
%DEFINE(mmcs_v)(%ARG)%'
%IF ((%NES(%mmcs_v,NONE)) AND (%NES(%mmcs_v,none))) THEN (%'
%'	'%IF (%EQS(%mpcs_v,0)) THEN (%'
ERROR -- MPCS register must be initialized to program the MMCS register
%'	') ELSE (%'
	DW	0ffa8h
	DW	%mpcs_v
	DW	0ffa6h
	DW	%mmcs_v
)FI )FI%'
%DEFINE(pacs_v)(%ARG)%'
%IF ((%NES(%pacs_v,NONE)) AND (%NES(%pacs_v,none))) THEN (%'
%'	'%IF (%EQS(%mpcs_v,0)) THEN (%'
ERROR -- MPCS register must be initialized to program the PACS register
%'	') ELSE (%'
	DW	0ffa8h
	DW	%mpcs_v
	DW	0ffa4h
	DW	%pacs_v
)FI )FI )FI%'
	DW	0
	DW	0

boot_186_init	ends
		assume	cs:code, ss:stack, ds:data
%'
)%'	END OF THE iAPX_186_INIT MACRO.
	
bootstrap_entry		label	far
	public	bootstrap_entry	; entry for SDMs
	xor	dl, dl		; clear inhibit_co flag
	pop	ax  		; return address
	pop	ax
	pop	di		; will change to BX later
	pop	es
	jmp	setup_reg  	; get ptr to cmd line

bootstrap_begin		label	far
	public  bootstrap_begin ; entry for SCT
	xor	dl, dl		; clear inhibit_co flag

s120_begin		label	far	; entry for system 120 BSL
	mov	di,ax		; will change to BX later
	mov	ax,ds
	mov	es,ax

setup_reg:

	mov	ss, cs: stackseg	; load stack segment
	mov	sp, stacksize		; load stack pointer

	assume	ss:stack, ds:data

	mov	ds, cs: dataseg		; load data segment
	mov	inhibit_co, dl		; load global flag used by monitor CO xface
	mov	bx,di			; return name pointer to ES:BX
	jmp	got_name

firststage	label	far		; first stage starts here
	public	firststage

	cli				; disable interrupts
	jmp	setup

	db	43H,6FH,70H,79H,72H,69H,67H,68H,74H
	db	' 1980 - 1991 Intel Corporation '
	db	'program_version_number=V8.3program_name=iRMX Bootstrap Loader',0


setup:
	
%IF (%is_bist) THEN (%'
$include(:f1:bbist.inc)
) FI

continue_186:				; jumped to by 186 init- bypass bist
	cli				; disable interrupts
	cld				; clear the direction flag in case SDM
					; is not around

%IF (%is_auto_config_mem) THEN (%'
	mov	al, 0F8H		; Set reset complete bits in the
	out	34H, al			; control/status register of the
	out	31H, al			; PSB control record.             
	mov	al, 0A4H		; Record type = 6; register = 29H.
	out	30H, al			; The values output must change if the 
	xor	ax, ax			; interconnect registers on the processor  
	out	3CH, al			; board  change. 

	mov	al, 0			; The values output must change if the
	out	34H, al			; interconnect registers on the CSM
	out	31H, al			; board change.
	mov	al, 0F0H		; Turn off error light on CSM board.
	out	30H, al			; Record type = FEH; register = 3CH
	mov	al, 40H
	out	3CH, al

	mov	ax, 080H
	mov	ss, ax			; load stack segment for onboard mem
	mov	sp, stacksize		; load stack pointer
	mov	ds, ax			; load data segment for onboard mem
) ELSE	(%'	
	mov	ss, cs: stackseg	; load stack segment
	mov	sp, stacksize		; load stack pointer
	mov	ds, cs: dataseg		; load data segment
	mov	inhibit_co, 0		; load global flag used by montior CO xface
) FI
	jmp	startup

%SET(is_loadfile, 0)
%*DEFINE(loadfile) (
	%SET(is_loadfile, -1)
)
%SET(is_console, 0)
%*DEFINE(console) (
	%SET(is_console, -1)
)
%SET(is_manual, 0)
%*DEFINE(manual) (
	%SET(is_manual, -1)
	%SET(is_console, -1)
	%SET(device_select, -1)
)
%SET(is_auto, 0)
%*DEFINE(auto) (
	%SET(is_auto, -1)
	%SET(device_select, -1)
)
%DEFINE(default_fn) ('/system/rmx86',0)
%*DEFINE(defaultfile(fn)) (
	%DEFINE(default_fn) (%fn, 0)
)

%DEFINE(times) (0)
%*DEFINE(retries(r)) (
	%DEFINE(times) (%r+1)
)

%SET(device_select, 0)
%SET(first_device, -1)

%*DEFINE(device(parameters))(%DEFINE(tail)(%parameters)%'
%SET(uinfo_exists, -1)
%DEFINE(name) (%ARG)
%DEFINE(unit) (%ARG)
%DEFINE(device_init) (%ARG)
%DEFINE(device_read) (%ARG)
%DEFINE(unit_info) (%ARG)
%IF (%LEN (%unit_info) EQ 0) THEN (
%'	'%DEFINE(unit_info)(0)
)ELSE(%'
%'	'%external(%unit_info,far)
) FI
%'
%external(%device_init,far)	;
%external(%device_read,far)	;

$include(:f1:bs1dev.inc)
)
%*DEFINE(end) (

	%IF (%device_select) THEN (
	db	0FFH			; terminate table
	) FI

default_file	label	byte
	public	default_file
	db	%default_fn

	%IF (%is_console) THEN (
bs_echo		label	byte			; Echo for Delete
	public	bs_echo			;
	db	bs_echo_end-bs_echo-1	;
	db	08H, 020H, 08H		;
bs_echo_end	label	byte			;
						;
can_echo	label	byte			; Echo for Cancel (CNTL/X)
	public	can_echo		;
	db	can_echo_end-can_echo-1	;
	db	'#', 0DH, 0AH		;
can_echo_end	label	byte			;
						;
prompt		label	byte			; Prompt character
	public	prompt			;
	db	'*'			;
	) FI
			public	sdm_config_table
sdm_config_table	dw	0FF80H, %sdm_base

			public	dmon_config_table
dmon_config_table	dw	0000H, 0040H

code		ends


%IF (%is_copy) THEN (%'

MODE		equ	0000010000000001B	;specifies system wide params for adma
ADMASTART	equ	10010B			;start command word for GCR
MEMXFER		equ	1100000011011101B	;channel command for command blk
GMR_PORT	equ	0208H			;gmr port address
GCR_PORT	equ	0200H			;gcr port address
GSR_PORT	equ	0204H			;gsr port address
CPRL0_PORT	equ	0220H			;cprl0 port address
CPRH0_PORT	equ	0222H			;cprh0 port address
STAT0		equ	03H			;status bits for channel 0
COPYSEG		equ	0FFF9H			;hardwired physical segment for copycode

; NOTE: COPYSEGLO and COPYSEGHI must be consistent with COPYSEG

COPYSEGLO	equ	0FF90H			;low word of COPYSEG
COPYSEGHI	equ	00FFH			;high word of COPYSEG 

RNCIAR		equ	0F8C0H			; reset not complete ic
RNCLO_PORT	equ	030H			; io address for low byte of ic
RNCHI_PORT	equ	034H			; io address for high byte of ic
DATA_PORT	equ	03CH			; io address for ic data
RESETCOM	equ	011111100B		; clears reset not complete


admablk	struc				;adma command block
	cmd		dw MEMXFER	;adma command
	asrc_lo		dw src_lo	;low word of source address
	asrc_hi		dw src_hi	;high word of source address
	adest_lo	dw dest_lo 	;low word of destination address
	adest_hi	dw dest_hi	;high word of destination address
	acount_lo 	dw count_lo	;low word of transfer count
	acount_hi	dw count_hi	;high word of transfer count
	status		dw ?		;status word
	stop_1		dw 0		;stop word
	stop_2		dw 0		;
	stop_3		dw 0
admablk	ends

copycode	segment	AT COPYSEG 




	assume cs:copycode

	ORG 0H

	dmacmd	admablk	<>			;command block for dma
promcopy	label near
	public	promcopy

; clear reset not complete bit in iPSB control/status register

	mov ax, RNCIAR		; ax <-- reset not complete ic address
	mov dx, RNCLO_PORT	; dx <-- port for low byte of RNCIAR
	out dx, al		; write low byte of reset not complete ic addr

	mov al, ah		; al <-- high byte of reset not complete ic addr
	mov dx, RNCHI_PORT	; dx <-- port for high byte of RNCIAR
	out dx, al		; write high byte of reset not complete ic addr

	mov dx, DATA_PORT	; dx <-- ic data port
	in al, dx		; get iPSB control/status register 
	and al, RESETCOM	; clear reset not complete bit

	out dx, al		; write it back to ic record

;Now copy prom to ram

	mov dx, GMR_PORT	; write mode word to
	mov ax, MODE		; adma mode register
	out dx, ax		;

	;convert command block pointer to 20 bit address

	mov ax, COPYSEGLO
	mov dx, CPRL0_PORT		; write low word of command pointer
	out dx, ax			; to pointer register on adma
	mov ax, COPYSEGHI
	mov dx, CPRH0_PORT		; write high word of command pointer 
	out dx, ax			; address to pointer register

	; start command

	mov ax, ADMASTART		;start
	mov dx, GCR_PORT		;command
	out dx, al

dmawait:
	mov dx, GSR_PORT		;get status
	in al, dx			;
	and al, STAT0			;and check if dma done
	cmp al, 0			;
	jne dmawait			;loop til done

	jmp firststage			;transfer control to code in ram



	ORG 	0FFF0H - COPYSEGLO
penter label near
	public penter 

	jmp	promcopy

copycode	ends
) FI

%' *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
%'	INPUTS:	NONE
%'	OUTPUTS: BDEV_INIT_LEN - number of device initialization outputs
%'		BDEV_INIT_STRUC_LEN - the length of the device init structure
%'	ABSTRACT:
%'	This macro declares four publics needed for device and serial
%'	channel init.
%' *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
	%IF (%is_cico) THEN (
$eject
boot_dev_init	segment

bdev_init_len		DW	%dev_cnt
bdev_init_struc_len	DW	size dev_init

boot_dev_init	ends

	) FI

		end)
