*
*-------------------------------------------------------------------------------------------------
*			Internal Binary Loader (IBL) for HP 5420A and 5423A Signal Analyzers
*-------------------------------------------------------------------------------------------------
*
*		Filename:		IBLROM.asm
*		Project Name:		HP 5420A/5423A Restoration Project
*		Project Purpose:	Restoration to full operation the HP 5420A Digital Signal
*					Analyzer and the HP 5423A Digital Structural Analyzer.
*
*		Target CPU:		HP 21MX
*		Date:			6 Jan 2013
*		Verson:			1.0.1
*		Author:			Peter D O'Neill
*		Source:			Disassembled from ROMs in a 5420A
*		
*		File Purpose:		This file is to initiate the system boot process, it performs
*					a checksum on itself, then resets enough of the system
*					hardware so as to allow operation of keys, LEDs, and the
*					tape drives. This first operation is the Light test #1.
*					Next the cartridge drives look for the presence of a tape.
*					When a tape is found it is read and the sofware looks for
*					a specific record type which indicates that it is the MGEN
*					software. Once sucessfully loaded the IBL hands over
*					program control to MGEN.
*
*-------------------------------------------------------------------------------------------------
*			Register Equates
*-------------------------------------------------------------------------------------------------
*
A			EQU	0		; A-register equate
B			EQU	1		; B-register equate
*
*-------------------------------------------------------------------------------------------------
*			Equates for MIOB
*-------------------------------------------------------------------------------------------------
*
MIOB.SELECT		EQU	10B		; I/O Select address for MIOB
KEYBOARD.DEVICE		EQU	20000B		; 0010	5443A Kyboard/Control -- Keyboard
TAPE.DEVICE		EQU	30000B		; 0011	5441A Display -- A9 Cartridge Interface
*
*-------------------------------------------------------------------------------------------------
*			Equates for LIGHT/KEY control bits
*-------------------------------------------------------------------------------------------------
*
REMOTE.LIGHT		EQU	000056B		; Select REMOTE light (default state is OFF)
INPUT.LIGHT		EQU	000057B		; Select INPUT light (default state is OFF)
VIEW.LIGHT		EQU	000060B		; Select View light (default state is OFF)
KBD.ENABLE		EQU	000067B		; Keyboard enable 
ON			EQU	000100B		; Light ON flag
GOLD.KEY		EQU	000072B		; 
KEY.ON.5441A		EQU	000100B		; Key is on 5441A
FIRST.PRESS		EQU	000200B		; First key press
*
*-------------------------------------------------------------------------------------------------
*			Equates for TAPE CARTRIDGE control bits
*-------------------------------------------------------------------------------------------------
*
FRONT			EQU	001000B		; Front cartridge on
SELECT			EQU	006000B		; Cartride select code
READ			EQU	002000B		; Read from tape control bit
RUN			EQU	000100B		; Run tape control bit
LITE			EQU	000040B		; Cartridge activity light
*
			ORG	100B
*
*-------------------------------------------------------------------------------------------------
*			Initialise System
*-------------------------------------------------------------------------------------------------
*
LOADER.START   		CLC     0B,C		; Clear all I/O devices             
Z000101			CLA,CLE                 ; Clear A and E reg prior to forming a checksum 
*						; of the IBL, the contents of this location are
*						; also used as mask data in other parts of the code
*
*-------------------------------------------------------------------------------------------------
*
*			Perform a checksum of the IBL program
*
*		        Location 000233 initially contains 000100 and (SEND.MIOB.CW) is 177500
*			These two locations are normally storage for subroutine return addresses
*			so they can be used as temporary storage. 000233 containds the address 
*			pointer to the locations being summed and 000256 contains the counter
*			which when at increment 300B is zero so the checksum will stop.
*
*-------------------------------------------------------------------------------------------------
*
GEN.CHECKSUM   		ADA     READ.FROM.TAPE,I ; Add contents of memory to A-reg        
               		ISZ     READ.FROM.TAPE	; increment the memory address          
               		ISZ     SEND.MIOB.CW 	; increment the word counter         
               		JMP     GEN.CHECKSUM	; if we are not done then continue to make checksum
               		INA,SZA			; increment the final data, if zero IBL is ok                 
