Fixes to mac128k PAL simulation issues, more documentation.

This commit is contained in:
Andrew Makousky 2020-11-28 16:30:45 -06:00
parent c490406c81
commit fe87fea02c
4 changed files with 163 additions and 87 deletions

View File

@ -1319,6 +1319,11 @@ module dramctl_bbu (n_res, clk, r_n_w,
// are in state 64.
assign bbu_dtack = drc_state[6];
// TODO FIXME Important! High speed control for column access
// strobes? The Macintosh 128K and Macintosh Plus use
// combinatorial logic to assert the *CAS signal for half of a C16M
// clock cycle, one pulse.
always @(negedge n_res) begin
// Initialize all output registers on RESET.
ra <= 10'bz; // Set to high-impedance to disable output.

View File

@ -56,13 +56,14 @@ module tsm(simclk, n_res,
// We must implement RESET for simulation or else this will never
// stabilize.
always @(negedge n_res) begin
casl <= 0; cash <= 0; s0 <= 0; dtack <= 0;
casl <= 1; cash <= 1; s0 <= 1; dtack <= 1;
ras <= 0; vclk <= 0; q2 <= 0; q1 <= 0;
ras <= 1; vclk <= 1; q2 <= 1; q1 <= 1;
end
// Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin
if (n_res) begin
casl <= ~(~s0 & s1 & sysclk // video
| ~s0 & ~ramen & ~lds // processor
| ~s0 & ~casl & sysclk
@ -77,22 +78,29 @@ module tsm(simclk, n_res,
| ~ras & ~ramen & ~s1 // guarantees that it will be recognized on the falling edge of `pclk` in state `s5`
| ~as & ~dtack & ramen // expects `as` to rise for disable
| ~as & ~dtack & ~s1); // but avoid video cycles (WE)
end
end
// Simulate registered logic.
always @(posedge clk) begin
ras <= ~(~pclk & q1 & s1 // video cycle
| ~pclk & q1 & ~ramen & dtack // processor cycle
| pclk & ~ras); // any other 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);
always @(negedge clk) begin
if (n_res) begin
ras <= @(posedge clk)
~(~pclk & q1 & s1 // video cycle
| ~pclk & q1 & ~ramen & dtack // processor cycle
| pclk & ~ras); // any other cycle
vclk <= @(posedge clk)
~(~q1 & pclk & q2 & vclk // divide by 8 (1MHz)
| ~vclk & q1
| ~vclk & ~pclk
| ~vclk & ~q2);
q1 <= @(posedge clk)
~(~pclk & q1
| pclk & ~q1); // divide `pclk` by 2 (4MHz)
q2 <= @(posedge clk)
~(~q1 & pclk & q2 // divide by 4 (2MHz)
| ~q2 & q1
| ~q2 & ~pclk);
end
end
endmodule
@ -119,8 +127,8 @@ module lag(simclk, n_res,
// We must implement RESET for simulation or else this will never
// stabilize.
always @(negedge n_res) begin
vshft <= 0; vsync <= 0; hsync <= 0; s1 <= 0; viapb6 <= 0;
snddma <= 0; reslin <= 0; resnyb <= 0;
vshft <= 1; vsync <= 1; hsync <= 1; s1 <= 1; viapb6 <= 1;
snddma <= 1; reslin <= 1; resnyb <= 1;
end
// Simulate combinatorial logic sub-cycles.
@ -128,38 +136,60 @@ module lag(simclk, n_res,
end
// Simulate registered logic.
always @(posedge sysclk) begin
vshft <= ~(s1 & ~vclk & snddma); // one pulse on the falling edge of `vclk`
vsync <= ~(reslin
| ~vsync & ~l28);
hsync <= ~(viapb6 & va4 & ~va3 & ~va2 & va1 // begins in 29 (VA5)
| /*~ ???*/resnyb
| ~hsync & viapb6); // ends in 0F
s1 <= ~(~p0q2 // 0 for processor and 1 for video
| ~vclk
| ~vsync & hsync
| ~vsync & viapb6 // only in vertical retrace we have sound cycles
| ~viapb6 & hsync & ~va4 & ~va3 & ~va2
| ~viapb6 & ~hsync & (~va4 | va4 & ~va3 & ~va2 |
always @(negedge sysclk) begin
if (n_res) begin
vshft <= @(posedge sysclk)
~(s1 & ~vclk & snddma); // one pulse on the falling edge of `vclk`
vsync <= @(posedge sysclk)
~(reslin
| ~vsync & ~l28);
// hsync <= @(posedge sysclk)
// ~(viapb6 & va4 & ~va3 & ~va2 & va1 // begins in 29 (VA5)
// | /*~ ???*/resnyb
// | ~hsync & viapb6); // ends in 0F
hsync <= @(posedge sysclk)
~(~viapb6 & ~va4 & ~va3 & va2 & va1 // begins in 29 (VA5)
| ~hsync & ~va4
| ~hsync & ~viapb6); // ends in 0F
s1 <= @(posedge sysclk)
~(~p0q2 // 0 for processor and 1 for video
| ~vclk
| ~vsync & hsync
| ~vsync & viapb6 // only in vertical retrace we have sound cycles
| ~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 in this output
| ~snddma & vclk); // ... indicates sound cycle
reslin <= ~(0); // ??? try to generate line 370
resnyb <= ~(vclk // increment VA5:VA14 in 0F and 2B
| viapb6 // ???
| va1
| va2
| ~viapb6 & va3
| hsync
| viapb6 & ~va3
| ~hsync & va3 & ~va4
| ~hsync & ~va3 & va4);
// viapb6 <= @(posedge sysclk)
// ~(~hsync & resnyb // 1 indicates horizontal retrace (pseudo VA6)
// | va1 & ~viapb6
// | va2 & ~viapb6
// | ~hsync & ~viapb6
// | resnyb & ~viapb6
// | vshft & ~viapb6);
viapb6 <= @(posedge sysclk)
~(hsync & ~va4 & ~va3 & va2 & va1 // 1 indicates horizontal retrace (pseudo VA6)
| ~viapb6 & snddma
| ~viapb6 & vclk);
snddma <= @(posedge sysclk)
~(viapb6 & va4 & ~va3 & va2 & va1 & p0q2 & vclk & ~hsync // 0 in this output
| ~snddma & vclk); // ... indicates sound cycle
reslin <= @(posedge sysclk) // try to generate line 370
~(l28
| ~vsync
| hsync
| ~viapb6
| ~vclk);
resnyb <= @(posedge sysclk)
~(vclk // increment VA5:VA14 in 0F and 2B
| viapb6 // ???
| va1
| va2
| ~viapb6 & va3
| hsync
| viapb6 & ~va3
| ~hsync & va3 & ~va4
| ~hsync & ~va3 & va4);
end
end
endmodule
@ -184,12 +214,13 @@ module bmu1(simclk, n_res,
// We must implement RESET for simulation or else this will never
// stabilize.
always @(negedge n_res) begin
csiwm <= 0; rd <= 0; cescc <= 0; vpa <= 0; romen <= 0;
ramen <= 0; io1 <= 0; l28 <= 0;
csiwm <= 1; rd <= 1; cescc <= 1; vpa <= 1; romen <= 1;
ramen <= 1; io1 <= 1; l28 <= 1;
end
// Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin
if (n_res) begin
csiwm <= ~(a23 & a22 & ~a21 & ~as); // DFE1FF
rd <= ~(a23 & ~a22 & ~a21 & ~as); // 9FFFF8
cescc <= ~(a23 & ~a22 & ~as); // 9FFFF8(R) or BFFFF9(W)
@ -205,6 +236,7 @@ module bmu1(simclk, n_res,
| ~l28 & ~va9
| ~l28 & ~va8
| ~l28 & ~va7);
end
end
endmodule
@ -227,26 +259,32 @@ module bmu0(simclk, n_res,
// We must implement RESET for simulation or else this will never
// stabilize.
always @(negedge n_res) begin
g244 <= 0; we <= 0;
g244 <= 1; we <= 1;
ava14 <= 0; l15 <= 0; vid <= 0; ava13 <= 0;
ava14 <= 1; l15 <= 1; vid <= 1; ava13 <= 1;
end
// Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin
if (n_res) begin
g244 <= ~(~ramen & rw
| ~g244 & ~ramen);
we <= ~(~ramen & ~rw
| ~we & ~dtack); // or `dtack` is shorter before the video cycle
end
end
// Simulate registered logic.
always @(posedge sysclk) begin
ava14 <= ~(~va14 & ~va13); // + 1
l15 <= ~(~va14 & ~va13 & ~va12 & ~va11 & ~va10 // we haven't passed line 15
| va14 & ~va13 & va12 & va11 & va10); // passed by 368
vid <= ~(servid); // here we invert: blanking is in `vshft`
ava13 <= ~(va13); // + 1
always @(negedge sysclk) begin
if (n_res) begin
ava14 <= @(posedge sysclk) ~(~va14 & ~va13); // + 1
l15 <= @(posedge sysclk)
~(~va14 & ~va13 & ~va12 & ~va11 & ~va10 // we haven't passed line 15
| va14 & ~va13 & va12 & va11 & va10); // passed by 368
vid <= @(posedge sysclk)
~(servid); // here we invert: blanking is in `vshft`
ava13 <= @(posedge sysclk) ~(va13); // + 1
end
end
endmodule
@ -267,34 +305,40 @@ module tsg(simclk, n_res,
// We must implement RESET for simulation or else this will never
// stabilize.
always @(negedge n_res) begin
d0 <= 0; ipl0 <= 0;
d0 <= 1; ipl0 <= 1;
q6 <= 0; clkscc <= 0; q4 <= 0; q3 <= 0; viacb1 <= 0;
pclk <= 0;
q6 <= 1; clkscc <= 1; q4 <= 1; q3 <= 1; viacb1 <= 1;
pclk <= 1;
end
// Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin
if (n_res) begin
ipl0 <= ~intscc | intvia; // CORRECTION
// ipl0 <= ~(0); // ??? /M nanda
d0 <= ~(~vpa & ~a19 & e); // F00000 sample the phase with 0 /n e' + usado
end
end
// Simulate registered logic.
always @(posedge sysclk) begin
always @(negedge sysclk) begin
if (n_res) begin
// TODO VERIFY: q6 missing?
q6 <= ~(0);
clkscc <= ~(clkscc & ~pclk & ~q4
| clkscc & ~pclk & ~q3
| clkscc & ~pclk & vclk
| ~clkscc & pclk
| ~clkscc & q4 & q3 & ~vclk); // skip one inversion every 32 cycles
viacb1 <= ~(0); // ??? /M nanda
pclk <= ~(pclk); // divide SYSCLK by 2 (8MHz)
q3 <= ~(~vclk); // `sysclk` / 16
q4 <= ~(q4 & q3 & ~vclk // `sysclk` / 32
| ~q4 & ~q3 // } J for generating CLKSCC
| ~q4 & vclk);
q6 <= @(posedge sysclk) ~(0);
clkscc <= @(posedge sysclk)
~(clkscc & ~pclk & ~q4
| clkscc & ~pclk & ~q3
| clkscc & ~pclk & vclk
| ~clkscc & pclk
| ~clkscc & q4 & q3 & ~vclk); // skip one inversion every 32 cycles
viacb1 <= @(posedge sysclk) ~(0); // ??? /M nanda
pclk <= @(posedge sysclk) ~(pclk); // divide SYSCLK by 2 (8MHz)
q3 <= @(posedge sysclk) ~(~vclk); // `sysclk` / 16
q4 <= @(posedge sysclk)
~(q4 & q3 & ~vclk // `sysclk` / 32
| ~q4 & ~q3 // } J for generating CLKSCC
| ~q4 & vclk);
end
end
endmodule

4
hardware/fpga/bbu/rom.v Normal file
View File

@ -0,0 +1,4 @@
// Here's how we initialize ROM in the simulation with hex bytes (yes,
// text input) from a file:
// $readmemh("hex_memory_file.mem", memory_array, [start_address], [end_address])

View File

@ -140,7 +140,7 @@ module ls161(n_clr, clk, a, b, c, d, enp, gnd,
wire [3:0] loadvec = { d, c, b, a };
reg [3:0] outvec;
assign rco = (outvec == 4'hf);
assign rco = (ent & (outvec == 4'hf));
assign { q_d, q_c, q_b, q_a } = outvec;
// Clear is asynchronous, so it is not dependent on the clock.
@ -179,6 +179,16 @@ module ls165(sh_n_ld, clk, e, f, g, h, n_q_h, gnd,
assign q_h = int_reg[7];
assign n_q_h = ~q_h;
// N.B. The '165 chips use asynchronous data loading. Don't
// confuse with '166! This is actuallly a continuous
// assignment... but the behavior is externally imperceptible until
// we change to shift mode, so we simply act on the rising edge of
// SH/*LD.
always @(posedge sh_n_ld) begin
int_reg <= { h, g, f, e, d, c, b, a };
end
// N.B. As soon as the falling edge of the clock is detected under
// the proper conditions, we propagate the shifted value to the
// output pins. We do not wait until the next falling edge of the
@ -187,7 +197,7 @@ module ls165(sh_n_ld, clk, e, f, g, h, n_q_h, gnd,
if (sh_n_ld)
int_reg <= { int_reg[6:0], ser };
else
int_reg <= { h, g, f, e, d, c, b, a };
; // Nothing to be done.
end
endmodule
@ -210,6 +220,9 @@ module ls166(ser, a, b, c, d, clk_inh, clk, gnd,
always @(negedge n_clr)
int_reg <= 0;
// N.B. The '166 chips uses synchronous data loading. Don't
// confuse with '165!
// N.B. As soon as the falling edge of the clock is detected under
// the proper conditions, we propagate the shifted value to the
// output pins. We do not wait until the next falling edge of the
@ -383,13 +396,23 @@ module ls393(s1a, s1clr, s1q_a, s1q_b, s1q_c, s1q_d, gnd,
assign { s1q_d, s1q_c, s1q_b, s1q_a } = s1reg;
assign { s2q_d, s2q_c, s2q_b, s2q_a } = s2reg;
always @(posedge s1clr)
// N.B. These counters propagate the incremented value to the
// output pins on the negative edge of the A input, unlike the '161
// counter.
// Also, for the sake of simulating the Macintosh 128K Main Logic
// Board signals correctly, we must continuously evaluate the RESET
// signals (not edge evaluate), due to the fact that we can have
// glitches on the counter input while RESET is still being
// held,and the fact that we need to assert the correct RESET value
// early on.
always @(s1clr)
s1reg <= 0;
always @(posedge s1a)
always @(negedge s1a)
s1reg <= s1reg + 1;
always @(posedge s2clr)
always @(s2clr)
s2reg <= 0;
always @(posedge s2a)
always @(negedge s2a)
s2reg <= s2reg + 1;
endmodule
@ -397,10 +420,10 @@ endmodule
// LS595: 8-bit serial input, parallel output shift register, with
// output latch.
module ls595(q_b, q_c, q_d, q_e, q_f, q_g, q_h, gnd,
n_q_h, n_srclr, srclk, rclk, n_oe, ser, vcc);
q_h_p, n_srclr, srclk, rclk, n_oe, ser, q_a, vcc);
output wire q_b, q_c, q_d, q_e, q_f, q_g, q_h;
`power wire gnd;
output wire n_q_h;
output wire q_h_p;
input wire n_srclr, srclk, rclk, n_oe, ser;
output wire q_a;
`power wire vcc;
@ -410,20 +433,20 @@ module ls595(q_b, q_c, q_d, q_e, q_f, q_g, q_h, gnd,
assign { q_h, q_g, q_f, q_e, q_d, q_c, q_b, q_a }
= (n_oe) ? 8'bz : int_reg;
assign n_q_h = q_h;
assign q_h_p = q_h;
always @(negedge n_srclr) begin
int_reg <= 0;
end
always @(posedge srclk) begin
int_reg = { int_reg[7:1], ser };
end
// N.B. As soon as the rising edge of the clock is detected under
// the proper conditions, we propagate the shifted value to the
// output pins. We do not wait until the next rising edge of the
// clock.
always @(posedge srclk) begin
int_reg <= { int_reg[6:0], ser };
end
always @(posedge rclk) begin
out_reg <= int_reg;
end