August 22, 2025

Sun 3 bootrom souce - the Sun 3/80 - nvram

When we watch the diagnostics during my first "in a long time" power up, we see:

I should say so. It isn't low, it is dead. At least I'm sure that after over 30 years it is dead.
Then after diagnostics finish we see:
ID PROM invalid.
ERROR: missing or invalid ID prom

NVRAM, EEPROM, or IDPROM?

These 3 terms get tossed around, even by the bootrom itself. So what is the story?

The 3/80 has NVRAM in the form of a M48T02, made by ST electronics. This is a 2Kx8 static ram with a piggyback battery. It also includes a clock/timer with some registers that hide the last few bytes of the ram.

This chip is the whole story for the 3/80. Older boards, like the 3/160 had an EEPROM along with an IDPROM. No battery on the old boards, which is nice. They still work after all this time without hassle or fuss. On these old boards the EEPROM was a 2Kx8 device and the clock/timer was yet a different chip. The IDPROM was a small bipolar memory that was programmed at the factory. It contained, among other things, the ethernet address.

Stick with me for how this plays out with the 3/80. First look at these addresses from the lovely "^A" command that the 3/80 prom provides:

Device:         Virtual Address: Physical Address:
EEPROM          0xFEF04000:      0x64000000:
TOD             0xFEF06000:      0x640007F8:
IDPROM          0xFEF047D8:      0x640007D8:
Look at the physical addresses. These are all in the same chip!

The TOD clock/timer registers at 0x7f8 cover the last 8 bytes of the ram in the M48T02, as we already have mentioned. But look! The IDPROM is just the last 32 bytes of that 2K ram! How much would you bet that the bipolar ROM used on a 3/160 was 32 bytes in size? This leaves the first 2k - 40 bytes of the static ram (battery backed) for what is erroneously called EEPROM.

I suppose we can forgive the Sun rom in this case. Although hardware wise, it is not really EEPROM, Sun sort of usurped the term EEPROM for what holds system configuration. So it is more of a functional term in that context.

For completeness at the risk of confusion, look at this address scheme as used by the Sun 3/160.

EEPROM -- 0x6400_0000  (0xfef0_4000 virtual)
TOD    -- 0x????_????  (0xfef0_6000 virtual)
On my board, the EEPROM is a SEEQ DQ2816A device. It is rated for 10,000 write cycles. the 5516 part number you see on the schematic is a pin identical device that allows up to 100,000 write cycles. It has no timer tucked away in the last 8 locations.

The clock/timer on the 3/160 is the Intersil 7170 chip. It is at an entirely different physical address and it seems unlikely that it has identical registers to the timer in the M48T02. However it is mapped to the same virtual address.

The IDPROM in the 3/160 is in a wildly different location.

How to get my 3/80 to boot

My 3/80 is not going to do anything that I would like it to do until I do something about the dead battery in the M48T02. I see 3 options: I actually think that rigging up a coin battery is the best solution. If I buy another M48T02, the battery in it will just go dead eventually. A coin battery in a holder can be easily replaced.

A software solution

I have a working serial connection. The M48T02 still functions as ram, it just doesn't hold data when powered off. I could write a program that runs on my linux machine and communicates with the bootrom and configures the "EEPROM" each and every time I power the machine up. This would be an interesting programming task rather than somewhat delicate cutting and soldering -- and I might try it.

Use the bootrom

The "Q" command in the bootrom accesses the EEPROM.

If you just type "q", it starts displaying bytes at address 0.
If you type "q7d0" it will start displaying at address 0x7d0.
You can do one of three things:

It is quite happy to let you look at values in the IDPROM area beginning at 0x7d8, but it won't let you modify them. I suppose this was intended so that ignorant users did not corrupt the IDPROM information.

You can look at the TOD registers in the 0x7f8 to 0x7ff range also. You can write to them also. They don't behave as ram, being device registers after all.

What goes into the IDPROM area?

7d8  --  01  version number, always this
7d9  --  42  first byte of hostid
7da  --  xx  1st byte of ether
7db  --  xx  2nd byte of ether
7dc  --  xx  3rd byte of ether
7dd  --  xx  4th byte of ether
7de  --  xx  5th byte of ether
7df  --  xx  6th byte of ether
7e0  --  00  date of manufacture
7e1  --  00  date of manufacture
7e2  --  00  date of manufacture
7e3  --  00  date of manufacture
7e4  --  yy  serial
7e5  --  yy  serial
7e6  --  yy  serial
7e7  --  ss  checksum
There you go, 16 bytes in all.
The checksum is just the XOR of the 15 preceding bytes.

