• Please review our updated Terms and Rules here

NOVA assembler question

Qbus

Veteran Member
Joined
Feb 23, 2011
Messages
961
Location
Salisbury Maryland
Have never been accused of being the sharpest tool in the shed and in the last couple years been trying to teach myself assembler for the Data General NOVA/Rolm military platform.
I have now a couple working systems and a small understanding of the layout of the system and have some experience loading and working with the 16 bit systems.
The problem I have now is how to use the JSR (jump sub routine) command, can use the JMP all day long to drive the PC to another location but need to be able to call a jump to a sub routine for doing things like printing but cannot see how you get the routine to go back to the next address in the PC? Think the manual says something about putting the return address in A3 but just cant see how that works, use to doing things like in Basic where you put return on the end of the sub routine but don’t understand the syntax for NOVA speak.
The problem is I want to have the system print out a string of characters to TT0 and right now have to do a LDA(020100)from a fixed address to A0, test TT0 for ready (063511) JMP back until TT0 ready (000777) then print DOA (061111) and start all over again. Want to have a JSR that executes Test TT0 063511, jump back until ready 000777 and when ready print A0 061111 so I don’t have to enter that string for each character.
This is what I currently have to do:

1000 020100 LDA 0 100
1001 063511 Test TT0
1002 000777 JMP back 1
1003 061111 DOAS print to TT0
1004 020101 LDA 0 101
1005 063511
1006 000777
1007 061111
1010 020102 LDA 0 102
1011 063511
1012 000777
1013 061111
1014 020103 LDA 103

I am using addresses 100 to around 150 for the stuff that gets printed out. But the executable program starts at 1000
 
From the "How to use the Nova Computers" document from DG.

The usual procedure for calling a subroutine is to give a JSR whose effective address is the starting location
of the routine. Since PC + 1 is saved in AC3, a subsequent return can be made to the location following the
JSR simply by giving a JMP 0,3. Note also that PC + 1 is saved in an accumulator.
 
Sounds surprisingly simple just use the JMP command back three. The problem is I am a hardware guy and not a software person.
 
Let's assume one character per word for simplicity (saving byte pointers for another day), with the string terminated by a null (0). Then you could do something like this:
Code:
[FONT=Courier New]
        LDA     2,HELLO
        LDA     0,0,2     ; GET CHARACTER FROM STRING
        MOV     0,0,SNR   ; END OF STRING?
        JMP     DONE      ;  YES - BAIL OUT
        JSR     PUTC      ;  NO - PRINT IT
        INC     2,2       ; MOVE TO NEXT CHARACTER
        JMP     .-5
DONE:                     ; CONTINUE PROCESSING...
        HALT

PUTC:   SKPBZ   TTO
        JMP     .-1
        DOAS    0,TTO
        JMP     0,3

HELLO:  .+1
        'H
        'E
        'L
        'L
        'O
        040                ; (SPACE)
        'W
        'O
        'R
        'L
        'D
        015                ; (CR)
        012                ; (LF)
        0
[/FONT]

This use of AC2 & 3 is known as indexed addressing - the target address is specified by the contents of the register plus or minus the specified offset.
 
Sounds surprisingly simple just use the JMP command back three. The problem is I am a hardware guy and not a software person.

It isn't jump back three, but JMP 0,3 means to jump to the contents of AC3 + 0. If the JSR stored the return adddress into AC3, then AC3 + 0 is the return address. This also means you have the address of the words following the JSR instruction and could potentially pass arguments inline in the code.

Back in university I did an independent study with another student by writing a Nova simulator to run on the PDP11/70 running BSD Unix. The basic Nova instruction set is very easy to simulate, very regular. The university used that simulator for a number of years to teach the assembly language course for which the actual hardware was a single Nova 800 attached to a Teletype 33 with a paper tape punch/reader for storage.
 
Let's see if this helps to explain Nova addressing modes to a hardware guy. Let's model the JMP instruction. This loads the PC register with a new value. Bits 6 & 7 of the instruction specify the addressing mode:
0 = absolute
1 = relative to PC
2 = relative to AC2
3 = relative to AC3

Bits 8-15 of the instruction specify the displacement. In the case of mode 0 (absolute), this is an unsigned value that specifies a memory location in the range 0-377 (octal) - sometimes called "Page 0." In the other cases, it is a signed value in the range -200 octal to +177 octal (-128 to +127 decimal) that is added to the value in the specified register.

So one possible hardware implementation uses multiplexers, with instruction bits 6 & 7 selecting the input. It looks something like this:

JMP.png

The A multiplexer is used to extend the sign bit of the 8-bit displacement value (or not). The B multiplexer selects the base value to which the offset (A value) is applied.
 
Finally learned how to work with the JMP and JSR commands. Next will be the ability to work beyond page zero in memory. This program is up and running on the hardware and would assume it will work on any Data General NOVA system although I am running it on a military Rolm 1602 system.

