diff --git a/hardware/fpga/bbu/bbu.v b/hardware/fpga/bbu/bbu.v index ab8098f..6ee4d6e 100644 --- a/hardware/fpga/bbu/bbu.v +++ b/hardware/fpga/bbu/bbu.v @@ -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. diff --git a/hardware/fpga/bbu/mac128pal.v b/hardware/fpga/bbu/mac128pal.v index 716bcd0..fade924 100644 --- a/hardware/fpga/bbu/mac128pal.v +++ b/hardware/fpga/bbu/mac128pal.v @@ -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 diff --git a/hardware/fpga/bbu/rom.v b/hardware/fpga/bbu/rom.v new file mode 100644 index 0000000..ac0f18e --- /dev/null +++ b/hardware/fpga/bbu/rom.v @@ -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]) diff --git a/hardware/fpga/bbu/stdlogic.v b/hardware/fpga/bbu/stdlogic.v index 293fca4..9ad3471 100644 --- a/hardware/fpga/bbu/stdlogic.v +++ b/hardware/fpga/bbu/stdlogic.v @@ -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