Apple Mac Classic

Background

The Apple Mac is an icon of the computer age. In the DOS ages, it pointed the way to how much better things could be. It was monochrome and modest, but it was to the 68000 what the ZX80/81 was to the Z80.

CPU An 8-MHz 68000
RAM 128Kbytes
ROM 64Kbytes
MPX Multiplexers
PALs Programmable Array Logic
IWM Integrated Woz machine

This page documents my peek into the dark logic of the PAL chips.

 


Translation from part of a report to Unitron about the Turbo Mac project. Translated by the author, Jecel Assumpcao Jr.

page 1 missing

page 2

... frequency, but with different phases and duty cycles. The most intuitive way of understanding these sets it to consider them as indicating the current state for a finite state machine.

[drawing with VIAPB6 and HSYNC waveforms]

Basic Cycle:

We will call the interval between two successive loads of the video register "the basic cycle". It was exactly this cycle that was changed, such that all other changes were merely consequences of this. In the original design this cycle was divided into two memory cycles: one for the processor and the other for video. The change was the division of the basic cycle into three cycles for the processor and one for video. The timing of the basic cycle is the same: 16 cycles of the system clock (SYSCLK) which is equivalent to 1021 nS. During the horizontal retrace the video cycles would not be used and so are given back to the processor (except for the last, which is used to generate sound and to control the floppy drive speed). During the vertical retrace all cycles belong to the processor, except for the sound ones.

[drawing with SYSCLK, PCLK, original cycle and turbo cycle waveforms]

We can see that the memory cycle now takes up only half the time that it did before. The only was possible due to the evolution of the technology for dynamic memory chips: the 4164-15 originally used needed a cycles of at least 300 nS, while the 41256-12 has a cycle of 230 nS. The increase in performance of the Turbo relative to the original design comes from the possibility of having the memory sending more information to the processor in the same time period. At first glance it might seem that we can extract three times as much from memory, but looking at the duration of a processor cycle we see that it can't use too successive memory cycles. This and the fact that during the retraces and access to ROM the processor is the limiting factor reduces the gain in performance to about 20 to 30%. Let us look at the waveforms generated by the first PAL, which we will call here "Timing State Machine" or PAL0. It is the VCLK that defines the basic cycles, but let's examine each part:

[drawing with SYSCLK, PCLK, Q1, Q2, VCLK, S1 and VSHFT waveforms]

SYSCLK is generate directly from the 15.6672MHz oscillator and all other clocks are derived from it. But PCLK is generated in PAL4 and is used directly by the processor. Q1 has a cycle of 255 nS, since it is PCLK divided by 2. This signal defines the memory cycles in the Turbo Mac. Next we find Q2 and VCLK, which together with Q1 and PCLK form a sort of counter. It is obvious that these signals are not all in the same phase. VCLK and Q2 are three clocks early relative to the memory signals. The reason for this will become clear when VSHFT is explained. These two signals divide the basic cycle into four memory cycles. The memory cycle where Q2 is high and VCLK is high is reserved for video. The negative edge of VCLK, which happens halfway through this cycle, increments the video counters. When we look at CASH and CASL next, it might seem that the falling edge of VCLK would change the video address before the hold time (though only in the worst case considering component tolerances) but this doesn't happen because the column address for video comes from the most significant bits of the counter which are incremented by RESNYB.

------ all following pages are missing


Examining the PAL chips

  I've just finished a first draft of re-drawing the Mac circuit in Orcad.   It is just to get an idea of how it works.   The ROM/RAM/CPU sections are not hard to fathom.   There are a load of multiplexers for CPU/VDU/audio access, not so simple but you can see what it is up to.   Most complexity lies in the PALs/IWM, but you can tell which PAL pins are definitely not outputs (those on the left of the chips.

I've managed to get an idea of what things are going on.   Perhaps I could make a web page of my own scribblings?   I don't know if I can be bothered to recreate the Mac, because the Atari ST is better (colour output, TV display, games). But maybe someone else is and would find my notes helpful

 


Excerts for the PAL Handbook by MMI

These should give you an idea of how to use PALs with the 68000. You will have to modify them for the Apple Mac

Interrupt Controller for 68000

Page 222 Introduction
Page 223
Page 224
Page 225
Page 226
Page 227 PAL1 (20L10) logic equations, (OCR text)
Page 228 PAL1 (20L10) fuse map,
Page 229 PAL2 (16R4) logic equations, (OCR text)
Page 230 PAL2 (16R4) fuse map

Interface Controller for 68000 to Zilog 8500 peripherals

Page 274 PAL (20X10) logic equations, (OCR)
Page 275 Function table,
Page 276 Description

Page 277 Fuse map
Page 278 Circuit


PAL equations gleaned from web ("Kartman")

Apple Mac Timing State Machine, PAL16R8


Initial PAL equations {with guessed English comment translations}

By Jecel Assumpcao Jr. for the now defunct Unitron of Brazil.

Unitron logic equations (1)
Unitron logic equations (2)

