This video showcases the Ardent Titan graphics supercomputer.

Part of the Vaxbarn collection is what could very well be the largest collection of Convex supercomputers in the world.

The Convex adventure started in 2016 with an eBay advertisement, and since then the collection has seen the addition of 9 Convex supercomputers, spanning three generations of machines.

In this video, we describe how, thirty years later, we recreated a historically significant rendering of a vibrating L-Shaped Membrane in MATLAB 3.5, running on a 1987 Ardent Titan Graphics Supercomputer (TITAN-MATLAB).

 

As if one project for the new year (New project: Eagle Emulator) isn't enough, I've also come to the conclusion that I need more space for the collection. Hence the proposed addition of a Large Systems Room to the VAXbarn.

*** UPDATED 24-APR-2017 ***

Almost a new year, time for a new project. Since the Convex C1 XP and Convex C1 XL I'm getting are missing their primary hard drive, I need to replace it with something. These systems are quite picky about what disks they support, but even if they weren't, working disks with an SMD (Storage Module Drive) interface are becoming somewhat rare. One disk I am sure these systems support is the Fujitsu M2351 ("Eagle") pictured above.

I have a TMS9900 based system on eurocards, FTI990 made by TEP. With this system, I have a copy of Eyring Research Institute's PDOS on floppy disks.

To save this OS, and to be able to share it with fellow TMS9900 enthousiasts, I have built a disk emulator for use with the FTI990, using my Digilent XUPV5 FPGA card.

Emulator (mounted on wooden plank) on top of the FTI990 system. From the left top side, clockwise: XUPV5 FPGA card, wire-wrap board with level shifters to interface with 5V logic, card with bus buffer IC's plugged into the FTI990, PCIe interface to laptop.

Above is a block diagram of the emulator: on the left is a PCIe interface to talk to the laptop used to capture the disk images. On the right is some logic to talk to the TMS9900 bus.

The emulator works as follows: part of the Boot ROM in the FTI990 is a table with four pointers to Boot-ROM provided disk device drivers; in my boot ROM, only the first pointer points to an actual driver, for that for the floppy disc controller. The other three pointers point to a table that indicates "no device here". When the FPGA sees a memory read transaction on the TMS9900 bus to read the second pointer in the table, it hijacks the bus to change the value read from the Boot ROM. It can do so, because the bus is held high with resistors, and pulled low by open-collector TTL logic outputs. This means that even though another device on the bus (the boot ROM) is already responding to that read transaction, we can change 1's into 0's in the read value by pulling those bits low. In this manner, we change the second pointer from F83A to E800. 

      +----------+
>0000 | |
| |
| RAM |
| |
>DFFF | |
+----------+
>E000 | | >E100->E1FF : sector buffer (256 bytes)
| Devices | >E200->E201 : sector# register (write) / status register (read)
| | >E202->E203 : single/double sided register
>EFFF | | >E800->E8FF : driver ROM
+----------+
>F000 | |
| Boot ROM | >FC2A->FC2B : hijacked driver pointer
>FFFF | |
+----------+

At address >E800 (in TMS 9900 assembly, '>' is the prefix for hexadecimal values), our emulator provides a driver for the emulated disk. when reading or writing a sector, the driver sends the sector# (logical block address) of the required sector to a sector# register at >E200. Then waits for that sector to become available in the buffer. If needed, the program running on the laptop will save the track that was previously in the buffer, and then load the buffer with the requested track. Once the status register indicates that the sector is available, the driver will copy the data to or from the 256-byte sector buffer located at >E100. Whenever sector 0 is read or written, the driver looks at the single/double-sided flag in that sector, and writes it to the single/double sided register at >E202. This is important, because when booting, the disk is always read in single-sided mode, even if it's a double-sided disk. Booting starts by reading a number of sectors from the disk, starting at sector 1136. Because the disk is treated as single-sided, sector 1136 is on track 71, not on track 35. However, after sector 0 is read, if it's a double-sided disk, whenever PDOS addresses sector 1136, we want to access track 35.