Data to be printed is stored in locations 100 to 113; you cannot print from memory directly with all I/O commands having to go thru an accumulator.
I am using the A0 accumulator to feed TT 0


1000 020100 LDA A0 100
1001 004300 JSR 300 This command also stores PC +1 in A3
1002 020101 LDA A0 101
1003 004300 JSR 300
1004 020102 LDA A0 102
1005 004300 JSR 300
1006 020103 LDA A0 103
1007 004300 JSR 300
1010 020104 LDA A0 104
1011 004300 JSR 300
1012 020105 LDA A0 105
1013 004300 JSR 300
1014 020106 LDA A0 106
1015 004300 JSR 300
1016 020107 LDA A0 107
1017 004300 JSR 300
1020 020110 LDA A0 110
1021 004300 JSR 300
1022 020111 LDA A0 111
1023 004300 JSR 300
1024 020112 LDA A0 112
1025 004300 JSR 300
1026 020113 LDA A0 113
1027 004300 JSR 300
1030 063077 HALT

Print Sub Routine

300 063511 Test TT0 if ready
301 000777 JMP back one until ready
302 061111 DOA print out (A0) to TT0
303 001400 JMP to address in A3
 
A favorite trick of Nova (and other architectures) was to place the text to be printed immediately after the JSR and terminate it with a zero word. On entry to the print subroutine, A3 would point to the first word to be printed. You just kept picking up more words in the print routine using A3 and incrementing it until you hit the zero word, then returned as normal using JMP 0,A3.
 
The problem with such a trick is that the range of PC-relative addressing is so limited that you could easily push something out of range by embedding a string inline with the code. Also, you can't skip over it. I've written and seen a lot of Nova code in my day (admittedly most of it running under RDOS which has .SYSTM calls to print a string) , and I don't believe I've ever seen it used. Never used it myself that I can recall.

But OP is making progress, which is good. A next simple step would be to move the print subroutine out of page zero, and that can be easily done by using indirect addressing. Instead of putting the subroutine (as small as it is in this case) at location 300, put it anywhere is memory and put its address in location 300. Then you call it with JSR @300 instead of JSR 300. You're still using a location in page zero, but only one and using that (instead of PC-relative addressing) means you can call that routine from anywhere in memory. Something like a print routine is likely to be called from a lot of places in your code.

Of course, another trick to call a subroutine from anywhere in memory that doesn't use page zero is:

JSR @.+1
FUNC

(FUNC is the address of the function you want to call).

Then in FUNC, you do JMP 1,3 instead of JMP 0,3 to return. Skipping is an issue here as well...
 
Of course, another trick to call a subroutine from anywhere in memory that doesn't use page zero is: ...
DG had an early Eclipse-era manual that listed hundreds of different coding tricks. They were pretty free with information in their manuals (as long as you weren't Keronix, DCC, or anybody else that got in their way). There was also a manual that listed the 74xx equivalents for all DG house part numbers. Neither are on Bitsavers.

I gave away my complete S/2xx system (an S/200 system that I hacked to be an S/230 + WCS), all of my manuals and software (including the source code for RDOS and XBASIC) around 1987 to someone who said that he was going to preserve it, but then vanished without a trace. So I no longer have any of that, though I may have some sales literature for later DG systems). That computer would be a nightmare to maintain as it was a combination of boards from several different DG processor models, plus some protoboards like the one that let the S/200 MAP work with S/230 semiconductor memory instead of S/200 core. A lot of that was in my head (it since fell out) and jotted notes, and any schematics I made were likely never updated as I kept adding and fixing things.
 
Hmmm... I haven't seen either of those manuals. But I'd like to if anyone's got 'em :)

Appendix E of the (Nova Line) Programmer's Reference Manual (015-000023-03) gives Instruction Use Examples: things like how to decrement a register & XOR two registers since there aren't instructions to do that. It's quite handy, though it doesn't have anything like these JSR tricks...
 
Hmmm... I haven't seen either of those manuals. But I'd like to if anyone's got 'em :)
It may be that they were internal documents, although they had the Eclipse-style blue-and-black swoosh on the cover. As you know, everyting DG producted had "Proprietary and Confidential" printed on it (probably even the toilet paper at WeBo), so it was hard to tell what was actually considered secret and what wasn't. DG sales learned early on to just sell me whatever I ordered, Field Service was terrified (probably starting when I ordered a 6061 drive which required re-wiring around half of the I/O paddles. In early Eclipsen these had individual wire-wrap wires, all white of course, which had to get wrapped to specific backplane pins which varied depending on the peripheral in question) and had the backplane and paddles re-wired by the time they showed up to do the time+materials installation/startup of the 6061 and found it up and running when they got there.

