1
0
mirror of https://github.com/livingcomputermuseum/Darkstar.git synced 2026-03-02 10:06:45 +00:00
Files
livingcomputermuseum.Darkstar/D/IOP/Source/IOPInit.asm,v
2023-09-27 16:17:41 -07:00

39 lines
16 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
head 1.1;
branch 1.1.1;
access ;
symbols start:1.1.1.1 Xerox:1.1.1;
locks ; strict;
comment @;; @;
1.1
date 2001.08.12.22.22.22; author freier; state Exp;
branches 1.1.1.1;
next ;
1.1.1.1
date 2001.08.12.22.22.22; author freier; state Exp;
branches ;
next ;
desc
@@
1.1
log
@Initial revision
@
text
@{
----------- Dandelion Processor Program - I/O Processor -----------
DESCRIPTION: Boot Program: IOP Initial code for Floppy Booting.
Last modification by Roy RXO : June 30, 1981 5:17 PM
File: IOPInit.asm
Stored: [Iris]<WMicro>DLion>IOPInit.asm
Written by Roy RXO .
Edited: Dennis DEG , 1-Sep-84 22:11:53 add copyright notice.
}
{ Copyright (C) 1981 by Xerox Corporation. All rights reserved. }
; Modification History:
; Version 1.0
; - Created (November 16, 1980 5:02 PM)
; Version 2.2
; - Created (December 23, 1980 12:18 PM)
; - Check for Mem 1 as pointer (December 23, 1980 12:18 PM)
; - Diagnostic Floppy bypasses (January 4, 1981 6:34 PM)
; - Indexed DiagBoot for Diagnostic Floppy (January 5, 1981 4:45 PM)
; Version 2.4
; - Added 2D,2S floppy booting (June 18, 1981 7:08 PM)
; - Fixed Floppy Phase 2 offset (June 18, 1981 7:40 PM)
; - Check for zero PVRP slots (June 18, 1981 7:40 PM)
; DEFNITIONS:
get "SysDefs"
get "BootDefs"
get "BootLinkDefs" ; Link information
{ This code constitutes the IOP code runs during Phase 2 of floppy booting. It gets control after
FloppyInitial.mc has been started in the CP.
To make the FloppyInitial.db boot file for the Floppy disk do the following
Assemble IOPInit: i8085a IOPInit
Bind IOPInitial: i8085b IOPInitial
Make .db file: MakeBoot FloppyInitial.db FloppyInitial.fb IOPInitial.bin/3000
(Use command file: MakeFloppyInitial.cm)
IOPInitial fetches the Physical Volume Root Page (PVRP), computes the floppy disk addresses of the
Germ (and Othello), the soft microcode, and the hard microcode. IOPInitial leaves them in IOP RAM.
IOPInitial then interprets the "Germ" (and Othello) CPR file and stores it into CP main memory.
It then sets up the disk address of the soft microcode (if DiagBoot is zero), and transfers
control to the EProm code at DoBootPhase. If DiagBoot is non-zero, then the hard microcode
boot file is set up, using DiagBoot as an index. }
{Notes:
CPR block in Main memory should not cross 64K boundary
}
;
;------------------------------------------------------
; Start location:
IOPInitialGo:
jmp IOPInitialStart
;------------------------------------------------------
; RAM variables:
; Starting disk addresses:
; Germ (really Othello)
GermCylinder:
ds 2
GermSector:
ds 1
GermSide:
ds 1
; Soft microcode.
SoftMCCylinder:
ds 2
SoftMCSector:
ds 1
SoftMCSide:
ds 1
; Hard microcode.
HardMCCylinder:
ds 2
HardMCSector:
ds 1
HardMCSide:
ds 1
; CPR block variables.
; Write main memory CPport control block (PCB).
WritePCB:
ds 2 ; Word 0: CP buffer pointer (low):
ds 2 ; Word 1: CP buffer pointer (high)
ds 2 ; Word 2: CP buffer count (words)
ds 2 ; Word 3: Pointer to IOP buffer (unused)
CPRBlockCnt:
ds 2 ; Count of words used during block processing
CPRBlockData:
ds 2 ; Data during block processing
CPRBlockDataHi equ CPRBlockData+1
InitMaxSector:
dw MaxSectorNo+1 ; Maximum sector number+1
;
; Start of Initial execution.
; The CP is executing FloppyInitial.
; Wait until it completes execution and sets Main memory 1 to nonzero.
IOPInitialStart:
lxi h,Phase ; Increment phase number
inr m
lxi h,MPStartPhase2Floppy+1 ; Put 250 in MPOffset
shld MPOffset
dcx h ; Put 249 in MPanel
call PutMPExt
; Check for diagnostic floppy booting. If so, leave the CP alone.
call CheckInitDiagFloppy
ora a ; A#0 => Diagnostic floppy booting
jnz FinishDiagInitial ; nz => Diagnostic floppy booting
; Not diagnostic floppy booting. Check Main memory.
InitialWaitMem1:
lxi h,1 ; Specify memory location 1
call ReadMainMemExt ; Read main memory 1
; Check for completion (low byte in A, high byte in B):
; high byte # 0 => Valid completion,
; high byte = 0, low byte # 0 => Error, error code in low byte,
; high byte = 0, low byte = 0 => not completed.
mov c,a ; Save low byte
mov a,b ; Get high byte
ora a
jnz FloppyInitialDone ; nz => completed
; High byte is zero, check low byte:
mov a,c
ora a
jnz FloppyInitialError ; nz => Error
; High byte is zero, low byte is zero:
jmp InitialWaitMem1
; CP has completed. Get the addresses in the Physical Volume root page.
FloppyInitialDone:
call IncrMPExt ; Put 250 in MPanel
call GetPVRP ; Read the PVRP from the floppy, compute disk addresses
lxi h,MPStartInterpretGerm ; Put 260 in MPanel
call PutMPExt
jmp DoInterpretCPR
; CP has completed in error. C has the error code.
FloppyInitialError:
jmp ErrorReportExt ; ERROR: Error in CP FloppyInitial
; START of the CPR file interpreter.
{ The CPR contains blocks af data destined for CP main memory.
The interpreter reads a block and stores it in main memory.
The format of a CPR block is as follows where each item is a word:
Block count (in words) - Zero means last block
CP real address high - High 16 bits of long real address
CP real address low - Low 16 bits of long real address
"count" words
At this point we know that the floppy disk is enabled, and the current state is correct.
Also the "Germ" disk address has been computed and stored. BootSource specifies the Floppy.
}
DoInterpretCPR:
lxi h,GermCylinder ; Point to the Germ disk address
call SetDiskAddr ; Initialize the disk address
ora a ; Check for invalid address
jnz StartCPRBlock ; nz => valid address
; Error:
mvi c,ErrorZeroGermAddress ; ERROR: Zero Germ Address
jmp ErrorReportExt ; Report the error
; Since we know that the BootSource is the Floppy we don't have to do any StartNextRead's.
StartCPRBlock:
lxi h,CPRBlockCnt ; Read the block count
call GetNextWordExt
xra a ; Check if it is zero
lhld CPRBlockCnt
cmp l ; Check low part
jnz DoCPRBlock ; nz => valid CPR block
; Low part was zero, check the high part.
cmp h ; Check high part
jnz DoCPRBlock ; nz => valid CPR block
; Count was zero, thus end of CPR file.
EndCPRFile:
jmp FinishIOPInitial ; Finsih up the Initial execution
; Interpret a CPR Block.
; The block is of nonzero length.
DoCPRBlock:
lhld CPRBlockCnt ; Store block count in PCB
shld WritePCB+CPCnt
; Get the memory address.
GetCPRAddr:
lxi h,WritePCB+CPAddr1 ; Point to the high address in PCB
call GetNextWordExt
lxi h,WritePCB+CPAddr3 ; Point to the low address in PCB
call GetNextWordExt
; Start the CP write through the port.
StartCPRWrite:
mvi a,CPWriteCmd ; Write command
lxi h,WritePCB ; Point to the WritePCB
call InitCPCmdExt ; Initialize the transfer
CPRBlockLoop:
lxi h,CPRBlockData ; Point to data slot
call GetNextWordExt ; Get the word
lhld CPRBlockData ; H,L _ Data word
xchg ; D,E _ Data word
call WriteCPwordExt ; Write word into port
; Decrement the count and check for zero.
lhld CPRBlockCnt ; Decrement the word count by 1
dcx h
shld CPRBlockCnt ; Store back
xra a
cmp l ; Check low part for zero
jnz CPRBlockLoop ; nz => nonzero
cmp h ; Check high part for zero
jnz CPRBlockLoop ; nz => nonzero
; The current block is completed (count is zero). Go and do the next block.
jmp StartCPRBlock
; Diagnostic floppy booting.
; Read the PVRP and complete the Initial phase.
FinishDiagInitial:
call IncrMPExt ; MP = 250
call GetPVRP ; Read the PVRP from the floppy, compute disk addresses
; Go to FinishIOPInitial.
; The CPR file has been interpretted. Finish off Initial's execution and transfer control back to the
; EProm code at DoBootPhase. Set up the disk address to the soft microcode,
; unless DiagBoot is true, then set up the disk address to the hard microcode.
FinishIOPInitial:
lxi h,MPEndPhase2Floppy ; MP = 285
call PutMPExt
lda DiagBoot ; Check DiagBoot
ora a
jnz SetHardMCDiskAddr ; nz => set the hard microcode disk address
; Boot file is the soft microcode.
SetSoftMCDiskAddr:
call IncrMPExt ; MP = 286
lxi h,SoftMCCylinder ; Point to the soft mc disk address
DoSetDiskAddr:
call SetDiskAddr ; Initialize the disk address
ora a ; Check for invalid address
jnz ExitIOPInitial ; nz => valid address
; Error:
mvi c,ErrorZeroSoftMCAddress ; ERROR: Zero Soft MC Address
jmp ErrorReportExt ; Report the error
; Indicate stage in MP.
ExitIOPInitial:
lxi h,MPStartPhase2Rigid ; MP = 200
shld MPOffset
call PutMPExt
jmp DoBootPhaseExt ; Interpret the boot file.
{
DiagBoot was indicated. This indicates that the hard microcode boot file should be interpretted.
The hard microcode file is actually a concatenation of boot files, indexed by the value of
DiagBoot. The first page of the hard microcode boot file is an array of pointers which is
indexed by DiagBoot to determine the word address of the start of the actual boot file.
The code here uses DiagBoot to index into the table and then fix the disk address so that the
next call to GetNextWord will start accessing the first word of the file.
}
; Clear the flag in DiagBoot.
SetHardMCDiskAddr:
call IncrMPExt ; MP = 286
call IncrMPExt ; MP = 287
lxi h,HardMCCylinder ; Point to the hard mc disk address
call SetDiskAddr ; Initialize the disk address
ora a ; Check for invalid address
jnz GetDiagBoot ; nz => valid address
; Error:
mvi c,ErrorZeroHardMCAddress ; ERROR: Zero Hard MC Address
jmp ErrorReportExt ; Report the error
; The table at the start of the boot file has the first two words reserved.
; DiagBoot = 1 is mapped to Entry 2, etc.
GetDiagBoot:
lda DiagBoot ; Increment DiagBoot
inr a
call DiscardFloppyWords ; Discard the first entries in the table
; The next word will contain the word pointer to the start of the boot file.
lxi h,CPRBlockData ; Put the pointer into CPRBlockData
call GetNextWordExt
; Compute the disk address of the page containing the start of the boot file.
lda CPRBlockDataHi ; Get high part of word index
mov c,a ; Use as counter in C
lxi h,HardMCSector ; Point to sector number
; Loop, updating the hard disk address.
HardMCAddrLoop:
inr m ; Increment sector number
lda InitMaxSector ; Compare to max sector+1
cmp m
jz InitTrackCross ; z => Sector number = MaxSector+1, i.e crossed track boundary
; Didn't cross the track boundary, see if we're done.
HardMCAddrCheck:
dcr c
jnz HardMCAddrLoop ; nz => Disk address not yet correct
; Disk address now is for the first page of the file. Set the address and check offset in the page.
lxi h,HardMCCylinder ; Point to the hard mc disk address
call SetDiskAddr ; Initialize the disk address (know that address is nonzero)
lda CPRBlockData ; Look at low part
ora a
jz ExitIOPInitial ; z => First word is at start of page, no more to do
; The first word is within the page. Discard the words before. A has number of words to discard.
call DiscardFloppyWords
; The next word accessed by GetNextWord will be the first word of the file.
jmp ExitIOPInitial
; Crossed Track boundary. Fix up the disk address.
; Single-sided disk:
; HardMCSector _ 1;
; HardMCCylinder _ HardMCCylinder + 1;
; Double-sided disk:
; HardMCSector _ 1;
; IF HardMCSide = 0 THEN HardMCSide _ 1
; ELSE {i.e. HardMCSide = 1} BEGIN DSide _ 0;
; HardMCCylinder _ HardMCCylinder + 1;
; END;
InitTrackCross:
mvi a,1 ; HardMCSector _ 1;
sta HardMCSector
in FDCStatusReg ; Check in external status reg. whether single or double-sided
ani FDCTwoSidedMask
jz DoSingleSide ; z => single sided
; Double sided disk.
lda HardMCSide
xri Side1Mask
sta HardMCSide ; HardMCSide _ HardMCSide xor Side1Mask
jnz HardMCAddrCheck ; nz => HardMCSide =1, i.e. was 0
; HardMCSide = 0, i.e. was 1. Increment the cylinder number.
DoSingleSide:
lda HardMCCylinder
inr a
sta HardMCCylinder
jmp HardMCAddrCheck
;
; IOPInitial SUBROUTINES.
; Subroutine: GetPVRP.
; Read the physical volume root page from the disk. Compute the HardMC, SoftMC, and Germ
; disk addresses and store in IOP RAM.
GetPVRP:
; Set starting disk address to PVRP.
lxi h,StartPVRPCylinder ; Initialize starting cylinder (a word)
shld DCylinder
mvi a,StartPVRPSector ; Initialize starting sector
sta Sector
mvi a,StartPVRPSide ; Initialize starting side
sta DSide
; Set the floppy buffer to empty. This will trigger a disk access when GetNextWord is called.
lxi h,0 ; FloppyBufCnt _ 0
shld FloppyBufCnt
; Read and discard the first uninteresting words (StartHardMCIndex words) in the I/O page.
; Use the low part of CPRBlockCnt as a counter.
DiscardFirstPVRP:
mvi a,StartHardMCIndex
call DiscardFloppyWords
; The next word will be the start of the HardMC disk address
GetHardMCPVRP:
lxi h,HardMCCylinder ; Point to the Cylinder location
call GetNextWordExt
lxi h,HardMCSector ; Point to the Sector/Side location
call GetNextWordExt
; Discard the next DiskFileID header.
mvi a,SizeDiskFileID-SizeDiskAddr
call DiscardFloppyWords
; The next word will be the start of the SoftMC disk address
GetSoftMCPVRP:
lxi h,SoftMCCylinder ; Point to the Cylinder location
call GetNextWordExt
lxi h,SoftMCSector ; Point to the Sector/Side location
call GetNextWordExt
; Discard the next DiskFileID header.
mvi a,SizeDiskFileID-SizeDiskAddr
call DiscardFloppyWords
; The next word will be the start of the Germ disk address
GetGermPVRP:
lxi h,GermCylinder ; Point to the Cylinder location
call GetNextWordExt
lxi h,GermSector ; Point to the Sector/Side location
call GetNextWordExt
ret
; Subroutine: DiscardFloppyWords.
; Read and discard a nember of words from the disk.
; On entry: A = Number of words (<256) to be discarded
; CPBlockCnt and CPRBlockData are used.
DiscardFloppyWords:
sta CPRBlockCnt
DiscardLoop:
lxi h,CPRBlockData ; Point to the data word
call GetNextWordExt
lxi h,CPRBlockCnt ; Check for last junk word
dcr m
jnz DiscardLoop ; nz => still more
ret
; Subroutine: SetDiskAddr
; Set up the desired disk address for the boot file, and set the floppy buffer to empty.
; On entry: H,L has pointer to a disk address.
; On exit: A=0 => Disk address was zero (i.e. Side = Cylinder = Sector = 0)
; A#0 => Disk address was nonzero
SetDiskAddr:
mov e,m ; Get low part of Cylinder
inx h
mov d,m ; D,E _ Cylinder
inx h
xchg ; H,L = desired cylinder, D,E has disk address pointer
shld DCylinder ; Store in desired cylinder
xchg ; D,E _ cylinder, H,L _ disk address pointer
mov a,m ; A _ Sector
sta Sector
ora d ; A _ Sector OR CylinderHi
ora e ; A _ Sector OR CylinderHi OR CylinderLo
mov b,a ; Save Sector OR CylinderHi OR CylinderLo
inx h ; Point to side
mov a,m ; A _ Side
sta DSide
ora b ; A # 0 for valid address, = 0 for zero address
; Set the floppy buffer to empty. This will trigger a disk access when GetNextWord is called.
lxi h,0 ; FloppyBufCnt _ 0
shld FloppyBufCnt
ret
; Subroutine: CheckInitDiagFloppy.
; Check DiagBoot and BootType to see if diagnostic floppy booting.
; On exit:
; A # 0 if (DiagBoot#0) AND (BootType=AltDiagFloppyBoot)
; A = 0 otherwise.
CheckInitDiagFloppy:
lda DiagBoot ; Check DiagBoot first
ora a
rz ; z => DiagBoot = 0, not diag floppy booting
; DiagBoot was not zero. Check if diagnostic floppy booting.
lda BootType ; Check the BootType
xri AltDiagFloppyBoot ; A _ 0 if BootType=AltDiagFloppyBoot
jnz NotInitDiagFloppyBoot ; nz => BootType#AltDiagFloppyBoot
; BootType=AltDiagFloppyBoot (A=0).
cma ; Complement sense: A#0 if BootType=AltDiagFloppyBoot
ret
NotInitDiagFloppyBoot:
xra a ; Return A = 0
ret
END IOPInit
@
1.1.1.1
log
@first add
@
text
@@