A subterfuge

The recipe says to set EEPROM 70b to 6:
q70b
6
We have to work around the bootrom protecting the IDPROM area.
I type the following
^t fef04000
Virtual Addr 0xFEF04000 is mapped to Physical Addr 0x64000000.
TIA Entry = 0xFFA500, TIB Entry = 0xFFB80A.
PTE = 0x64000049
Then we do:
m a fedfa000
ffa500
.
m b fedfa000
ffb80a
.
p fedfa000
64000049
.
o fedfa7d8
Now you type in the 16 bytes for the idprom. You can use "q 7d8" to check.
I use "k2" to reboot.

Note! I only set the 16 IDPROM bytes in the NVRAM to get this to work! There is plenty of other stuff in the NVRAM, but we don't need to worry about it to get the machine booting.

Now it tries to boot

Requesting Internet address for 8:0:20:1:DB:2
le: No Carrier
le: No Carrier
Using IP Address 192.168.0.27 = C0A8001B
Boot: le(0,0,0)
We move the network cable in the midst of the above.

Wireshark tells us it is looking for C0A8001B.SUN3X rather than just C0A8001B. We rename the file accordingly. Now we get:

Auto-boot in progress...
le: cannot initialize
Retrying
Using IP Address 192.168.0.27 = C0A8001B
Boot: le(0,0,0)
Booting from tftp server at 192.168.0.5 = C0A80005
Downloaded 2776 bytes from tftp server.

Error (PSR = 0x203) Timeout Bus Error:
  Vaddr: 0FE02004, Paddr: 00FFA004, Read, FC 5, Size 1 at 0x000048A2.
Now the game is to find out what my demo is doing at address 0x48A2. I rebuild the demo, and use k2 again. Now I get:
Downloaded 2784 bytes from tftp server.

Error (PSR = 0x203) Timeout Bus Error:
  Vaddr: 0FE02004, Paddr: 00FFA004, Read, FC 5, Size 1 at 0x000048AA.
I can use "v 4800 4900" to get the rom to dump memory for me. I verify that my dump file and what is in memory do match.
The offending instruction is in xx:
 48aa:   1028 0004       moveb %a0@(4),%d0
This ought to be a write to the uart data register. Indeed, the memory map shows 0xFEF02000 to be the base address for the serial port. Could it be that the rom has cleared the page maps before transfering control?

The Sun 3/80 doesn't have the nice set of 8 diag LED that I can blink or play with.

Try my blink demo

This was the first thing I ran on the 3/280.
Using IP Address 192.168.0.27 = C0A8001B
Boot: le(0,0,0)
Booting from tftp server at 192.168.0.5 = C0A80005
Downloaded 206 bytes from tftp server.

Error (PSR = 0x203) Timeout Bus Error:
  Vaddr: 0FE06011, Paddr: 00000011, Write, FC 5, Size 1 at 0x00004084.
The address 0FE06011 is a register in the Intersil 7071 TOD chip, which doesn't even exist on the 3/80, so this experiment doesn't tell us much. I write to that address to turn off timer interrupts that interfere with my blink demo.

Where do we go from here?

One possibility is to dig into the ROM disassembly and find out where it transfers control to the loaded program. Does it change (or reduce) the virtual address map in a way that explains why we cannot access the serial port uart? We have seen that code is loaded and started at 0x4000. This is LOADADDR in the rom source -- not to be confused with USERCODE at 0x2000!

On a successful load, the function boot() will return with the load address. It returns to code in sys/commands.c which will generally call "bootreset" which is in trap.s. The comments here say things like:

Reset the world's maps.

The code in trap.s is surprisingly convoluted. It doesn't just branch to the LOADADDR, but seems to set up a trap frame so it can use a RTE instruction to launch the user code! And what about the address USERCODE at 0x2000? The code in trap.s has dealings with this and this is the one and only place this symbol is referenced. Clearly our demo got loaded (and started) at 0x4000. All mysterious to me at this point. A deep study of trap.s would be educational.

Another possiblity is to make calls back to the ROM via "romvec". There are both putchar() and printf() entry points in romvec. It we are able to use these, we could then write a program to display the address map. If the maps have generally been reset, will these work? What is the point of having them if they don't?


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org