Thursday, May 5, 2016

Modifying the 'C' in SimH to run a Point 4

This page is a part of the "Understanding IRIS" collection.  Many thanks to David Takle, for figuring this out, and sharing this with us:

------------------------------------------------------------------

If you know how to read the 'c' language, it could help move us forward. I can barely make sense of it myself.

I am attaching one of the texts that was used to compile the NOVA adaptation for SimH. It's purpose is to convert Nova Assembler commands into something that SimH can recognize as DKP commands. (hope that makes sense).

The Nova instructions can potentially include the following I/O commands

DOA, DIA, DOB, DIB, DOC, DIC 

as well as 3 possible control lines ( P for pulse, C for clear, S for start ).
If you remember, the control lines can be set with any of the I/O commands or with NIO. So possible combinations might be

NIOC / DOCS / DOBP and so on.

Documenting the connection between Nova assembly and the requirements of SimH DKP drives could help us write the new drivers.

For example, I think the DOB command is what is used to set the memory address for the block transfer. So our new driver has to use that I/O command to tell SimH where in memory we want to read or write a block of data.

The goal is to figure out how to communicate with SimH using Nova commands. Let me know if you figure out any of the attached c program.

-------------------------------------------------------------------

I followed one of the links you provided to bitsaver.org/pdf and as I scrolled down my eye caught the /dg/ directory which I'd never seen before. When I went there I found at least 2 docs that contain extensive information on how to write a disc driver for DKP devices !!

This looks like the missing link. It should also help make sense of the 'c' program I referred to earlier.
...

HowToUseNova_Oct74 chapter 5 is amazing. This is what helped me figure out how DG views disc controllers.

Nova_PgmrRefMan_Jan76 is good general knowledge of the Nova instruction set and how to use it.

-------------------------------------------------------------------

David,  I'm wondering if I shouldn't make it my "next mission" in this project to work on changing the open-source C code in SimH to accommodate the disc driver(s) that is/are present and active on the current unmodified restorations of the LU0-LU4 on the backup system you've been working on?

I know that you don't understand C that well, but with a bit more direction from your understanding of the IRIS environment and hardware architecture, I may be able to make the necessary modifications.

What can you tell me about the parameters of the Diablo 31 disc drive that SimH has by default, vs the different parameters needed for the disc drivers currently enabled/active on the system that we are restoring?

Bruce refers to it as the standard DG "Zebra" controller (Model 6060/6061/6067) 

Does this match what you see was there in the unmodified state of LU0?

-------------------------------------------------------------

The differences in drivers can be very extensive.
One might use DOA commands to set the drive and cylinder, another might use DOC.
One might include a sector count in a positive format, another in negative.
One might allow 40 sectors, another only 12.

To answer your question, it would be necessary to pick one drive and define its characteristics. I've done that for the Diablo, using the DG documentation.
See attached ASM listing I am hoping will boot up. As you can see, there is a lot of detail involved, and this is just the boot driver -- which is quite a bit simpler than the main system driver in REX.

One of the biggest problems we face is that it is very difficult to figure out what model disc is being supported by looking at a given driver. Even if I reverse assemble and annotate a driver, we might not be able to figure out what model it is. I could probably document it well enough to allow you to modify 'c' code, but it would take a while.
Take a look at the attachment and tell me if that would be enough documentation to modify the 'c' code (assuming that it was something other than the known D31).

Whatever way we choose to approach this, the LU0, LU1, LU2, LU3, LU4 set gives us an additional challenge. The simH DKP device only supports 4 devices. AND most of the LU's are too big to fit on a Diablo 31.We can probably take care of the size problem by bringing up the larger Diablo (44?) driver. I think it's in CONFIG.
As for the # drives, there are 2 approaches.
(1)  Create a DSK driver to handle LU0 (I think these are easier to write than DKP drivers), and put LU1 to LU4 on the DKP driver. 
(2) Bring up a driver for a monster model  (might need to write or modify a driver) that can partition and put 2 LU's on a single drive.

I am also working on an alternate path, (when I get a chance) in case the 'c' code thing turns out to be too confusing to make work.
 I am designing a SYSGEN program that will allow us to rebuild an LU0 with any driver that we already know.

Plugging away.
~David

--------------------------------------------------

; SECTORZERO.T
; Generic Sector zero with Diablo 31 driver (DG 4046/4047)
;
; Modified for simH boot sectors by David Takle, 5/22/2016

.LOC 10000 ; arbitrary addresss to prevent page zero refs
.PART = . + 300  ; PARTITION TABLE FOR DRIVER
BZDRV = 24000 ; ADDR FOR THIS BLOCK DURING SIR
BREXH = 24400 ; ADDR FOR REX HDR
JMP STOP1  ; CATCH ANY JMP 0 ERROR
2          ; if interrupts get turned on, halt.
STOP1: HALT
JMP .-1
;=======================================================
; everything from here to about 10350 is available for the driver

