[vcf-midatlantic] Fabri-Tek MP-12 Industrial Computer

Kyle Owen kylevowen at gmail.com
Tue Dec 8 16:44:21 EST 2015

I made this post to the Vintage Computer Forum, and some bits and pieces to
cctalk, but since Connor brought his to Festivus, I figured I'd share with
you all what we've learned about it. And on that note, sorry I couldn't
make it up there! It wouldn't have been feasible for me to make it up there
for the weekend, considering I had to be back Monday at 8am for a final

Apologies to anyone offended by this wall of text. Here are some pictures,
first: http://imgur.com/a/oziVX

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:

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

    1              /BIN LOADER FOR FABRITEK
    2              /KYLE OWEN - 4 DEC 2015
    4        7653  *7653
    5 07653  0000  SWITCH, 0
    6 07654  0000  CHAR,   0
    7 07655  0000  CHKSUM, 0
    8 07656  0000  ORIGIN, 0
   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
   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
   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
   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
   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
   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
   77        7776  WORD1=7776
   78 07754  0000  WORD2,  0
   80        7755  *7755
   81 07755  5317          JMP BEGIN-1
   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 Connor for his help in reverse engineering parts of the
hardware for better understanding of the system, and for dumping the ROMs,
among other things!


More information about the vcf-midatlantic mailing list