COUNT.01        	HLT     10B,C            
*
*-------------------------------------------------------------------------------------------------
*			Here if the IBL Checksum verified, Now perform a light test
*-------------------------------------------------------------------------------------------------
*
LIGHT.TEST        	LDA     COUNT.01        ; Use the above halt code as count data
               		STA     A.COUNTER       ; save it to the (A.COUNTER) to be used in LONG.DELAY
               		LDA     Z000254		; Start of light test with control word 044000 
*						; though to 077777 then from 000000 to 027600        
LIGHT.TEST.1        	JSB     SEND.MIOB.CW    ; Send an MIOB Control Word     
               		INA			; increment                       
               		CPA     Z000325 	; 027600 should be in the (Z000325) 
*						; Note Page 9-35 of manual says "The final control
*						; word sent (027600) causes the keyboard to generate
*						; a master PUP (MPUP) to all MIOB devices, restarting
*						; all MIOB operations" but 027600 isn't sent but
*						; 027577 is. However, according to the KPUP (Bit 9)
*						; and the MPUP (Bit 7) definitions both KPUP and MPUP
*						; should have been triggered before a count of 027577
               		RSS                     ; skip if A-reg = (Z000325)
               		JMP     LIGHT.TEST.1
*
*-------------------------------------------------------------------------------------------------
*			Turn on the Keyboard so operator can restart the tape read
*-------------------------------------------------------------------------------------------------
*
               		LDA     KEYBOARD.ENABLE	; Enable the keyboard          
               		JSB     SEND.MIOB.CW    ; Send an MIOB Control Word 
*
*-------------------------------------------------------------------------------------------------
*			Check if the front panel is connected, and if so reverse the order of
*			tape drive cartridge searching, normall rear then front. If the front
*			panel is found the order changes to front then rear.
*-------------------------------------------------------------------------------------------------
*
               		LIB     1B		; is the special front panel plugged in?
*						; if it is not plugged data will be 177777              
               		ISZ     B               ; if the result here is 0 then skip for normal operation
               		JMP     FRONT.DRIVE 	; with front panel connected start with front cartridge drive         
*
*-------------------------------------------------------------------------------------------------
*			Select Tape Drive (Initially select bits are set for Front Tape Drive)
*			so if front panel is not plugged in we start with internal cartridge
*			Each time we return here we change drive selection from Front to internal
*			or internal to front.
*-------------------------------------------------------------------------------------------------
*
OTHER.DRIVE        	LDA     SELECT.TAPE 	; Get the tape select bits         
               		XOR     DRIVE.MASK	; Flip the bits to select the other tape drive          
               		STA     SELECT.TAPE 	; save the result         
*
FRONT.DRIVE        	JSB     SELECT.A.CART 	; Select the cartridge drive         
               		JSB     LONG.DELAY          
               		LDA     TAPE.STOPPED	; Place tape in read mode, tape motion stopped          
               		JSB     SEND.MIOB.CW    ; Send an MIOB Control Word         
               		JSB     READ.FROM.TAPE          
               		LDA     RUN.TAPE	; Start tape running          
               		JSB     SEND.MIOB.CW    ; Send an MIOB Control Word         
*
*-------------------------------------------------------------------------------------------------
*			Start looking for an Inter Record Gap (IRG)
*-------------------------------------------------------------------------------------------------
*
GET.IRG        		LDA     VIEW.OFF        ; Turn off the VIEW light         
        		JSB     SEND.CW.TEST          
*
GET.IRG.1        	JSB     READ.FROM.TAPE	; IRG, Waiting for inter-record gap or is cart in drive?                  
               		LDA     CODE.WORD.STORE ; return the code word 
               		AND     Z000101         ; mask off all but IRG, ERROR, and MVG bits 
               		CPA     IRG.ERROR       ; compare with IRG and ERROR 
               		RSS                     ; Reverse skip sense 
               		JMP     GET.IRG.1       ; loop if not equal  
               		LDA     REMOTE.OFF	; Turn off the REMOTE light   
               		JSB     SEND.CW.TEST          
