gavare.se > Old machines > HP 700/RX

Intro

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.

Photos

Here are some photos of the machine.

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.)

X server software download

Finding technical information about the HP 700/RX (or its cousins) is very hard. So is finding the X server software that it is meant to run. Here are the only two links that I have found so far:

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.

Boot procedure and a quick look at the standard software

https://lisas.de/~adrian/envizex/ describes the boot procedure. In essence, it downloads files via TFTP.

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

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.>.\.>.\|
...

binutils and gcc for i960

In order to generate code for i960, and/or to disassemble the standard software, it is a good idea to have GNU binutils and GCC for the i960 architecture. I have not been able to find a version that builds on modern amd64 hosts, so I had to do this inside NetBSD/pmax 7.1.2 inside GXemul. When installing, remember to configure network (10.0.0.1, with nameserver/gateway at 10.0.0.254), and install pkgsrc. After booting NetBSD/pmax the first time, install gmake from pkgsrc. It is required when building gcc.

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 ,g14
   4:   24 00 00 00 

00000008 :
   8:   1e 16 90 5c     mov     g14,g2
   c:   00 1e f0 5c     mov     0,g14
  10:   05 0e a4 59     shlo    5,g0,g4
  14:   10 01 a5 59     subo    g0,g4,g4
  18:   02 0e a5 59     shlo    2,g4,g4
  1c:   10 01 a5 59     subo    g0,g4,g4
  20:   91 1d 85 8c     lda     (g4)[g1*8],g0
  24:   00 00 00 0a     ret
        ...

00000030 <_r>:
  30:	10 16 28 5c 	mov	g0,r5
  34:	01 09 84 59 	subo	1,g0,g0
  38:	05 16 a0 5c 	mov	r5,g4
  3c:	20 60 09 3b 	cmpibge	1,r5,5c <_r+0x2c>
  40:	00 30 00 86 	callx	30 <_r>
  44:	30 00 00 00 
  48:	10 16 20 5c 	mov	g0,r4
  4c:	02 49 81 59 	subo	2,r5,g0
  50:	00 30 00 86 	callx	30 <_r>
  54:	30 00 00 00 
  58:	04 00 a4 59 	addo	r4,g0,g4
  5c:	14 16 80 5c 	mov	g4,g0
  60:	00 00 00 0a 	ret
	...

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.|

Further analysis...

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.

Idea for How to attempt to figure out the HP 700/RX memory map

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.

April 2019: Further experiments

Figuring out what the exact file format is for the main binary and the modules is tricky. Partly because the screen turns black when starting the main binary, and partly because the modules seem smaller and simpler, I decided to have a go at mimicing the modules first.

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=1
The 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=1
The 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.

May 2019: More mapping progress

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

May 2019 (Later): Link to more HP files

http://blog.schmorp.de/2018-11-29-hp700rx-x-terminal-software.html

October 2020: Looking at the ROM startup sequence

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            ret                 
which, 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.

April 2021: Emulator switching back to C...

The GXemul emulator has now switched back from C++ to C, thus dropping what was supposed to become the "new" emulation framework. The i960 stuff was in that new framework. It was not that hard, however, to just copy the disassembly parts into the remaining framework code (C). Instruction execution is still not implemented though, so no news compared to previously, but at least it is now more fun again to work on the framework. Extending it to support the kind of variable-length instructions that the i960 uses will be an interesting challenge. Also, RISC-V has variable length encodings (16-bit for compressed, and 32-bit for most), so it will be useful not just for i960 to extend the framework's functionality.

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.