On the laptop, we continuously poll two registers on the PCIe side; one is the "current generation number" register. Every time a sector is written to by the FTI990, the value in this register increments by one. The software on the laptop keeps track of the generation number, and when it changes, it knows it has to read the track data back from the track buffer to keep it's disk image up to date. Once that's done, it writes the updated generation number to the "last seen generation number" register. The second register that's read is the "wanted track" register. If it's different from the track currently loaded in the track buffer, the software will write the requested track to the track buffer, then update the "loaded track" register.

The emulator will tell the FTI990-side driver that it's busy when either the "wanted track" doesn't match the "loaded track", or when the "current generation number" doesn't match the "last seen generation number".

PDOS boot floppy

PDOS 2.4 booting from the emulated disk

Emulator with test leads for debugging (with a logic analyzer)

Finally, here is the driver code as contained in the ROM:

                        ; -------------------------------------
; Driver linkage table
;--------------------------------------
E800    100D            JMP    INIT        ; init vector
E802    1010            JMP    READ        ; read vector
E804    1014            JMP    WRIT        ; write vector
E806    100D            JMP    MOFF        ; motor-off vector
E808    0470 DATA >1136 ; boot sector
E80A    0470 DATA >1136
E80C    0470 DATA >1136
E80E    0470 DATA >1136
E810    4645 4939 3930  TEXT   "FTI990-EMU"
    2D45 4D55
E81A    0000            BYTE   >00
; -------------------------------------
; Initialization routine
;--------------------------------------
E81C    04E0 E202    INIT:    CLR    @>E202      ; Clear double-sided register
E820    045B            RT
; -------------------------------------
; Periodic routine
;--------------------------------------
E822    045B    MOFF:    RT
; -------------------------------------
; Read sector routine
;--------------------------------------
E824    C06D 0004 READ:    MOV    @4(R13),R1 ; destination: memory
E828    0202 E100       LI     R2, >E100  ; source: sector buffer
E82C    1004            JMP    COMN ; continue with read/write common code
; -------------------------------------
; Write sector routine
;--------------------------------------
E82E    C0AD 0004 WRIT:    MOV    @4(R13),R2    ; source: memory
E832    0201 E100       LI     R1, >E100      ; destination: sector buffer
; -------------------------------------
; Common read/write code
; -------------------------------------
E836    C020 E200 COMN:    MOV    @>E200, R0    ; ready ?
E83A    11FD            JLT    COMN ; no; wait
E83C    C82D 0002 E200 MOV    @2(R13),@>E200 ; request sector
E842    C020 E200 SEEK:    MOV    @>E200, R0     ; ready ?
E846    11FD            JLT    SEEK           ; no; wait
E848    1304            JEQ    DOIT           ; ready, no error; continue    
E84A    0200 0065       LI     R0, >101     ; error; return error #101 (invalid track number)
E84E    0460 E870       B      RETN
E852    0200 0080       LI     R0, 128        ; number of words to copy
E856    CC72    COPY:    MOV    @R2+, @R1+     ; copy 1 word
E858    0600            DEC    R0            ; are we done?
E85A    16FD            JNE    COPY           ; no; copy next word
E85C    C02D 0002       MOV    @2(R13), R0    ; yes; sector is zero?
E860    1605            JNE    SUCC           ; no; we're done
E862    C06D 0004       MOV    @4(R13), R1    ; yes, get address of buffer
E866    C821 001E E202           MOV    @30(R1), >E202 ; copy double-sided flag from sector buffer to double sided register
E86C    04C0    SUCC:    CLR    R0 ; indicate success
E86E    05CE            INCT   R14 ; increment return address by two (no error)
E870    04E0 2FE8 RETN:    CLR    @L3LOCK        ; clear OS lock
E873    0380            RTWP ; return to OS

I have the following X1215 disk packs (23 in total) in my collection.

