þ a‹R þ w Qþ m^9     þ hý	 oP    þ nSystem-wide    NAME Roms

; This is Rom.Asm.  This file contains
; the routines that deal with the low level
; roms

DGROUP GROUP DATA
CGROUP GROUP CODE

PUBLIC CpGetMySlot, CpBankInfo, CpSetActiveSlot, CpGetSlotAddress
PUBLIC curSlot, slotInfo, numSlots

; constants

TRUE              EQU 1
FALSE             EQU 0
nullWord          EQU 0ffffh
nullByte          EQU 0ffh

numRomSlots       EQU 4

thirtyTwoKOff     EQU 0A2h
thirtyTwoKMask    EQU 80h
setThirtyTwo      EQU 1
clearThirtyTwo    EQU 0

SlotInfoType STRUC
    waitStateCode DB ?
    romID         DW ?
    slotAddress   DW ?
    validRom      DB ?
    slots         DB ?
    spare         DB ?
SlotInfoType ENDS

slotInfoTypeSize  EQU 8

; this size must be a power of 2, and 8 is assumed
; in many ways

slotOffsetFromSP  EQU 4    ; where value slot will be if only argument

addr1Sel          EQU 0dfe0h
addr1Off          EQU 08h

$EJ

; data

DATA SEGMENT PUBLIC 'DATA'

    curSlot  DB ?
    numSlots DB ?
    slotInfo SlotInfoType numRomSlots DUP (<>)

    temp DB ?

DATA ENDS

$EJ

CODE SEGMENT PUBLIC 'CODE'
    ASSUME CS:CGROUP

; CpBankInfo : PROCEDURE PTR CLEAN
;
; This will return a pointer to the slot information

CpBankInfo PROC FAR

    MOV AX, DATA
    MOV ES, AX
    MOV BX, OFFSET curSlot

    RET
CpBankInfo ENDP

$EJ

; CpGetSlotAddress : PROCEDURE (slot) PTR CLEAN
;     DCL slot BYTE;
;
; This will return the actual address of a given slot
; by looking at the table that was set up init time
; If slot is nullByte, then curSlot will be used

CpGetSlotAddress PROC FAR

    MOV AX, DATA
    MOV ES, AX

    MOV SI, SP
    ADD SI, slotOffsetFromSP
    MOV BL, SS:[SI]              ; BL := slot

    CMP BL, nullByte             ; IF slot = nullByte THEN
    JNE CpGetCont

    MOV BL, ES:curSlot           ;     slot := curSlot

CpGetCont:

    XOR BH, BH                   ; BH := 0
    SHL BX, 1
    SHL BX, 1                    ; BX := slot * 8
    SHL BX, 1
    ADD BX, OFFSET slotInfo

; now ES:BX ^ element of slotInfo

    MOV AX, ES:[BX].slotAddress  ; AX := selector of address
    MOV ES, AX                   ; return in ES:BX
    XOR BX, BX                   ; BX := 0

    RET 2
CpGetSlotAddress ENDP

$EJ

; CpGetMySlot : PROCEDURE (romID) BYTE CLEAN
;     DCL romID WORD
;
; This will return the slot # of the rom which
; has the given ID.  If the romID is not found, then
; nullByte will be returned

CpGetMySlot PROC FAR

    MOV AX, DATA
    MOV ES, AX
    MOV BX, OFFSET slotInfo     ; ES:BX ^ first element of slotInfo

    MOV SI, SP
    ADD SI, slotOffsetFromSP
    MOV DX, SS:[SI]             ; DX = romID

    MOV CX, numRomSlots

    XOR AL, AL                  ; AX (slot) = 0

CpGetMyTopOfLoop:

    CMP ES:[BX].romID, DX       ; IF romID = slotInfo(i).romID THEN

    JE CpGetMyDone              ;     RETURN (AL)

    ADD BX, slotInfoTypeSize    ; ES:BX ^ next element

    INC AL                      ; slot = slot + 1
    LOOP CpGetMyTopOfLoop

    MOV AL, nullByte            ; romID was not found RETURN (nullByte)

CpGetMyDone:

    RET 2
CpGetMySlot ENDP

$EJ

; CpSetActiveSlot : PROCEDURE (slot) BYTE CLEAN;
;     DCL slot BYTE;
;
; This will make the rom is slot be the "active" rom.
; It assumes that slot is either valid, or nullByte.  The
; current active slot will be returned.

CpSetActiveSlot PROC FAR

    MOV AX, DATA
    MOV ES, AX

    MOV DL, ES:curSlot          ; save current slot

    MOV SI, SP
    ADD SI, slotOffsetFromSP
    MOV AL, SS:[SI]             ; AL = slot

    CMP AL, NULLBYTE            ; IF AL = nullByte THEN RETURN
    JE CpSetDone

    MOV BL, AL
    XOR BH, BH
    SHL BL, 1
    SHL BL, 1
    SHL BL, 1
    ADD BX, OFFSET slotInfo

; Before going further check if this is a valid slot

    CMP ES:[BX].validRom, 1     ; IF NOT slot.validRom THEN RETURN
    JE  SetTheSlot
    MOV DL, NULLBYTE            ; oldSlot = NULLBYTE
    JMP CpSetDone

SetTheSlot:
    MOV ES:curSlot, AL          ; curSlot := slot

; ES:BX ^ proper entry in slotInfo

    MOV DH, ES:[BX].slots          ; all the slots to set
    MOV AH, ES:[BX].waitStateCode  ; num wait states for all slots

    MOV BX, addr1Sel               ; point to rom select area
    MOV ES, BX
; See if we have a 32k rom
    MOV BX, thirtyTwoKOff          ; set 32k mode 
    MOV AL, setThirtyTwo           ; 256Kbit part
    TEST AH, thirtyTwoKMask
    JNZ  NowWriteIt
    MOV AL, clearThirtyTwo         ; 1 Mbit part

NowWriteIt:
    MOV ES:[BX], AL                ; set or clear the 32k flag

    MOV BX, addr1Off               ; first 32k area 
    MOV CX, 4                      ; 4 roms to set

BackToHere:
    MOV AL, DH
    AND AL, 3                    ; mask all but this slot
    OR  AL, AH                   ; add in the wait states

    MOV ES:[BX], AL              ; write out the code
    INC BX
    INC BX
    SHR DH, 1
    SHR DH, 1
    Loop BackToHere

CpSetDone:

    MOV AL, DL                  ; return current slot

    RET 2
CpSetActiveSlot ENDP

CODE ENDS

    END