*
*-------------------------------------------------------------------------------------------------
*
*			Here we are waiting for status from the tape indicating that the IRG 
*			has finished, and the new data word from the tape should be the first
*			word of the record header for MGEN. Based on the operation of the following
*			code the struction of the MGEN record appears to be:
*
*			Header:
*
*				Word #1  MGEN identifier, -257 or 177377B
*				Word #2  Absolute start address (masked to below 16k boundary)
*				Word #3  Count of words to load
*				Word #4  Checksum of header
*
*			Data:
*
*				1st Word  First data word
*                                  |
*                               nth Word  Nth data word
*                               Checksum of data
*			
*-------------------------------------------------------------------------------------------------
*
IRG.LOOP        	JSB     READ.FROM.TAPE	; Cart is on, found IRG, waiting for end of IRG    	          
               		LDA     CODE.WORD.STORE ; return a code word 
               		AND     IRG.MASK        ; mask off all but IRG and DATA bits
               		SZA                     ; Skip if IRG has finished 
               		JMP     IRG.LOOP        ; loop otherwise 
        		LDA     REMOTE.ON	; Turn on the REMOTE light          
        		JSB     SEND.CW.TEST          
        		LDB     TAPE.DATA	; Get the Record identification           
               		STB     RECORD.ID       ; Save it RECORD.ID
 
               		JSB     READ.FROM.TAPE  ; get the block start address (second header word from tape)
               		AND     MASK.16K	; mask the address to ensure it is below the 16k boundary          
               		STA     MGEN.POINTER    ; save to the address pointer location 
               		STA     MGEN.XFR        ; save the start address to the MGEN transfer storage location 
               		JSB     READ.FROM.TAPE  ; Get third header word from tape
        		CMA,INA                 ; complement A-reg and inc by one -- 2's complement 
               		IOR     MINUS.4K        ; Or the result with 170000  
               		STA     RECORD.COUNT	; and save it         
               		STB     CHECKSUM	; save the checksum from B-reg          
               		JSB     READ.FROM.TAPE  ; read the header checksum        
               		CPA     CHECKSUM        ; do we have a checksum match?  
               		RSS                     ; skip next instruction if the checksum was okay 
               		JMP     GET.IRG         ; otherwise loop back and start looking for the next IRG 
               		LDA     VIEW.ON		; Turn on the view light, Unloaded was 100100          
               		JSB     SEND.CW.TEST          
               		LDA     MGEN.POINTER    ; get the MGEN pointer/start address         
               		AND     MINUS.1K        ; mask of all but the important part of the address
               		SZA,RSS                 ; test if the result is zero, if not then skip 
               		JMP     GET.IRG         ; else, it wasn't correct for MGEN, go look for next IRG 
*
READ.RECORD        	JSB     READ.FROM.TAPE	; Read a word from the tape          
               		STA     MGEN.POINTER,I  ; save it to memory 
               		CPA     MGEN.POINTER,I  ; read it back and do they match? 
               		RSS                     ; Yes, then skip 
               		JMP     WAIT.FOR.KEY.3  ; no match, indicate there is a memory error 
               		LDA     CODE.WORD.STORE          
               		AND     Z000101          
               		SZA                     
               		JMP     GET.IRG          
               		ISZ     MGEN.POINTER	; increment the memory pointer and skip if zero          
MASK.16K        	ABS	037777B		; This is a tricky multi-use, this code is an ISZ
*					        ; for location	001777 in the current page which
*						; happens to be page zero. Also the code is used
*						; a mask for for the MGEN pointer address.
*						; This increments the word count and exits reading
*						; the tape when all words are read.          
               		JMP     READ.RECORD	; Loop if not all words have been read          
               		STB     CHECKSUM        ; save the calculated checksum   
               		JSB     READ.FROM.TAPE  ; read the checksum word from tape        
               		CPA     CHECKSUM        ; Do the checksums match?  