Imaged

  • X1215 IPL 63C2
    Testprograms update 85-12-18
    DOM9A/02 IT/10, DOM9C/02 IT/11
    Userid: SDAPRO
    s:$load (for running testprograms) [Internal label: TP09; Does indeed contain test programs]
  • P800 (X1215) [Internal Label: ECA58; Contains games]
  • SAG3
    KERNEL 3
    MULTIBASIC [Internal label: DJO-PACK; Contains development tools (BASIC, Assembler,...)]
  • DOM 210 & 211 for X1215
    update P800 testprograms
    27-09-'84 R.v.d.Heyden [Internal label: RINUS; Contains test programs]
  • TP00 Test Pack [Internal label: RINUS; Contains test programs + other stuff (eg ISCOS100 stuff)]
  • PHILIPS unlabeled [Internal label: TP0; Contains test programs]
  • CPU ISCOS 70
    4022 250 0004.1
    PAB nr 8122 141 0470.1
    BD83 [Test or Manufacturing Data For Philips ISCOS 70 PLC CPU]
  • Ext Mem Mod 286
    4022 226 2340.1
    PAB nr 8122 141 0456.1
    BD82 [Test or Manufacturing Data]
  • VIP V12
    4311 027 1629.1
    PAB nr 8122 141 0277.1
    BD51 [Test or Manufacturing Data]
  • DISK Unit 1 [Internal label: ECA59]
  • TRAINING 004
    P.H.Kraaijeveld [Internal label: TRAINING]
  • FPP KENIA [Formatted Empty pack]
  • 4 x PHILIPS unlabeled [Formatted Empty pack]
  • MEMOREX unlabeled [Formatted Empty Pack]
  • 2 x CDC unlabeled [Unformatted Empty pack]

Problems

  • DOM_HARRY OLDREL
    old sources of release 01-10-82 [Lots of bad spots]
  • Graphics 8P-A
    4022 226 3470.1
    PAB nr 8122 141 0286.1
    BD58 [Many read problems]
  • Service pack 1
    various programmes [Reads OK, but weird file system structure issues]
  • X1216 IPL 63C2
    Test programs update 85-12-18
    -DOM9 A/02 IT/10 FL/03 IT/11 [Test or Manufacturing Data]
    Userid: SDAPRO
    s:$LOAD [X1216 Pack]
  • DOM 811 adr/02 intr/11
    terminal adr/10 intr/6
    update test programs 27-09-84
    IPL/65C2 [X1216 Pack]
  • LAB Backup [X1216 Pack]
  • TEST TP1
    R=0002 [X1216 Pack]

The X1215 drive imaging system is now working properly, and I have successfully created disk images for two disk packs.

First I had to fix the drive to start at track 0, as it should. Before, it started at track 4. Fortunately, on the x1215 you can change which track is seen as track 0 by moving the optical zero sensor. That means that the meander tracks used for positioning can remain in place so you don't lose alignment.

After that, I let the drive create images for each track, which were then analyzed. The resulting disk image looked ok for the first disk, labeled "FPP Kenia", which turned out to be a blank, formatted disk. The second disk, labeled "Testprograms" also seemed ok at first sight, but the resulting disk image was still wrong, as booting it produced a hang in Theo Engel's P856 emulator. It turned out that the data for the two heads (0 and 1) was the same on each track.

Some debugging with the logic analyzer showed that the head-select and address-bus lines were correctly getting asserted to change the read head, and that these signals correctly reached the DC logic card in the drive, but that the head-select lines from the DC card didn't change as a result. The problem turned out to be a flip-flop (half of a 7474 IC) on the DC card, so once this was replaced, I took another image of the "Testprograms" disk.

As the header shows, this disk pack was written in 1982 (not 1985 like it says on the label). 32 years later I can still read the data:

==============================================
PHILIPS P800 X1215 CARTRIDGE DISC DRIVE READER
==============================================
(c) Copyright 2014 by C. Vanderhoeven

DSK-I-LABEL: Sector offset determined to be 1. Disk label:
     0000 0000 2020 2020 414c 4542 204c 203d 5054 3930         LABEL = TP09
     2020 2020 2020 2020 2020 2020 2020 4144 4554 3d20               DATE =
     2020 3130 2020 3630 2020 3238 2020 3231 3531 4150   01  06  82  1215PA
     4b43 4e20 5242 3d20 2020 3030 3530 0200 1000 0300 CK NBR =  0005
     9a01 0500 6400 0000 0000 0000 0000 0000 0000 0000      d
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 ff7f ffff ffff ffff ffff
     ffff ffff ffff 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000

