Data General Nova
Program Load Listing

    This document is a listing of a hand- disassembled version of the program which is loaded into core memory from a small ROM when the "program load" switch is activated on the computer's front panel. I got this code by hitting the load switch on one of my Novas with the data switches set to zero, disassembling the resulting data that showed up in the low 32 words of memory, and feeding the hand- disassembly back through the Nova's Extended Assembler to produce the listing shown here.

    It's self-modifying code, explaining why it has to run from main memory rather than having the ROM mapped temporarily into the main address space. The self- modification is used to set up the device addresses in the I/O instructions.

    I've commented it for clarity. All the numbers are in octal notation, which DG opted to use for the Nova instead of hexidecimal. Perhaps the octal notation is part of the designer's DEC heritage showing through.

    In any event, here it is:


               		.TITL	BOOT
         000000 	.LOC	0
               	
   00000 062677 START:	IORST			; Reset I/O Bus
   00001 060477 	READS	0		; Get switches to AC0
   00002 024026 	LDA	1, DVMSK	; Load Device Mask into AC1
   00003 107400 	AND	0, 1		; Mask off Device Bits
   00004 124000 	COM	1, 1		; Form Negative of AC1

               	;  The code fragment from 5 to 11 forms the nucleus of the
               	; self-modification portion of the program load program. The
               	; device ID from the switches is complemented and incremented
               	; in a counter 'til it overflows (goes to 0). The various
               	; I/O instructions are incremented to the desired device ID
               	; in said loop.

   00005 010014 IOSLP:	ISZ	IOI1		; INC NIOS Instr at 14
   00006 010030 	ISZ	IOI2		; INC SKPDN Instr at 30
   00007 010032 	ISZ	IOI3		; INC DIAS Instr at 32
   00010 125404 	INC	1, 1, SZR	; If loop done, skip - else 5
   00011 000005 	JMP	IOSLP		; Loop back

               	;    At this point, all the I/O instruction lower 6 bits
               	; contain the correct device ID (from the switches) and we
               	; can begin the actual boot process. First we load a JMP 377
               	; from location 16 and store it into location 377. This sets
               	; up the logic for a Data CHannel device load.

   00012 030016 	LDA	2, SJMP		; Load self-jump
   00013 050377 	STA	2, 377		; Save at 377
   00014 060077 IOI1:	060077			; ((NIOS 0) -1) [1]
   00015 101102 	MOVL	0, 0, SZC	; Test for DCH device in SWS
   00016 000377 SJMP:	JMP	377		; Jump + wait for DCH device

               	;    The previous JMP 377 is called only if we're loading from
               	; a data channel device (i.e. switch 0 was up). The program
		; will loop endlessly at 377 until that location is
		; overwritten by data from the device (it loads 400 octal
		; words). Location 377, once overwritten, becomes the
		; start point for the newly-loaded program.

   00017 004030 LEADR:	JSR	GETCH		; Get a character
   00020 101065 	MOVC	0, 0, SNR	; Test for NULL
   00021 000017 	JMP	LEADR		; Ignore initial NULLs
   00022 004027 NXTWRD:	JSR	GPACK		; Get, and pack, bytes
   00023 046026 	STA	1, @CURLC	; Save new word thru 26
   00024 010100 	ISZ	100		; Bump word count (from device)
   00025 000022 	JMP	NXTWRD		; Get next word

               	;    Location 26 is an auto-increment location when accessed
               	; via an indirect (deferred) access. The initial value of 77
               	; will autoincrement to 100 during the first access from
               	; the instruction at location 23. It also serves, at time of
               	; initialisation as the mask for the device bits in the console
               	; switches. At the end of this program, location 26 will
		; contain the entry address of the program just loaded.

		DVMSK:	
   00026 000077 CURLC:	77

               	;    Beginning at location 27 is the routine to get bytes from
               	; the selected input device and pack them into words for later
               	; storage. Remember we're dealing with a big-endian macine
               	; here. The routine has two entry points, GPACK and GETCH.
                ; GPACK gets, and packs bytes two per word; GETCH gets, and
                ; returns a single character in the low-order 8 bits.

   00027 126420 GPACK:	SUBZ	1, 1		; Clear AC1 and set carry

               	GETCH:
               	IOLP1:
   00030 063577 IOI2:	063577			; ((SKPDN 0) -1) [1]
   00031 000030 	JMP	IOLP1		; Dev Not Done - Loop
   00032 060477 IOI3:	060477			; ((DIAS 0, 0) -1) [1]
   00033 107363 	ADDCS	0, 1, SNC	; Pack data from dev into AC1
   00034 000030 	JMP	IOLP1		; Word not done - get next char
   00035 125300 	MOVS	1, 1		; Word done - swap bytes back
   00036 001400 	JMP	0, 3		; Return from JSR

   00037 000000 FILLR:	0

         000000 	.END	START

[1]
The three instructions at IOI1:, IOI2:, and IOI3: are stored in the ROM one less than their intended instructions. This is due to the workings of the self- modification loop which tests for done at the bottom of the loop. It looks like magic, but it's really not.

    Note that the tactic of using device ID 0 to get this information won't work on an Eclipse S/130. On that system, a program load from device zero is a special case which starts a self- test in the microcode.



[ Museum Lobby ] [ Museum Catalogue ] [ Carl's Homepage ]


Copyright © 1997 - 2003, Carl R. Friend. All rights reserved.
Webspace design by: Carbon & Silicon Alliance

Comments to: carl.friend@rcsri.org
Last Modified: Sun Jul 5 11:00:29 EDT 1998