432 lines
16 KiB
Verilog
432 lines
16 KiB
Verilog
/* Implementation of Macintosh 128k/512k PALs in Verilog,
|
|
mainly to assist verification of the Macintosh SE BBU. They are
|
|
not identical, of course, but this should at least be helpful is
|
|
spotting significant flaws.
|
|
|
|
Note that the signal names use here are the same as used in the
|
|
Unitron Macintosh clone's reverse engineering documentation. Many
|
|
of the signals are active low but not indicated here, for now.
|
|
|
|
Written in 2020 by Andrew Makousky
|
|
|
|
Public Domain Dedication:
|
|
|
|
To the extent possible under law, the author(s) have dedicated all
|
|
copyright and related and neighboring rights to this software to
|
|
the public domain worldwide. This software is distributed without
|
|
any warranty.
|
|
|
|
You should have received a copy of the CC0 Public Domain Dedication
|
|
along with this software. If not, see
|
|
<http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
|
|
*/
|
|
|
|
/* Note: All arguments are listed in the order of the pinout of each
|
|
PAL chip.
|
|
|
|
Another point, our cheap and easy way to hand self-referential PAL
|
|
logic equations is to simply treat them as registered sequential
|
|
logic equations and use enough simulation sub-cycles on them for
|
|
them to reach settle time. `simclk` controls these sub-cycles.
|
|
|
|
Also note, PAL registers do not have a deterministic
|
|
initialization, hence the absence of a RESET signal.
|
|
*/
|
|
|
|
`ifndef MAC128PAL_V
|
|
`define MAC128PAL_V
|
|
|
|
`include "common.vh"
|
|
|
|
// PAL0-16R4: Timing State Machine
|
|
module tsm(simclk, clk, sysclk, pclk, s1, ramen, romen, as, uds, lds, gnd,
|
|
oe1, casl, cash, ras, vclk, q2, q1, s0, dtack, vcc);
|
|
input `virtwire simclk;
|
|
input wire clk;
|
|
input wire sysclk, pclk, s1, ramen, romen, as, uds, lds;
|
|
`power wire gnd;
|
|
input wire oe1;
|
|
output `simwire casl, cash;
|
|
output reg ras, vclk, q2, q1;
|
|
output `simwire s0, dtack;
|
|
`power wire vcc;
|
|
|
|
// Simulate combinatorial logic sub-cycles.
|
|
always @(posedge simclk) begin
|
|
casl <= ~(~s0 & s1 & sysclk // video
|
|
| ~s0 & ~ramen & ~lds // processor
|
|
| ~s0 & ~casl & sysclk
|
|
| pclk & ~casl);
|
|
cash <= ~(~s0 & s1 & sysclk // video
|
|
| ~s0 & ~ramen & ~uds // processor
|
|
| ~s0 & ~cash & sysclk
|
|
| pclk & ~cash);
|
|
s0 <= ~(~ras & ~sysclk // 0 for `cas` and 1 for `ras` (estamos contando com o atraso da PAL)
|
|
| ~ras & ~s0);
|
|
dtack <= ~(~romen // se a ROM for de 250 nS ou SCC ou IWM
|
|
| ~ras & ~ramen & ~s1 // garante que vai ser reconhecido na descida de `pclk` no estado `s5`
|
|
| ~as & ~dtack & ramen // espera `as` subir para desativar
|
|
| ~as & ~dtack & ~s1); // mas evite ciclas de video (WE)
|
|
end
|
|
|
|
// Simulate registered logic.
|
|
always @(posedge clk) begin
|
|
ras <= ~(~pclk & q1 & s1 // video cycle
|
|
| ~pclk & q1 & ~ramen & dtack // processor cycle
|
|
| pclk & ~ras); // any other (?) (segura mais um ciclo) cycle
|
|
vclk <= ~(~q1 & pclk & q2 & vclk // divide by 8 (1MHz)
|
|
| ~vclk & q1
|
|
| ~vclk & ~pclk
|
|
| ~vclk & ~q2);
|
|
q1 <= ~(~pclk & q1
|
|
| pclk & ~q1); // divide `pclk` by 2 (4MHz)
|
|
q2 <= ~(~q1 & pclk & q2 // divide by 4 (2MHz)
|
|
| ~q2 & q1
|
|
| ~q2 & ~pclk);
|
|
end
|
|
endmodule
|
|
|
|
// ras of processor: a16| a8| a7| a6| a5| a4| a3| a2| a1
|
|
// cas of processor: a17|a16|a15|a14|a13|a12|a11|a10| a9
|
|
// ras of video: pup| v8| v7| v6| v5| v4| v3| v2| v1
|
|
// cas of video: pup|pup|vpg|3q1|3q4|v12|v11|v10| v9
|
|
// ras of sound: pup|3q4|v12|v11|v10|?v8|?v9| v7| v6
|
|
// cas of sound: pup|pup|pup|spg|pup|spg|spg|spg|3q1
|
|
|
|
// PAL1-16R8: Linear Address Generator
|
|
module lag(simclk, sysclk, p2io1, l28, va4, p0q2, vclk, va3, va2, va1,
|
|
gnd, oe2, vshft, vsync, hsync, s1, viapb6, snddma,
|
|
reslin, resnyb, vcc);
|
|
input `virtwire simclk;
|
|
input wire sysclk;
|
|
input wire p2io1, l28, va4, p0q2, vclk, va3, va2, va1;
|
|
`power wire gnd;
|
|
input wire oe2;
|
|
output reg vshft, vsync, hsync, s1, viapb6, snddma, reslin, resnyb;
|
|
`power wire vcc;
|
|
|
|
// Simulate combinatorial logic sub-cycles.
|
|
always @(posedge simclk) begin
|
|
end
|
|
|
|
// Simulate registered logic.
|
|
always @(posedge sysclk) begin
|
|
vshft <= ~(s1 & ~vclk & snddma); // um pulso depois da descida de `vclk`
|
|
vsync <= ~(reslin
|
|
| ~vsync & ~l28);
|
|
hsync <= ~(viapb6 & va4 & ~va3 & ~va2 & va1 // comec,a em29 (VA5)
|
|
| /*~ ???*/resnyb
|
|
| ~hsync & viapb6); // termina em 0F
|
|
s1 <= ~(~p0q2 // 0 for processor and 1 for video
|
|
| ~vclk
|
|
| ~vsync & hsync
|
|
| ~vsync & viapb6 // no vertical retrace s'o temos ciclos de som
|
|
| ~viapb6 & hsync & ~va4 & ~va3 & ~va2
|
|
| ~viapb6 & ~hsync & (~va4 | va4 & ~va3 & ~va2 |
|
|
va4 & ~va3 & va2 & ~va1));
|
|
viapb6 <= ~(~hsync & resnyb // 1 indicates horizontal retrace (pseudo VA6)
|
|
| va1 & ~viapb6
|
|
| va2 & ~viapb6
|
|
| ~hsync & ~viapb6
|
|
| resnyb & ~viapb6
|
|
| vshft & ~viapb6);
|
|
snddma <= ~(viapb6 & va4 & ~va3 & va2 & va1 & p0q2 & vclk & ~hsync // 0 nesta sa'ida
|
|
| ~snddma & vclk); // ... indicates sound cycle
|
|
reslin <= ~(0); // ??? tentamos gerar linha 370
|
|
resnyb <= ~(vclk // incrementa VA5:VA14 em 0F e 2B
|
|
| viapb6 // ???
|
|
| va1
|
|
| va2
|
|
| ~viapb6 & va3
|
|
| hsync
|
|
| viapb6 & ~va3
|
|
| ~hsync & va3 & ~va4
|
|
| ~hsync & ~va3 & va4);
|
|
end
|
|
endmodule
|
|
|
|
// 32 ciclas atiuas par linha - UA6..UA1 = 0 to 1F
|
|
// 1 ciclos de som/pwm = 2B
|
|
// 11 ciclos de retrac,o = 20 to 2A
|
|
|
|
// 342 linhas ativas - VA6..VA14 = 010011100 to 111110001
|
|
// 28 linhas de retrac,o = 010000000 to 010011011
|
|
|
|
// PAL2-16L8: Bus Management Unit 1
|
|
module bmu1(simclk, va9, va8, va7, l15, va14, ovlay, a23, a22, a21, gnd,
|
|
as, csiwm, rd, cescc, vpa, romen, ramen, io1, l28, vcc);
|
|
input `virtwire simclk;
|
|
input wire va9, va8, va7, l15, va14, ovlay, a23, a22, a21;
|
|
`power wire gnd;
|
|
input wire as;
|
|
output `simwire csiwm, rd, cescc, vpa, romen, ramen, io1, l28;
|
|
`power wire vcc;
|
|
|
|
// Simulate combinatorial logic sub-cycles.
|
|
always @(posedge simclk) begin
|
|
csiwm <= ~(a23 & a22 & ~a21 & ~as); // DFE1FF
|
|
rd <= ~(a23 & ~a22 & ~a21 & ~as); // 9FFFF8
|
|
cescc <= ~(a23 & ~a22 & ~as); // 9FFFF8(R) or BFFFF9(W)
|
|
vpa <= ~(a23 & a22 & a21 & ~as); // acima de E00000 'e s'incrano
|
|
romen <= ~(~a23 & a22 & ~a21 & ~as // 400000
|
|
| ~a23 & ~a22 & ~a21 & ~as & ovlay // (and 000000 with `ovlay`)
|
|
| a23 & ~a22 & ~as
|
|
| a23 & ~a21 & ~as); // para gerar DTACK (n~ao acessa ROM: A20)
|
|
ramen <= ~(~a23 & ~a22 & ~a21 & ~as & ~ovlay // 000000
|
|
| ~a23 & a22 & a21 & ~as & ovlay); // (600000 with `ovlay`)
|
|
io1 <= ~(0); // ???
|
|
l28 <= ~(~l15 & ~va9 & ~va8 & va7 // chegamos a 370 ou n~ao passamos da limha 28
|
|
| ~l28 & ~va9
|
|
| ~l28 & ~va8
|
|
| ~l28 & ~va7);
|
|
end
|
|
endmodule
|
|
|
|
// PAL3-16R4: Bus Management Unit 0
|
|
module bmu0(simclk, sysclk, ramen, romen, va10, va11, va12, va13, va14, rw,
|
|
gnd, oe1, g244, we, ava14, l15, vid, ava13, servid, dtack, vcc);
|
|
input `virtwire simclk;
|
|
input wire sysclk;
|
|
input wire ramen, romen, va10, va11, va12, va13, va14, rw;
|
|
`power wire gnd;
|
|
input wire oe1;
|
|
output `simwire g244, we;
|
|
output reg ava14, l15, vid, ava13;
|
|
// N.B. Although this is nominally an output we can treat it as an
|
|
// input?
|
|
input wire servid, dtack;
|
|
`power wire vcc;
|
|
|
|
// Simulate combinatorial logic sub-cycles.
|
|
always @(posedge simclk) begin
|
|
g244 <= ~(~ramen & rw
|
|
| ~g244 & ~ramen);
|
|
we <= ~(~ramen & ~rw
|
|
| ~we & ~dtack); // o dtack 'e mais curto antes de ciclo de video
|
|
end
|
|
|
|
// Simulate registered logic.
|
|
always @(posedge sysclk) begin
|
|
ava14 <= ~(~va14 & ~va13); // + 1
|
|
l15 <= ~(~va14 & ~va13 & ~va12 & ~va11 & ~va10 // n~ao passamos da linha 15
|
|
| va14 & ~va13 & va12 & va11 & va10); // passamos de 368
|
|
vid <= ~(servid); // aqui estamos invertendo: blanking est'a em `vshft`
|
|
ava13 <= ~(va13); // + 1
|
|
end
|
|
endmodule
|
|
|
|
// PAL4-16R6: Timing Signal Generator
|
|
module tsg(simclk, sysclk, vpa, a19, vclk, p0q1, e, keyclk, intscc, intvia,
|
|
gnd, oe3, d0, q6, clkscc, q4, q3, viacb1, pclk, ipl0, vcc);
|
|
input `virtwire simclk;
|
|
input wire sysclk;
|
|
input wire vpa, a19, vclk, p0q1, e, keyclk, intscc, intvia;
|
|
`power wire gnd;
|
|
input wire oe3;
|
|
output `simwire d0;
|
|
output reg q6, clkscc, q4, q3, viacb1, pclk;
|
|
output `simwire ipl0;
|
|
`power wire vcc;
|
|
|
|
// Simulate combinatorial logic sub-cycles.
|
|
always @(posedge simclk) begin
|
|
ipl0 <= ~intscc | intvia; // CORRECTION
|
|
// ipl0 <= ~(0); // ??? /M nanda
|
|
d0 <= ~(~vpa & ~a19 & e); // F00000 amostra a fase como 0 /n e' + usado
|
|
end
|
|
|
|
// Simulate registered logic.
|
|
always @(posedge sysclk) begin
|
|
// TODO VERIFY: q6 missing?
|
|
q6 <= ~(0);
|
|
clkscc <= ~(clkscc & ~pclk & ~q4
|
|
| clkscc & ~pclk & ~q3
|
|
| clkscc & ~pclk & vclk
|
|
| ~clkscc & pclk
|
|
| ~clkscc & q4 & q3 & ~vclk); // a cada 32 ciclos n~ao vira
|
|
viacb1 <= ~(0); // ??? /M nanda
|
|
pclk <= ~(pclk); // divide SYSCLK por 2 (8MHz)
|
|
q3 <= ~(~vclk); // `sysclk` / 16
|
|
q4 <= ~(q4 & q3 & ~vclk // `sysclk` / 32
|
|
| ~q4 & ~q3 // } J p/gerar CLKSCC
|
|
| ~q4 & vclk);
|
|
end
|
|
endmodule
|
|
|
|
/* TODO: Now in order to fully implement the Macintosh's custom board
|
|
capabilities, we must as a baseline have an implementation of some
|
|
standard logic chips that are found on the Macintosh Main Logic
|
|
Board. This is where we implement the modules. */
|
|
`include "stdlogic.v"
|
|
|
|
// Wire that PAL cluster together, along with supporting standard
|
|
// logic chip. Here, we try to better indicate active high and active
|
|
// low because we also need to stick in a hex inverter chip.
|
|
module palcl();
|
|
input `virtwire simclk;
|
|
`power wire vcc;
|
|
`power wire gnd;
|
|
input wire n_res;
|
|
input wire n_sysclk; // 16MHz
|
|
|
|
// Clocks
|
|
// 8,4,3.686,2,1,1,0.5 MHz
|
|
output wire pclk, p0q1, clkscc, p0q2, vclk, q3, q4;
|
|
input wire e; // 6800 synchronous I/O "E" clock, ~1MHz
|
|
input wire keyclk;
|
|
|
|
// TODO: Also implement dual video address counter ICs as part of
|
|
// the PAL cluster.
|
|
// Video address signals, comes from video counter IC
|
|
wire va14, va13, va12, va11, va10, va9, va8, va7,
|
|
va6, va5, va4, va3, va2, va1;
|
|
// Audio address signals?
|
|
output wire ava14, ava13;
|
|
|
|
// Video control signals
|
|
output wire n_vsync, n_hsync, vid;
|
|
|
|
// MC68000 CPU address signals
|
|
input wire a23, a22, a21, a20, a19, a17, a16,
|
|
a15, a14, a13, a12, a11, a10, a9,
|
|
a8, a7, a6, a5, a4, a3, a2, a1;
|
|
// not used: a18
|
|
input wire n_as, n_uds, n_lds;
|
|
output wire n_dtack;
|
|
input wire r_n_w;
|
|
inout wire d0, d1, d2, d3, d4, d5, d6, d7,
|
|
d8, d9, d10, d11, d12, d13, d14, d15;
|
|
|
|
// Chip enable signals
|
|
output wire n_ramen, n_romen, n_csiwm, n_sccrd, n_cescc, n_vpa;
|
|
|
|
// Interrupt signals
|
|
input wire n_intscc, n_intvia;
|
|
output wire n_ipl0;
|
|
|
|
// VIA signals
|
|
output wire viapb6; // horizontal blanking
|
|
input wire ovlay; // Boot-time overlay
|
|
output wire viacb1; // keyboard interrupt
|
|
// wire d0; // Video timing phase sense signal
|
|
|
|
// DRAM signals
|
|
output wire casl, cash, ras, we;
|
|
output wire ra0, ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9;
|
|
inout wire rdq0, rdq1, rdq2, rdq3, rdq4, rdq5, rdq6, rdq7,
|
|
rdq8, rdq9, rdq10, rdq11, rdq12, rdq13, rdq14, rdq15;
|
|
|
|
// Internal video signals
|
|
wire n_vshft, n_snddma, servid;
|
|
|
|
// Address multiplexer signals?
|
|
wire s0, s1, l28, l15, n_245oe;
|
|
|
|
// PAL chip-select and unknown "IO" signals
|
|
wire tsm_oe1, lag_oe2, bmu0_oe1, tsg_oe3;
|
|
|
|
// Internal PAL cluster use only, supports video
|
|
wire reslin, resnyb; // video counter controllers?
|
|
wire p2io1, q6;
|
|
|
|
// Wires to/from standard logic chips.
|
|
wire sysclk, snddma, n_a20, n_sndres, sndres, n_snd, snd, wr, n_wr;
|
|
|
|
// N.B.: *WR comes from IWM chip, WR goes to floppy drives. *A20
|
|
// goes to VIA.CS1. *SNDDMA comes from the LAG. *SYSCLK comes
|
|
// from the 16MHz crystal oscillator.
|
|
|
|
// *DMALD is generated by ASG.
|
|
|
|
wire c8mf, c16mf, n_dmald, u12f_tc, ram_r_n_w_f;
|
|
wire vmsh; // video mid-shift, connect two register chips together
|
|
wire n_lermd; // ???
|
|
wire n_ldps; // => n_vshft
|
|
wire s5;
|
|
|
|
wire vid_n_a4; // => s1
|
|
// tc => vclk
|
|
wire l13, l12; // ???
|
|
wire n_sndpg2; // ???
|
|
wire n_vidpg2; // ???
|
|
|
|
// TODO FIXME! We're not using assign correctly! `assign` implies
|
|
// diode isolation between separate nets. We want to merge
|
|
// multiple names together for the same net.
|
|
|
|
// N.B. on PCB, use c8mf for high-frequency signal
|
|
// filter/conditioning.
|
|
assign c8mf = pclk;
|
|
assign c16mf = sysclk;
|
|
assign ram_r_n_w_f = we;
|
|
|
|
/* N.B. The reason why phase calibration is required in the
|
|
Macintosh is because the PALs do not have a RESET pin. It is
|
|
the logic designer's discretion to implement one explicitly, of
|
|
they could forgo it to allow for more I/O pins. Hence the
|
|
motivation to use software phase correction instead. */
|
|
|
|
// Inverters and 16MHz clock buffer
|
|
f04 u4d(n_sysclk, sysclk, n_snddma, snddma, a20, n_a20, gnd,
|
|
n_sndres, sndres, n_snd, snd, wr, n_wr, vcc);
|
|
// Dual PWM disk drive counters
|
|
ls161 u13e(n_sndres, c8mf, rdq12, rdq13, rdq14, rdq15, n_snd, gnd,
|
|
n_dmald, u12f_tc, , , , , snd, vcc);
|
|
ls161 u12f(n_sndres, c8mf, rdq8, rdq9, rdq10, rdq11, n_snd, gnd,
|
|
n_dmald, n_sndres, , , , , u12f_tc, vcc);
|
|
// Dual video shift registers
|
|
ls166 u10f(vmsh, rdq8, rdq9, rdq10, rdq11, 1'b0, c16mf, gnd,
|
|
s5, rdq12, rdq13, rdq14, n_lermd, rdq15, n_ldps, vcc);
|
|
ls166 u11f(s5, rdq0, rdq1, rdq2, rdq3, 1'b0, c16mf, gnd,
|
|
s5, rdq4, rdq5, rdq6, vmsh, rdq7, n_ldps, vcc);
|
|
// Dual RAM data bus transceivers
|
|
ls245 u9e(ram_r_n_w_f, rdq0, rdq1, rdq2, rdq3, rdq4, rdq5, rdq6, rdq7,
|
|
gnd, d7, d6, d5, d4, d3, d2, d1, d0, n_245oe, vcc);
|
|
ls245 u10e(ram_r_n_w_f, rdq8, rdq9, rdq10, rdq11, rdq12, rdq13, rdq14,
|
|
rdq15, gnd, d15, d14, d13, d12, d11, d10, d9, d8,
|
|
n_245oe, vcc);
|
|
// RAM RA8/RA9 row/column video/CPU address multiplexer
|
|
f253 u10g(snddma, s1, va9, s5, a9, a17, ra8, gnd,
|
|
ra9, a20, a19, s5, s5, p0q2/*c2m*/, 1'b0, vcc);
|
|
// Dual video address counters
|
|
ls393 u1f(vclk, resnyb, va1, va2, va3, va4, gnd,
|
|
va8, va7, va6, va5, reslin, resnyb, vcc);
|
|
ls393 u1g(va8, reslin, va9, va10, va11, va12, gnd,
|
|
, , l13, l12, reslin, va12, vcc);
|
|
// RAM row/column video/CPU address multiplexers
|
|
f257 u2f(p0q2/*c2m*/, s5, va6, ra0, n_snd, va7, ra1, gnd,
|
|
ra3/*???*/, va9, n_sndpg2, ra2, va8, n_sndpg2, n_snddma, vcc);
|
|
f257 u2g(p0q2/*c2m*/, s5, va10, ra4, n_sndpg2, va11, ra5, gnd,
|
|
ra7, va13, s5, ra6, va12, s5, n_snddma, vcc);
|
|
f253 u3f(snddma, s1, va3, va11, a3, a11, ra2, gnd,
|
|
ra3, a12, a4, va12, va4, p0q2/*c2m*/, snddma, vcc);
|
|
f253 u3g(snddma, s1, va5, va13, a5, a13, ra4, gnd,
|
|
ra5, a14, a6, va14, va6, p0q2/*c2m*/, snddma, vcc);
|
|
f253 u4f(snddma, s1, va1, s5, a1, a9, ra0, gnd,
|
|
ra1, a10, a2, va10, va2, p0q2/*c2m*/, snddma, vcc);
|
|
f253 u4g(snddma, s1, va7, n_vidpg2, a7, a15, ra6, gnd,
|
|
ra7, a16, a8, s5, va8, p0q2/*c2m*/, snddma, vcc);
|
|
|
|
tsm pal0(simclk, sysclk, sysclk, pclk, s1, n_ramen, n_romen, n_as, n_uds, n_lds,
|
|
gnd, tsm_oe1, casl, cash, ras, vclk, p0q2, p0q1, s0, n_dtack, vcc);
|
|
lag pal1(simclk, sysclk, p2io1, l28, va4, p0q2, vclk, va3, va2, va1,
|
|
gnd, lag_oe2, n_vshft, n_vsync, n_hsync, s1, viapb6,
|
|
n_snddma, reslin,
|
|
resnyb, vcc);
|
|
bmu1 pal2(simclk, va9, va8, va7, l15, va14, ovlay, a23, a22, a21, gnd,
|
|
n_as, n_csiwm, n_sccrd, n_cescc, n_vpa, n_romen, n_ramen, p2io1, l28, vcc);
|
|
bmu0 pal3(simclk, sysclk, n_ramen, n_romen, va10, va11, va12, va13, va14,
|
|
r_n_w, gnd, bmu0_oe1, n_245oe, we, ava14, l15, vid, ava13,
|
|
servid, n_dtack, vcc);
|
|
tsg pal4(simclk, sysclk, n_vpa, a19, vclk, p0q1, e, keyclk, n_intscc,
|
|
n_intvia, gnd, tsg_oe3, d0, q6, clkscc, q4, q3, viacb1,
|
|
pclk, n_ipl0, vcc);
|
|
|
|
// TODO FIXME: ASG not implemented.
|
|
// asg u11e(c16mf, rdq0, rdq1, rdq2, rdq3, rdq4, rdq5, n_dma, vclk, gnd,
|
|
// tsen2, n_dmald, pwm, , , , , , , vcc);
|
|
endmodule
|
|
|
|
`endif // not MAC128PAL_V
|