This time, the disk image works! I can boot it in Theo's emulator, and I get the following little dialog going (what I typed in bold):

MONITOR ? DOM9A

LOAD ADDRESS: 0000
**DOS 09 ** 8701 312 84000 *‼

 DATE : 

 TIME : 

 BATCH PROCESSING ? N

USERID: SDAPRO
S:LSD
LABEL = TP09              DATE =  01  06  82  1215PACK NBR =  0005‼
*********LIBRARY DIRECTORY*********‼
****FILENAME****TYPE****ADDRESS****‼
    BPTR1       LM      0540‼
    BSER1       LM      0560‼
    BCR1        LM      0578‼
    BDIOD1      LM      0588‼
    BCASS1      LM      0598‼
    BCDD1       LM      05B8‼
    BMAGT1      LM      05D8‼
    BDISP1      LM      05F0‼
    BCDC2       LM      0608‼
    BMAGT2      LM      0630‼
    BSLCU2      LM      0648‼
    B-ALCU      LM      06B0‼
    BMA8AC      LM      0710‼
    BLSM16      LM      0748‼
    BV28CM      LM      0798‼
    BHDLC       LM      07F0‼
    BZSAC1      LM      0828‼
    BSLCU4      LM      0850‼
    BPTP1       LM      08B0‼
    BLP1        LM      08D0‼
    CPA4K1      LM      08F0‼
    CPA4K2      LM      09E8‼
    CPA8K       LM      0A90‼
    BMEMO       LM      0AB8‼
    BBMMU1      LM      0AC0‼
    BBFPP1      LM      0AD8‼
    BPRTC1      LM      0AE8‼
    BRAM        LM      0AF8‼
    CPB8K       LM      0B00‼
    CPZ8K       LM      0B30‼
    BBMEMO      LM      0B60‼
    BFLOP1      LM      0B70‼
    BBDISP      LM      0BA0‼
    BP817       LM      0BB0‼
    BFHD1       LM      0BE0‼
    BZ1250      LM      0BF0‼
    IPLC1       LM      0C08‼
    BBRAM       LM      0C20‼
    BATYPE      LM      0C38‼
    BBSER1      LM      0C40‼
    BZSCU       LM      0C50‼
    BX1216      LM      0C68‼
    BZ1216      LM      0C88‼
    BZCDD1      LM      0CA8‼
    SBCA        LM      0CC8‼
    CP1A        LM      0CE0‼
    CP57RE      LM      0D10‼
    REMMU1      LM      0D48‼
    REPAF       LM      0D68‼
    BF1MZ       LM      0D88‼
    BF1MB       LM      0DB0‼
    BVCCU4      LM      0DD8‼
    BASCU4      LM      0E08‼
    BACCZ       LM      0E28‼
    PRORAM      LM      0E40‼
    BZTTY1      LM      0E48‼
    FLCOPY      LM      0E60‼
    COPY        LM      0E78‼
    ADJUST      LM      0EA8‼
    BIGD2S      LM      0EC0‼
    EFPP1       LM      0EF0‼
    BIGD2C      LM      0F10‼
    BWDAB1      LM      0F38‼
    BHLVCU      LM      0F78‼
    WDDU        LM      0FB8‼
    WDABU       LM      0FF8‼
    BSLCUZ      LM      1040‼
    CP1/2B      LM      1070‼
    MMU2B       LM      10D8‼
    PAF2B       LM      10F0‼
    BWDD1       LM      1110‼
    BWDH1       LM      1140‼
    SCSISH      LM      1180‼
    BWJA1       LM      1190‼
    IOPZR       LM      11F0‼
    ID12NC      UF      11F8‼
    INDICE      UF      1208‼
    GENT1       UF      1240‼
    GENT2       UF      1248‼
    GENT3       UF      1250‼
    GENT4       UF      1258‼
    GENT5       UF      1260‼
    GENT6       UF      1268‼
    GENT7       UF      1270‼
    GENF1       UF      1278‼
    GENF2       UF      1280‼
    GENF3       UF      1288‼
    GENF4       UF      1290‼
    GENF5       UF      1298‼
    GENF6       UF      12C0‼
    GENF7       UF      12C8‼
    GENF8       UF      12D0‼
    GENF9       UF      12D8‼
    GENF10      UF      12E0‼
    GENF11      UF      12E8‼
    GENF12      UF      12F0‼
    MEMTS1      LM      12F8‼
    BELUNI      LM      1310‼
    BDIPA       LM      1348‼
    INTER       LM      1358‼
    WDEU        LM      1360‼
    STRIMR      LM      13A8‼
    BHLX        LM      13E8‼
    WDHU        LM      1400‼
    BWDE1       LM      1448‼
    BAMA4Z      LM      1480‼
    BWMF1       LM      14C8‼
    BCIPH1      LM      14E8‼