Software took a while longer. I was sending in a steady stream of STRs (bug reports), mostly on XBASIC but some on RDOS. The tipping point was when I sent in my [in]famous STR about "XBASIC will allow any 32 terminals to be configured, as long as they're the first 32". I ended up running XBASIC in both FG and BG with 32 terminals on each, and a method for submitting batch jobs in other languages (a combination of normal XBASIC file I/O and a bunch of "CALL n" assembler subroutines) so that XBASIC in BG could be shut down and the various other batch jobs run and the results returned to the users as files in their accounts. Anyway, that STR came back on top of a stack of other STRs and a magtape, with a note that said "Congratulations! You're the new XBASIC maintainer!". I believe I cleared all but one (which was written by me, anyway) of the STRs within the year. That was probably due to the abomination that was XBASIC 5.0 - it shipped with bugs like:
Code:
10 FOR I = 1 TO 10
20 PRINT I
30 LET I  = I + 1
40 NEXT

resulting in the following:
Code:
0
0
0
0
[continue forever]

The 5.0.1 patch (on the infamous Data General Mini-Reel - think DECtape spools but for regular 9-track tape) shipped a few days later.

Anyway, the bug I couldn't fix was something well beyond the intent of the original designers. ENTER (load code into the current working space) could be used as both an immediate command and as a program statement. I was using it in statement mode to implement poor man's overlays, replacing chunks of existing programs while running. Unfortunately, the code that implemented ENTER ran in a different, asynchronous routine than the code interpreter, so the interpreter could stumble into a mishmash of old and new code, and the only way around it was to introduce long waits between executing the ENTER and trying to access that code space. And if the computer was particularly loaded (as I recall, the ALGOL 60 compiler was a pig), the wait wouldn't be long enough. I tried all sorts of things including setting a flag at the end of the ENTER processing code and then doing a CALL to wait for the flag to be set, but could never get it to work reliably enough (there was only one ENTER subroutine across all 32 users, while code execution was per-user).

I learned DG assembler to implement one simple function - there was no way to flush the lineprinter (Centronics 101A) spool from XBASIC. There was (IIRC) a SPKILL primitive, but it was only available in RDOS, not from XBASIC. So I used the user-written assembler subroutine option to implement it in XBASIC. The both good and bad thing was that any code written that way was fully privileged. Actually, since the machine had no concept of privileges, everything was privileged but XBASIC prevented you from foot-shooting other users. No such protections in assembler. By the time I had advanced to allowing execution of assembly code embedded in XBASIC DIMension statements, this was downright dangerous. So I implemented protected programs that could not be listed or modified, only executed, to keep people out (this was an academic timesharing environment, after all).

Speaking of Field Service, the reason I got involved with the hardware was because I was writing programs on that DG for a friend who was attending SPC while I was still in high school. Every once in a while, the terminal would spit out "ERROR 4 SYSTEM" (which was expanded in XBASIC 5 to "ERROR 4 - Unknown software or hardware fault") and the entire program would be lost. Since this tended to happen on SAVE commands, you'd also lose the on-disk copy. Anyway, I went into the computer room which was a converted classroom divided into offices and a "computer room", pulled out the chassis (it was on rails) and noticed some of the fans weren't running. I scavenged some appropriate replacement fans from the Physics department out of equipment they weren't using (to monitor experiments on their nuclear reactor*) and had the processor apart on the floor. Some guy comes in (there had been nobody in these unlocked rooms when I got there) and says "Who the hell are you and what do you think you're doing?" and I said "Fixing the computer, and who the hell are you?" That's how I met the director of Academic Computing and started a 22-year-long career there.

Anyway, the reason for problems like that was that they would alternate between having a service contract and trying to save money by not having a service contract, betting that the computer would break infrequently enough that they'd save money. If you know those early Eclipse systems and 4000-series peripherals, you know that that was a pretty bad bet. So we'd call for time+materials service and 2 guys would come out around 10 AM, unpack their tools and lounge around for an hour, then vanish (to the pub at the end of the block) and reappear around 2 PM and spend an hour packing up their tools and leave around 3 PM, billing us for 5 hours of "service". To those not familiar with the rather bizarre DG culture of the mid-70s this might seem impossible, but it was pretty much standard operating procedure when they could get away with it.

* The above might sound like the imaginings of a deranged mind, but I assure you this is all true. Strange days. After I left, they finally gave up the reactor (it had lost its operating license when they flushed it out and let the contaminated water run down the street, and had a storage-only license that was expiring). The chair of the physics department wrote a hand-scrawled letter to the NRC saying, essentially "BTW, we lost 7kg of uranium slugs. Hope you don't mind. K thx bye." Since that is utterly unbelieveable, here is a copy of the letter from the NRC's archives.
 
