Revisited PAL logic equations, now looking really great!

This commit is contained in:
Andrew Makousky 2021-04-03 16:44:32 -05:00
parent f039437b21
commit 20c56b0eda
1 changed files with 80 additions and 111 deletions

View File

@ -64,13 +64,13 @@ module tsm(simclk, n_res,
// Simulate combinatorial logic.
assign casl
= ~(~s0 & s1 & sysclk // video
| ~s0 & ~ramen & ~lds // processor
| ~s0 & ~casl & sysclk
| ~s0 & ~ramen & ~lds & sysclk // processor
| ~s0 & ~casl
| pclk & ~casl);
assign cash
= ~(~s0 & s1 & sysclk // video
| ~s0 & ~ramen & ~uds // processor
| ~s0 & ~cash & sysclk
| ~s0 & ~ramen & ~uds & sysclk // processor
| ~s0 & ~cash
| pclk & ~cash);
assign s0
= ~(~ras & ~sysclk // 0 for `cas` and 1 for `ras` (counting with the delay of the PAL)
@ -139,129 +139,66 @@ module lag(simclk, n_res,
vsync <=
~(reslin
| ~vsync & ~l28);
// hsync <=
// ~(viapb6 & va4 & ~va3 & ~va2 & va1 // begins in 29 (VA5)
// | /*~ ???*/resnyb
// | ~hsync & viapb6); // ends in 0F
// hsync <=
// ~(~viapb6 & ~va4 & ~va3 & va2 & va1 // begins in 29 (VA5)
// | ~hsync & ~va4
// | ~hsync & ~viapb6); // ends in 0F
// TODO FIXME: This is incorrect, temporary equations in order
// to get at least partial behavior for analysis.
// TODO FIXME: We trigger hsync a bit too soon at the end of the
// scanline. And, we release it too soon at the beginning.
// HACKED ~vclk inserted
hsync <=
~(viapb6 & ~vclk & va1 & va2 & va3 & va4 /* FIXME & va4 & ~va3 & ~va2 & va1 */
~(~viapb6 & ~va4 & ~va3 & va2 & ~va1 // begins in 22 (VA6)
| ~hsync & ~viapb6
| ~hsync & ~va4
| ~hsync & ~va3
| ~hsync & va3
| ~hsync & va2
| ~hsync & va1);
// TODO TEST NEATER REWRITES:
// viapb6 <=
// ~(~hsync & ~va4 & ~va3 & va2 & va1
// | ~viapb6 & snddma
// | ~viapb6 & vclk);
// hsync <=
// ~(~viapb6 & ~va4 & ~va3 & va2 & ~va1
// | ~hsync & ~viapb6
// | ~hsync & ~va4);
| ~hsync & va1); // ends in 07
s1 <=
~(~p0q2 // 0 for processor and 1 for video
| ~vclk
| ~vsync & hsync
| ~vsync & viapb6 // vertical retrace only has sound cycles
// Next line HACKED, was: ~viapb6 & hsync & ~va4 & ~va3 & ~va2
| ~vsync & ~viapb6 & ~hsync & va4 & va3 & va2 & va1
| ~viapb6 & hsync & ~va4 & ~va3 & ~va2
| ~viapb6 & ~hsync & ~va4
| ~viapb6 & ~hsync & va4 & ~va3 & ~va2
| ~viapb6 & ~hsync & va4 & ~va3 & va2 & ~va1);
// viapb6 <=
// ~(~hsync & resnyb // 1 indicates horizontal retrace (pseudo VA6)
// | va1 & ~viapb6
// | va2 & ~viapb6
// | ~hsync & ~viapb6
// | resnyb & ~viapb6
// | vshft & ~viapb6);
// viapb6 <=
// ~(hsync & ~va4 & ~va3 & va2 & va1 // 1 indicates horizontal retrace (pseudo VA6)
// | ~viapb6 & snddma
// | ~viapb6 & vclk);
// TODO FIXME: This is incorrect, temporary equations in order
// to get at least partial behavior for analysis.
// TODO FIXME: Why this latches up and is broken, we should not
// use memory access to clock this to one sensitivity cycle.
// TODO FIXME: Okay, this is how to do it. The trick is within
// "self-latching" logic equations. When another clock period
// remains the same, we use self-latching logic equations, but
// they loose effect... okay, I don't know what I'm talking
// about.
viapb6 <=
~(~hsync // 1 indicates horizontal retrace (pseudo VA6)
/* | ~viapb6 & p0q2
| ~viapb6 & ~s1 */
| ~viapb6 & ~vclk
| ~viapb6 & ~va1 // TODO FIXME wrong phase
| ~viapb6 & ~va2
| ~viapb6 & ~va3
| ~viapb6 & ~va4);
~(hsync & ~va4 & ~va3 & va2 & va1 // 1 indicates horizontal retrace (pseudo VA6)
| ~viapb6 & snddma
| ~viapb6 & vclk);
snddma <=
~(~viapb6 & va4 & ~va3 & va2 & va1 & p0q2 & vclk & ~hsync // 0 in this output
| ~snddma & vclk); // ... indicates sound cycle
reslin <= // try to generate line 370
~(l28
| ~vsync
| ~hsync // HACKED previously hsync, but negated for testing.
| viapb6 // HACKED previously ~viapb6 but negated for testing.
| hsync
| ~viapb6
| ~vclk);
// N.B. Primary conceptual equation:
// resnyb <=
// ((~viapb6 & hsync & ~va4 & ~va3 & ~va2 & ~va1)
// | (~viapb6 & ~hsync & va4 & va3 & ~va2 & ~va1));
// TODO FIXME HACK: Possibly incorrect interpretation of viapb6
// with hsync.
resnyb <=
~(vclk // increment VA5:VA14 in 0F and 2B
| // viapb6 // TODO FIXME HACK PHASE
| p0q2
| va1
| va2
| hsync & va4
| hsync & va3
| ~hsync & ~va4
| ~hsync & ~va3
| ~va4 & va3
| va4 & ~va3);
// TODO TEST NEATER REWRITES:
// ??? = /SOM . /VCLK + HS . P6 . /4 . /3 . /2 . /1
// /RN = P2 . P6 . /4 . /3 . /2 . /1 + /RN . P2 + /RN . SOM . 4 + /RN . SOM . 3 + /RN . SOM . 2 + /RN . SOM . 1 + /RN . /P6 . HS + VCLK
// ??? = P6 . /VCLK . /P2 . /HS . 4 . 3 . /2 . /1 + /VCLK . /P2 . /P6 . <CHOPPED OFF?>/4 . /3 . /2 . /1
// N.B. P2 maybe shorthand for P0Q2?
// POSSIBLY SIMPLIFIED EQUATIONS?
// ??? = HS . 4 + HS . 3 + /HS . /4 + /4 . 3 + /HS . /3 + 4 . /3
// ??? = [/P6 VCLK P2 2 1] + (HS + /4 + /3)(/HS + 4 . <CHOPPED OFF>
// ??? = /VA4 * /VA3 * /HSYNC * /V <CHOPPED OFF>
// ...<CONTINUE> VA4 * VA3 * /HSYNC * V <CHOPPED OFF>
| ~viapb6 & va3
| hsync & ~viapb6
| hsync & va3
| hsync & va4
| viapb6 & ~va3 & ~hsync
| ~hsync & va3 & ~va4
| ~hsync & ~va3 & va4);
end
end
endmodule
/*
This LAG doesn't work correctly, here's how it is supposed to work.
/* Here's how the LAG works.
1. Count video addresses to 32. During this count, generate resnyb
every time we need a carry.
(reset nybble) every time we need a carry.
2. Once we reach 32, that's 512 pixels, one scanline. Now, we assert
the *HSYNC signal. But please note, at this point we do **not**
2. Once we reach 32, that's 512 pixels, one scanline. Wait 16 more
pixels to generate a blank overscan image. Now, we assert the
*HSYNC signal. But please note, at this point we do **not**
generate resnyb for the carry at 32, instead we let that counter
wrap around to zero without a carry.
3. When the *HSYNC signal is asserted, we only count to 12. That's
192 pixels for horizontal blanking. Just when we're about to reach
the end, we assert the *SNDDMA signal. That's when we fetch the
sound sample, at the very end of horizontal blanking, not the very
3. During horizontal blanking, we only count to 12. That's 192 pixels
for horizontal blanking. Just when we're about to reach the end,
we assert the *SNDDMA signal. That's when we fetch the sound
sample, at the very end of horizontal blanking, not the very
beginning.
Finally, we assert resnyb to clear the counter and finally
@ -275,12 +212,46 @@ But, to implement this... it's tricky because va5 and va6 are not
connected to any PAL. How do we generate the signals then? We can
otherwise only count to 16, we need to get to 32.
Okay, I think I've got it figured out. VIAPB6 is a little white lie,
it's not the actual horizontal blanking signal, it's a prep signal
before the horizontal blanking actually occurs. But, nevertheless, it
is almost the same thing, 16 cycles at 16MHz rather than 12 cycles.
For the 8 MHz CPU, it pretty much looks like the same thing. And
that's where we hide the additional bit of memory we need.
Okay, I've got it figured out. VIAPB6 is a little white lie, it's not
the actual horizontal blanking signal, it's a prep signal before the
horizontal blanking actually occurs. But, nevertheless, it is almost
the same thing, 19 cycles at 1MHz rather than 12 cycles. Here's how
the whole interplay works in detail.
1. Immediately after *SNDDMA is asserted, VIAPB6 is asserted.
2. Now, here's where the real trickery comes into play. Even though
horizontal blanking is supposed to end right now, we delay
de-asserting the *HSYNC signal until we reach video address 8, such
that we start shifting out visible screen pixels apparently during
the horizontal blanking period. Why? Well we need this glitched
behavior so we can count to 32 with only 4 video address bits.
Apparently this is still within the tolerance of the CRT circuitry:
the CRT actually completes horizontal blanking and starts the
regular visible area sweep before we de-assert *HSYNC, so actually
we won't be drawing these pixels during horizontal blanking.
3. Now, the ultimate conclusion of the glitched counter. When we
wrap-around to zero, both *HSYNC and VIAPB6 are still asserted. We
check for this condition to generate resnyb in the middle of a
scanline.
4. VIAPB6 is deasserted at video address 19. Therefore, it is
asserted for a total of 19 cycles at 1MHz.
Let's summarize the information pertinent to sound timing and VIAPB6.
1. *SNDDMA is asserted at the very end of horizontal blanking, just
before the beginning of the visible line.
2. Immediately after *SNDDMA is asserted, VIAPB6 is asserted (+5V).
3. VIAPB6 remains high for 19 cycles @ 1MHz.
4. VIAPB6 is deasserted.
Sound sample #0 is fetched from the Macintosh's sound buffer at the
end of the first vertical blanking line, #28 at the end of the first
visible video line, and the last sound sample #369 is fetched at the
end of the last visible video line.
*/
@ -327,15 +298,15 @@ module bmu1(simclk, n_res,
= ~(~a23 & ~a22 & ~a21 & ~as & ~ovlay // 000000
| ~a23 & a22 & a21 & ~as & ovlay); // (600000 with `ovlay`)
assign io1
= ~(~l15 & ~va9 & va8 & ~va7 // reached 368 or we don't pass line 26
| ~l28 & ~l15
= ~(~l15 & ~va9 & va8 & ~va7 // reached 368
| ~l28 & ~l15 // ... or we don't pass line 26
| ~l28 & ~va9
| ~l28 & va8
| ~l28 & ~va7
| ~n_res); // SIMULATION ONLY: Else we never settle.
assign l28
= ~(~l15 & ~va9 & ~va8 & va7 // reached 370 or we don't pass line 28
| ~l28 & ~l15
= ~(~l15 & ~va9 & ~va8 & va7 // reached 370
| ~l28 & ~l15 // ... or we don't pass line 28
| ~l28 & ~va9
| ~l28 & ~va8
| ~l28 & va7
@ -411,10 +382,11 @@ module tsg(simclk, n_res,
// Simulate combinatorial logic.
assign ipl0
= ~intscc | intvia; // CORRECTION
// assign ipl0 = ~(0); // ??? /M nanda
= ~intscc | intvia;
// N.B.: We tristate D0 so that we don't interfere with unrelated
// address bus uses.
assign d0
= ~(~vpa & ~a19 & e); // F00000 sample the phase with 0 /n e' + usado
= (~vpa & ~a19 & e) ? ~(vcc) : 'bz; // F00000 sample the phase with 0 /n e' + usado
// Simulate registered logic.
always @(posedge sysclk) begin
@ -427,7 +399,7 @@ module tsg(simclk, n_res,
| clkscc & ~pclk & vclk
| ~clkscc & pclk
| ~clkscc & q4 & q3 & ~vclk); // skip one inversion every 32 cycles
viacb1 <= ~(0); // ??? /M nanda
viacb1 <= ~(~keyclk); // buffer the keyboard clock
pclk <= ~(pclk); // divide SYSCLK by 2 (8MHz)
q3 <= ~(~vclk); // `sysclk` / 16
q4 <=
@ -734,9 +706,6 @@ module palcl(simclk, vcc, gnd, n_res, n_sysclk,
// TSEN1: 150 ohm resistor to GND for LAG.
assign lag_oe2 = gnd;
// Pull-down resistor shared by TSG, ASG, and CAS (if present).
// TODO INVESTIGATE: Surely this is controlled by another switch
// related to the RAM data bus switches, otherwise D0 is
// unconditionally coerced for non-phase read accesses.
assign tsg_oe3 = gnd;
// S5: Pull-up resistor. TODO FIXME: Should this be controlled by
// another thing too?