S:$LOAD
RUN 0‼

  LOADER OF STAND ALONE TEST PROGRAMS 82 11 22
  DOS 04/6/9
  PROGRAM NAME TO BE LOADED : CPA8K

  THE 12 NC NUMBER OF THE LOADED PROGRAM IS :     5111 199 74512
Execution stopped with a HLT

Run/Boot: emulation stopped at address  02FC
90203587 instructions in 125.605228 seconds: 718151 instructions per second

As you can see, there are a lot of different test programs there.

Reading and decoding a disk pack takes me a while. The steps involved are:

  1. Carefully checking the disk pack for dust and damage using a flashlight
  2. Spinning up the disk pack in a second X1215 (with faulty electronics and no heads) and letting it spin for an hour or so to get rid of any dust
  3. A second inspection of the disk pack for any remaining dust
  4. Mounting the disk pack on the X1215 used for imaging
  5. Spinning up the disk
  6. Start the imaging program like this:
    C:\> X1215 cartridge tp09
    
  7. If the imaging program aborts because of an UNSAFE condition on the drive, spin down the disk and spin it up again (to clear the condition), then restart the imaging program to restart at the track at which the error occurred, like this:
    C:\> X1215 cartridge tp09 154-203
  8. Repeat the last step until the entire disk has been imaged, you now have a list of files named tp09_ttt_h.img where ttt is the track number and h is the head number
  9. Start the analysis program to compile the disk image, like this:
    C:\> X1215 decode tp09 tp09.img
  10. If there are no disk errors reported, we're done, and you can spin down and unload the disk; otherwise, continue
  11. The analysis program spits out a list at the end with tracks that have errors on them, like this:
    ****************************************
    ***
    ***   ERRORS IN TRACKS:
    ***   36-41,68,203
    ***
    ****************************************
  12. Start the imaging program to read these tracks again, like this:
    C:\> X1215 cartridge tp09 36-41,68,203
  13. Go back to step 9 and repeat until you're satisfied with the error list.
    NOTE: There may still be errors in the list at this point, because the disk may really have bad tracks or sectors. Tracks 200 - 203 are spare tracks that the operating system uses to map bad tracks to.

As you can imagine, this takes a while, but it is very rewarding to see the error list dwindle down to almost nothing. The end result of the entire operation may look something like this:

C:\src\x1215_reader\driver\Release>X1215 d aa tp09.img

==============================================
PHILIPS P800 X1215 CARTRIDGE DISC DRIVE READER
==============================================
(c) Copyright 2014 by C. Vanderhoeven

DSK-I-LABEL: Sector offset determined to be 1. Disk label:
     0000 0000 2020 2020 414c 4542 204c 203d 5054 3930         LABEL = TP09
     2020 2020 2020 2020 2020 2020 2020 4144 4554 3d20               DATE =
     2020 3130 2020 3630 2020 3238 2020 3231 3531 4150   01  06  82  1215PA
     4b43 4e20 5242 3d20 2020 3030 3530 0200 1000 0300 CK NBR =  0005
     9a01 0500 6400 0000 0000 0000 0000 0000 0000 0000      d
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 ff7f ffff ffff ffff ffff
     ffff ffff ffff 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
     0000 0000 0000 0000 0000

