4 * VIA6522 module for minimigmac.
6 * The processor interface part of the VIA modified to use my
7 * home made bus interface. The rest is hugely simplified to
8 * only operate in the modes used by a Macintosh. The shift
9 * register is not implemented as such, instead, we have a
10 * direct 8 bit bus to the keyboard interface.
12 * My understanding of the original Mac design is that the VIA
13 * two phase clock is fed from the original m68k's E line, thus
14 * ticks at 1/10 of the 7.82 Mhz CPU frequency.
16 * In this variant, the register interface is clocked at the full
17 * internal system clock, and we generate artificially a 782 kHz
18 * enable signal from it to feed the timers. We don't aim for
19 * great precision here, so for now we simply divide 16.666 Mhz
20 * by 21 which gives us an approximate 793kHz.
22 * In addition, to simplify the logic, the direction of the
23 * port A and B bits is hard wired and the reset values adapted
24 * to enable the ROM overlay at startup.
28 /* Register numbers */
29 `define VIA_REG_ORB 4'h0
30 `define VIA_REG_ORA 4'h1
31 `define VIA_REG_DDRB 4'h2
32 `define VIA_REG_DDRA 4'h3
33 `define VIA_REG_T1CL 4'h4
34 `define VIA_REG_T1CH 4'h5
35 `define VIA_REG_T1LL 4'h6
36 `define VIA_REG_T1LH 4'h7
37 `define VIA_REG_T2CL 4'h8
38 `define VIA_REG_T2CH 4'h9
39 `define VIA_REG_SR 4'ha
40 `define VIA_REG_ACR 4'hb
41 `define VIA_REG_PCR 4'hc
42 `define VIA_REG_IFR 4'hd
43 `define VIA_REG_IER 4'he
44 `define VIA_REG_ORA2 4'hf
55 module via6522(input sysclk,
58 /* Bus interface. 4-bit address, to be wired
59 * appropriately upstream (to A9..A12)
68 /* Port A and B signals. Fixed direction. Port B bit
69 * 0 (RTC data) is duplicated for in/out.
73 output [2:0] pb_out2_0,
78 /* CA1 and CA2 are inputs always */
82 /* Pseudo shift-register keyboard interface */
86 output reg sr_out_strobe);
119 /* Register selects */
137 assign rs_orb = cs && rs == `VIA_REG_ORB;
138 assign rs_ora = cs && rs == `VIA_REG_ORA;
139 assign rs_ddrb = cs && rs == `VIA_REG_DDRB;
140 assign rs_ddra = cs && rs == `VIA_REG_DDRA;
141 assign rs_t1cl = cs && rs == `VIA_REG_T1CL;
142 assign rs_t1ch = cs && rs == `VIA_REG_T1CH;
143 assign rs_t1ll = cs && rs == `VIA_REG_T1LL;
144 assign rs_t1lh = cs && rs == `VIA_REG_T1LH;
145 assign rs_t2cl = cs && rs == `VIA_REG_T2CL;
146 assign rs_t2ch = cs && rs == `VIA_REG_T2CH;
147 assign rs_sr = cs && rs == `VIA_REG_SR;
148 assign rs_acr = cs && rs == `VIA_REG_ACR;
149 assign rs_pcr = cs && rs == `VIA_REG_PCR;
150 assign rs_ifr = cs && rs == `VIA_REG_IFR;
151 assign rs_ier = cs && rs == `VIA_REG_IER;
152 assign rs_ora2 = cs && rs == `VIA_REG_ORA2;
154 /* Outputs & interrupt generation */
155 assign pa_out = pa[6:0] ;
156 assign pb_out2_0 = pb[2:0];
157 assign pb_out7 = acr[7] ? t1pb7 : pb[7];
159 assign ifr7 = (ifr & ier) != 7'b0000000;
163 assign pb0_v = ddr_b0 ? pb[0] : pb_in0;
166 assign rdata = rs_ora ? { pa_in7, pa[6:0] } :
167 rs_ora2 ? { pa_in7, pa[6:0] } :
168 rs_orb ? { pb[7], pb_in6_3, pb[2:1], pb0_v } :
169 rs_ddrb ? { 1'b1, 4'b0000, 2'b11, ddr_b0 } :
170 rs_ddra ? { 1'b0, 7'b1111111 } :
174 rs_t1lh ? t1l[15:8] :
180 rs_ifr ? { ifr7, ifr } :
181 rs_ier ? { 1'b1, ier } :
185 always@(posedge sysclk or posedge reset) begin
188 else if (we && (rs_ora || rs_ora2))
193 always@(posedge sysclk or posedge reset) begin
196 else if (we && rs_orb)
200 /* Write to DDRA ignored */
202 always@(posedge sysclk or posedge reset) begin
205 else if (we && rs_orb)
210 always@(posedge sysclk or posedge reset) begin
213 else if (we && rs_acr)
218 always@(posedge sysclk or posedge reset) begin
221 else if (we && rs_pcr)
227 * Note: When writing to TnCH, we load the timer immediately
228 * and start counting on the next tstrobe (ie. P2 clock), which
229 * means that depending on when the CPU hits, the first P2 period
230 * might be reduced to one sysclk ... this could be "fixed" by causing
231 * all VIA accesses to wait for a P2 clock to complete but I'm happy
232 * to ignore the "problem" for now.
234 * Also, to keep things simple, PB7 goes up right after writing to
235 * T1CH, tho then follows proper periods (hopefully)
238 /* Clock division. We divide by 21 to get approx 793kHz */
239 always@(posedge sysclk or posedge reset) begin
249 assign tstrobe = (ckdiv == 0);
250 assign ckhalf = (ckdiv == 10);
252 /* Timer 1 latches */
253 always@(posedge sysclk or posedge reset) begin
257 if (we && (rs_t1cl || rs_t1ll))
259 if (we && (rs_t1ch || rs_t1lh))
264 /* Timer 1 counter */
265 always@(posedge sysclk or posedge reset) begin
269 /* Handle transfer from latch on write */
270 if (we && rs_t1ch) begin
273 end else if (tstrobe) begin
274 /* In "free run", reload from latch
276 * XXX There's an inconsistency in the doco
277 * as to whether we shall just roll over and
278 * count in one-shot mode or whether we shall
279 * -also- reload from the latch on T1 (it's
280 * clear for T2). For now I just let it roll
281 * over, we'll see if any SW gets upset
283 if (acr[6] && t1_fired)
291 /* "armed" latch. This is set on a write and cleared when
292 * running out in "one shot" mode
294 always@(posedge sysclk or posedge reset) begin
298 /* Always armed when in continuous mode, else
299 * arm when writing to T1CH
301 if ((we && rs_t1ch) || acr[6])
303 else if (t1_fired && !acr[6])
308 /* "fired" latch. This is set on tstrobe with counter == 0
309 * and is used to do whatever has to be done (irq, pb7, ...)
310 * on the next half phase 2 clock. It's set for the duration
311 * of the next P2 period.
313 always@(posedge sysclk or posedge reset) begin
318 t1_fired <= t1_armed && t1 == 0;
322 /* Generate PB7 output */
323 always@(posedge sysclk or posedge reset) begin
327 /* We are 0 when timer is armed and not fired yet */
330 /* We invert when fired */
331 if (ckhalf && t1_fired)
337 assign t1irq = ckhalf & t1_fired;
341 * Either one shot or count PB6 pulses (ie. hblank)
343 always@(posedge sysclk or posedge reset) begin
347 pb6_old <= pb_in6_3[6];
349 assign t2strobe = acr[5] ? (pb6_old & ~pb_in6_3[6]) : tstrobe;
351 /* Timer 2 latche (low only) */
352 always@(posedge sysclk or posedge reset) begin
361 /* Timer 2 counter */
362 always@(posedge sysclk or posedge reset) begin
366 /* Handle transfer from latch on write */
367 if (we && rs_t2ch) begin
370 end else if (t2strobe)
375 /* T2 "armed" latch (see T1) */
376 always@(posedge sysclk or posedge reset) begin
387 /* "fired" latch. This is set on tstrobe with counter == 0
388 * or in pulse counting right when hitting the 0 -> -1
389 * transitionand. It's set for the duration of the next P2 period
390 * in the former case, and for one sysclk in the later case.
392 always@(posedge sysclk or posedge reset) begin
397 t2_fired <= t2_armed && t2 == 0;
398 if (acr[5] && t2_fired)
404 assign t2irq = acr[5] ? t2_fired : (t2_fired & ckhalf);
408 * CB1 is the kbd clock, CB2 the shift register,
409 * we don't implement them that way, instead we
410 * have a direct 8-bit bus to the PS2 conversion
411 * module. The Mac only uses these ACR modes:
412 * 111 used when sending to the keyboard
413 * 110 used to assert the data line to 0 to start comm
414 * 011 used when receiving from the keyboard
415 * 000 used when transitioning
417 * We ignore the 110 mode as we don't need the
418 * keyboard to clock us. Thus we only care about
419 * mode 111 and 011. In the former, any write to
420 * sr results in an sr_out_strobe pulse to signal
421 * the keyboard. In mode 011, a pulse on sr_in_strobe
422 * results in updating the SR and eventually signaling
426 /* Write to SR (including external input) */
427 always@(posedge sysclk or posedge reset) begin
433 if (acr[4:2] == 3'b011 && sr_in_strobe)
438 /* Generate sr_out_strobe */
439 always@(posedge sysclk or posedge reset) begin
441 sr_out_strobe <= 1'b0;
443 if (we && rs_sr && acr[4:2] == 3'b111)
450 /* CA1 / CA2 edge detection */
451 always@(posedge sysclk or posedge reset) begin
466 always@(posedge sysclk or posedge reset) begin
469 else if (we && rs_ier) begin
471 ier <= ier | wdata[6:0];
473 ier <= ier & ~wdata[6:0];
478 always@(posedge sysclk or posedge reset) begin
482 /* First, write-1-to-clear */
484 ifr <= ifr & ~wdata[6:0];
486 /* Now clear individual sources based on
489 if (rs_ora && (pcr[3:1] == 3'b000 ||
496 if (rs_orb && (pcr[7:5] == 3'b000 ||
503 if ((!we) && rs_t2cl)
505 if (we && (rs_t1ch || rs_t1lh))
507 if ((!we) && rs_t1cl)
510 /* Finally set sources based on relevant
514 /* -- SR interrupt --
516 /* Note that when shifting out, we strobe and
517 * thus interrupt immediately when ACR is set
518 * to 111 (shift under external clock). That is
519 * sending commands to the keyboard.
521 * When ACR is set to 110 (sending a 0 pulse to
522 * the keyboard to wake it up), we just swallow
523 * everything here and don't generate an interrupt,
524 * the Mac ROM seems to be happy enough that way.
527 /* Shift out under control of external clock */
528 if (we && rs_sr && acr[4:2] == 3'b111)
531 /* Shift in under control of external clock */
532 if (acr[4:2] == 3'b011 && sr_in_strobe)
537 ((!pcr[2] && ca2_old && !ca2) ||
538 ( pcr[2] && !ca2_old && ca2)))
542 if ((!pcr[0] && ca1_old && !ca1) ||
543 ( pcr[0] && !ca1_old && ca1))
546 /* No CB1/CB2 on the mac ? Well they are kbd data
547 * and clock, I don't think they are ever used, but
548 * we may want to check...