; 32 ciclos ativas par linha - VA6..VA1 = 0 a 1F  {32 active cycles per line}
; 1  ciclos de som/pwm                  = 2B      { 1 cycle  per ???/PWM}
; 11 ciclos de retraco                  = 20 a 2A {11 cycles retracing}
; 324 linhas ativas      - va6..va14 = 010011100 a 111110001  {324 active lines}
;  28 linhas de retraco              = 010000000 a 010011011   {28 cycles retracing}
PAL2-16L8 Bus management Unit 1
VA9 VA8 VA7 L15 VA15 OVLAY A23 A22 A21 GND
AS CSIWM RD CESCC VPA ROMEN RAMEN IO1 L28 VCC
/CSIWM = A23 *  A22 * /A21 * /AS ; DFE1FF
/RD    = A23 * /A22 * /A21 * /AS ; 9FFFF8
/CESCC = A23 * /A22        * /AS ; 9FFFF8(R) or 9FFFF9(W)
... not done yet...

quick draft VHDL translations

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

--  Uncomment the following lines to use the declarations that are
--  provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;

entity AppleMac is
    Port (
			clk	: in std_logic;
			-- address and data buses
			A : in std_logic_vector(23 downto 1);
			D : inout std_logic_vector(15 downto 0);
			-- asynchronous control
			n_AS,			-- address strobe
			n_UDS,			-- upper data strobe
			n_LDS 			-- lower data strobe
					: in std_logic;
			n_DTACK : out std_logic;

			-- processor status
			FC : in std_logic_vector(2 downto 0);
			-- interrupt control
			n_IPL			-- interrupt priority level
			: out std_logic_vector(2 downto 0);
			n_INTACK : out std_logic_vector(7 downto 1);
			RNW : in std_logic;
			-- arbitration control
			n_BR : out std_logic;		-- bus request
			n_BG : in std_logic;		-- bus grant
			n_BGACK : out std_logic;	-- bus grant acknowledge
			-- 6800 peripheral control
			E : in std_logic;
			n_VMA : in std_logic;		-- valid memory address
			n_VPA : in std_logic;		-- valid peripheral address
			-- system control
			n_BERR : in std_logic;		--  bus error
			n_RESET : in std_logic;		-- reset
			n_HALT : inout std_logic;	-- halt
			-- non-CPU signals
			-- 
			OSC_in  : in  std_logic;
			OSC_out : out std_logic;
			CLK_CNT : out std_logic_vector(3 downto 0);
			n_IRQ : in std_logic_vector(7 downto 1)
			);
end AppleMac;
architecture Behavioral of AppleMac is
	----------------------------------------
	signal
		-- internal regs:
		-- write:
		s_clk_cnt		-- clock counter
		: std_logic_vector(3 downto 0);
	----------------------------------------
begin
	----------------------------------------
	-- inverter for simple crystal oscillator
	process (  OSC_in
	) is
	begin
		OSC_out <= not OSC_in;
	end process;
 	----------------------------------------
	-- clocked counter
	-- clk is about 16 MHz, so 
	-- CLK_CNT(0) = 8 MHz,
	-- CLK_CNT(1) = 4 MHz,
	-- CLK_CNT(2) = 2 MHz,
	-- CLK_CNT(3) = 1 MHz.
	-- Zilog 8500 peripherals typically run at 	PLCK = 4 MHz
	-- 
	process (  clk, s_clk_cnt
	) is
	begin
		if rising_edge(clk)
		and n_RESET = '1'
		then
			s_clk_cnt <= s_clk_cnt-1;	-- decrementing
		end if;
	end process;
	----------------------------------------
	CLK_CNT <= s_clk_cnt;
	----------------------------------------
	-- INTACK generation and vector output
	-- Interrupt vector is 8 bits but
	-- this logic just encodes 3 of them.
	-- A(8 downto 4) can be pulled up with resistors.
	process (  n_AS, A, D, FC
	) is
	begin
		if	n_AS = '0'
		and	FC = "111" 
		then	D(2 downto 0) <= A(3 downto 1);
			case A(3 downto 1) is
			when "000" => n_INTACK <= "1111111";
			when "001" => n_INTACK <= "1111110";
			when "010" => n_INTACK <= "1111101";
			when "011" => n_INTACK <= "1111011";
			when "100" => n_INTACK <= "1110111";
			when "101" => n_INTACK <= "1101111";
			when "110" => n_INTACK <= "1011111";
			when "111" => n_INTACK <= "0111111";
			when others =>	
				null;
			end case;
		else
			D(2 downto 0)	<= "ZZZ";	-- tristate
			n_INTACK	<= "ZZZZZZZ";	-- tristate?
		end if;
	end process;
	----------------------------------------
	--
	-- interrupt priority level encoding
	process (  clk, n_AS, FC, n_IRQ
	) is
	begin
		if rising_edge(clk)
		then 
			case n_IRQ is
			when "1111111" => n_IPL <= "111";
			when "1111110" => n_IPL <= "110";
			when "111110-" => n_IPL <= "101";
			when "11110--" => n_IPL <= "100";
			when "1110---" => n_IPL <= "011";
			when "110----" => n_IPL <= "010";
			when "10-----" => n_IPL <= "001";
			when "0------" => n_IPL <= "000";
			when others    => null;
			end case;
		end if;
	end process;
	----------------------------------------
	-- n_DATACK generation
	process (  clk, n_AS, FC, n_IRQ
	) is
	begin
		if	n_AS = '0'
		and	FC = "111" 
		then
			case n_IRQ is
			when "0------"	=>	n_DTACK	 	 <= 'L';
			when others	=>	n_DTACK	 	 <= 'Z';
			end case;
		else
			n_DTACK	 	 <= 'Z';
		end if;
	end process;
	----------------------------------------
	----------------------------------------
	----------------------------------------
	----------------------------------------

end Behavioral;