DSK-I-SECZERO: Sector 0 to be found at: 81572 1333359 2585078 3836955
TRK-W-DUPL: Same data on both heads in track 23
TRK-W-SECDIF: 36/0 can't handle sector difference of 2817287
TRK-W-DUPL: Same data on both heads in track 52
TRK-W-DUPL: Same data on both heads in track 55
TRK-W-DUPL: Same data on both heads in track 62
SEC-W-NODATA: No valid sector data found for sector 68/1/0
SEC-W-NODATA: No valid sector data found for sector 68/1/1
SEC-W-NODATA: No valid sector data found for sector 68/1/2
SEC-W-NODATA: No valid sector data found for sector 68/1/3
SEC-W-NODATA: No valid sector data found for sector 68/1/4
SEC-W-NODATA: No valid sector data found for sector 68/1/5
SEC-W-NODATA: No valid sector data found for sector 68/1/6
SEC-W-NODATA: No valid sector data found for sector 68/1/7
SEC-W-NODATA: No valid sector data found for sector 68/1/8
SEC-W-NODATA: No valid sector data found for sector 68/1/9
SEC-W-NODATA: No valid sector data found for sector 68/1/10
SEC-W-NODATA: No valid sector data found for sector 68/1/11
SEC-W-NODATA: No valid sector data found for sector 68/1/12
SEC-W-NODATA: No valid sector data found for sector 68/1/13
SEC-W-NODATA: No valid sector data found for sector 68/1/14
SEC-W-NODATA: No valid sector data found for sector 68/1/15
TRK-W-DUPL: Same data on both heads in track 142
TRK-W-DUPL: Same data on both heads in track 170
TRK-W-DUPL: Same data on both heads in track 176
SEC-W-NODATA: No valid sector data found for sector 203/0/0
SEC-W-NODATA: No valid sector data found for sector 203/0/1
SEC-W-NODATA: No valid sector data found for sector 203/0/2
SEC-W-NODATA: No valid sector data found for sector 203/0/3
SEC-W-NODATA: No valid sector data found for sector 203/0/4
SEC-W-NODATA: No valid sector data found for sector 203/0/5
SEC-W-NODATA: No valid sector data found for sector 203/0/6
SEC-W-NODATA: No valid sector data found for sector 203/0/7
SEC-W-NODATA: No valid sector data found for sector 203/0/8
SEC-W-NODATA: No valid sector data found for sector 203/0/9
SEC-W-NODATA: No valid sector data found for sector 203/0/10
SEC-W-NODATA: No valid sector data found for sector 203/0/11
SEC-W-NODATA: No valid sector data found for sector 203/0/12
SEC-W-NODATA: No valid sector data found for sector 203/0/13
SEC-W-NODATA: No valid sector data found for sector 203/0/14
SEC-W-NODATA: No valid sector data found for sector 203/0/15
SEC-W-NODATA: No valid sector data found for sector 203/1/0
SEC-W-NODATA: No valid sector data found for sector 203/1/1
SEC-W-NODATA: No valid sector data found for sector 203/1/2
SEC-W-NODATA: No valid sector data found for sector 203/1/3
SEC-W-NODATA: No valid sector data found for sector 203/1/4
SEC-W-NODATA: No valid sector data found for sector 203/1/5
SEC-W-NODATA: No valid sector data found for sector 203/1/6
SEC-W-NODATA: No valid sector data found for sector 203/1/7
SEC-W-NODATA: No valid sector data found for sector 203/1/8
SEC-W-NODATA: No valid sector data found for sector 203/1/9
SEC-W-NODATA: No valid sector data found for sector 203/1/10
SEC-W-NODATA: No valid sector data found for sector 203/1/11
SEC-W-NODATA: No valid sector data found for sector 203/1/12
SEC-W-NODATA: No valid sector data found for sector 203/1/13
SEC-W-NODATA: No valid sector data found for sector 203/1/14
SEC-W-NODATA: No valid sector data found for sector 203/1/15
TRK-W-DUPL: Same data on both heads in track 203

****************************************
***
***   ERRORS IN TRACKS:
***   36,68,203
***
****************************************

****************************************
***
***   DUPLICATES IN TRACKS:
***   23,52,55,62,142,170,176,203
***
****************************************