IRG.MASK        	RSS                      
               		JMP     GET.IRG         ; No, then go and look for the next IRG 
               		LDA     SELECT.TAPE          
               		LDB     RECORD.ID	; Get the off tape record identification          
               		CPB     MGEN.ID		; was it an MGEN recird?          
               		JMP     MGEN.XFR,I 	; Yes, Then transfer control to MGEN       
               		JMP     GET.IRG         ; No, then go and look for the next IRG 
*	
*-------------------------------------------------------------------------------------------------
*    			Subroutine, Read a word from the tape with error handling 
*			If the data was without error then it is returned in A-reg
*			as well as being stored to TAPE.DATA, B-reg returns the current
*			value of the checksum.
*-------------------------------------------------------------------------------------------------
*
READ.FROM.TAPE        	ABS	100B		; Initially 100B, used as the address pointer
*						; for the Checksum test routine           
               		CLC     MIOB.SELECT	; set to data mode?              
               		JSB     GET.CODE.WORD	; Get a code word from the MIOB          
               		STA     CODE.WORD.STORE ; Save the returned code word          
               		IOR     TAPE.MASK       ; OR A-reg with TAPE MIOB Address   
               		CPA     CODE.WORD.STORE	; Compare the result with code word          
               		RSS                     ; and skip next if we don't have a match
               		JMP     WAIT.FOR.KEY 	; Here if the code word was not from the tape interface         
               		RAR,RAR			; shift the COUT bit to bit 0                  
               		SLA,RAR                 ; if the cartridge in the drive skip next instruction 
               		JMP     OTHER.DRIVE     ; If here, toggle the drive selection to the other drive       
               		RAR,SLA,RAR             ; Skip next instruction if EOT was not found, shift to MERR+EOT
               		JMP     HANDLE.EOT      ; If here, go and manage the EOT condition    
FORWARD.REVERSE		SLA                     ; if MERR+EOT bit not set then skip next instruction 
               		JMP     WAIT.FOR.KEY.2  ; if here then we have a motor error, indicate major fault      
               		JSB     GET.CODE.WORD   ; Get data from the tape       
               		STA     TAPE.DATA	; Save the data in temporary storage           
Z000254        		ADB     A               ; Add new data to the checksum in B-reg 
               		JMP     READ.FROM.TAPE,I ; Return to caller        
*
*-------------------------------------------------------------------------------------------------
*	       		Subroutine, Send MIOB Control Word, on entry control word is in A-reg
*-------------------------------------------------------------------------------------------------
*
SEND.MIOB.CW        	ABS	177500B		; initially was 177500, used as checksum counter            
               		STA     CONTROL.WORD    ; Save the control word to be sent
               		CLC     MIOB.SELECT,C 	; Set DATA Mode           
               		SFC     MIOB.SELECT	; Switch MIOB to Control Mode              
