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. // are in state 64.
assign bbu_dtack = drc_state[6]; 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 always @(negedge n_res) begin
// Initialize all output registers on RESET. // Initialize all output registers on RESET.
ra <= 10'bz; // Set to high-impedance to disable output. 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 // We must implement RESET for simulation or else this will never
// stabilize. // stabilize.
always @(negedge n_res) begin 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 end
// Simulate combinatorial logic sub-cycles. // Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin always @(posedge simclk) begin
if (n_res) begin
casl <= ~(~s0 & s1 & sysclk // video casl <= ~(~s0 & s1 & sysclk // video
| ~s0 & ~ramen & ~lds // processor | ~s0 & ~ramen & ~lds // processor
| ~s0 & ~casl & sysclk | ~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` | ~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 & ramen // expects `as` to rise for disable
| ~as & ~dtack & ~s1); // but avoid video cycles (WE) | ~as & ~dtack & ~s1); // but avoid video cycles (WE)
end
end end
// Simulate registered logic. // Simulate registered logic.
always @(posedge clk) begin always @(negedge clk) begin
ras <= ~(~pclk & q1 & s1 // video cycle if (n_res) begin
| ~pclk & q1 & ~ramen & dtack // processor cycle ras <= @(posedge clk)
| pclk & ~ras); // any other cycle ~(~pclk & q1 & s1 // video cycle
vclk <= ~(~q1 & pclk & q2 & vclk // divide by 8 (1MHz) | ~pclk & q1 & ~ramen & dtack // processor cycle
| ~vclk & q1 | pclk & ~ras); // any other cycle
| ~vclk & ~pclk vclk <= @(posedge clk)
| ~vclk & ~q2); ~(~q1 & pclk & q2 & vclk // divide by 8 (1MHz)
q1 <= ~(~pclk & q1 | ~vclk & q1
| pclk & ~q1); // divide `pclk` by 2 (4MHz) | ~vclk & ~pclk
q2 <= ~(~q1 & pclk & q2 // divide by 4 (2MHz) | ~vclk & ~q2);
| ~q2 & q1 q1 <= @(posedge clk)
| ~q2 & ~pclk); ~(~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 end
endmodule endmodule
@ -119,8 +127,8 @@ module lag(simclk, n_res,
// We must implement RESET for simulation or else this will never // We must implement RESET for simulation or else this will never
// stabilize. // stabilize.
always @(negedge n_res) begin always @(negedge n_res) begin
vshft <= 0; vsync <= 0; hsync <= 0; s1 <= 0; viapb6 <= 0; vshft <= 1; vsync <= 1; hsync <= 1; s1 <= 1; viapb6 <= 1;
snddma <= 0; reslin <= 0; resnyb <= 0; snddma <= 1; reslin <= 1; resnyb <= 1;
end end
// Simulate combinatorial logic sub-cycles. // Simulate combinatorial logic sub-cycles.
@ -128,38 +136,60 @@ module lag(simclk, n_res,
end end
// Simulate registered logic. // Simulate registered logic.
always @(posedge sysclk) begin always @(negedge sysclk) begin
vshft <= ~(s1 & ~vclk & snddma); // one pulse on the falling edge of `vclk` if (n_res) begin
vsync <= ~(reslin vshft <= @(posedge sysclk)
| ~vsync & ~l28); ~(s1 & ~vclk & snddma); // one pulse on the falling edge of `vclk`
hsync <= ~(viapb6 & va4 & ~va3 & ~va2 & va1 // begins in 29 (VA5) vsync <= @(posedge sysclk)
| /*~ ???*/resnyb ~(reslin
| ~hsync & viapb6); // ends in 0F | ~vsync & ~l28);
s1 <= ~(~p0q2 // 0 for processor and 1 for video // hsync <= @(posedge sysclk)
| ~vclk // ~(viapb6 & va4 & ~va3 & ~va2 & va1 // begins in 29 (VA5)
| ~vsync & hsync // | /*~ ???*/resnyb
| ~vsync & viapb6 // only in vertical retrace we have sound cycles // | ~hsync & viapb6); // ends in 0F
| ~viapb6 & hsync & ~va4 & ~va3 & ~va2 hsync <= @(posedge sysclk)
| ~viapb6 & ~hsync & (~va4 | va4 & ~va3 & ~va2 | ~(~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)); va4 & ~va3 & va2 & ~va1));
viapb6 <= ~(~hsync & resnyb // 1 indicates horizontal retrace (pseudo VA6) // viapb6 <= @(posedge sysclk)
| va1 & ~viapb6 // ~(~hsync & resnyb // 1 indicates horizontal retrace (pseudo VA6)
| va2 & ~viapb6 // | va1 & ~viapb6
| ~hsync & ~viapb6 // | va2 & ~viapb6
| resnyb & ~viapb6 // | ~hsync & ~viapb6
| vshft & ~viapb6); // | resnyb & ~viapb6
snddma <= ~(viapb6 & va4 & ~va3 & va2 & va1 & p0q2 & vclk & ~hsync // 0 in this output // | vshft & ~viapb6);
| ~snddma & vclk); // ... indicates sound cycle viapb6 <= @(posedge sysclk)
reslin <= ~(0); // ??? try to generate line 370 ~(hsync & ~va4 & ~va3 & va2 & va1 // 1 indicates horizontal retrace (pseudo VA6)
resnyb <= ~(vclk // increment VA5:VA14 in 0F and 2B | ~viapb6 & snddma
| viapb6 // ??? | ~viapb6 & vclk);
| va1 snddma <= @(posedge sysclk)
| va2 ~(viapb6 & va4 & ~va3 & va2 & va1 & p0q2 & vclk & ~hsync // 0 in this output
| ~viapb6 & va3 | ~snddma & vclk); // ... indicates sound cycle
| hsync reslin <= @(posedge sysclk) // try to generate line 370
| viapb6 & ~va3 ~(l28
| ~hsync & va3 & ~va4 | ~vsync
| ~hsync & ~va3 & va4); | 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 end
endmodule endmodule
@ -184,12 +214,13 @@ module bmu1(simclk, n_res,
// We must implement RESET for simulation or else this will never // We must implement RESET for simulation or else this will never
// stabilize. // stabilize.
always @(negedge n_res) begin always @(negedge n_res) begin
csiwm <= 0; rd <= 0; cescc <= 0; vpa <= 0; romen <= 0; csiwm <= 1; rd <= 1; cescc <= 1; vpa <= 1; romen <= 1;
ramen <= 0; io1 <= 0; l28 <= 0; ramen <= 1; io1 <= 1; l28 <= 1;
end end
// Simulate combinatorial logic sub-cycles. // Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin always @(posedge simclk) begin
if (n_res) begin
csiwm <= ~(a23 & a22 & ~a21 & ~as); // DFE1FF csiwm <= ~(a23 & a22 & ~a21 & ~as); // DFE1FF
rd <= ~(a23 & ~a22 & ~a21 & ~as); // 9FFFF8 rd <= ~(a23 & ~a22 & ~a21 & ~as); // 9FFFF8
cescc <= ~(a23 & ~a22 & ~as); // 9FFFF8(R) or BFFFF9(W) cescc <= ~(a23 & ~a22 & ~as); // 9FFFF8(R) or BFFFF9(W)
@ -205,6 +236,7 @@ module bmu1(simclk, n_res,
| ~l28 & ~va9 | ~l28 & ~va9
| ~l28 & ~va8 | ~l28 & ~va8
| ~l28 & ~va7); | ~l28 & ~va7);
end
end end
endmodule endmodule
@ -227,26 +259,32 @@ module bmu0(simclk, n_res,
// We must implement RESET for simulation or else this will never // We must implement RESET for simulation or else this will never
// stabilize. // stabilize.
always @(negedge n_res) begin 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 end
// Simulate combinatorial logic sub-cycles. // Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin always @(posedge simclk) begin
if (n_res) begin
g244 <= ~(~ramen & rw g244 <= ~(~ramen & rw
| ~g244 & ~ramen); | ~g244 & ~ramen);
we <= ~(~ramen & ~rw we <= ~(~ramen & ~rw
| ~we & ~dtack); // or `dtack` is shorter before the video cycle | ~we & ~dtack); // or `dtack` is shorter before the video cycle
end
end end
// Simulate registered logic. // Simulate registered logic.
always @(posedge sysclk) begin always @(negedge sysclk) begin
ava14 <= ~(~va14 & ~va13); // + 1 if (n_res) begin
l15 <= ~(~va14 & ~va13 & ~va12 & ~va11 & ~va10 // we haven't passed line 15 ava14 <= @(posedge sysclk) ~(~va14 & ~va13); // + 1
| va14 & ~va13 & va12 & va11 & va10); // passed by 368 l15 <= @(posedge sysclk)
vid <= ~(servid); // here we invert: blanking is in `vshft` ~(~va14 & ~va13 & ~va12 & ~va11 & ~va10 // we haven't passed line 15
ava13 <= ~(va13); // + 1 | 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 end
endmodule endmodule
@ -267,34 +305,40 @@ module tsg(simclk, n_res,
// We must implement RESET for simulation or else this will never // We must implement RESET for simulation or else this will never
// stabilize. // stabilize.
always @(negedge n_res) begin always @(negedge n_res) begin
d0 <= 0; ipl0 <= 0; d0 <= 1; ipl0 <= 1;
q6 <= 0; clkscc <= 0; q4 <= 0; q3 <= 0; viacb1 <= 0; q6 <= 1; clkscc <= 1; q4 <= 1; q3 <= 1; viacb1 <= 1;
pclk <= 0; pclk <= 1;
end end
// Simulate combinatorial logic sub-cycles. // Simulate combinatorial logic sub-cycles.
always @(posedge simclk) begin always @(posedge simclk) begin
if (n_res) begin
ipl0 <= ~intscc | intvia; // CORRECTION ipl0 <= ~intscc | intvia; // CORRECTION
// ipl0 <= ~(0); // ??? /M nanda // ipl0 <= ~(0); // ??? /M nanda
d0 <= ~(~vpa & ~a19 & e); // F00000 sample the phase with 0 /n e' + usado d0 <= ~(~vpa & ~a19 & e); // F00000 sample the phase with 0 /n e' + usado
end
end end
// Simulate registered logic. // Simulate registered logic.
always @(posedge sysclk) begin always @(negedge sysclk) begin
if (n_res) begin
// TODO VERIFY: q6 missing? // TODO VERIFY: q6 missing?
q6 <= ~(0); q6 <= @(posedge sysclk) ~(0);
clkscc <= ~(clkscc & ~pclk & ~q4 clkscc <= @(posedge sysclk)
| clkscc & ~pclk & ~q3 ~(clkscc & ~pclk & ~q4
| clkscc & ~pclk & vclk | clkscc & ~pclk & ~q3
| ~clkscc & pclk | clkscc & ~pclk & vclk
| ~clkscc & q4 & q3 & ~vclk); // skip one inversion every 32 cycles | ~clkscc & pclk
viacb1 <= ~(0); // ??? /M nanda | ~clkscc & q4 & q3 & ~vclk); // skip one inversion every 32 cycles
pclk <= ~(pclk); // divide SYSCLK by 2 (8MHz) viacb1 <= @(posedge sysclk) ~(0); // ??? /M nanda
q3 <= ~(~vclk); // `sysclk` / 16 pclk <= @(posedge sysclk) ~(pclk); // divide SYSCLK by 2 (8MHz)
q4 <= ~(q4 & q3 & ~vclk // `sysclk` / 32 q3 <= @(posedge sysclk) ~(~vclk); // `sysclk` / 16
| ~q4 & ~q3 // } J for generating CLKSCC q4 <= @(posedge sysclk)
| ~q4 & vclk); ~(q4 & q3 & ~vclk // `sysclk` / 32
| ~q4 & ~q3 // } J for generating CLKSCC
| ~q4 & vclk);
end
end end
endmodule 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 }; wire [3:0] loadvec = { d, c, b, a };
reg [3:0] outvec; 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; assign { q_d, q_c, q_b, q_a } = outvec;
// Clear is asynchronous, so it is not dependent on the clock. // 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 q_h = int_reg[7];
assign n_q_h = ~q_h; 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 // N.B. As soon as the falling edge of the clock is detected under
// the proper conditions, we propagate the shifted value to the // the proper conditions, we propagate the shifted value to the
// output pins. We do not wait until the next falling edge of 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) if (sh_n_ld)
int_reg <= { int_reg[6:0], ser }; int_reg <= { int_reg[6:0], ser };
else else
int_reg <= { h, g, f, e, d, c, b, a }; ; // Nothing to be done.
end end
endmodule endmodule
@ -210,6 +220,9 @@ module ls166(ser, a, b, c, d, clk_inh, clk, gnd,
always @(negedge n_clr) always @(negedge n_clr)
int_reg <= 0; 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 // N.B. As soon as the falling edge of the clock is detected under
// the proper conditions, we propagate the shifted value to the // the proper conditions, we propagate the shifted value to the
// output pins. We do not wait until the next falling edge of 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 { s1q_d, s1q_c, s1q_b, s1q_a } = s1reg;
assign { s2q_d, s2q_c, s2q_b, s2q_a } = s2reg; 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; s1reg <= 0;
always @(posedge s1a) always @(negedge s1a)
s1reg <= s1reg + 1; s1reg <= s1reg + 1;
always @(posedge s2clr) always @(s2clr)
s2reg <= 0; s2reg <= 0;
always @(posedge s2a) always @(negedge s2a)
s2reg <= s2reg + 1; s2reg <= s2reg + 1;
endmodule endmodule
@ -397,10 +420,10 @@ endmodule
// LS595: 8-bit serial input, parallel output shift register, with // LS595: 8-bit serial input, parallel output shift register, with
// output latch. // output latch.
module ls595(q_b, q_c, q_d, q_e, q_f, q_g, q_h, gnd, 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; output wire q_b, q_c, q_d, q_e, q_f, q_g, q_h;
`power wire gnd; `power wire gnd;
output wire n_q_h; output wire q_h_p;
input wire n_srclr, srclk, rclk, n_oe, ser; input wire n_srclr, srclk, rclk, n_oe, ser;
output wire q_a; output wire q_a;
`power wire vcc; `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 } assign { q_h, q_g, q_f, q_e, q_d, q_c, q_b, q_a }
= (n_oe) ? 8'bz : int_reg; = (n_oe) ? 8'bz : int_reg;
assign n_q_h = q_h; assign q_h_p = q_h;
always @(negedge n_srclr) begin always @(negedge n_srclr) begin
int_reg <= 0; int_reg <= 0;
end 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 // N.B. As soon as the rising edge of the clock is detected under
// the proper conditions, we propagate the shifted value to the // the proper conditions, we propagate the shifted value to the
// output pins. We do not wait until the next rising edge of the // output pins. We do not wait until the next rising edge of the
// clock. // clock.
always @(posedge srclk) begin
int_reg <= { int_reg[6:0], ser };
end
always @(posedge rclk) begin always @(posedge rclk) begin
out_reg <= int_reg; out_reg <= int_reg;
end end