; when incorporating new device driver, 
;      adjust or comment this line out to make space
; .BLK 100  ; THIS SPACE AVAILABLE FOR DRIVER USE

;-----------------------------------------------------
; DIABLO 31 DRIVER STUFF
; 0313 CYLINDERS // 02 TRACKS // 014 SECTORS
; CAPACITY 1,247,232 (10) WORDS (ABOUT 2.5 MB)

; DOA AC,DKP -- SELECT MODE AND CYLINDER, AND CLEAR DONE FLAGS
;   174000 = DONE FLAGS
;     1400 = MODE  (2 bits) 0=read, 400=write, 1000=seek, 1400=recalibrate
;      377 = CYLINDER ( 0-312 )
;
; DOB AC,DKP -- SET MEMORY ADDRESS FROM ac
;
; DOC AC,DKP -- SELECT DRIVE, SURFACE, SECTOR, SECTOR COUNT
;   140000 == DRIVE BITS ( 2 BITS == DRIVES 0-3)
;      400 == SURFACE BIT (0 OR 1)
;      360 == SECTOR BITS (4 BITS == SECTORS 0-13)
;       17 == SECTOR COUNT ( IN 2'S COMPLEMENT )
;          I.E. '17' = 1 SECT // '16' = 2 SECT // '00' = 020 SECT (16)
;
; DIA AC,DKP -- READ CONTROLLER STATUS
;   174000 = DONE FLAGS // 100000 = READ/WRITE
;       OTHERS ARE SEEK DONE   40000 = DRIVE 0 // 4000 = DRIVE 3
;     3600 = SEEKING ==> 2000 = DRIVE 0 // 200 = DRIVE 3
;      100 = DISK READY
;       40 = SEEK ERROR
;       20 = END ERROR
;       10 = UNSAFE
;        4 = CHECK ERROR
;        2 = DATA LATE
;        1 = ERROR (ANY)
;
; DIB AC,DKP -- READ CURRENT ADDRESS COUNTER INTO AC
;       AT END OF WRITE, COUNTER IS 2 GREATER THAN LAST WORD
;
; DIC AC,DKP -- READ DRIVE STATUS (SAME BITS AS DOC)
;

DKP = 33  ; DEVICE CODE

RDA: 0
RWRTN: 0
NSCTR: 14  ; # SECTORS
XCYL: 2000  ; extra cylinder flag (undocumented feature, perhaps larger drive)
C377: 377
K1: 175000  ; for DOA, clear all done flags (174000) and set seek mode (1000)
K2: 74000 ; SEEK DONE FLAGS
AC2: 0  ; MEM

; Read or Write --- ENTER WITH AC0=MODE, AC1=RDA, AC2=MEM
D31RW: STA 2,AC2
STA 1,RDA
STA 3,RWRTN
DOBC 2,DKP   ; SET MEM ADDR, CLEAR BUSY AND DONE
LDA 2,NSCTR  ; C14
SUB 3,3,SKP ; Track # relative to Cylinder 0, Track 0
INC 3,3 ; COUNT TRACKS
SUBZ 2,1,SZC  ; SLOW DIVIDE BY 14, SKIP WHEN C14 WAS > #SECTORS LEFT
JMP .-2 
ADDZL 2,1  ; ADD BACK TO CALC SECTOR #
MOVOL 1,1  ; shift left 4 bits, and shift in c17 for -1 block count
MOVOL 1,1
MOVOL 1,1  ; ac1 now contains the 377 bits for a DOC command
MOVR 3,3   ; divide tracks by 2 >>> Cylinder# in AC3 with track in Carry
SUBCL 2,2  ; shift Track bit into low order bit 1
MOVS 2,2   ; move track bit into 400 bit
ADD 2,1    ; add track to DOC bits
LDA 2,PART  ; drive bits
ADD 2,1     ; finish DOC command
DOC 1,DKP  ; SELECT DRIVE, SURFACE, SECTOR, COUNT
LDA 2,PART1  ; optional cylinder offset for partition
ADD 2,3    ; add to Cyl address
LDA 1,XCYL ; c2000 -- undocumented bit (see DG How to use Nova)
MOVS 3,2      ; effectively divide #CYL's by c400
MOVR# 2,2,SNC  ; using cylinder > 377 ?
SUB 1,1 ; no, drop XCYL flag
LDA 2,C377  ; mask
AND 3,2   ; limit cylinder# to 377 bits
ADD 2,1   ; add cyl# to XCYL flag
LDA 2,K1   ; get seek command (1000)
ADD 1,2    ; add cyl to seek
ADD 1,0    ; add cyl to original read/write command
RETRY: DOAP 2,DKP  ; CYLINDER, DO SEEK
LDA 3,K2   ; SEEK DONE FLAGS
DIA 1,DKP  ; GET STATUS
AND# 3,1,SNR ; DONE?
JMP .-2    ; NO, WAIT
MOVR# 1,1,SZC  ; any error?
JMP SKERR      ; yes
DOAS 0,DKP  ; START READ/WRITE
SKPBZ 0,DKP  ; WAIT FOR DONE
JMP .-1 ; WAIT
LDA 2,AC2  ; RESTORE AC2, AC1 for caller
LDA 1,RDA
DIA 0,DKP
MOVR# 0,0,SNC  ; any error?
ISZ RWRTN ; no, do SKIP return
JMP @RWRTN
; RETURN WITH   A0=STATUS  /  A1 = RDA  /  A2 = A(MEM)
; if timeout, do non-skip return with A0=0

;-------------------------------------------------------------------
; WARNING --- MAKE SURE PREVIOUS WORD ASSEMBLED BELOW 10300
;------------------------------------------------------------------
.LOC .PART ; RELATIVE 300
PART: 0   ; selects drive --- for D31, See DOC command (zero = drive 0)
PART1: 0   ; optional cylinder offset for LU

; read/write entry points... A1 = RDA // A2 = Address
174000 ; READ MODE + CLEAR ALL DONE FLAGS
READBLOCK: ; MUST BE AT 303
LDA 0,.-1    ; READ ENTRY POINT
JMP D31RW
174400 ; WRITE MODE + CLEAR ALL DONE FLAGS
WRITBLOCK: ; MUST BE AT 306
LDA 0,.-1    ; WRITE ENTRY POINT
JMP D31RW

; Recalibrate on Seek Error; can ONLY change AC1
; NOTE: this is here for nostalgic reasons only. Seek errors are not possible on simH.
SKERR: DSZ RCLMT    ; limit how many times we try ths, or it will break drive
JMP .+2      ; ok
HALT         ; give up
LDA 1,RECAL  ; pick up recal bit
DOAP 1,DKP   ; recalibrate -- send heads to cyl 0
DIA 1,DKP  ; GET STATUS
AND 3,1,SNR ; DONE?
JMP .-2    ; NO, WAIT
MOVR# 1,1,SZC  ; any error?
HALT      ; yes-- no recovery from recalibrate
JMP RETRY
RCLMT: 4
RECAL: 175400

; patch space or driver space

;====================================================================================
; WARNING --- INSURE PREVIOUS WORD ASSEMBLED BELOW THIS LOCATION
; everything following is standard code
;================================================================================

.LOC BZUP - 32  ; ADJ TO FINISH AT 377

CM400: 177400  ; -400

; COPY BLOCK OF WORDS FROM (A0) TO (A2)
0
MOVEW: STA 3,.-1
MOV 0,3
LDA 1,CM400
MOV1: LDA 0,0,3
STA 0,0,2
INC 3,3
INC 2,2
INC 1,1,SZR
JMP MOV1
JMP @MOVEW-1

REX: 2 ; RDA REX HEADER
AREX: BREXH ; a(rex header)
ABZD: BZDRV ; A ( BZUP DRIVER )

BEGIN: SUB 0,0      ; A (THIS BLOCK)
LDA 2,ABZD   ; A (BZUP DEST)
JSR MOVEWORDS    ; COPY THIS BLOCK TO 24000
; use simH 'BREAK 370' prior to BOOT DKP to halt IPL prior to reading REX
JMP -7,2 ; JMP TO 24400-7 = 24371 (I.E. 370: JMP 24371)
LDA 2,AREX
LDA 1,REX
JSR READBLOCK
JMP .-3  ; NON-SKIP FAIL
JSR 100,2 ; jump to REX header 100 WITH (A3) = READ entry point
JMP READBLOCK ; step for REX header routine
JMP BEGIN  ; JMP AFTER BOOT LOAD

.END ; SECTORZERO.T
------------------------------------------------------------------------------------

David had this conversation on the [SimH] mailing list once again:

[Simh] Nova Device Codes

and concluding with 

[Simh] [simh] Nova Device Codes

where Bob Supnik provides the device list...

SimH's list is contained in nova_defs.h:

#define DEV_MDV         001          /* multiply/divide */
#define DEV_ECC         002          /* ECC memory control */
#define DEV_MAP         003          /* MMPU control */
#define DEV_TTI         010          /* console input */
#define DEV_TTO         011          /* console output */
#define DEV_PTR         012          /* paper tape reader */
#define DEV_PTP         013          /* paper tape punch */
#define DEV_CLK         014          /* clock */
#define DEV_PLT         015          /* plotter */
#define DEV_CDR         016          /* card reader */
#define DEV_LPT         017          /* line printer */
#define DEV_DSK         020          /* fixed head disk */
#define DEV_MTA         022          /* magtape */
#define DEV_DCM         024          /* data comm mux */
#define DEV_ADCV        030          /* A/D converter */
#define DEV_QTY         030          /* 4060 multiplexor */
#define DEV_DKP         033          /* disk pack */
#define DEV_CAS         034          /* cassette */
#define DEV_ALM         034          /* ALM/ULM multiplexor */
#define DEV_PIT         043          /* programmable interval timer */
#define DEV_TTI1        050          /* second console input */
#define DEV_TTO1        051          /* second console output */
#define DEV_CPU         077          /* CPU control */

For a more extensive list, consult the Nova documentation on 
http://bitsavers.org/pdf.

/Bob Supnik

I find it interesting that the octal address for the  "Zebra" Disk Drive that we are trying to use <027> does not exist in this list.
------------------------------------------------------------------

My first stab at this modification is found on Simh mailing list here.

And a C compiler Upwork job here.

------------------------------------------------------------------

If you can just tell me what you need in the Accumulators with each DOA, DOB, DOC, and what you will return with DIA, (DIB and DIC are really optional), then I can write a driver to give you those values. Also need to define what happens with the Pulse, Start, and Clear functions.
The standard DG was to do a SEEK when it got a Pulse, and a Read or Write when it got a Start. Clear just reset all busy and done flags.

Also found out that with the simulator's DKP, you can mix and match the 4 drive types even though they all use device 33.
....
If you could tell me how the 'c' program parses each of the commands (DOA, DOB, DOC, DIA, DIB, DIC)
that should be sufficient to write a driver that will provide those terms.

Because the logic would be standard DG controller process. We just need to know what bits to use for what data.

------------------------------------------------------------------

one of the SimH people have critiqued my code modifications, so I need to change those. Here are the code modifications, which I will attempt to make:

This looks potentially OK, but you’re missing one more step necessary when adding a complexly new device. In the file nova_sys.c, there is an array called sim_devices which needs to have an entry for the new device.

It looks like you’ve merely copied the nova_dsk.c and renamed various internal variables and routines to be dzp. This is absolutely fine, but unless the DZP (and the original IRIS device) actually supported all of the disk drive variants that DG supported (as supported by the code in the original nova_dkp.c) then you should probably remove the extra disk types here so that better alignment to reality exists. Also, you’ve left the drv_tab array’s name unchanged and as such it will conflict with the definition in the original nova_dkp module. You can make this array and many other variables local to the nova_dzp module as static variables and routines. The only global which needs to exist is the dzp_dev.

------------------------------------------------------------------

DOA, DOB, DOC, DIA, DIB, DIC, are all nova instructions. Their purpose is to send 16 bits from a CPU register (AC0,AC1,AC2,AC3) to a device "register".
NIO is also a command, but no registers are sent.

A control line can also be set with any of the I/O commands. They are
S = Start
C = Clear
P = Pulse

By convention, Clear generally resets the device busy and done logic to zero.
Start initiates the device. In the case of Disk drives, it tells the controller to set Busy and begin the defined read or write operation.
DG has decided that the Pulse would be used to initiate a seek, which would set Busy on the selected Drive but not the controller.

When the drive completes a seek, it sets Done for the drive.
In the case of read/write, the controller sets the Done flag for the controller (and clears busy).

IRIS does not use any interrupts on disk drives. They are always disabled.

Regarding the 'c' code and writing drivers ..... I've made some progress on understanding how DG controllers work.
I highly recommend "HowToUseNova" from DG for a long hand description of how their controllers work.

The DKP come in 2 formats. The newer one handled larger drive capacities.
See the attached text file. It must be viewed in mono-spaced format to make sense.
I doctored up the nova_dkp.c file to explain a few things about how the Nova communicates with the c-code.
It also provide clues as to how the DKP c-code has to communicate with the simh code to get results.
It looks like nova_dkp takes the register bits it gets from the nova I/O commands and puts them into registers that the simulator understands.
I'm guessing that in order to create a new drive type DZP, you may need both a simh file to talk to the emulator, and a nova file that converts the I/O commands 

The simulator seems to simulate some latency for head movement. So there is a slight delay (micro-seconds) between the program setting busy and the simulator setting done.

Hope this helps clear some things up.

~David

------------------------------------------------------------------

This page is a part of the "Understanding IRIS" collection.  

No comments:

Post a Comment