The Wang Professional Computer
The Wang Professional Computer is one of the first generation of competitors to the IBM PC: an MS-DOS machine that isn't compatible with the IBM at a hardware level.
I wrote the bulk of this page based on reverse-engineering, before discovering a copy of the Technical Reference manual online at bitsavers.org. Corrections from the Technical Reference manual have been applied where appropriate.
The case is roughly the size of an IBM XT, sideways on, but taller. At the front are two full-height 5.25" drive bays; the right-hand one holds a 5.25" floppy drive, and the left-hand one holds a Quantum Q540 hard drive, formatted to 32Mb (the boot ROM refers to this as a 'Winchester', as this page will from now on). From the design of the case, a twin-floppy configuration would also be possible.
A large power supply occupies the left-hand rear corner of the case. The remainder of the bottom level of the case contains the L-shaped motherboard, which contains the processor, memory, floppy controller, serial port, parallel port and keyboard interface.
The motherboard plugs into a vertical backplane which is attached to the side of the power supply. This backplane provides six slots: one for the motherboard, and five for expansion cards.
Cards, from top to bottom:
- Winchester controller
- 256k memory board
- Local Interconnect (with Remote / Local switch, network connector, LED)
- Video card (with video and power connectors for mono monitor)
- Remote Communications board (with two DB-25 connectors — RS232?)
- Motherboard (with RS232 port, keyboard connector, parallel port)
The cards then occupy the right-hand side of the case (as seen from the front). While they aren't as big as the motherboard, they are still much bigger than the cards in IBM PCs — about twice the size. The Winchester controller normally occupies the top slot, where provision has been made for MFM cables running to the right-hand drive bay.
Top: Full-size ISA video card. Bottom: Full-size Wang video card.
At the I/O level, each slot occupies a different range in the processor's address space. Motherboard devices have addresses betweeen 1000h and 10FFh; then the device in the first slot appears at 1100h-11FFh, the second at 1200h-12FFh and so on. The boot ROM scans fifteen address ranges (11xxh - 1Fxxh). This system ensures that I/O ranges used by different cards will not clash, and allows a system to support (for example) multiple display cards.
The high bit of the value read from xxFEh is set if the device is interrupting. An interrupt service routine should check all cards to see which one the interrupt came from.
The low 7 bits of the value read from xxFEh give the device class, which can include:
- PM029 Winchester card
- Colour video card (40×25)
- 11h / 15h
- PM001-B Monochrome video card (80×25), or PM101 IBM Mono Emulation board
- 13h / 17h
- Text / Image / Graphics video card
- IBM-compatible CGA (80×25)
- PM040-B remote communications
- Multiport Communications option
- PM070 local interconnect
- Local Communications Option
- CP/M-80 emulation card
- PM031-B memory expansion
- Scanner / Printer Card
- Laser Printer Controller
- Local Com Option
This port can also be written to; on the Winchester card, for example, it configures DMA access.
Devices on the mainboard include:
- 8086 processor.
- Empty socket for an 8087.
- Two 2764 EPROMs holding the boot firmware.
- 8253 timer.
- 8259A programmable interrupt controller.
- 8237 DMA controller (actually, an AM9517: the AMD version).
- 8272 floppy disc controller.
- SCN2661C serial controller (for the serial port).
- 8255A PPI (for the parallel port control lines, and other things)
- IM6402 UART (for the keyboard).
- 4 DIP switches.
Motherboard I/O Ports
Without any technical documentation, I've had to guess most of these...
1000: Bit 0: Set if the DMA chip should stop the floppy controller when it reaches terminal count. Bit 1: Set to disconnect the FDC from DMA channel 2, clear to connect Bit 2: Set to reset interrupt generated by drive 0 changeline Bit 3: Set to reset interrupt generated by drive 1 changeline 1004-1012: Drive selection / motor logic. It does not seem to matter what bytes are written to these ports; any write will do. 1004: Deselect drive A: 1006: Select drive A: 1008: Deselect drive B: 100A: Select drive A: 100C: Stop motor for drive A: 100E: Start motor for drive A: 1010: Stop motor for drive B: 1012: Start motor for drive B: 1014: FDC main status register 1016: FDC data register 1018: } Any read or write access to these ports will reset the FDC. 101A: } 101C: } Any read or write access to these ports will send a Terminal Count 101E: } signal to the FDC. 1020: PPI channel A (input): Centronics port status Bit 7: 0 if printer has acknowledged last byte. Reset by writing port 10ECh. Bit 6: 1 if paper out. Bit 5: 0 if fault. Bit 4: 1 if printer busy. Bit 3: 1 if printer selected. Bit 2: 0 if character received; the character can be read from port 10EAh. Bit 1: 0 if printer supports bidirectional communication. Bit 0: 0 if printer power on. 1022: PPI channel B (input): Source of mainboard interrupt. Bit 0: zero if IRQ1 triggered by timer channel 2. Reset by reading port 10E2h. Bit 1: zero if IRQ1 triggered by serial port. Reset by servicing the interrupt at the SCN2661. Bit 2: zero if IRQ1 triggered by parallel port. Reset by reading port 10ECh. Bit 3: zero if IRQ2 triggered by the DMA controller reaching terminal count. Reset by reading port 10E6h. Bit 4: set if IRQ2 triggered by sending byte to keyboard. Reset by writing port 10E6h. Bit 5: set if IRQ2 triggered by input from keyboard. Reset by reading the scancode. Bit 6: set if IRQ2 triggered by the floppy controller. Read port 10E0h (bits 3-5) to see what caused the interrupt. Bit 7: set if IRQ2 triggered by the 8087. 1024: PPI channel C (bits 0-3 output, 4-7 input) Bit 0: Centronics Auto Feed (active low) Bit 1: Centronics Select (active low) Bit 2: Centronics Reset (active low) Bit 3: Unused Bits 4-7: Motherboard DIP switches. 1026: PPI control register (always write 9Bh). 1040: i8253, channel 0 (system tick. Generates interrupts on IRQ0). 1042: i8253, channel 1 (used for memory refresh) 1044: i8253, channel 2 (general purpose clock. Generates interrupts on IRQ1). 1046: i8253, control register 1060: i8259, main register 1062: i8259, initialisation command registers 1080: Serial port (SCN2661): Read receive holding register 1082: Serial port (SCN2661): Read status register 1084: Serial port (SCN2661): Read mode register 1086: Serial port (SCN2661): Read command register 1088: Serial port (SCN2661): Write transmit holding register 108A: Serial port (SCN2661): Write SYN1 / SYN2 / DLE registers 108C: Serial port (SCN2661): Write mode register 108E: Serial port (SCN2661): Write command register 10A0: i8237 DMA channel 0 base address 10A2: i8237 DMA channel 0 word count 10A4: i8237 DMA channel 1 base address (channel 1 is for Winchester drives) 10A6: i8237 DMA channel 1 word count 10A8: i8237 DMA channel 2 base address (channel 2 is for floppy drives) 10AA: i8237 DMA channel 2 word count 10AC: i8237 DMA channel 3 base address 10AE: i8237 DMA channel 3 word count 10B0: i8237 DMA status / command register 10B2: i8237 DMA write request register 10B4: i8237 DMA mask register 10B6: i8237 DMA mode register 10B8: i8237 DMA clear flip-flop 10BA: i8237 DMA master clear register 10BC: i8237 DMA clear mask register 10BE: i8237 DMA write mask register 10C0: DMA segment, channel 0 10C2: DMA segment, channel 1 10C4: DMA segment, channel 2 10C6: DMA segment, channel 3 10E0: When read, the following bits have meaning: Bit 0: Normally 1. Becomes 0 if there is a memory parity error. Bit 1: Normally 1. Becomes 0 if there is an I/O error. Bit 3: Set if the floppy controller interrupted. Reset by performing a SENSE INTERRUPT STATUS command. Bit 4: Set if floppy 0 changeline has changed. This flag is reset by writing to port 1000h with bit 2 set. Bit 5: Set if floppy 1 changeline has changed. This flag is reset by writing to port 1000h with bit 3 set. Bit 6: Floppy 0 changeline: set if drive 0 not ready. Bit 7: Floppy 1 changeline: set if drive 1 not ready. When written, resets IRQ0 and timer channel 0. 10E2: When read, resets IRQ1 and timer channel 2. When written, the bottom bit enables (1) or disables (0) the NMI. 10E4: When read, lights the diagnostic LED. When written, the bottom bit enables (1) or disables (0) the 8087 interrupt. 10E6: Writes to this port clear the keyboard transmit interrupt. Reads clear the DMA controller interrupt. 10E8: Keyboard UART (IM6402) data port. 10EA: Parallel port data latch, bidirectional. 10EC: Write to clear parallel port Acknowledge flag. Read to clear parallel port Busy flag. 10EE: Write to clear parity flag. Read to turn the diagnostic LED off. 10FE: Bits 6-0 are always 0. Bit 7 set if FDC is interrupting.
Keyboard scancodes and commands are listed on their own page.
The boot ROM performs a hardware self-test, and then determines the system console. By default, the keyboard is used for input. Output is sent to a video card (if present) or the serial port (otherwise).
If a bootable device is found, its boot program will be loaded and launched. If not, a menu will be displayed, allowing the system console to be reassigned and the boot device to be chosen. The ROM can boot from either floppy drive, a Winchester, the serial port, or the keyboard (with the boot program typed in as hex bytes).
Unless booting from the keyboard, the boot program needs a valid signature ('Wang' at offset 3) and the 8-bit checksum of the first 512 bytes should be zero using the calculation below:
xor ax, ax mov cx, 200h calc: adc al, es:[bx] inc bx loop calc
The boot program will be entered with DH = slot number of boot device.
Note that the boot services and memory layout shown below are not available to programs running under MS-DOS, which overwrites these tables with its own BIOS.
Boot Environment: Interrupts
The following services are provided to the boot program:
- INT 80h - INT 87h
- Hardware interrupt handlers.
- INT 88h
- Poll console input. Returns AL=waiting character if present, else 0. Does not remove waiting character from the queue.
- INT 89h
- As INT 88h, but if a character is waiting, remove it from the queue.
- INT 8Ah
- Output character in AL to the console.
- INT 8Bh
- Output 0-terminated string at DS:SI to the console.
- INT 91h
- Read sector(s):
AL = number of sectors to read BX = first sector number to read DL = retry count ES:SI = load address Returns AH=80h if OK, else error: 01h: Drive not ready 02h: Controller fault (returning results when none expected) 03h: Read error (eg CRC) 04h: Format error (No Data / Missing Address Mark) 05h: Controller failed 08h: Too many sectors (would cross segment boundary) 0Bh: Cannot find file.
- INT 92h
- Set drive geometry.
AL = sectors / track AH = heads DX = offset in sectors to start of partition CL = read/write gap CH = sector size: 0=>128, 1=>256, 2=>512, 3=>1024
- INT 97h
- Display boot menu. BX = flags:
Bit 0: Offer G=Go Bit 1: Offer R=Retry Bit 2: Offer D=Choose start device Bit 3: Offer P=Power-up diagnostics Bit 5: Offer Q=Quick Restart Bit 13: Beep Bit 15: Do not print a newline before showing the boot menu.
Boot Environment: Device Table
The boot ROM creates a table of detected devices at 40h:0. Each entry is 8 bytes long, and the table has 20 entries. The first 15 are for devices in slots, while the last five are for motherboard resources.
The format of an entry is:
00 DB id ;Bit 7 is 0 if device is present and operational. ;Bits 6-0 give device class (as read from port xxFEh) 01 DB flags ;Bit 7 set if device self-test failed. ;Bits 6-4 give device type: ; 0 => first floppy ; 1 => second floppy ; 2 => keyboard ; 3 => serial port ; 4 => parallel port ; 5 => device with its own driver ROM ('NEWDEV') ;Bit 3 set if device is the boot device ;Bit 1 set if device is the boot console ; ; If flags bit 7 set: ; 02 DW error ;Error message 04 DW error ;Secondary error message ; ; For a block device (floppy / Winchester): ; 02 DB sectors / track 03 DB heads 04 DW offset to start of partition 06 DB read/write gap 07 DB physical sector shift (0 => 128 bytes, 1 => 256 bytes etc.) ; ; For the keyboard: ; 02 DB keyboard type ; ; For a NEWDEV device: ; 04 DW offset to driver ROM header (relative to boot ROM code segment)
Additional character or block devices can be added to the boot environment. The boot ROM contains drivers for two of these — one for a video card (class 13h / 17h) and one for a 'Local Com Option' (class 38h / 78h). Other cards can provide these by means of an add-on ROM; if they do, the device class read from port xxFE must be in the range 50h-5Fh.
For add-on cards, the boot ROM writes 0F5h to xxFAh, making the device ROM visible at 0F4000h. The boot ROM then copies data from the card ROM to RAM. The ROM is paged out by writing 0F4h to xxFAh.
If bit 5 of the device flag byte is 0, the boot ROM assumes the device ROM is stored at even addresses only (so the first three bytes are at F400:0, F400:2 and F400:4).
The ROM begins with a header. The boot ROM populates the segments of DWORD addresses, bytes 1E-1F and 22-2A.
0000 DW length of driver, bytes 0002 DW length of RAM required, bytes 0004 DW version 0006 DD device selftest routine 000A DD device reset routine 000E DD ? 0012 DD device set boot geometry (cf INT 92h) 0016 DD device load boot track (cf INT 91h) 001A DD character output 001E DB slot number 001F DB CRTC initialisation flag 0020 DW offset of device name 0022 DW segment of boot ROM 0024 DW 0 0026 DW offset of 'thick' font in boot ROM 0028 DW offset of 'thin' font in boot ROM 002A DB 7Fh ;Length of fonts (in characters) minus 1
The boot ROM has support for three different video cards: Classes 10h, 11h / 15h and 13h / 17h.
This is a colour card, based around a graphical framebuffer. There are two resolutions: 40 × 25 in 16 colours (initialised by the BIOS) and 80 × 25 in 4 colours.
When paged in, the framebuffer is 64k at E000:0. Each line is 256 bytes, and there are 256 lines.
In 16-colour mode, the memory is treated as four planes, with the low 2 bits of a byte's address giving the plane. So the first pixel is defined by bit 7 of the bytes at E000:0000, E000:0001, E000:0002 and E000:0003. In 4-colour mode, the principle is the same but there are only two planes.
Maximum resolution in 16-colour mode would be 512×256, but in practice the CRTC is set up for 320×225 by the ROM BIOS, and 320×200 by MS-DOS. In 4-colour mode, MS-DOS programs the CRTC for a 640×225 screen.
The following I/O ports are provided by this card:
- CRTC register select
- CRTC register data
- Bit 0 is set to page the video card's memory in,
clear to page it out.
Bit 2 is set for 24×80, reset for 24×40.
Bit 3 is set to raise an interrupt (IRQ3) on vertical blanking.
- Sets which row of video RAM is to be displayed at the top left-hand corner of the screen. The high byte is the first pixel row to display, plus 0EBh. The low byte is the leftmost column, divided by 2.
- Bit 2: In vertical refresh.
Bit 3: VSYNC active
Bit 4: HSYNC active
- xx40 - xx5E
- The palette. These are word registers, each one if which is treated as four nibbles. The values written by the BIOS are either 0 or F for each nibble. Only the top bit of each nibble appears to be significant; going from high to low, they give I R G B values for each of the 16 possible colours.
- Write to reset the interrupt flag.
- Bits 6-0 are 10h. Bit 7 is set if an interrupt
has been raised on IRQ3.
Class 11h / 15h (PM-001)
The PM-001 video card has a small edge-connector on the top edge. This appears to be for a PM-002B graphics daughterboard. The card class is 11h if the daughterboard is absent, 15h if it is present.
This card operates like an MDA, with display generated from a buffer containing character codes. Resolution is 800x300, with each character cell 10 pixels wide and 12 high.
When this card is paged in, its character / attribute buffer is at F000:0000; even-numbered bytes are attributes, odd-numbered bytes are characters. This is the reverse of the way the MDA does it.
The technical reference describes the attributes as: as:
Bit 0: Blink Bit 1: Reverse video Bit 2: Blank -- character renders as blank Bit 3: Bold (bright) Bit 4: Overscore Bit 5: Underscore Bit 6: Subscript: Moves character down by one line Bit 7: Superscript: Moves character up by one line.
The character bitmaps are stored at F200:0000, with 16 little-endian words per character. The low 10 bits of each word are used.
If the graphics daughterboard is present, it is mapped at E000:0000.
The following I/O ports are provided by this card:
- CRTC register select
- CRTC register data
- Bit 0 is set to page the video card's memory in,
clear to page it out.
Bit 3 is set to generate an IRQ3 interrupt on VSYNC.
- The boot ROM seems to use this interchangeably with xx10.
- Bits 6-0 return 11h or 15h, depending whether the graphics daughterboard is connected. Bit 7 is set if an IRQ3 interrupt is pending; reading the port clears the interrupt.
Class 13h / 17h
This card uses two NEC uPD7220 Graphic Display Controllers — one for text, one for graphics. I/O ports include:
- xx00 - xx1E
- Attribute table
- Read: Text GDC status register
Bit 1 set: Processor busy Bit 2 set: Command completed? Bit 5 set: Vertical blanking interval.Write: Parameter into FIFO
- Read: Read data from FIFO
Write: Command into FIFO
- xx24 As xx20, for graphics GDC
- xx26 As xx22, for graphics GDC
- Underline position
- Set DMA channel
Bit 0: Set to give DMA to the graphics GDC, clear for the text GDC Bit 1: Set for DMA1 Bit 2: Set for DMA2 Bit 3: Set for DMA3 Bit 4: If set, card ID is 17h. If clear, 13h.
- Bits 6-0 return 13h or 17h, depending on bit 4 of the value written to port xx2A.
Main status register. Bit 0 set if the controller is busy. Bit 1 set if the controller failed self-test. Bit 2 set if controller has result bytes to return (through the data register). Bit 3 set if the Z80 in the controller received a non-maskable interrupt. The technical guide specifies that 5Mb drives set this bit to 0, all others to 1. Bits 7-4 are a counter that increments with each byte written to the controller. The boot ROM requires this to be on 0A0h during its self-test. Bit 8 is checked by the IRQ2 service routine in MS-DOS; if it is not set and the controller is raising an interrupt, the controller is reset. Immediately after a DMA transfer, the boot ROM requires a read of the main status register to return a count that increments with each DMA transfer.
- Data register. Used to send commands and retrieve results.
- The boot ROM reads this (and ignores the result) when handling a hard drive interrupt, presumably to acknowledge the interrupt.
- Select DMA channel. The boot ROM writes 00h for none, 02h for DMA1, 04h for DMA2 or 08h for DMA3. This appears also to select the IRQ the Winchester interrupts on: 02h for IRQ5, 04h for IRQ6, 08h for IRQ7.
- Reset the controller.
- When read, returns the device class (always 1) in the bottom 7 bits. The top bit is 1 if the device is interrupting. When written, appears to select DMA channel as for xx06.
The first cylinder of a Winchester drive is reserved for system purposes, and has to be accessed using different commands at the controller level (F4 / F5 rather than C0 / C1). It is laid out as follows:
Sector 0: Configuration
00000000 57 72 69 74 65 20 70 72 6F 74 65 63 74 65 64 20 Write protected 00000010 3F 20 4E 6F 20 20 00 50 61 73 73 57 6F 72 64 20 ? No .PassWord 00000020 3D 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 = ..............
If there is valid configuration information, the byte at 12h should be 'Y'. If so, the byte at 1Ch holds the flags: Bit 0 set for software read-only, bit 1 for password (at offset 22h).
Sector 1: Partition table
00000000 01 00 80 00 00 00 00 00 00 00 01 00 00 00 00 00 ................ 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 00000020 A0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 00000040 50 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 P............... 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 00000060 50 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 P............... 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 00000080 50 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 P............... 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 000000A0 50 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 P............... 000000B0 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 000000C0 1D 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ 000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 41 01 09 .............A.. 000000E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
The partition table has up to 16 entries, each 32 bytes. The following bytes in an entry appear to have meaning:
00 DW number of cylinders in this partition. 0 means end of table. 01 DB flags: Bit 7 set if partition hidden Bit 1 set if partition format-protected Bit 0 set if partition write-protected 08 DW Partition type: 0=Generic, exact type is given by class. 1=Wang MSDOS 2=IBM 09 DW Class: 00000h: Normal 00001h: Boot 00100h: Wang / IBM 080FFh: Reserved 0FFFFh: System 1D DW 0141h ; Initialised using BIOS 01.65 1F DB 09 ; Initialised using firmware 09.00
If the first entry begins with zero, the drive is not partitioned, and should contain a single filesystem.
Other system track sectors
Sector 2 is blank. Sector 3 contains information about the drive:
00000000 57 35 31 31 30 30 30 31 30 31 35 00 50 41 52 54 W5110001015.PART 00000010 49 54 49 4F 4E 45 44 3D 59 45 53 07 00 00 00 00 ITIONED=YES..... 00000020 EA FE 01 08 10 00 02 00 00 00 00 00 00 00 00 00 ................ 00000030 00 00 00 00 00 00 00 00 00 00 00 80 00 41 01 09 .............A.. 00000040 80 00 00 20 00 00 10 00 00 00 01 00 00 00 00 00 ... ............ 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060 C1 07 01 01 00 00 0A 0F 32 2E 30 31 2E 31 30 20 ........2.01.10 00000070 41 01 09 00 00 00 06 00 49 4E 49 54 57 00 00 00 A.......INITW... 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0 C5 07 04 07 12 00 27 02 32 2E 30 30 20 20 20 20 ......'.2.00 000000B0 41 01 09 00 00 00 00 00 00 00 00 00 00 00 00 00 A............... 000000C0 C1 07 01 01 14 0B 51 39 32 2E 30 30 20 20 20 20 ......Q92.00 000000D0 41 01 09 00 00 00 00 00 00 00 00 00 00 00 00 00 A...............
The value at 00h-0Bh is the drive name. The 'PARTITIONED=YES' indicator is followed by 7, which is the number of partitions on the drive. If the drive is not partitioned (ie, it is a single volume) it reads 'PARTITIONED=NO ' and is followed by a zero.
The bytes at 20h are as follows:
20 DB partition control byte, 0 if drive is not partitioned. 21 DW cylinders, not including reserved cylinder. In the example above, the drive has 512 cylinders, but the size reported is 510. The reserved cylinder is deducted, and the innermost cylinder is used as a landing zone. 23 DB heads 24 DB sectors 26 DW sector size in bytes 28 zeroes 3B DW number of sectors per cylinder 3D DW BIOS version, as in the partition table 3F DB Firmware version, as in the partition table 40 D3 start of data area (ie, sectors in this reserved cylinder) 43 D3 start of vendor track (assumed to be 1 track long, and only exists if drive has more than 2 heads) 46 D3 start of defects track (assumed to be 1 track long) 49 DW sectors per cylinder * 2
The 32 bytes at 60h are written by the format utility:
00 dw year ;Date stamp 02 db month 03 db day 04 db minute 05 db hour 06 db centisecond 07 db second 08 db format utility version (8 characters) 10 dw BIOS version, as at 3Dh 12 db firmware version, as at 3Dh 16 dw options used by format program (bit flags) Bit 0: -Z, ignore bad system tracks Bit 1: -W, confirm formatting Winchester drive Bit 2: -R Bit 3: -Q Bit 4: -P Bit 5: -N, ignore errors in vendor defect map Bit 6: -M, load vendor defect map from file "MFG#####.DTA" Bit 7: Bit 8: -F, save vendor defect map to file Bit 9: Bit 10: -B Bit 11: -D, Input device name Bit 12: -? Bit 13: -S, override hardware read-only flag? Bit 14: -J, blank the reserved cylinder Bit 15: -V, no volume label 18 db format program name
The partitioning utility PDISKDEF writes a very similar structure (less the program name) at offset 0A0h. The example given has a third structure at 0C0h, presumably generated by another disk utility.
If the drive was formatted with the -F or -D options, there will be a device name at offset 0100h of this sector.
What I believe to be the list of bad blocks is stored at Cylinder 0, head 1, sector 0. Its format is unknown:
00000000 03 00 87 83 00 23 8A 00 4F DF 00 00 00 00 00 00 .....#..O.......
If the drive has more than two heads, then a vendor defect map is stored at Cylinder 0, head 2, sector 0:
00004000 56 45 4E 4D 41 50 00 00 00 00 00 00 00 00 00 00 VENMAP..........
The data area follows the system track. On a bootable drive it should begin with a standard Wang-format boot sector — either the volume boot sector, if the drive is not partitioned, or the master boot record if it is.
The Winchester card is based on a Z80 processor, with a 4k ROM containing firmware. Unlike the Winchester card on an IBM XT or an Apricot PC, it only supports one drive, not two; two drives would require two cards in two slots.
I/O ports are:
All commands to the Winchester (except 0FFh, which is used in the register self-test) are 8 bytes long. For each byte to send, read the main status register until bit 0 is 0; then write the value to the data register. Once the eight bytes have been sent, wait for an interrupt on the Winchester's interrupt line (5, 6 or 7). Clear the interrupt by reading port xx04, then read result bytes until bit 2 of the main status register goes to 0. There will normally be 8 result bytes.
The normal format of a command packet is:
DB command DB 0 ;Not normally used on input DW cylinder ;Cylinder to read/write, 0-based. DB head ;Head, 0-based DB sector ;Sector, 0-based DW sec_count ;Count of sectors to transfer
Note that the normal C0 and C1 commands internally add 1 to the cylinder number, so they cannot be used to access the system track.
The 8-byte result packet will then be:
DB command DB result ;80h for OK, 1-7Fh for error. Errors are: ;02h: Write protected ;03h: CRC error ;04h: Sector not found ;05h: Verify failed: data did not match ;08h: Unknown command ;09h: Drive fault DW cylinder ;The next cylinder / head / sector to transfer DB head DB sector DW sec_count ;Count of sectors actually transferred
Command bytes understood by the Winchester:
44: Internal read sector command. C0: Read sector(s). C1: Write sector(s). C2: Verify sector(s). Checks that the sectors can be loaded into controller RAM, but does not do any DMA transfer to/from main memory. C3: Format track. Only cylinder and head parameters are used. C9: Equivalent to C1 followed by C0: Write then reread, using the same sector parameters for both operations. F0: Reset the controller. F1: Reset retry count. F2: Return the retry count in the sec_count record. F3: Format the entire drive. Initialise the system track to 0 and populate sector 0. Bytes 3-6 of the command are month (byte), day (byte) and year (word). F4: Read sector(s) from the system track. As C0, except the cylinder number is ignored. * The technical guide calls this 'Read Error Data', but this does not match the behaviour of actual software. F5: Write sector(s) to the system track. As C1, except that the cylinder number is ignored. * The technical guide calls this 'Read Reserved Cylinder', but this does not match the behaviour of actual software. F6: Set drive read-only and password settings (saved in sector 0 of the system track). Byte 1 of command is 0 for none, 1 for read-only, 2 for password, 3 for both. Bytes 2-7 of command are password. * The technical guide calls this 'Write Enable'. F7: The technical guide calls this 'Write Protect'. Takes password in bytes 2-7 of command. F8: Returns two ECC counters, at offsets 4 and 6 of the results block. F9: Reset the two ECC counters. FA: Returns 700h bytes through the DMA, from 1000h-16FFh in the Z80's address space. FB: Load custom firmware. Loads 700h bytes through the DMA, and executes them in the Z80's address space at 1000h. FC: Read drive geometry. 8-byte command. Byte 1: 80h if drive does not support hardware readonly, 81h if it does. Byte 2,3: Max cylinder Byte 4: Max head Byte 5: Bit 7-5 Drive hardware type, specified in a table in the controller firmware: ID cylinders heads rwc wp 0 609 2 128 1 1 611 4 0 0 2 1023 8 1025 0 5 511 8 256 0 6 644 7 256 0 7 305 4 128 0 I have assumed that 'rwc' is a reduced-write-current cylinder. 'wp' is 1 if the drive support hardware write protect. Bit 4 status of hardware write protect. Bit 3 always 1 Bit 2 always 0 Bit 1 password protected Bit 0 software read-only Byte 6: Firmware version, minor Byte 7: Firmware version, major FD: One parameter: a byte at command+2. Possibly retry count? FE: Enter register test mode. FF: Enter register test mode. Other commands are invalid and will generate an 8-byte error packet: 00 08 00 00 00 00 00 00
Memory Expansion Card
This is based on disassembly of the MS-DOS self-test procedure, rather than the study of real hardware.
The memory card (class 3Fh) contains 1-4 banks of memory, 128k in size, which can be mapped into the processor's address space. This memory is paged in or out by a word write to port xxC0h.
Bit 15: Page in bank 4 Bits 14-12: Base address of bank 4, divided by 128k Bit 11: Page in bank 3 Bits 10-8: Base address of bank 3, divided by 128k Bit 7: Page in bank 2 Bits 6-4: Base address of bank 2, divided by 128k Bit 3: Page in bank 1 Bits 2-0: Base address of bank 1, divided by 128k
John Elliott 3 January 2012.