;	SCCSID = @(#)ibmhalo.asm	1.1 85/04/10
;   On 2K (800h) boundaries beginning at address C0000h and ending at EF800h
;   there is a header that describes a block of rom program.  This header
;   contains information needed to initialize a module and to provide PCDOS
;   with a set of reserved names for execution.
;
;   This header has the following format:
;
;   rom_header	STRUC
;	Signature1  DB	55h
;	Signature2  DB	AAh
;	rom_length  DB	?		; number of 512 byte pieces
;	init_jmp    DB	3 dup (?)
;	name_list   name_struc <>
;   rom_header	ENDS
;
;   name_struc	STRUC
;	name_len    DB	?
;	name_text   DB	? DUP (?)
;	name_jmp    DB	3 DUP (?)
;   name_struc	ENDS
;
;   The name list is a list of names that are reserved by a particular section
;   of a module.  This list of names is terminated by a null name (length
;   is zero).
;
;   Consider now, the PCDOS action when a user enters a command:
;
;	COMMAND.COM has control.
;	o   If location FFFFEh has FDh then
;	o	Start scanning at C0000h, every 800h for a byte 55h followed
;		    by AAh, stop scan if we get above or = F0000H
;	o	When we've found one, compare the name entered by the user
;		    with the one found in the rom.  If we have a match, then
;		    set up the environment for execution and do a long jump
;		    to the near jump after the found name.
;	o	If no more names in the list, then continue scanning the module
;		    for more 55h followed by AAh.
;	o   We get to this point only if there is no matching name in the
;		rom.  We now look on disk for the command.
;
;   This gives us the flexibility to execute any rom cartridge without having
;   to 'hard-code' the name of the cartridge into PCDOS.  Rom modules that
;   want to be invisible to the DOS should not have any names in their lists
;   (i.e. they have a single null name).
;
;   Consider a new release of BASIC, say, that patches bugs in the ROM version.
;   Clearly this version will be available on disk.  How does a user actually
;   invoke this new BASIC??  He cannot call it BASIC on the disk because the
;   EXEC loader will execute the ROM before it even looks at the disk!	Only
;   solution:
;
;   o	Keep things consistent and force the user to have his software named
;	differently from the ROM names (BASIC1, BASIC2, etc).

rom_header  STRUC
    Signature1	DB  ?
    Signature2	DB  ?
    rom_length	DB  ?
    init_jmp	DB  3 dup (?)
    name_list	DB  ?
rom_header  ENDS

name_struc  STRUC
    name_len	DB  ?
    name_text	DB  1 DUP (?)
    name_jmp	DB  3 DUP (?)
name_struc  ENDS

ASSUME	CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

;
; Check for IBM PC Jr rom cartrides. DS:DX is a pointer to name
;
ROM_SCAN:
	PUSH	ES
	PUSH	SI
	PUSH	DI
	PUSH	CX
	PUSH	AX
	PUSH	BX
;
; check for PC Jr signature in rom
;
	MOV	AX,0F000h
	MOV	ES,AX
	CMP	BYTE PTR ES:[0FFFEh],0FDh
	JZ	SCAN_IT
NO_ROM:
	CLC
ROM_RET:
	POP	BX
	POP	AX
	POP	CX
	POP	DI
	POP	SI
	POP	ES
	RET
SCAN_IT:
;
; start scanning at C000
;
	MOV	AX,0C000h
SCAN_ONE:
	MOV	ES,AX
	XOR	DI,DI
SCAN_MODULE:
;
; check for a valid header
;
	CMP	WORD PTR ES:[DI],0AA55h
	JZ	SCAN_LIST
	ADD	AX,080h
SCAN_END:
	CMP	AX,0F000h
	JB	SCAN_ONE
	JMP	NO_ROM
;
; trundle down list of names
;
SCAN_LIST:
	MOV	BL,ES:[DI].rom_length	; number of 512-byte jobbers
	XOR	BH,BH			; nothing in the high byte
	SHL	BX,1
	SHL	BX,1			; number of paragraphs
	ADD	BX,7Fh
	AND	BX,0FF80h		; round to 2k

	MOV	DI,name_list
SCAN_NAME:
	MOV	CL,ES:[DI]		; length of name
	INC	DI			; point to name
	XOR	CH,CH
	OR	CX,CX			; zero length name
	JNZ	SCAN_TEST		; nope... compare
	ADD	AX,BX			; yep, skip to next block
	JMP	SCAN_END
;
; compare a single name
;
SCAN_TEST:
	MOV	SI,DX
	INC	SI
	REPE	CMPSB			; compare name
	JZ	SCAN_FOUND		; success!
SCAN_NEXT:
	ADD	DI,CX			; failure, next name piece
	ADD	DI,3
	JMP	SCAN_NAME
;
; found a name. save entry location
;
SCAN_FOUND:
	CMP	BYTE PTR DS:[SI],'?'
	JZ	SCAN_SAVE
	CMP	BYTE PTR DS:[SI],' '
	JNZ	SCAN_NEXT
SCAN_SAVE:
	MOV	[rom_cs],ES
	MOV	[ROM_ip],DI
	STC
	JMP	ROM_RET

;
; execute a rom-placed body of code. allocate largest block
;
ROM_EXEC:
	MOV	BX,0FFFFh
	MOV	AH,ALLOC
	INT	int_command
	MOV	AH,ALLOC
	INT	int_command
	PUSH	BX
	PUSH	AX
;
; set terminate addresses
;
	MOV	AX,(set_interrupt_vector SHL 8) + int_terminate
	PUSH	DS
	MOV	DS,[RESSEG]
	ASSUME	DS:RESGROUP
	MOV	DX,OFFSET RESGROUP:EXEC_WAIT
	INT	int_command
	MOV	DX,DS
	MOV	ES,DX
	ASSUME	ES:RESGROUP
	POP	DS
	ASSUME	DS:NOTHING
;
; and create program header and dup all jfn's
;
	POP	DX
	MOV	AH,DUP_PDB
	INT	int_command
;
; set up dma address
;
	MOV	DS,DX
	MOV	DX,080h
	MOV	AH,SET_DMA
	INT	int_command
;
; copy in environment info
;
	MOV	AX,[ENVIRSEG]
	MOV	DS:[PDB_environ],AX
;
; set up correct size of block
;
	POP	BX			; BX has size, DS has segment
	MOV	DX,DS
	ADD	DX,BX
	MOV	DS:[PDB_block_len],DX
;
; change ownership of block
;
	MOV	DX,DS
	DEC	DX
	MOV	DS,DX
	INC	DX
	MOV	DS:[arena_owner],DX
	MOV	DS,DX
;
; set up correct stack
;
	CMP	BX,1000h
	JB	GOT_STACK
	XOR	BX,BX
GOT_STACK:
	MOV	CL,4
	SHL	BX,CL
	MOV	DX,DS
	MOV	SS,DX
	MOV	SP,BX
	XOR	AX,AX
	PUSH	AX
;
; set up initial registers and go to the guy
;
	NOT	AX
	PUSH	[ROM_CS]
	PUSH	[ROM_IP]
	MOV	ES,DX
ASSUME ES:NOTHING
FOOBAR	PROC	FAR
	RET
FOOBAR	ENDP
