The Compact Mac is getting close to thirty years old. In these thirty years, nobody seems to have completely reverse engineered the PALs. Or rather, of course people must have, but that information is not on the net. The closest is Jecel's information, solicited by Grant and Kryten -- Kryten's website has since disappeared, but I kept a copy. I also have a copy of Jecel's pages from the Wayback machine.
Firstly, the easy ones. BMU1 and CAS are non-registered devices. They have no memory, and can be reverse-engineered quite easily.
But first, some background info. Here's the memory map of the very first (128k) Macintosh, Byte, February 1984.
And some fascinating reading, the
Macintosh Hardware Memory Map by Burrell Smith and Brian Howard, dated 13 April 1983. It notes that the addresses used by the
software and documentation is at the upper end of the memory block allocated for the device (all the address lines are not decoded,
so any device appears multiple times in the address space) to save "a small amount of power".
The 128k and 512k Macs have BMU0 and BMU1 PALs, with BMU0 being a registered PAL responsible for wait states etc. In the Mac Plus this becomes BMU1 (with the same pinout / pin assignment as the 128k Mac) and BMU2. The Mac Plus also adds a CAS PAL which controls the four SIMMs.
I removed the PALs from my Mac Plus, fitted sockets. The idea is to program new devices so the Mac still works. Let's start with the easy stuff first.
/AS | I | 11 | 10 | GND | ||
/IWM | O | 12 | 9 | I | A21 | |
/SCCRD | O | 13 | 8 | I | A22 | |
/SCCEN | O | 14 | 7 | I | A23 | |
/VPA | O | 15 | 6 | I | OVERLAY | |
/ROM | O | 16 | 5 | I | L13 | |
/RAM | O | 17 | 4 | I | /VCA | |
VC0 | O | 18 | 3 | I | VA6 | |
VC1 | O | 19 | 2 | I | VA7 | |
Vcc | 20 | 1 | I | VA8 |
OVERLAY is a signal from PA4 on the 6522. It's used to map the ROM to address zero after reset, once the code starts executing it jumps to $40 0000 (128k Mac) and then RAM is mapped into 0.
L13 comes from the video circuitry, as does VA6..VA8.
/VCA comes from BMU2 (BMU0 on the 128k Mac).
From Jecel's notes (for the 128k / 512k Mac):
/IWM := A23 * A22 * /A21 * /AS ; 0xC0 0000 - 0xDF FFFF (0xDF E1FF) /SCCRD := A23 * /A22 * /A21 * /AS ; 0x80 0000 - 0x9F FFFF (0x9F FFF8) /SCCEN := A23 * /A22 * /AS ; 0x80 0000 - 0xBF FFFF (0x9F FFF8 - RD, 0xBF FFF9 - WR) /VPA := A23 * A22 * A21 * /AS ; Synchronous I/O (6800 style) 0xE0 0000 - 0xFF FFFF /ROM := /A23 * A22 * /A21 * /AS ; 0x40 0000 - 0x5F FFFF + /A23 * /A22 * /A21 * /AS * OVERLAY ; 0x00 0000 - 0x1F FFFF when OVERLAY enabled + A23 * /A22 * /AS ; 0x80 0000 - 0xBF FFFF + A23 * /A21 * /AS ; 0x80 0000 - 0x9F FFFF and 0xC0 0000 - 0xDF FFFF /RAM := /A23 * /A22 * /A21 * /AS * /OVERLAY ; 0x00 0000 - 0x1F FFFF + /A23 * A22 * A21 * /AS * OVERLAY ; 0x60 0000 - 0x7F FFFF when OVERLAY is enabled VC0 := VC1 :=
So one Saturday morning I sat down with my Expro 80 EPROM programmer and the source code to ALL03, and modified the pic16x8y file to apply the 1024 possible combinations to the input pins of a 16L8 and to read the one byte output. Wrote some code to analyze the results, worked on it off and on.
2014-10-04: I heard there's a program that works out PAL equations for you if you feed it the data in the correct format. It's called Minilog and it's part of Publicad. So I modified my code to produce the proper output. Messed around with that for a while, and when I got to the CAS I discovered than Minilog can't handle more than 2000 input terms. So I switched to espresso for a while.
<Historical cruft removed, check the Wayback Machine if you have a morbid case of the curiosities>
2017-02-23: Heard about Logic Friday. This too is a bit clunky, but I rewrote the BMU file in the correct format
/AS,A21,A22,A23,OVERLAY,L13,/VCA,VA6,VA7,VA8,,/IWM,/SCCRD,/SCCEN,/VPA,/ROM,/RAM,VC0,VC1 0,0,0,0,0,0,0,0,0,0,,1,1,1,1,1,0,1,1 0,0,0,0,0,0,0,0,0,1,,1,1,1,1,1,0,1,0 [...]and that gives a very presentable
Minimized: /IWM = /AS + A21 + A22' + A23' ; /SCCRD = /AS + A21 + A22 + A23' ; /SCCEN = /AS + A22 + A23' ; /VPA = /AS + A21' + A22' + A23' ; /ROM = A21 A22 A23 + A21 A22 OVERLAY + A22' A23' OVERLAY' ; /RAM = A22 A23 + A22 OVERLAY' + A22' A23' OVERLAY + A21' A23' OVERLAY ; VC0 = /VCA + L13 VA6' + L13' VA7' + L13' VA8; VC1 = /VCA + L13 VA6' + L13' VA7 + L13' VA8'; Minimized Product of Sums: /IWM = (/AS+A21+A22'+A23'); /SCCRD = (/AS+A21+A22+A23'); /SCCEB = (/AS+A22+A23'); /VPA = (/AS+A21'+A22'+A23'); /ROM = (A22+A23')(A21+A22')(A22+OVERLAY')(A22'+A23+OVERLAY); /RAM = (A22+A23')(A22+OVERLAY)(A21'+A22'+A23+OVERLAY'); VC0 = (L13'+/VCA+VA6')(L13+/VCA+VA7'+VA8); VC1 = (L13'+/VCA+VA6')(L13+/VCA+VA7+VA8');
OK, moving on with the analysis. A function for an active low signal using OR means that the output is asserted when all the input terms are low. Therefore, /IWM will be asserted (low) when /AS is low AND A21 is low AND A22 is high and A23 is high. Likewise, /ROM will be asserted (low) when any of the four terms are low.
/IWM = /AS + A23' + A22' + A21 ; 110x 0xC0 0000 - 0xDF FFFF (0xDF E1FF) /SCCRD = /AS + A23' + A22 + A21 ; 100x 0x80 0000 - 0x9F FFFF (0x9F FFF8) /SCCEN = /AS + A23' + A22 ; 10xx 0x80 0000 - 0xBF FFFF (0x9F FFF8 - RD, 0xBF FFF9 - WR) /VPA = /AS + A23' + A22' + A21' ; 111x Synchronous I/O (6800 style) 0xE0 0000 - 0xFF FFFF /ROM = A23 + A22' + OVERLAY ; 01xx 0x40 0000 - 0x7F FFFF when OVERLAY = 0 AND A22 + OVERLAY' ; x0xx 0x00 0000 - 0x3F FFFF and 0x80 0000 - 0xBF FFFF when OVERLAY = 1 AND A23' + A22 ; 10xx 0x80 0000 - 0xBF FFFF AND A22' + A21 ; x10x 0x40 0000 - 0x5F FFFF and 0xC0 0000 - 0xDF FFFF /RAM = A23 + A22' + A21' + OVERLAY' ; 011x 0x60 0000 - 0x7F FFFF when OVERLAY=1 AND A22 + OVERLAY ; x0xx 0x00 0000 - 0x03 FFFF and 0x80 0000 - 0x9F FFFF when OVERLAY = 0 A23' + A22 ; 10xx 0x80 0000 - 0xBF FFFF VC0 = /VCA + L13 VA6' + L13' VA7' + L13' VA8; VC1 = /VCA + L13 VA6' + L13' VA7 + L13' VA8';
This means that /ROM and /RAM clash at 0x80 0000 to 0xBF FFFF. This is consistent with the original 512 K memory map. However, on the Plus, /ROM and /RAM are not the actual chip selects, some further logic happens in the TSM. As a matter of fact, /ROMCE comes from the CAS, which doesn't even use /ROM as an input. /ROM goes to the BMU2 and TSM. Go figure. (They probably just kept the 512 K BMU on the basis of "if it ain't broke").
TSEN2 | I | 13 | 12 | GND | ||
RAMSIZE | I | 14 | 11 | I | ROWS | |
/ROMCE | O | 15 | 10 | I | /CASH | |
OVERLAY | I | 16 | 9 | I | /CASL | |
/CAS0L | O | 17 | 8 | I | VID/u* | |
/CAS0H | O | 18 | 7 | I | C2M | |
/CAS1L | O | 19 | 6 | I | A23 | |
/CAS1H | O | 20 | 5 | I | A22 | |
/SCSI | O | 21 | 4 | I | A21 | |
/DACK | O | 22 | 3 | I | A20 | |
/AS | I | 23 | 2 | I | A19 | |
Vcc | 24 | 1 | I | A9 |
The CAS, TSC and ASG share TSEN2, which is pulled low via R36, a 150 ohm resistor. The detail is lost in the breaks between the scans of the schematic but I don't think this signal goes anywhere else. I included it in the analysis anyway.
RAMSIZE and ROWS come from two jumpers, R8 and R9. When using 4 x 256K SIMMS for 1 Mbyte these both need to be present. When fitting 4 x 1M SIMMS for 4 Mbyte RAM, you need to snip R8 or R8 and R9.
/ROMCE is the ROM /CE line (/ROM is something else). On the Plus, A17 is connected to the ROM /OE so take that into consideration when computing memory maps.
/SCSI and /DACK go to the 5380 SCSI controller.
/CASL and /CASH are from the TSM, and /CAS0L|H|1L|H are the CAS signals for the four SIMMs.
Now we're dealing with more inputs, and fewer outputs -- one of the possible outputs is used as an input. I tried to change my code in such a way that it supports both the 16L8 and 20L8 PALs, i.e. have a #define section assigning the power pin, defining the number of input and output pins and the pin mapping, etc.
This is where Minilog shat the bed:
[...] 00011111010000 | 1000000 CAN'T HANDLE MORE THAN 2000 INPUT TERMS
Espresso was more help:
# ./espresso -oeqntott CAS-inv.pla /ROMCE = (OVERLAY&!TSEN2&!A23&!A21&!A20) | (!TSEN2&!A23&A22&!A21&!A20); /CAS0L = (!TSEN2&!/CASL); /CAS0H = (!TSEN2&!/CASH); /CAS1L = (ROWS&!TSEN2&!/CASL&VID/u*) | (ROWS&!TSEN2&!/CASL&C2M) | (ROWS &!TSEN2&!/CASL&A23) | (ROWS&!TSEN2&!/CASL&A22) | (ROWS&!TSEN2&!/CASL &A21) | (!RAMSIZE&ROWS&!TSEN2&!/CASL&A20) | (!RAMSIZE&ROWS&!TSEN2 &!/CASL&A19) | (!OVERLAY&!RAMSIZE&!ROWS&!/AS&!TSEN2&!/CASH&!/CASL); /CAS1H = (!OVERLAY&!RAMSIZE&!ROWS&!/AS&!TSEN2&!/CASH) | (ROWS&!TSEN2 &!/CASH&/CASL) | (ROWS&!TSEN2&!/CASH&VID/u*) | (ROWS&!TSEN2&!/CASH &C2M) | (ROWS&!TSEN2&!/CASH&A23) | (ROWS&!TSEN2&!/CASH&A22) | (ROWS &!TSEN2&!/CASH&A21) | (!RAMSIZE&ROWS&!TSEN2&!/CASH&A20) | (!RAMSIZE &ROWS&!TSEN2&!/CASH&A19); /SCSI = (!/AS&!TSEN2&!A23&A22&!A21&A20&A19&!A9); /DACK = (!/AS&!TSEN2&!A23&A22&!A21&A20&A19&A9);Note that TSEN features everywhere, even though it's pulled low in the schematic. I'm guessing this is some sort of test mode that the Apple engineers built in to be able to disable the PALs in-circuit. From here on I pulled it low and removed it from the dump.
Logic Friday still gives the best results.
Minimized: /ROMCE = A23 + A21 + A20 + OVERLAY' A22' ; /CAS0L = /CASL ; /CAS0H = /CASH ; /CAS1L = /CASL + OVERLAY ROWS' + RAMSIZE ROWS' + ROWS' /AS + ROWS' /CASH + RAMSIZE VID/u' C2M' A23' A22' A21' + ROWS VID/u' C2M' A23' A22' A21' A20' A19' ; /CAS1H = /CASH + OVERLAY ROWS' + RAMSIZE ROWS' + ROWS' /AS + RAMSIZE /CASL' VID/u' C2M' A23' A22' A21' + ROWS /CASL' VID/u' C2M' A23' A22' A21' A20' A19' ; /SCSI = /AS + A23 + A22' + A21 + A20' + A19' + A9; /DACK = /AS + A23 + A22' + A21 + A20' + A19' + A9'; Minimized Product of Sums: /ROMCE = (A23+A22'+A21+A20)(OVERLAY'+A23+A21+A20); /CAS0L = (/CASL); /CAS0H = (/CASH); /CAS1L = (ROWS'+/CASL+A22')(ROWS'+/CASL+VID/u')(ROWS'+/CASL+C2M')(ROWS'+/CASL+A23')(ROWS'+/CASL+A21')(RAMSIZE+ROWS'+/CASL+A20')(RAMSIZE+ROWS'+/CASL+A19')(OVERLAY+RAMSIZE+ROWS+/AS+/CASH+/CASL); /CAS1H = (ROWS'+/CASH+A22')(ROWS'+/CASH+/CASL')(ROWS'+/CASH+VID/u')(ROWS'+/CASH+C2M')(ROWS'+/CASH+A23')(ROWS'+/CASH+A21')(RAMSIZE+ROWS'+/CASH+A20')(RAMSIZE+ROWS'+/CASH+A19')(OVERLAY+RAMSIZE+/AS+/CASH+/CASL')(OVERLAY+RAMSIZE+ROWS+/AS+/CASH+/CASL); /SCSI = (/AS+A23+A22'+A21+A20'+A19'+A9); /DACK = (/AS+A23+A22'+A21+A20'+A19'+A9');
Analysis
/ROMCE = A23 + A22' + A21 + A20 ; 0100 0x40 0000 - 0x4F FFFF A23 + A21 + A20 + OVERLAY' ; 0x00 0x0000 - 0x0F FFFF and 0x40 0000 - 0x4F FFFF with OVERLAY = 1 With ROWS = 0 and RAMSIZE = 0 /CAS1L = /CASL + OVERLAY + /AS + /CASH /CAS1H = /CASH + OVERLAY' + /AS With ROWS = 0 and RAMSIZE = 1 /CAS1L = 1 /CAS1H = 1 With ROWS = 1 and RAMSIZE = 0 /CAS1L = /CASL + OVERLAY + VID/u' C2M' A23' A22' A21' A20' A19' ; /CAS1H = /CASH + /CASL' VID/u' C2M' A23' A22' A21' A20' A19' ; With ROWS = 1 and RAMSIZE = 1 /CAS1L = /CASL + OVERLAY + VID/u' C2M' A23' A22' A21' + VID/u' C2M' A23' A22' A21' A20' A19' ; /CAS1H = /CASH + /CASL' VID/u' C2M' A23' A22' A21' + /CASL' VID/u' C2M' A23' A22' A21' A20' A19' ;
If all SIMMS are 256kbit, R8 "256K BIT" should be installed, which pulls RAMSIZE = 0. With 1Mbit SIMMS R8 is removed and RAMSIZE = 1.
I still have a lot to learn here.
/TSEN0 | /OE | 13 | 12 | GND | ||
/TSEN0 | I | 14 | 11 | I | /DMA | |
RA8 | O | 15 | 10 | I | C2M | |
/245OE | O | 16 | 9 | I | R/W | |
VA13 | R | 17 | 8 | I | L13 | |
VA12 | R | 18 | 7 | I | L12 | |
/VCA | R | 19 | 6 | I | VA11 | |
/VIDOUT | R | 20 | 5 | I | VA10 | |
RAM R/W | O | 21 | 4 | I | VA9 | |
SERVID | I | 22 | 3 | I | /ROM | |
/DTACK | I | 23 | 2 | I | /RAM | |
Vcc | 24 | 1 | CLK | C16M |
SERVID from the dual LS166 video shifters and VIDOUT to the monitor.
The LAG can probably be described as the heart of the Macintosh.
LAG is a 16R8 device which performs the majority of the video control functions. It has as inputs most of the video address counter outputs, which are decoded to create output signals which load the video shift register, provide the CRT sweep circuitry with horizontal and vertical syncs, increment and reset the video address counters, and switch the RAM address multilplexers between CPU, video, and sound addresses. Source
/TSEN | /OE | 11 | 10 | GND | ||
/LDPS | R | 12 | 9 | I | VA0 | |
/NSYNC | R | 13 | 8 | I | VA1 | |
/HSYNC | R | 14 | 7 | I | VA2 | |
VID/u* | R | 15 | 6 | I | TC | |
H4 | R | 16 | 5 | I | C1M | |
/DMA | R | 17 | 4 | I | VA3 | |
RESLYN | R | 18 | 3 | I | VC1 | |
RESNYB | R | 19 | 2 | I | VC0 | |
Vcc | 20 | 1 | CLK | C16M |
A 16R8 has eight (+ a clock) inputs and eight outputs.
Clock: C16M
Inputs: VC0, VC1, VA0, VA1, VA2, VA3, TC, C1M
Outputs: /LDPS, /VSYNC, /HSYNC, VID/u*, H4, /DMA, RESLYN, RESNYB
TSM is a 16R4 device whose major function is control of the dynamic RAM. For inputs, it has the decoded RAM enable signal, along with the address and data strobes from the processor which signify whether the data transfer will be low byte, hi byte, or word. From these the RAS and CAS strobes are generated, and the row/column address multiplexer is controlled. Until there were PALs, this type of dynamic RAM control function required either about 10-20 discrete TTL packages, or a 40 pin LSI dynamic RAM controller which usually didn't do what you wanted anyway. Source
/TSEN0 | /CS | 11 | 10 | GND | ||
/CASL | O | 12 | 9 | I | /LDS | |
/CASR | O | 13 | 8 | I | /UDS | |
/RAS | R | 14 | 7 | I | /AS | |
TC | R | 15 | 6 | I | /ROM | |
C1M | R | 16 | 5 | I | /RAM | |
C4M | R | 17 | 4 | I | VID/u* | |
C2M | O | 18 | 3 | I | C8M | |
/DTACK | O | 19 | 2 | I | C16M | |
Vcc | 20 | 1 | CLK | C16M |
From Kryten's (now gone) page:
Apple Mac Timing State Machine, PAL16R8
NB: Not verified yet!
PAL16R8 PAL DESIGN SPECIFICATIONS 16MBUF C16M 8M MU RAMEN ROMEN AS UDS LDS GND TSEN CAS0 CAS1 RAS TC 1M 4M 2M DTACK VCCRAS is the DRAM Row Address Strobe.
RAS: = /4M * /RAS + 8M * 4M * /RAS + + /8M * 4M * /2M * /RAS + 8M * /4M * 1M * RAS + 8M * /4M * /1M * 2M * RAS + /8M * 4M * /1M * RAS * LDS + /8M * 4M * /1M * RAS * UDS + /8M * 4M * /1M * RAS * /LDS * /UDS * /CAS0 +TC goes to the LAG and to the video counter (U1F)
TC:= 8M + /4M + 2M + /1M + RAS
1M: = /8M * 4M * /2M * 1M * /RAS + /1M * 8M * /4M * /RAS + /1M * /8M * 4M * 2M * /RAS + /1M * RAS + /1M * /8M * /4M * /RAS + /1M * 8M * 4M * /RAS
4M: = 1M * RAS + 8M * 4M * 2M * /1M * RAS + /8M * /4M * /1M * RAS + 8M * /4M * 2M * /1M * RAS + /8M * 4M * /2M * /RAS + there may be a line missing here.....
2M: = /C16M * /8M * /4M * /RAS + /2M + /8M + /4M + /2M + /1M + * /TC + C16M * /2M + /C16M * /8M * /4M * /1M * RAS * /ROMEN * /RAMEN * /AS + /2M * 4M + /2M * 8M * /4M *1M * MU
DTACK := /C16M * /8M * /4M * /RAS * /AS * /ROMEN * RAMEN + /C16M * /8M * /4M * /1M * /RAS * /AS * /RAMEN * ROMEN + /C16M * /8M * /4M * 1M * /RAS * /AS * /RAMEN * ROMEN * /MU + /C16M * /8M * 4M * /1M * RAS * /AS * /RAMEN * /ROMEN + /DTACK * /UDS + /DATACK * /LDS + /DATACK * /RASThis is probably not right for the Mac Plus...
CAS0: = 4M * /2M * /RAS * /DTACK * /RAMEN * ROMEN * /LDS * MU + 4M * /2M * 1M * /RAS * MU + /CAS0 + /RAS + 8M + 4M + /2M * /1M * RAS * /DTACK + /CAS0 * /2M + /1M
CAS1: = 4M * /2M * /RAS * /DTACK * /RAMEN * ROMEN * /UDS * MU + 4M * /2M * 1M * /RAS * MU + /CAS1 + /RAS
This one is my favorite. The TSG is a 16R6 device which illustrates the power of programmable logic. It serves a couple of mundane functions concerning interrupts and the keyboard clock, but by far it's most interesting job is as a clock generator for the SCC serial chip.The master oscillator frequency in the Macintosh is 15.667 MHz. This is divided by 2 in the TSG to get the 7.834 MHz processor clock. In order for the SCC to be able to operate at a baud rate of 230.4 KBaud, which is what AppleTalk requires, it needs an input clock frequency of 3.686 MHz.
If you pull down your calculator desk accessory, you'll find that 15.667 ÷ 3.686 = 4.25. This means that the TSG needs to divide the 15.667 MHz master oscillator by 4.25 in order to get a 3.686 MHz clock. How is this done, since 4.25 is not even an integer, let alone a binary number?
Let's call the 15.667 MHz clock the MO_clk and the 3.686 MHz clock the SCC_clk. For every 17 MO_clk periods there are 4 SCC_clk periods (17 ÷ 4 = 4.25). The way the TSG generates the SCC_clk is count to 4 three times and then count to 5 once (4 + 4 + 4 + 5 = 17). See Figure 11 for a graphical description. Try that using a single TTL counter chip! Source
/TSEN2 | /OE | 11 | 10 | GND | ||
D0 | O | 12 | 9 | I | /VIAIRQ | |
N/C | R | 13 | 8 | I | /IPL1 | |
C3.7MF | R | 14 | 7 | I | KBD.ACLK | |
N/C | R | 15 | 6 | I | Eu | |
N/C | R | 16 | 5 | I | 4M | |
KBD.SCLK | R | 17 | 4 | I | TC | |
C8M | R | 18 | 3 | I | A19 | |
IPL0 | O | 19 | 2 | I | /VPA | |
Vcc | 20 | 1 | CLK | C16M |
C8M :=
Sound generator
As usual, Burrell's new design was very clever. The Macintosh was already continuously fetching data from memory to drive the video display, interleaving memory bandwidth between the display and processor in a similar fashion to the Apple II. But every 44 microseconds, there was a "horizontal blanking interval" where no video data was needed, so Burrell used that time to fetch data for the sound. That gave us a sample rate of 22kHz, which would allow us to do frequencies up to 11kHz, which isn't too bad. -- Source
/TSEN2 | /OE | 11 | 10 | GND | ||
/DMALD | R | 12 | 9 | I | TC | |
PWM | R | 13 | 8 | I | /DMA | |
N/C | R | 14 | 7 | I | RDQ5 | |
N/C | R | 15 | 6 | I | RDQ4 | |
N/C | R | 16 | 5 | I | RDQ3 | |
N/C | R | 17 | 4 | I | RDQ2 | |
N/C | R | 18 | 3 | I | RDQ1 | |
N/C | R | 19 | 2 | I | RDQ0 | |
Vcc | 20 | 1 | CLK | C16MF |
|
Back to Wouter's Macintosh Page | (This page last modified 2021-10-27) |