In this example, track 36 should be re-imaged, as there's a large gap where no data was read. Track 68 head 1 is a genuine bad track that has been replaced, and track 203 simply isn't there (it would seem that some older X1215's can only write 203 tracks rather than 204).

The duplicates indicated mean that the data on heads 0 and 1 is identical for that track. That check was added when I had the head-selection problem described earlier. In this case, it's probably valid, as you would expect to see this if all sectors in these tracks are empty (all zeroes)

The X1215 imager project has been completed to the point were I can now read data from the disk. The drive mechanism is not too stable (the heads may drift away, resulting in an UNSAFE condition), so I've chosen to image disk packs as separate images for each track, to make it easy to restart without having to redo everything. As the disks have 204 tracks on each side, this results in 408 files of half a megabyte each. The disk images contain the raw data as delivered by the disk, sampled at 50 MHz. That's 20 bits of sampling data for each bit cell. The track image is made during three full revolutions of the disk, so there should be 3 copies of each sector in each file. That way, if one copy is bad, another copy may have the correct data.

I've written a second program that takes one of these image files, and tries to recover the data from it. It will try to separate the data from the inter-sector gaps, and then analyze each sector to find the preamble (a lot of '0's followed by a single '1' to mark the beginning of the sector), the sector data (205 16-bit words), and the checksum word. If the checksum word matches the calculated checksum (XOR of each data word), the sector is good. If not, the backup copies are tried.

The output is presented like this:

ANALYZE SECTOR 14
340 bit preamble after 0 bits of crud
XOR: 6c9b LRC: 6c9b
0003 018e 2043 4f4e 5452 4f4c 2d53 5441 5455 5320      CONTROL-STATUS
4152 4541 2028 2f44 4354 2920 004c 0168 003c 0050 AREA (/DCT)  L h < P
2020 2020 2020 2020 2044 4154 4120 2020 2030 2020          DATA    0
2020 2020 2020 2020 2020 2020 2044 5754 4154 543a              DWTATT:
2041 5454 4143 4820 4c4f 4341 5449 4f4e 004d 0024  ATTACH LOCATION M $
003e 0050 2020 2020 2020 2020 2044 4154 4120 2020  > P         DATA
2032 3320 2020 2020 2020 2020 2020 2020 2044 5754  23              DWT
5353 543a 204c 4556 454c 2d23 2028 474e 494d 4f4e SST: LEVEL-# (GNIMON
2920 004d 0064 0006 0050 2a20 004d 00a6 0014 0050 )  M d   P*  M     P
2a20 2020 4457 5420 464f 5220 5050 3330 004d 00b0 *   DWT FOR PP30 M
0006 0050 2a20 004d 00c8 0038 0050 443a 5050 3330    P*  M   8 PD:PP30
2020 2044 4154 4120 2020 2027 5050 2720 2020 2020    DATA    'PP'
2020 2020 2020 2044 5754 444e 203a 2044 4556 4943        DWTDN : DEVIC
452d 4e41 4d45 004d 00d2 003c 0050 2020 2020 2020 E-NAME M   < P
2020 2044 4154 4120 2020 202f 3330 2020 2020 2020    DATA    /30
2020 2020 2020 2044 5754 4441 203a 2044 4556 4943        DWTDA : DEVIC
452d 4144 4452 4553 5320 004d 010e 0040 0050 2020 E-ADDRESS  M   @ P
2020 2020 2020 2044 4154 4120 2020 2038 3020 2020        DATA    80
2020 2020 2020 2020 2020 2044 5754 424c 473a 2042            DWTBLG: B
4553 5420 5245 434f 5244 204c 454e 4754 4820 004d EST RECORD LENGTH  M
014e 4e3a 0000 0000 0000                           NN:

This is already looking pretty decent. There's a slight problem, however. The first track read should be track 0, but it's not. The first track read appears to be track 2, so I'm missing the first two tracks. That means adjusting the head position, which I'm not very keen on doing, as I haven't got the proper alignment packs. It'll be a kind of informed twiddling around with the alignment until I get track 0 data.

Once this is done, I'll complete the program to combine the different raw image files into a final image file containing just the data.

I'm making some progress on the X1215 Imager. I can send commands to the drive to select heads, step to tracks, and to start reading.

