antiquekid3
Veteran Member
A handful of folks have a few of these Fabri-Tek MP-12 industrial control computers, including another user here, conmega. Together, we've been working on reverse engineering bits and pieces (software and hardware) to get these doing something useful.
First thing's first: pictures!
Here's a summary of what we've done so far:
1. These systems date to 1975 or so, but were used up into the 2000s for controlling movie film developing tanks, as I understand it. Thus, powering them up was as easy as plugging them in...almost. There's no obvious spot for power, but upon removing the cover, it became clear that it would obtain power via the paper tape reader and I/O box with a V.35 connector. So instead, we've hot-wired in a line cord across the transformer in the main box. 120VAC power is transmitted over a straight-through DA-15 connector...kind of scary, but I guess it works.
2. I wrote some very simple code to test the front panel operations. Turns out that while the machine runs, the front panel lights only show what's on the bus, so watching the accumulator is not possible. You can single-step, though. Also, to show how limited the front panel really is: the deposit operation doesn't increment PC automatically. So if you're having to toggle in much, it's address, load, data, load, and repeat. However, if you're clever and not toggling in too many JMP, JSR, SKP, or other such operations that change the PC, you can use single-step to increment the PC.
3. Just the Fabri-Tek by itself is kind of lame. It has no I/O without the paper tape reader and I/O box connected via the DA-15 cable (using a high-speed synchronous serial connection with a bunch of 7400-series shift registers). It also only has 4k of core (and a dash of ROM at the top). The ROM is a very basic paper tape loader, dare I say, even more basic than DEC's RIM loader. It took quite a while for me to fully understand how it worked, but I am finally there now. The ROM's used are 512 by 4 bit bipolar PROMs. It would appear as though when the word is equal to 7777 octal, core is referenced instead. Otherwise, the ROM values are read. Writing to the location does nothing, best I can tell. Here's the disassembly listing of the ROM code:
Notice there are two locations there that are "NOT IN ROM." These are unprogrammed in the PROM, allowing for the system to read and write from core in those locations. Understanding what 6012 and 6015 did were the tricks, though. I wrongfully assumed that the reader was compatible with the high speed reader that DEC used or the IOmec reader, but instead, this has its own instructions. 6012, instead of reading the buffer like on a PC8E, advances the tape one byte. What should've clued me in that this wasn't DEC was that 6015 isn't used on the PC8E except in perhaps very rare circumstances, as it's a combination of clear flag and skip if flag. On the IOmec reader, it skips if the end of tape flag is set. In the Fabri-Tek, 6015 reads the buffer and skips if the reader is ready, apparently.
Once that was figured out, it became clear that this was similar to the RIM loader, but only to a point. Starting at 7777, the loader jumps immediately to START, where it loads 7755 into the AC, then deposits into a temporary address. It then advances the tape, clears the link and rotates an empty AC around 6 times. Then it reads the buffer and will jump back to LOOP since the link is not set. It then repeats, advancing the tape, clearing link, rotating accumulator, and reads again. If the first byte it read in had a 1 in the 6th bit, the link will now be 1, causing it to skip. The second byte should only have data in the bottom 6 bits (bits 0 through 5, if you will) so that you don't disturb the upper 6 bits in the AC. This value is then dumped into the address indirectly referenced by TEMP, which as we loaded initially, is still 7755, with the label BEGIN. The temporary address is then incremented and now points to itself: location 7756 contains 7756, and location 7755 contains the word constructed from the first two bytes on the paper tape.
Here's where things get funky: the program jumps to 7755 (BEGIN), not 7763 (LOOP) as one might expect. I was very confused; why would it want to jump to the word it just deposited from paper tape? Unless that first word is a jump instruction, you're not going to get very far.
Well, that's exactly what I decided to do. Obviously this loader is pretty useless by itself, but maybe I can find a way for it to load a custom BIN loader that will support checksums and other niceties. If the first instruction on paper tape is 5363, you will JMP BEGIN (5355) at location 7775, then JMP LOOP (5363) at location 7755 (BEGIN). That will allow the loader to read another two bytes off the tape, construct them into a word, and deposit into the TEMP location. As you've probably figured out, TEMP holds the pointer to where the next word will be stored. Since TEMP is pointing to TEMP, this next word should be the starting address of your program (minus one; there's an ISZ TEMP prior to the deposit of the next data word). Now we're onto something! You can keep loading data sequentially with this manner. But how do you stop? Well, if you want, you can put some unpunched trailing tape which will never deposit anything since bit 6 isn't punched, or you can put your code up at the very top of the 4k field such that your last instruction overwrites location 7755 with a HLT or JMP instruction; when the loader issues JMP BEGIN, it will now be jumping to your new instruction that you loaded at 7755, letting you break out of the loader. Now there's an idea for the BIN loader! The BIN loader is generally put right under the RIM loader anyways, so the last instruction on the tape could be a JMP to a HLT instruction immediately before the normal start of the BIN loader.
See that location near the top: 7776? It never got used. I decided to use it for the BIN loader; turns out DEC did too. 7777 was the starting address for the BIN loader (similar to here, it jumps to the actual start of the program), but unfortunately, that part's in ROM, so it can't be (easily) changed. The CLA HLT instruction at 7757 was never really used either, but that's alright. Not very important, best I can tell.
I've since written a simple C program (available upon request) that reads a DEC BIN or RIM tape and outputs a Fabri-Tek RIM format tape, adding the required JMP LOOP instruction and organizing the data so that the sequential loader puts it in the right spot; sure beats editing tapes by hand in a hex editor. I've found I can't mix hex and octal in my head very easily. These tapes are best edited in an octal editor, which I haven't really found. My workaround is a Vim script that converts the buffer from binary to octal digits and back. A little tedious, but not too bad.
4. All this to say, here's the custom BIN loader I wrote based on DEC's original BIN loader:
I opted to keep some of DEC's comments, but got lazy when retyping out parts and didn't include all of them. DEC did a very nice job with this loader; it's very efficient. I made it more efficient by stripping the field support (the Fabri-Tek may never get extended memory, or at least not anytime soon). There's also only a high-speed reader here, so I stripped the low-speed code as well.
The process for loading the BIN loader is super simple: load the tape into the reader, reset the Fabri-Tek to clear AC, load 7777 into PC and run. The BIN loader is quickly loaded, and upon completion, the loader jumps to the HLT instruction prior to the start of the BIN loader. Take out the BIN loader tape, put in a BIN-formatted tape, and run. When the trailer is encountered, the checksum is verified in AC (should show zero), and you should be ready to roll with your newly-loaded program.
5. We also deciphered some more instructions for the I/O box: 6052 and 6053 read the buttons and switch on the front of the reader box. 6070 through 6073 allow you to turn on the seven 7-segment displays on the front of the unit. Each instruction except the lasts updates two at a time. They use a 7442 to drive the displays, so you only get 0-9, garbage, and blank. Too bad they're not connected directly to shift registers so that you could turn on individual segments and make some letters too. 6074 writes to 8 open-collector outputs on the back, and 6075 controls two relays. We've seen potential references to device code 06 and other potential instructions for 05 and 07, but further investigation is required before we can determine what they do.
Think that's about it for now...trying to track down a V.35 connector so I can feel a bit better about the power situation, and eventually I'll port my SPI-controlled LED string program to the machine so I can have something to impress my family members with in a couple of weeks.
Big thanks to conmega for his help in reverse engineering parts of the hardware for better understanding of the system, and for dumping the ROMs, among other things!
Kyle
First thing's first: pictures!
Here's a summary of what we've done so far:
1. These systems date to 1975 or so, but were used up into the 2000s for controlling movie film developing tanks, as I understand it. Thus, powering them up was as easy as plugging them in...almost. There's no obvious spot for power, but upon removing the cover, it became clear that it would obtain power via the paper tape reader and I/O box with a V.35 connector. So instead, we've hot-wired in a line cord across the transformer in the main box. 120VAC power is transmitted over a straight-through DA-15 connector...kind of scary, but I guess it works.
2. I wrote some very simple code to test the front panel operations. Turns out that while the machine runs, the front panel lights only show what's on the bus, so watching the accumulator is not possible. You can single-step, though. Also, to show how limited the front panel really is: the deposit operation doesn't increment PC automatically. So if you're having to toggle in much, it's address, load, data, load, and repeat. However, if you're clever and not toggling in too many JMP, JSR, SKP, or other such operations that change the PC, you can use single-step to increment the PC.
3. Just the Fabri-Tek by itself is kind of lame. It has no I/O without the paper tape reader and I/O box connected via the DA-15 cable (using a high-speed synchronous serial connection with a bunch of 7400-series shift registers). It also only has 4k of core (and a dash of ROM at the top). The ROM is a very basic paper tape loader, dare I say, even more basic than DEC's RIM loader. It took quite a while for me to fully understand how it worked, but I am finally there now. The ROM's used are 512 by 4 bit bipolar PROMs. It would appear as though when the word is equal to 7777 octal, core is referenced instead. Otherwise, the ROM values are read. Writing to the location does nothing, best I can tell. Here's the disassembly listing of the ROM code:
Code:
1 7755 *7755
2 07755 0000 BEGIN, 0
3 07756 7755 TEMP, BEGIN /NOT IN ROM
4 07757 7602 CLA HLT /7602
5 07760 7755 ADDR, BEGIN /7755 STARTING ADDRESS?
6 07761 1360 START, TAD ADDR /1360 GET STARTING ADDRESS?
7 07762 3356 DCA TEMP /3356 SAVE TEMPORARILY
8 07763 6012 LOOP, 6012 /6012 ADVANCE TAPE
9 07764 7106 CLL RTL /7106
10 07765 7006 RTL /7006
11 07766 7006 RTL /7006 ROTATE SO BIT 0 IS IN BIT 7, BIT 4 IN BIT 11, ETC.
12 07767 6015 6015 /6015 READ TAPE AND SKIP
13 07770 5367 JMP .-1 /5367
14 07771 7420 SNL /7420 SKIP IF LINK IS SET (BIT 6 OF PAPER TAPE IS SET)
15 07772 5363 JMP LOOP /5363
16 07773 3756 DCA I TEMP /3756
17 07774 2356 ISZ TEMP /2356
18 07775 5355 JMP BEGIN /5355
19 07776 7776 7776 /NOT IN ROM
20 07777 5361 JMP START /5361
21 $
Notice there are two locations there that are "NOT IN ROM." These are unprogrammed in the PROM, allowing for the system to read and write from core in those locations. Understanding what 6012 and 6015 did were the tricks, though. I wrongfully assumed that the reader was compatible with the high speed reader that DEC used or the IOmec reader, but instead, this has its own instructions. 6012, instead of reading the buffer like on a PC8E, advances the tape one byte. What should've clued me in that this wasn't DEC was that 6015 isn't used on the PC8E except in perhaps very rare circumstances, as it's a combination of clear flag and skip if flag. On the IOmec reader, it skips if the end of tape flag is set. In the Fabri-Tek, 6015 reads the buffer and skips if the reader is ready, apparently.
Once that was figured out, it became clear that this was similar to the RIM loader, but only to a point. Starting at 7777, the loader jumps immediately to START, where it loads 7755 into the AC, then deposits into a temporary address. It then advances the tape, clears the link and rotates an empty AC around 6 times. Then it reads the buffer and will jump back to LOOP since the link is not set. It then repeats, advancing the tape, clearing link, rotating accumulator, and reads again. If the first byte it read in had a 1 in the 6th bit, the link will now be 1, causing it to skip. The second byte should only have data in the bottom 6 bits (bits 0 through 5, if you will) so that you don't disturb the upper 6 bits in the AC. This value is then dumped into the address indirectly referenced by TEMP, which as we loaded initially, is still 7755, with the label BEGIN. The temporary address is then incremented and now points to itself: location 7756 contains 7756, and location 7755 contains the word constructed from the first two bytes on the paper tape.
Here's where things get funky: the program jumps to 7755 (BEGIN), not 7763 (LOOP) as one might expect. I was very confused; why would it want to jump to the word it just deposited from paper tape? Unless that first word is a jump instruction, you're not going to get very far.
Well, that's exactly what I decided to do. Obviously this loader is pretty useless by itself, but maybe I can find a way for it to load a custom BIN loader that will support checksums and other niceties. If the first instruction on paper tape is 5363, you will JMP BEGIN (5355) at location 7775, then JMP LOOP (5363) at location 7755 (BEGIN). That will allow the loader to read another two bytes off the tape, construct them into a word, and deposit into the TEMP location. As you've probably figured out, TEMP holds the pointer to where the next word will be stored. Since TEMP is pointing to TEMP, this next word should be the starting address of your program (minus one; there's an ISZ TEMP prior to the deposit of the next data word). Now we're onto something! You can keep loading data sequentially with this manner. But how do you stop? Well, if you want, you can put some unpunched trailing tape which will never deposit anything since bit 6 isn't punched, or you can put your code up at the very top of the 4k field such that your last instruction overwrites location 7755 with a HLT or JMP instruction; when the loader issues JMP BEGIN, it will now be jumping to your new instruction that you loaded at 7755, letting you break out of the loader. Now there's an idea for the BIN loader! The BIN loader is generally put right under the RIM loader anyways, so the last instruction on the tape could be a JMP to a HLT instruction immediately before the normal start of the BIN loader.
See that location near the top: 7776? It never got used. I decided to use it for the BIN loader; turns out DEC did too. 7777 was the starting address for the BIN loader (similar to here, it jumps to the actual start of the program), but unfortunately, that part's in ROM, so it can't be (easily) changed. The CLA HLT instruction at 7757 was never really used either, but that's alright. Not very important, best I can tell.
I've since written a simple C program (available upon request) that reads a DEC BIN or RIM tape and outputs a Fabri-Tek RIM format tape, adding the required JMP LOOP instruction and organizing the data so that the sequential loader puts it in the right spot; sure beats editing tapes by hand in a hex editor. I've found I can't mix hex and octal in my head very easily. These tapes are best edited in an octal editor, which I haven't really found. My workaround is a Vim script that converts the buffer from binary to octal digits and back. A little tedious, but not too bad.
4. All this to say, here's the custom BIN loader I wrote based on DEC's original BIN loader:
Code:
1 /BIN LOADER FOR FABRITEK
2 /KYLE OWEN - 4 DEC 2015
3
4 7653 *7653
5 07653 0000 SWITCH, 0
6 07654 0000 CHAR, 0
7 07655 0000 CHKSUM, 0
8 07656 0000 ORIGIN, 0
9
10 07657 0000 BEGG, 0
11 07660 3253 DCA SWITCH
12 07661 4304 JMS READ /GET CHAR
13 07662 1317 TAD M376 /TEST FOR 377, SUBTRACT 376
14 07663 7750 SPA SNA CLA /DON'T SKIP IF BIT 0 IS SET
15 07664 5270 JMP .+4
16 07665 2253 ISZ SWITCH /YES, COMPLEMENT SWITCH
17 07666 7040 CMA
18 07667 5260 JMP BEGG+1
19 07670 1253 TAD SWITCH /NOT 377
20 07671 7640 SZA CLA /IS SWITCH SET?
21 07672 5261 JMP BEGG+2 /YES, IGNORE
22 07673 1254 TAD CHAR /NO, TEST FOR CODE
23 07674 0313 AND MASK /TYPES
24 07675 1343 TAD M200
25 07676 7510 SPA
26 07677 2257 ISZ BEGG /DATA OR ORIGIN
27 07700 7750 SPA SNA CLA
28 07701 5657 JMP I BEGG /DATA, ORIGIN OR L/T
29 07702 7402 HLT /IF FIELD SETTING, HALT!
30 07703 5320 JMP BEGIN
31
32 07704 0000 READ, 0
33 07705 6012 6012
34 07706 6015 6015
35 07707 5306 JMP .-1
36 07710 3254 DCA CHAR
37 07711 1254 TAD CHAR
38 07712 5704 JMP I READ
39 07713 0300 MASK, 300
40
41 07714 4345 BEND, JMS ASSEMB
42 07715 7041 CIA
43 07716 1255 TAD CHKSUM
44 07717 7402 M376, HLT
45 07720 4257 BEGIN, JMS BEGG
46 07721 5320 JMP .-1
47
48 07722 3255 GO, DCA CHKSUM
49 07723 1254 TAD CHAR
50 07724 3376 DCA WORD1
51 07725 4304 JMS READ
52 07726 3354 DCA WORD2
53 07727 4257 JMS BEGG
54 07730 5314 JMP BEND
55 07731 4345 JMS ASSEMB
56 07732 7420 SNL
57 07733 5341 JMP MEMFLD
58
59 07734 3256 DCA ORIGIN
60 07735 1376 CHEX, TAD WORD1
61 07736 1354 TAD WORD2
62 07737 1255 TAD CHKSUM
63 07740 5322 JMP GO
64
65 07741 3656 MEMFLD, DCA I ORIGIN
66 07742 2256 ISZ ORIGIN
67 07743 7600 M200, 7600
68 07744 5335 JMP CHEX
69 07745 0000 ASSEMB, 0
70 07746 1376 TAD WORD1
71 07747 7106 CLL RTL
72 07750 7006 RTL
73 07751 7006 RTL
74 07752 1354 TAD WORD2
75 07753 5745 JMP I ASSEMB
76
77 7776 WORD1=7776
78 07754 0000 WORD2, 0
79
80 7755 *7755
81 07755 5317 JMP BEGIN-1
82
83 $
I opted to keep some of DEC's comments, but got lazy when retyping out parts and didn't include all of them. DEC did a very nice job with this loader; it's very efficient. I made it more efficient by stripping the field support (the Fabri-Tek may never get extended memory, or at least not anytime soon). There's also only a high-speed reader here, so I stripped the low-speed code as well.
The process for loading the BIN loader is super simple: load the tape into the reader, reset the Fabri-Tek to clear AC, load 7777 into PC and run. The BIN loader is quickly loaded, and upon completion, the loader jumps to the HLT instruction prior to the start of the BIN loader. Take out the BIN loader tape, put in a BIN-formatted tape, and run. When the trailer is encountered, the checksum is verified in AC (should show zero), and you should be ready to roll with your newly-loaded program.
5. We also deciphered some more instructions for the I/O box: 6052 and 6053 read the buttons and switch on the front of the reader box. 6070 through 6073 allow you to turn on the seven 7-segment displays on the front of the unit. Each instruction except the lasts updates two at a time. They use a 7442 to drive the displays, so you only get 0-9, garbage, and blank. Too bad they're not connected directly to shift registers so that you could turn on individual segments and make some letters too. 6074 writes to 8 open-collector outputs on the back, and 6075 controls two relays. We've seen potential references to device code 06 and other potential instructions for 05 and 07, but further investigation is required before we can determine what they do.
Think that's about it for now...trying to track down a V.35 connector so I can feel a bit better about the power situation, and eventually I'll port my SPI-controlled LED string program to the machine so I can have something to impress my family members with in a couple of weeks.
Big thanks to conmega for his help in reverse engineering parts of the hardware for better understanding of the system, and for dumping the ROMs, among other things!
Kyle