mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-03-02 10:06:45 +00:00
39 lines
16 KiB
Plaintext
39 lines
16 KiB
Plaintext
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
|
||
@@
|