Connecting the oscilloscope to the output of the read amplifier, I can see the data go by. The encoding is very primitive, which makes things easy. One bit-cell takes 400 nanoseconds. If there is a single flux-transition in a cell, it reads as a 0, if there are 2, it reads as a 1. So, on the picture above you can read "10100" from left to right.

 

One of my projects is to emulate the Philips X1215 cartridge disc drive (at the drive level, so the emulator connects to the original CDD controller).

The system consists of a laptop with a special driver and program on it, an FPGA card that is programmed to emulate the disk, some level shifters to provide I/O at the 5 volts level the controller operates at, and a cable to connect the level shifters to the controller. The cable has an extra connector on it to easily attach a logic analyzer for debugging purposes.

The chain between the disk image (sitting on a PC) and the P800 is as follows:

  • Disk image on PC
  • Disk serving application on PC
  • PCIe bus
  • FPGA card
  • Level converters (3.3v <==> 5v)
  • Cable
  • CDD X1215 control unit in P800
  • P800 CPU

 

Disk image on PC

The disk image is a binary file that simply contains the data found on a disk pack. So, it's got 2 * 204 * 16 blocks that are each 410 bytes long. Theo Engel has some images available for download from his site.

Disk serving application on PC

This is a fairly simple application that communicates with the FPGA over the PC's PCIe bus. It presents a simple dialog; something like this:

  X1215 DISK SERVER v0.0
Fixed disk? C:\P800\disk0.img
Unit off-line, load a cartridge to bring it on-line or type EXIT
Cartridge? C:\P800\disk1.img
Unit on-line, type YES to take unit off-line
Off-line? YES
Unit off-line, load a cartridge to bring it on-line or type EXIT
Cartridge? C:\P800\disk2.img
File does not exist. Do you want to create a new image? YES
Unit on-line, type YES to take unit off-line
Off-line? YES
Unit off-line, load a cartridge to bring it on-line or type EXIT
Cartridge? EXIT
Bye bye

Communication with the FPGA is through a 32KB memory range. This range is divided into 4 * 16 512-byte blocks. This is enough to contain all the data for one track on both the fixed and the removable platters at once. This way, the memory only needs to be updated when a SEEK is issued, which the controller expects to take some time.Of course, only 410 bytes out of each 512 byte block are actually used for data. One 32-bit word in the unused area is used for status communication.

<OPERATION

 

  1. When the disk serving application starts, it loads the track 0 data into the FPGA, then writes data to the status word to inform the FPGA that a) the disk is online and that b) data has been loaded for track 0.
  2. If a seek is issued by the control unit, the FPGA signals this to the application by changing the track number to the one needed. If the previous track has been written to, a dirty flag is set in the status word.
  3. When the application sees the changed track number, it examines the dirty flag. If it is set, the data from the FPGA is read back to the application's copy of the disk images.
  4. The application now loads the data for the new track into the FPGA. It signals the FPGA by writing the new track number to the status word.
  5. When the user opts to unload the cartridge, the PC signals the FPGA that the unit goes off-line. It then checks the dirty flag and reads back the track data if needed. It then closes the disk image file after updating it.

FPGA Card

The FPGA card is the heart of the emulated disk drive. It responds to commands from the control unit by instructing the application to perform seeks, selecting the right head, and performing read and write operations. It properly serializes data for reading, and unserializes data for writing. It provides all the necessary timing signals (sector and index pulses) to the control unit.
The FPGA card used is a Xilinx XUPV5.

 

Level converters

These are necessary because the FPGA uses 3.3 volts for a logic "1", and the control unit uses 5 volts for a logic "1". I'm building a sandwiched interface card that sits on top of the FPGA card, containing 64 level converters (more than is needed here, but I like the flexibility so I can use it for more projects requiring more pins). I'm building it out of perfboard, using wire-wrap technique to connect the converters to the connectors.

Cable

This is a custom-made cable that has a 50-pin IDC connector on one end (to connect to the level converter board), and a 74-pin card edge connector on the other end (to connect to the CDD). Why Philips couldn't use a more common connector size is beyond me!
The cable has also been fitted with two 20-pin IDC connectors for direct connection to my logic analyzer.

P800 and CDD

The P800 and CDD themselves remain completely unchanged. The emulator connects to the CDD the same way a real X1215 would.