DRIVE.MASK        	ALR,ARS                 ; No MIOB addresses above 3 (don't know how 7 is addressed)
               		OTA     MIOB.SELECT	; Send the command              
               		STC     MIOB.SELECT,C   ; Issue a COMMC            
               		JMP     SEND.MIOB.CW,I	; Return to caller       
*
*-------------------------------------------------------------------------------------------------
*			Handle End Of Tape
*-------------------------------------------------------------------------------------------------
*
HANDLE.EOT        	JSB     LONG.DELAY          
               		JSB     SELECT.A.CART          
               		LDB     MGEN.ID      
               		LDA     RUN.TAPE	; Get the tape run control word          
               		XOR     FORWARD.REVERSE	; Flip the Forward/Reverse bit         
               		STA     RUN.TAPE 	; Save the tape run control word          
*
HANDLE.EOT.1        	JSB     SEND.MIOB.CW    ; Send an MIOB Control Word to reverse the tape direction         
               		ISZ     B                
               		JMP     HANDLE.EOT.1          
               		JMP     WAIT.FOR.KEY.2	; Unloaded was 100100 
*         
               		ABS     105577B         ; Special IBL Load instruction used in 5420 and 5423A 
*
*-------------------------------------------------------------------------------------------------
*    			Subroutine to get a code word, and or data from a tape
*-------------------------------------------------------------------------------------------------
*
GET.CODE.WORD        	ABS     024100B    	; Initially 024100 or JMP 100B, saves return address        
               		STC     MIOB.SELECT,C   ; Set Control bit of I/O Channel 10B
IRG.ERROR        	CLA                     ; Set up the loop counter for 65k   
*						; This is also used as a mask for IRG and ERROR bits
WAIT.FOR.DATA        	INA,SZA,RSS             ; increment counter and skip next instruction till A reg = 0             
               		JMP     WAIT.FOR.KEY    ; Here if we lost data, handle lost data
               		SFS     MIOB.SELECT     ; Skip next instruction MIOB flag set, device ready     
               		JMP     WAIT.FOR.DATA   ; loop and increment the counter 
               		LIA     MIOB.SELECT     ; Read a word from the MIOB   
               		JMP     GET.CODE.WORD,I ; Return to caller
*
*-------------------------------------------------------------------------------------------------
*    			LONG DELAY Subroutine, Timing dependent on locations B.COUNTER and A.COUNTER
*-------------------------------------------------------------------------------------------------
*
LONG.DELAY        	ABS     150570B 	; Initially was 150570, saves return address            
               		LDA     A.COUNTER       ; Initialize the A-reg count  
LONG.DELAY.1       	LDB     B.COUNTER       ; Initialize the B-reg count 
LONG.DELAY.2     	ISZ     B		; Increment B-reg counter, and skip if zero                
               		JMP     LONG.DELAY.2         
               		ISZ     A               ; Increment A-reg counter, and skip if done 
               		JMP     LONG.DELAY.1         
               		JMP     LONG.DELAY,I	; Return to caller
*
*-------------------------------------------------------------------------------------------------
*    			Data storage MIOB control words and count values
*-------------------------------------------------------------------------------------------------
*
SELECT.TAPE        	ABS	TAPE.DEVICE+SELECT+FRONT+LITE         
TAPE.STOPPED        	ABS	TAPE.DEVICE+READ                
RUN.TAPE        	ABS	TAPE.DEVICE+READ+RUN+LITE        
Z000325        		ABS	027600B          
REMOTE.ON      		ABS     KEYBOARD.DEVICE+REMOTE.LIGHT+ON   
REMOTE.OFF     		ABS     KEYBOARD.DEVICE+REMOTE.LIGHT         
VIEW.ON        		ABS     KEYBOARD.DEVICE+VIEW.LIGHT+ON            
VIEW.OFF       		ABS     KEYBOARD.DEVICE+VIEW.LIGHT    
INPUT.ON       		ABS     KEYBOARD.DEVICE+INPUT.LIGHT+ON         
INPUT.OFF      		ABS     KEYBOARD.DEVICE+INPUT.LIGHT         
KEYBOARD.ENABLE        	ABS     KEYBOARD.DEVICE+KBD.ENABLE+ON         
GOLD.PRESSED		ABS	KEYBOARD.DEVICE+GOLD.KEY+KEY.ON.5441A+FIRST.PRESS
MINUS.4K        	ABS	-4096              
MINUS.1K        	ABS	-1024              
B.COUNTER        	ABS     -5B        
TAPE.MASK        	ABS     TAPE.DEVICE                 
MGEN.ID        		ABS     -257       
*
*-------------------------------------------------------------------------------------------------
*     			SELECT A TAPE CARTRIDE DRIVE
*-------------------------------------------------------------------------------------------------
*
SELECT.A.CART        	NOP           		 ; saves return address
               		LDA     SELECT.TAPE      ; get the Cartridge select control word
               		JSB     SEND.MIOB.CW     ; Send an MIOB Control Word          
               		JMP     SELECT.A.CART,I  ; Return to caller
*
*-------------------------------------------------------------------------------------------------
*    			Subroutine Send a Control Word and test for MIOB fault
*-------------------------------------------------------------------------------------------------
*
SEND.CW.TEST        	NOP                      ; saves return address 
               		JSB     SEND.MIOB.CW     ; Send an MIOB Control Word         
               		SFS     MIOB.SELECT 	 ; was the FLAG set?               
               		JMP     WAIT.FOR.KEY     ; no
               		LIA     MIOB.SELECT      ; yes, read the returned word
               		CPA     CONTROL.WORD     ; was it the same as was control word we sent?     
               		JMP     SEND.CW.TEST,I 	 ; if we have a match then return to caller
*
*-------------------------------------------------------------------------------------------------
*    			Wait for the GOLD/Shift key, Flash INPUT/ALPHA light while waiting
*			WAIT.FOR.KEY.3, Memory failure test, light flashes 12 times/sec
*			WAIT.FOR.KEY, MIOB failure, light flashes 3 times/sec 
*			WAIT.FOR.KEY.2, EOT or MOTOR SERVO ERROR, light flashes once every 2sec 
*-------------------------------------------------------------------------------------------------
*
WAIT.FOR.KEY        	LDB     MINUS.4K          ; Get a count of 4096
WAIT.FOR.KEY.1        	STB     A.COUNTER	 ; save it to A.COUNTER for LONG.DELAY          
WAIT.FOR.KEY.2        	LDA     INPUT.OFF        ; Turn off INPUT/ALPHA light  
               		JSB     SEND.MIOB.CW     ; Send the MIOB Control Word         
               		CLC     MIOB.SELECT              
               		STC     MIOB.SELECT,C            
               		JSB     LONG.DELAY          
               		LIB     MIOB.SELECT	 ; Read the Code Word from the MIOB              
               		CPB     GOLD.PRESSED	 ; Was the GOLD (5420A) or SHIFT (5423A) key pressed?          
               		JMP     LIGHT.TEST	 ; Yes, then Restart the Boot process at the light test          
               		JSB     SELECT.A.CART          
               		LDA     INPUT.ON 	 ; Turn on INPUT/ALPHA light          
        		JSB     SEND.MIOB.CW     ; Send the MIOB Control Word         
               		JSB     LONG.DELAY          
               		JMP     WAIT.FOR.KEY.2          
*
WAIT.FOR.KEY.3        	LDB     MINUS.1K          ; count of 1024. fastest flash rate for memory error           
               		JMP     WAIT.FOR.KEY.1
*          
               		NOP			 ; Unloaded was 100100                      
               		CLC     0B,C             
MGEN.POINTER        		CLA,RSS                  
*
MGEN.XFR        	ABS	063756B          
RECORD.ID        	ABS	006700B                 
TAPE.DATA        	ABS	017742B          
CODE.WORD.STORE        	ABS	007306B          
CONTROL.WORD        	ABS	027713B		 ; MIOB Control Word storage          
CHECKSUM        	ABS	002006B                  
A.COUNTER        	ABS	027703B              
               		ABS	102077B             
               		ABS	027700B          
               		ABS	077754B          
               		ABS	017742B          
               		ABS	017742B          
               		ABS	074000B               
               		ABS	077755B		; 037755B         
               		ABS	067755B          
               		ABS	047777B          
               		ABS	002040B                     
               		ABS	027740B          
               		ABS	017742B          
               		ABS	040001B                
               		ABS	177755B        
               		ABS	037755B          
               		ABS	000040B                      
               		ABS	037754B         
               		ABS	027720B          
               		ABS	017742B          
               		ABS	054000B                
               		ABS	027702B          
               		ABS	102011B              
               		ABS	027700B          
               		ABS	102055B              
               		ABS	027700B
*
*-------------------------------------------------------------------------------------------------
*			This looks like a subroutine that is relocated and or gets used by MGEN
*			(12/2/2015) from what I know now this isn't used by MGEN   
*-------------------------------------------------------------------------------------------------
*
          
               		NOP                      
               		CLB,CME                  
               		STC     MIOB.SELECT,C            
               		SFS     MIOB.SELECT              
               		ABS	027745B         
               		MIB     MIOB.SELECT              
               		SEZ,RSS                  
               		ABS	127742B        
               		BLF,CLE,BLF              
               		ABS	027744B 
*        
               		NOP                      
               		NOP                      
               		ABS	177765B        
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
               		NOP                      
			ORG	1777B
RECORD.COUNT			BSS	1
*
	       		END
