The HP 700/RX is an X-terminal, built by HP in the 1990s. It has an i960 CPU, which was a relatively obscure RISC processor made by Intel. Obscure in the sense that it was not used much as the main CPU in general purpose personal computers or workstations. It used register windows, somewhat like SPARC did, and (at least for some instructions?) it has conditional execution (like ARM). It was also one of the first super-scalar processors. (An interesting video about a slightly different variant of the i960, the i960Jx, can be found on YouTube.)
NOTE: The HP 700/RX user community is probably extremely small, so if you have one of these machines in working order, please send me an email just to keep in touch. My address can be found here.
Here are the specs quoted from Wikipedia's article about the machine:
and I think this is what I have in mine:
The text on the CPU in mine says "A80960CA-25 L1401453 S V907 (M)(C)'89". The text on the RAMDAC chip says "BT458LPJ135 555 9122", so it is a Brooktree 458. The text on a chip at the back says "TL16C451FN" which is a Serial/Parallel port controller.
Although its original purpose in life was to be an X-terminal, i.e. to run X Server display software, another way of seeing it is that it is a simple computer, but with no harddisk so it has to load its software over ethernet (or via ROM) every time it boots up.
A manual for the i960CA CPU can be found here:
An important thing to note is that this machine (if I understood correctly) does not have an MMU, so it will never be able to run a complete modern Unix such as one of the BSDs or Linux. However, I thought it would be a fun and interesting/complex challenge to see if it could run something other than the original software.
The last photo shows the 700/RX in use an an X-terminal (it is the right-most monitor in the photo).
When it is powered on, the boot screen (graphical) is brought up pretty quickly. Mouse and keyboard are used to configure the machine, if necessary. It also has a self-test function. (Since I have a HIL keyboard and not a PS/2 keyboard attached, it fails the PS/2 keyboard test, which is as expected.)
where the first link has working downloadable files, but the second one does not seem to have them any more. Also, the first of the links refers to the second one.
One of the goals of this web page is to describe what I have found out about running and writing custom code for the 700/RX, so that the original software will not be necessary at all.
I have not found anything at all on the Internet about technical specs needed to run custom code, so this will be a trial-and-error endeavour.
A quick look at the files in the 700RX.tar.gz archive:
$ file *
C2700A: i960 b.out relocatable object
C2708A: i960 b.out relocatable object
DEC_XTrap.b06: i960 b.out relocatable object not stripped
KBidExt.b06: i960 b.out relocatable object not stripped
ListXtal.b06: i960 b.out relocatable object not stripped
...
modules.700rx: ASCII text
xtouch.mt.b06: i960 b.out relocatable object not stripped
Actually, it first loads the C2708A binary, then optionally some modules as defined in modules.700rx, and then (presumably) calls back into the first binary again. I don't know yet if it is the C2708A binary that itself triggers the loading of modules, or if that is the way the PROM forces things to work.
Here are two photos, showing the main C2708A binary being loaded (with a modified string in the header showing "hello world" just to see if it would complain about that), and the module loading, showing the ListXtal.b06 module being executed. I had intenionally changed one of the instructions in that binary to cause an infinite loop, to make it hang.
Otherwise, if the modules don't hang or wait, the machine will quickly switch over to the main C2708A X-Server program and clear the screen to show the plain X desktop.
I tried placing an infinite-loop instruction in the C2708A binary, but then the machine just frooze with a blank display. This indicates that the ROM first turns off the display, then jumps to the C2708A binary, and then... something happens. Either the C2708A binary reinitializes the video output, or it doesn't. Then perhaps it hands control back to the ROM, or perhaps it only uses the ROM to output text messages while it is loading the extra modules. I am not sure. In any case, at the end of module loading, the familiar X desktop is displayed, which means that the C2708A binary is running again.
The b.out file format is similar to the traditional
a.out format, with some additional i960-specific fields.
After the header, it looks like regular data and machine code,
using 32-bit aligned instructions. Here is one source of information about its origin and purpose.
$ hexdump -C C2708A | more
00000000 0d 01 00 00 8c 7f 18 00 00 00 00 00 34 3d 00 00 |............4=..|
00000010 00 00 00 00 00 50 e0 3f 00 00 00 00 00 00 00 00 |.....P.?........|
00000020 00 50 e0 3f 00 10 e0 3f 04 02 04 00 53 4d 63 44 |.P.?...?....SMcD|
00000030 1f 00 00 00 00 00 00 00 00 00 00 00 40 28 23 29 |............@(#)|
00000040 37 30 30 2f 52 58 20 53 65 72 76 65 72 20 43 6f |700/RX Server Co|
00000050 64 65 2c 20 52 65 6c 65 61 73 65 20 42 2e 30 36 |de, Release B.06|
00000060 2e 31 30 20 2d 20 54 75 65 20 41 70 72 20 30 32 |.10 - Tue Apr 02|
00000070 20 30 31 3a 34 32 3a 31 37 20 31 39 39 36 20 20 | 01:42:17 1996 |
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ab cd |................|
000000c0 00 01 18 8c 83 c4 18 65 06 1e 20 5c 00 30 68 8c |.......e.. \.0h.|
000000d0 00 30 00 c0 00 50 23 82 08 1e 88 5c 00 50 74 90 |.0...P#....\.Pt.|
000000e0 00 1e f0 5c 00 30 18 8c 02 00 1f 00 00 30 20 8c |...\.0.......0 .|
000000f0 02 00 1f 00 80 ca 20 65 00 3e 10 5c 00 3e 08 5c |...... e.>.\.>.\|
...
The commands required to build binutils and gcc inside NetBSD/pmax
inside GXemul are approximately:
CROSSDEV=$HOME/crossdev
mkdir -p $CROSSDEV
ftp -4 http://ftp.gnu.org/gnu/binutils/binutils-2.16.1.tar.bz2
tar zxf binutils-2.16.1.tar.bz2
cd binutils-2.16.1
./configure --prefix=$CROSSDEV/ --target=i960-unknown-coff --disable-werror
make
make install
cd ..
PATH=$CROSSDEV/bin:$PATH
ftp -4 http://ftp.gnu.org/gnu/gcc/gcc-3.4.6/gcc-core-3.4.6.tar.bz2
tar zxf gcc-core-3.4.6.tar.bz2
cd gcc-3.4.6
mkdir objdir
cd objdir
../configure --prefix=$CROSSDEV/ --target=i960-unknown-coff --disable-werror --enable-obsolete
gmake
gmake install
cd ../..
cat > apa.c
int f(int x, int y)
{
int z = 123 * x + (y << 3);
return z;
}
int r(int n)
{
if (n <= 1)
return n;
return r(n-1) + r(n-2);
}
(CTRL-D)
i960-unknown-coff-gcc apa.c -c -O2
i960-unknown-coff-objcopy apa.o --output-target=b.out.little apa2.o
file apa*.o
which results in:
apa.o: MIPSEB-LE ECOFF executable not stripped - version 120.101
apa2.o: i960 b.out relocatable object not stripped
and both of these can be dumped with objdump:
apa2.o: file format b.out.little
Disassembly of section .text:
00000000 <_f>:
0: 00 30 f0 8c lda 24
The b.out variant looks like similar to the HP 700/RX' standard software:
# hexdump -C apa2.o
00000000 0d 01 00 00 70 00 00 00 00 00 00 00 00 00 00 00 |....p...........|
00000010 54 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |T...............|
00000020 00 00 00 00 70 00 00 00 04 00 00 00 00 30 f0 8c |....p........0..|
00000030 24 00 00 00 1e 16 90 5c 00 1e f0 5c 05 0e a4 59 |$......\...\...Y|
00000040 10 01 a5 59 02 0e a5 59 10 01 a5 59 91 1d 85 8c |...Y...Y...Y....|
00000050 00 00 00 0a 00 00 00 00 00 00 00 00 10 16 28 5c |..............(\|
00000060 01 09 84 59 05 16 a0 5c 20 60 09 3b 00 30 00 86 |...Y...\ `.;.0..|
00000070 30 00 00 00 10 16 20 5c 02 49 81 59 00 30 00 86 |0..... \.I.Y.0..|
00000080 30 00 00 00 04 00 a4 59 14 16 80 5c 00 00 00 0a |0......Y...\....|
00000090 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |................|
000000a0 04 00 00 04 44 00 00 00 04 00 00 04 54 00 00 00 |....D.......T...|
000000b0 04 00 00 04 04 00 00 00 04 00 00 00 00 00 00 00 |................|
000000c0 0a 00 00 00 05 00 00 00 00 00 00 00 0d 00 00 00 |................|
000000d0 04 00 00 00 08 00 00 00 12 00 00 00 05 00 00 00 |................|
000000e0 30 00 00 00 15 00 00 00 06 00 00 00 70 00 00 00 |0...........p...|
000000f0 1b 00 00 00 08 00 00 00 70 00 00 00 20 00 00 00 |........p... ...|
00000100 7d 00 00 00 00 00 00 00 26 00 00 00 2e 74 65 78 |}.......&....tex|
00000110 74 00 5f 66 00 66 2e 6c 66 00 5f 72 00 2e 64 61 |t._f.f.lf._r..da|
00000120 74 61 00 2e 62 73 73 00 61 70 61 2e 63 00 |ta..bss.apa.c.|
Now, using objdump to look at the C2708A binary, we can draw some more
immediate conclusions:
# i960-unknown-coff-objdump -x C2708A
C2708A: file format b.out.little
C2708A
architecture: i960:core, flags 0x00000002:
EXEC_P
start address 0x3fe05000
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00187f8c 3fe05000 3fe05000 0000002c 2**4
CONTENTS, ALLOC, LOAD, CODE
1 .data 00000000 3fe01000 3fe01000 00187fb8 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00003d34 3fe01000 3fe01000 00000000 2**4
ALLOC
SYMBOL TABLE:
no symbols
# i960-unknown-coff-objdump -d C2708A
Disassembly of section .text:
3fe05000 <.text>:
3fe05000: 53 4d 63 44 .word 0x44634d53 <----- Entry point claims to be here
3fe05004: 1f 00 00 00 .word 0x0000001f
...
3fe05010: 40 28 23 29 .word 0x29232840
3fe05014: 37 30 30 2f .word 0x2f303037
3fe05018: 52 58 20 53 .word 0x53205852
3fe0501c: 65 72 76 65 modtc sf5,25,sf14
3fe05020: 72 20 43 6f .word 0x6f432072
3fe05024: 64 65 2c 20 testno 5
3fe05028: 52 65 6c 65 .word 0x656c6552
3fe0502c: 61 73 65 20 testno 12
3fe05030: 42 2e 30 36 cmpoble.f 6,pfp,0x3fe05e70
3fe05034: 2e 31 30 20 testno.f 6
3fe05038: 2d 20 54 75 .word 0x7554202d
3fe0503c: 65 20 41 70 .word 0x70412065
3fe05040: 72 20 30 32 cmpobe.f 6,pfp,0x3fe050b0
3fe05044: 20 30 31 3a cmpibe 6,r4,0x3fe04064
3fe05048: 34 32 3a 31 cmpobg 7,r8,0x3fe0427c
3fe0504c: 37 20 31 39 cmpibg.f 6,sf4,0x3fe05080
3fe05050: 39 36 20 20 testno 4
...
3fe05090: 00 fe ab cd .word 0xcdabfe00
3fe05094: 00 01 18 8c lda 0x100,r3 <----- This looks like the first "real" instruction
3fe05098: 83 c4 18 65 sysctl r3,r3,r3
3fe0509c: 06 1e 20 5c mov 6,r4 <----- Write to something at 0xc0003000
3fe050a0: 00 30 68 8c lda 0xc0003000,r13
3fe050a4: 00 30 00 c0
3fe050a8: 00 50 23 82 stob r4,(r13)
3fe050ac: 08 1e 88 5c mov 8,g1
3fe050b0: 00 50 74 90 ld (g1),r14
3fe050b4: 00 1e f0 5c mov 0,g14
3fe050b8: 00 30 18 8c lda 0x1f0002,r3
3fe050bc: 02 00 1f 00
3fe050c0: 00 30 20 8c lda 0x1f0002,r4
3fe050c4: 02 00 1f 00
3fe050c8: 80 ca 20 65 modpc 0,r3,r4
3fe050cc: 00 3e 10 5c mov 0,sf2 <----- Only possible if
3fe050d0: 00 3e 08 5c mov 0,sf1 we are in supervisor mode
3fe050d4: 00 3e 00 5c mov 0,sf0
3fe050d8: 00 1e 00 5c mov 0,pfp
3fe050dc: 40 00 f8 8c lda 0x40,fp
3fe050e0: 40 e0 0f 8c lda 0x40(fp),sp
3fe050e4: 0c 5e 18 59 shlo 12,1,r3
3fe050e8: 83 c2 20 64 modac r3,r3,r4
3fe050ec: 1e 5e 80 59 shlo 30,1,g0
3fe050f0: 00 30 88 8c lda 0x2000000,g1
3fe050f4: 00 00 00 02
3fe050f8: 00 30 a0 8c lda 0xa5a5a5a5,g4
3fe050fc: a5 a5 a5 a5
3fe05100: 00 30 a8 8c lda 0x5a5a5a5a,g5
3fe05104: 5a 5a 5a 5a
we see that although the instructions a couple of lines down the dump look like
reasonable startup code (the mov instructions, the instructions that move test
values such as 0xa5a5a5a5 etc into registers), the first instructions correspond to
the text, as can be seen in the hexdump:
00000000 0d 01 00 00 8c 7f 18 00 00 00 00 00 34 3d 00 00 |............4=..|
00000010 00 00 00 00 00 50 e0 3f 00 00 00 00 00 00 00 00 |.....P.?........|
00000020 00 50 e0 3f 00 10 e0 3f 04 02 04 00 53 4d 63 44 |.P.?...?....SMcD|
00000030 1f 00 00 00 00 00 00 00 00 00 00 00 40 28 23 29 |............@(#)|
00000040 37 30 30 2f 52 58 20 53 65 72 76 65 72 20 43 6f |700/RX Server Co|
00000050 64 65 2c 20 52 65 6c 65 61 73 65 20 42 2e 30 36 |de, Release B.06|
00000060 2e 31 30 20 2d 20 54 75 65 20 41 70 72 20 30 32 |.10 - Tue Apr 02|
00000070 20 30 31 3a 34 32 3a 31 37 20 31 39 39 36 20 20 | 01:42:17 1996 |
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ab cd |................|
000000c0 00 01 18 8c 83 c4 18 65 06 1e 20 5c 00 30 68 8c |.......e.. \.0h.|
000000d0 00 30 00 c0 00 50 23 82 08 1e 88 5c 00 50 74 90 |.0...P#....\.Pt.|
000000e0 00 1e f0 5c 00 30 18 8c 02 00 1f 00 00 30 20 8c |...\.0.......0 .|
so even though objdump -x claimed that the start address is 0x3fe05000,
it seems likely that either "SMcD" is some instruction that objdump is
not aware of, or more likely that it is a magic marker of some kind.
Or the entry point simply is implicitly known to be further down.
Or defined elsewhere.
Luckily, it seems the processor is running in Supervisor mode when the C2708A binary is executed. Chapter 2.2.3 of http://www.nj7p.info/Manuals/PDFs/Intel/270710-003.pdf says that the Special Function Registers sf0, sf1, and sf2 are only available in Supervisor mode. Otherwise, an "operation-invalid-opcode fault" occurs. This is good, because if we want to run custom code, including writing an operating system kernel for example, then it would be bad if we were not running in supervisor mode.
Another observation is that the initialization code in the C2708A
binary only goes to address 0x3fe0608c:
3fe0608c: 00 00 00 0a ret
After that, it looks like compressed data. This makes sense, in a way, because it is unnecessary to send an uncompressed binary to each client machine when starting up. (On the other hand, why not send everything as e.g. a gzip stream? Who knows, but perhaps it made development/debugging of the initial software for the machine easier if it was just plain binaries. I'm just guessing here...)
The code here and there refers to addresses around 0x3fe0xxxx, so it is probably really running at that address, it is not just a bogus address used by the linker.
3fe05274: 00 30 f0 8c lda 0x3fe0521c,g14 3fe05278: 1c 52 e0 3f
So, the Memory map derived from a quick look at the binary is:
Address: Usage: 0x3fe05000 The C2708A b.out image is loaded at this address. 0xc0003000 A value (6) is written here during startup.
It is a mind-boggling but fascinating undertaking to figure out a memory map for such an unknown machine.
One idea is to first get custom code to run instead of the standard software. Then, one could try to show things on the screen by writing to video ram, making "guesses" about the vram addresses. This would be a lengthy trial-and-error procedure, with many reboots probably, and there is always a risk that EEPROM settings could be overwritten. If one can figure out where video ram is located and how it works (bits per pixel, line stride etc), then that may be enough to write a simple routine that dumps the entire memory range including Boot ROM, as some pixels that can then be photographed (or recorded as a movie), and later decoded on another machine.
A better alternative would be to use printf() or logPrintf() calls to dump memory, both to dump the ROM and to find out where devices are located. It looks like some of the modules in the standard X-server distribution have symbol names in them, that, when googled for, reveal that the boot ROM software is likely written in VxWorks. logPrintf is one of those symbols, and I am hoping that the machine's serial port can be used to output those log messages.
Finally, emulation of the i960CA could be implemented in GXemul, and the boot ROM could be run in the emulator. Memory accesses performed by the ROM during bootup could be investigated; for example it may be possible to identify what is the initialization code for the serial port controller, BT458 RAMDAC, etc.
Most of the above was written in March 2018.
The modules are b.out files with code and data, with an entry point specified which points outside the code segment and into the data segment! It points to a tiny struct that looks something like this:
unsigned int entry_point_data[3] = { 0xa9ad646a, 2, (unsigned int) &f };
I have no idea what the first and second values do, but the third is a pointer to the actual entry point (the C function f() in this case).
The modules also contain references to undefined symbols, such as _printf and ___divdf3.
The module list seems to be formatted like this:
# HP 700/RX modules file, This file is expected to be named # /usr/lib/X11/700X/bin/xxxxx.modules.ld # where xxxxx is the client machine name as configured on the 700/RX. # #-prefixed lines are comments. Filenames are relative to /usr/lib/X11/700X/ # # A module from the original 700/RX distribution looked like this: # # bin/ListXtal-hang.b06 "Ext2 autoload (C2700A, C2703A, C2707A, C2708A, C3225A)" \ # cry "List crystal freq" # # This did NOT work: # bin/ListXtal.b06 "apa" bepa "cepa" # # This works: # bin/ListXtal.b06 "Ext2 autoload (C2708A)" bepa "cepa" # # This works too: # bin/ListXtal.b06 "Ext2 autoload (C2708A)" bepa bin/ListXtal.b06 "Ext2 autoload (C2708A)" bepa bin/ListXtal-hang.b06 "Ext2 autoload (C2700A, C2703A, C2707A, C2708A, C3225A)" \ cry2 "List crystal freq2"
Changing the text/data/bss alignment values from 04 04 04 00 to 04 03 03 00: it still works. So it does not seem to care about the alignment values. (Perhaps these are only used when relinking...) Good.
Overwriting the comment-like fields at the start of ListXtal.b06 with 0x00: it still works. So the comments are not needed. Good.
Changing %d to %p in ListXtal.b06' string: it still works. It says "Crystal in slot #0x0" instead of "in slot 0". Good.
Changing magic value in entry point struct from 6a 64 ad a9 to 61 64 ad a9: it does NOT work. It says "bepa: Unable to load." So the magic number (or whatever it is) really needs to be there.
Changing the symbol _logPrintf at the end of ListXtal.b06 to _logprintf with lower-case p: it does NOT work. It says: "bepa: Unable to load." So it does not like unresolved symbols.
Changing the seemingly unused letters "nci" at the end of ListXtal.b06 to "mmm": it still works. :-) Adding a couple of bytes of nonsense after the regular end of the ListXtal.b06 file: it still works. :-) So no magic at the end of the file. Good.
Overwriting the call to _logPrintf so that it points to _printf:
dd if=ListXtal.b06 of=ListXtal.b06 bs=1 conv=notrunc iseek=604 oseek=516 count=1The file runs but nothing it outputted!
Overwriting the call to _printf so that it instead points to _logPrintf:
dd if=ListXtal.b06 of=ListXtal.b06 bs=1 conv=notrunc iseek=516 oseek=604 count=1The file runs, and outputs:
Crystal in slot #0 has measured frequency of 64.112 Crystal in slot #1 has measured frequency of 84.594 Crystal in slot #2 has measured frequency of 108.112 Crystal in slot #3 has measured frequency of 135.004 Crystal in slot #0 has measured frequency of 3f Crystal in slot #1 has measured frequency of 3f Crystal in slot #2 has measured frequency of 3f Crystal in slot #3 has measured frequency of 3f
Note the wrong "3f" at the end. This indicates that it is _logPrintf that displays stuff on the screen during bootup.
Compiling and linking a module of my own that mimics the modules is tricky. I have tried more or less every combination of options for the linker, objcopy, and strip, in various formats. My latest attempt involves not running strip, since it seems to mess up the b.out files. Instead, I link the result as a COFF (not b.out) and then objcopy-and-strip to a b.out.
First, create a hello.c which contains the following:
int f() { logPrintf("Hello\n"); return -2; } unsigned int entry_point_data[3] = { 0xa9ad646a, 2, (unsigned int) &f };
And then compile it like this:
i960-unknown-coff-gcc -c hello.c -Wall i960-unknown-coff-ld hello.o -o hello --relocatable -e _entry_point_data i960-unknown-coff-objcopy hello -O b.out.little hello.bout --strip-unneeded i960-unknown-coff-objdump -x hello.bout
There will be warnings about logPrintf not being known, since I don't have the VxWorks header files (or whatever the OS is). But it's just a warning.
Running objdump -x is a good way to verify if the produced hello.bout is similar enough to the stock modules.
SUCCESS! It seems to have worked. The machine accepts the module.
Here is a quick test to dump the memory. 0x40xxxxxx perhaps is RAM.
The next step was to figure out where the machine starts, by inspecting the Initial Boot Record (one of the architecturally defined special structs for the i960CA) at 0xffffff00. It says:
ffffff00 48 00 00 00 94 00 00 00 08 00 00 00 00 00 00 00 |H...............| ffffff10 00 b0 f8 ff 30 ff ff ff fe ff ff ff 00 00 00 00 |....0...........| ...
i.e. the first instruction address is 0xfff8b000. I assumed that the ROM ranged from 0xfff80000..0xffffffff (512 KB) and dumped that via the serial port. (Luckily, one of the devices in the VxWorks-based operating system on the machine is "/dev/serial", which can be opened using open(), and then written to using write().)
There are some strings in the ROM indicating that it is indeed VxWorks:
/tyCo/1 WIND version 1.0 VxWorks boot str err:
but maybe HP bought the rights to call their specific application/OS something else; the machine does not claim to be running VxWorks in the GUI. Another interesting string is:
Panacom BT70 X-terminal
Googling for "Panacom X-terminal" returns a few hits regarding HP, but at least at a quick glance, nothing interesting.
There are also a bunch of strings mentioning "82596" or "i82596" close to other network interface related strings, indicating that the Ethernet device in the machine is an Intel i82596. A possible open source implementation of a driver could be iee(4).
Starting GXemul with the ROM, running a (very experimental) HP 700/RX machine, can be done like this:
gxemul -V -e hp700rx raw:0xfff80000:0:0xfff8b000:hp700rx-rom.bin
and one can then see, by just disassembling and looking at the displacement part of some instructions, what addresses may be used. Combining that with previous information and discoveries made while attempting to dump various parts of the address space yields the following table:
Range: Purpose (guess): 0x00000000 .. 0x000003ff 1 KB on-chip RAM (i960CA-specific). 0x10000000... Read from this causes a HANG with weird graphics disturbance. 0x30000000 .. 0x301fffff RAM, perhaps 2 MB in size? 0x3fe00000 .. RAM? X-server software gets loaded here. Maybe some address line bits are ignored, and all of 0x3....... is mapped to 2 MB of RAM? 0x40000000 RAM, "extended" 8 MB region? 0x50000000... Read from this causes a HANG with weird graphics disturbance. 0x90000000... Read from this causes a straight HANG. 0xc0000000 Devices 0xc0000800 .. 0xc0000803 (All of these accessed using 0xc0001000 .. 0xc0001003 8-bit loads and stores?) 0xc0001800 .. 0xc0001803 0xc0002000 .. 0xc0002001 0xc0003000 && 0xc0003002 0xc0003800 0xc0004000 0xc0004800 .. 0xc0004803 0xc0005800 .. 0xc000580f 0xfff80000 ROM
There are lots of other values used in the displacement fields in the disassembly, but it is not until actual execution of the i960 machine code is implemented in the emulator that I will know for sure which addresses are really used by the ROM. For example:
0xfff9da6c 8c203000 39000000 lda 0x39000000,r4 0xfff9da74 88a52024 ldos 0x24(g4),g4
indicates that something is at 0x39000000. If that is the case, then the guess that everything starting with 0x3xxxxxxx is RAM would be false.
I have now verified how the 2 MB base RAM works and the 8 MB extended RAM. I have also found what may be the video RAM, but only for half the screen. Perhaps there is some interleaving or paging going on.
The map (short format) is pretty much as before:
Range: Purpose (guess): 0x00000000 .. 0x000003ff 1 KB on-chip RAM (i960CA-specific). 0x3xxxxxxx Base RAM, 2 MB in size, repeated. 0x40000000 Extended RAM, 8 MB. (Repeated?) 0x41000000 Video RAM, 2 MB. But possibly interleaved/paged. 0xc0000000 Devices 0xfff80000 ROM
I haven't had any time to work on the emulator, so no news when it comes to executing the ROM binary, but I thought I'd have a look at it by just reading the disassembly.
ROM is 512 KB, from 0xfff80000 to 0xffffffff.
At the very end of the ROM is 256 bytes (0xffffff00 to 0xffffffff) that has special meaning to the i960 CPU during bootup. The only thing of interest right now is the initial program counter value, 0xfff8b000.
Code starts running at 0xfff8b000.
gxemul -V -e hp700rx raw:0xfff80000:0:0xfff8b000:hp700rx-rom.bin
Disassembly using GXemul indicates that the following happens:
* Some system registers are set. * The stack pointer sp is set to 0x30000400 (i.e. 1 KB above bottom of the motherboard RAM). * The byte value 0x25 is written to address 0xc0003800, one of the device registers. * The byte value 2 is written to address 0xc0004000. * The byte value 0 is written to address 0xc0003002. * The byte value 1 is written to address 0xc0003000. * A little delay loop that looks like this waits for a while: 0xfff8b094 8c283000 00003a98 lda 0x00003a98,r5 0xfff8b09c 5c801610 mov g0,g0 0xfff8b0a0 5c881611 mov g1,g1 0xfff8b0a4 5a294b00 cmpdeco 0,r5,r5 0xfff8b0a8 15fffff4 bne 0xfff8b09c (Something like for (int i = 0; i < 15000; ++i) { g0=g0; g1=g1; } * The byte value 0x76 is written to address 0xc0001003 * The byte value 0x1c is written to address 0xc0001001 * The byte value 0 is written to address 0xc0001001 * A byte 0x00 is written to 0x40000000, which is the start of expansion RAM. * Another for i=0 to 15000 delay loop. * The byte value 2 is written to address 0xc0003000 * Then there is a short piece of code which maybe (?) tries to figure out how much expansion RAM there is. * The byte value 3 is written to address 0xc0003000 * After that, it copies ROM 0xfff81bc0..0xffffe6ef (which is the last byte of the ROM that contains anything meaningful) down to RAM at 0x30001000, which is in motherboard RAM, one byte at a time. * The byte value 4 is written to address 0xc0003000 * Some form of system call is performed, which perhaps sets the instruction pointer to 0x30001010, i.e. 0x10 bytes into the code just copied down from ROM to RAM.
Although the emulator doesn't run the code yet, the following "tweak" of the command line can fake that the binary was loaded at 0x30001000, skipping 0xb1c0 bytes, and uses 0x30001010 as the entry point:
gxemul -V -e hp700rx raw:0x30001000:0xb1c0:0x30001010:hp700rx-rom.bin
Continuing:
* The byte value 17 is written to address 0xc0003000 * Various registers and other things are set up. * The byte value 18 is written to address 0xc0003000 * Various routines are called, and between each, increasing byte values (19, 20, 21, 22, 23) are written to 0xc0003000.
On some old DEC machines, there were diagnostics LEDs at the back. Perhaps 0xc0003000 is something similar on the HP?
Giving up for now on disassembling/understanding the bootup flow; implementing more i960 support in the emulator will be the next step.
However, I decided to see if the address 0x41000000 (what I think is the base of video RAM) could be found somewhere. It can be found only once (!). Looking at some of the routines surrounding that code indicates that the device at 0xc0005800..0xc000580f is accessed. Lots of small routines. Perhaps this is the BrookTree RAMDAC? Things like:
0x3002bf90 8ca83000 c0005800 lda 0xc0005800,g5 0x3002bf98 8ca03000 c0005801 lda 0xc0005801,g4 0x3002bfa0 82855000 stob g0,(g5) 0x3002bfa4 828d1000 stob g1,(g4) 0x3002bfa8 82951000 stob g2,(g4) 0x3002bfac 829d1000 stob g3,(g4) 0x3002bfb0 0a000000 retwhich, with some imagination, could take an index and R, G, and B values, and write those to a RAMDAC's index and data registers? Just a wild guess.
OpenBSD's bt458reg.h indicates that there are 8 registers, whereas 16 consecutive byte addresses are accessed by the ROM's firmware. So some more thought is needed on how things are actually mapped.
Randomly googling for HP 700/RX turned up an ebay auction for a Vintage HP 700/RX X-Station Terminal Software 4MB Flash Memory PC Card C272. By the time anyone reads this, the ebay page may be gone, so I'll summarize here: It's a ROM card with the following text:
C2725B Part No. C2700-10070 HP 700 / RX X Station Software 4 MB English VERSION B.04.00 Recorded in Canada. Copyright (C) Hewlett-Packard Co. 1992 NOTICE: DO NOT DROP! DO NOT BEND! DO NOT EXPOSE TO EXTREME TEMPERATURE OR WETNESS! INSERT THIS SIDE UP
and on the back it said "Flash Series 2, 4 MByte Memory Card, ExCA (Exchangable Card Architecture)" and Intel Corporation 1992.
Perhaps running the ROM in the emulator will reveal the address where the machine maps this 4 MB extra card.