When you says XBASIC, do you mean Extended BASIC or was it some other version that only ran on the Eclipse? I'm familiar with Extended BASIC 4.0. This was when I was in high school. We had a Nova 820 running RDOS. We had an attendance system that was written in FORTRAN that we would run every day after school. But during school hours, the system ran Extended BASIC. As provided by Data General, you could generate versions that ran a single terminal, multiple terminals (time shared) or batch mode, which used the card reader and line printer as I/O devices. We wanted to run timeshare and batch mode simultaneously. We asked Data General why the card reader and line printer couldn't just be treated as another terminal. We didn't get a good response, except that they didn't think it could be done. Then our local Application Engineer (I think that was the term they used for the guys in the field offices) slipped us an under-the-table copy of the source code and we proceeded to modify it. And it worked, though we never ran more than 3 terminals and CDR/LPT. We even designed our own mark-sense programming cards to make batch use easier (just mark the bubble for the keyword instead of having to spell it out in Hollerith code and stuff like that...). I hand-delivered the complete source code listings to Data General (I think the name of the guy I met there and talked to was Jerry Spielman), but I don't think they ever did anything with it. I was off to college and didn't use BASIC again. But I was working in a lab in college that had a Nova, and they got their hands on the RDOS sources (somehow, also under-the table). So I've looked through those as well... :)
 
When you says XBASIC, do you mean Extended BASIC or was it some other version that only ran on the Eclipse?
Yes, Extended BASIC as opposed to the somewhat-later Commercial BASIC (CBASIC) which I think was developed outside of DG and brought in-house. DG wanted something to compete with MAI Basic Four's systems. That's what drove the Dasher series of terminals to have a veritable forest of function keys - Basic Four had customized Lear Siegler CRTs that had keyboards with 4 "programmable" function keys, I through IV. So 15 or so (along with dedicated numeric and editing keypads) had to be better, right? I also think the MicroNOVA might have had some genesis in a desire to make a much more inexpensive system to compete with Basic Four - after they stopped using Microdata CPUS (anyone remember Clock/Reset/Run?) and built them in-house, their costs went down and margins went up. Something DG badly needed at the time.

As provided by Data General, you could generate versions that ran a single terminal, multiple terminals (time shared) or batch mode, which used the card reader and line printer as I/O devices. We wanted to run timeshare and batch mode simultaneously.
Yup. That was the root of my infamous STR - DG never improved the XBASIC generation procedure when the ALM chassis was introduced - you could have 128 terminals or more, depending on whether you wanted modem control or not. But XBASIC's config asked you how many terminals you wanted and what their line numbers were, and wouldn't accept a line number greater than 32.

By batch, I assume you mean XBASIC batch as opposed to other languages? If NOVA RDOS supported BG and FG partitions (I don't remember if it did), it should have been a simple procedure to build a timesharing partition and a single-user partition. There was enough space in the QTY driver (the original 4-port async multiplexor, before the ALM) to patch the driver to talk to the card reader and line printer. Is that what you did?

Then our local Application Engineer (I think that was the term they used for the guys in the field offices) slipped us an under-the-table copy of the source code and we proceeded to modify it.
Yup, at the time all of the local field offices got copies of the full source for everything. Before corporate software decided "Tag! You're it!" with me and XBASIC, I'd visit the local sales office with a 4234 (Diablo 44 - I think the inhouse DG design was the 6021) 5MB pack and get the latest code. I still dropped in even after I started getting source directly from corporate, mostly to sponge freebie manuals and sales literature, but also to shoot the breeze with some of their hardware people, who were amazed at what I'd done to take one of the very first S/200 systems (shipped July '75 IIRC) and make it into something that was for all intents and purposes an S/230+WCS. Every once in a while I'd get a visit from someone who would be very confused and want to run S/200 diagnostics, and I'd say they needed the S/230 variants*. They would go "But... the front panel says S/200 and has bulbs, not LEDs" and I'd have to explain things (I still used FS for non-CPU issues like disk drive head crashes).

* You may remember that RDOS came in a dozen or more variants, ARDOS, MRDOS (mapped), etc. Some were generated from the same distribution tapes, but others used completely different tapes. At the time it was "classic NOVA", "NOVA 3", "Eclipse" and "Advanced Eclipse" as we as some subvariants. Then the S/140 and Nova 4 came along (same thing, different skin and microcode - AMD 2901-based, IIRC - the S/200 was 74181-based) and introduced yet more variants.

I remember one time asking somebody there (this was around the time of the M/600 - a machine wandering the darkness looking for a market) about the parking space reserved for "Bird Machine" in the office park next to the DG spaces. Mostly I got blank stares, but somebody picked me up and dragged me into an inner office and said it wasn't their parking space, but how the hell did I know about "Eagle"? I had to explain that I'd been clued in by corporate. And most of corporate was still unaware as well, as announcement was a few months away.
 
Back
Top