]> git.ozlabs.org Git - minimigmac.git/blob - fpga/via6522.v
Initial commit
[minimigmac.git] / fpga / via6522.v
1 `timescale 1ns / 100ps
2
3 /*
4  * VIA6522 module for minimigmac.
5  * 
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.
11  *
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.
15  * 
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.
21  * 
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.
25  * 
26  */
27
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
45
46 /* Interrupt bits */
47 `define CA2_IRQ         0
48 `define CA1_IRQ         1
49 `define SR_IRQ          2
50 `define CB2_IRQ         3
51 `define CB1_IRQ         4
52 `define T2_IRQ          5
53 `define T1_IRQ          6
54   
55 module via6522(input            sysclk,
56                input            reset,
57
58                /* Bus interface. 4-bit address, to be wired
59                 * appropriately upstream (to A9..A12)
60                 */
61                input            cs,
62                input            we,
63                input [3:0]      rs,
64                input [7:0]      wdata,
65                output [7:0]     rdata,
66                output           _irq,
67
68                /* Port A and B signals. Fixed direction. Port B bit
69                 * 0 (RTC data) is duplicated for in/out.
70                 */
71                input [7:7]      pa_in7,
72                output [6:0]     pa_out,
73                output [2:0]     pb_out2_0,
74                output           pb_out7,
75                input [6:3]      pb_in6_3,
76                input            pb_in0,
77                
78                /* CA1 and CA2 are inputs always */
79                input            ca1,
80                input            ca2,
81                
82                /* Pseudo shift-register keyboard interface */
83                input [7:0]      sr_in,
84                input            sr_in_strobe,
85                output [7:0]     sr_out,
86                output reg       sr_out_strobe);
87
88
89         /* Registers */
90         reg [7:0]  pa;
91         reg [7:0]  pb;
92         reg [7:0]  sr;
93         reg [7:0]  acr;
94         reg [6:0]  ier;
95         reg [6:0]  ifr;
96         reg [7:0]  pcr;
97         reg [15:0] t1;
98         reg [15:0] t1l;
99         reg [15:0] t2;
100         reg [7:0]  t2l;
101         reg        ddr_b0;
102         wire       pb0_v;
103         wire       ifr7;
104         reg        ca1_old;
105         reg        ca2_old;
106         reg        pb6_old;
107         reg        t1_armed;
108         reg        t2_armed;    
109         reg        t1_fired;
110         reg        t2_fired;    
111         reg [4:0]  ckdiv;
112         wire       ckhalf;
113         reg        t1pb7;       
114         wire       tstrobe;
115         wire       t2strobe;
116         wire       t1irq;
117         wire       t2irq;          
118
119         /* Register selects */
120         wire       rs_orb;
121         wire       rs_ora;
122         wire       rs_ddrb;
123         wire       rs_ddra;
124         wire       rs_t1cl;
125         wire       rs_t1ch;
126         wire       rs_t1ll;
127         wire       rs_t1lh;
128         wire       rs_t2cl;
129         wire       rs_t2ch;
130         wire       rs_sr;
131         wire       rs_acr;
132         wire       rs_pcr;
133         wire       rs_ifr;
134         wire       rs_ier;
135         wire       rs_ora2;
136
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;
153
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];
158         assign sr_out = sr;
159         assign ifr7 = (ifr & ier) != 7'b0000000;
160         assign _irq = ~ifr7;
161
162         /* PB[0] value */
163         assign pb0_v = ddr_b0 ? pb[0] : pb_in0;
164         
165         /* Register reads */
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 }                   :
171                        rs_t1cl ? t1[7:0]                                :
172                        rs_t1ch ? t1[15:8]                               :
173                        rs_t1ll ? t1l[7:0]                               :
174                        rs_t1lh ? t1l[15:8]                              :
175                        rs_t2cl ? t2[7:0]                                :
176                        rs_t2ch ? t2[15:8]                               :
177                        rs_sr   ? sr                                     :
178                        rs_acr  ? acr                                    :
179                        rs_pcr  ? pcr                                    :
180                        rs_ifr  ? { ifr7, ifr }                          :
181                        rs_ier  ? { 1'b1, ier }                          :
182                        8'b11111111;     
183         
184         /* Write to ORA */
185         always@(posedge sysclk or posedge reset) begin
186                 if (reset)
187                   pa <= 8'b11111111;
188                 else if (we && (rs_ora || rs_ora2))
189                   pa <= wdata;
190         end
191
192         /* Write to ORB */
193         always@(posedge sysclk or posedge reset) begin
194                 if (reset)
195                   pb <= 8'b11111111;
196                 else if (we && rs_orb)
197                   pb <= wdata;          
198         end
199
200         /* Write to DDRA ignored */
201         /* Write to DDRB */
202         always@(posedge sysclk or posedge reset) begin
203                 if (reset)
204                   ddr_b0 <= 1'b0;
205                 else if (we && rs_orb)
206                   ddr_b0 <= wdata[0];
207         end
208
209         /* Write to ACR */
210         always@(posedge sysclk or posedge reset) begin
211                 if (reset)
212                   acr <= 8'b0;
213                 else if (we && rs_acr)
214                   acr <= wdata;
215         end
216
217         /* Write to PCR */
218         always@(posedge sysclk or posedge reset) begin
219                 if (reset)
220                   pcr <= 8'b0;
221                 else if (we && rs_pcr)
222                   pcr <= wdata;
223         end
224
225         /* Timers
226          *
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.
233          * 
234          * Also, to keep things simple, PB7 goes up right after writing to
235          * T1CH, tho then follows proper periods (hopefully)
236          */
237
238         /* Clock division. We divide by 21 to get approx 793kHz */
239         always@(posedge sysclk or posedge reset) begin
240                 if (reset)
241                   ckdiv <= 20;
242                 else begin
243                         if (ckdiv == 0)
244                           ckdiv <= 20;
245                         else
246                           ckdiv <= ckdiv - 1;
247                 end
248         end
249         assign tstrobe = (ckdiv == 0);
250         assign ckhalf = (ckdiv == 10);
251         
252         /* Timer 1 latches */
253         always@(posedge sysclk or posedge reset) begin
254                 if (reset)
255                         t1l <= 0;
256                 else begin
257                         if (we && (rs_t1cl || rs_t1ll))
258                           t1l[7:0] <= wdata;                  
259                         if (we && (rs_t1ch || rs_t1lh))
260                           t1l[15:8] <= wdata;
261                 end
262         end
263
264         /* Timer 1 counter */
265         always@(posedge sysclk or posedge reset) begin
266                 if (reset)
267                         t1 <= 0;
268                 else begin
269                         /* Handle transfer from latch on write */
270                         if (we && rs_t1ch) begin
271                                 t1[7:0] <= t1l[7:0];
272                                 t1[15:8] <= wdata;
273                         end else if (tstrobe) begin
274                                 /* In "free run", reload from latch
275                                  *
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
282                                  */
283                                 if (acr[6] && t1_fired)
284                                   t1 <= t1l;
285                                 else
286                                   t1 <= t1 - 1;
287                         end
288                 end
289         end
290
291         /* "armed" latch. This is set on a write and cleared when
292          * running out in "one shot" mode
293          */
294         always@(posedge sysclk or posedge reset) begin
295                 if (reset)
296                   t1_armed <= 0;
297                 else begin
298                         /* Always armed when in continuous mode, else
299                          * arm when writing to T1CH
300                          */
301                         if ((we && rs_t1ch) || acr[6])
302                           t1_armed <= 1;
303                         else if (t1_fired && !acr[6])
304                           t1_armed <= 0;
305                 end
306         end                     
307
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.
312          */
313         always@(posedge sysclk or posedge reset) begin
314                 if (reset)
315                   t1_fired <= 0;
316                 else begin
317                         if (tstrobe)
318                           t1_fired <= t1_armed && t1 == 0;
319                 end             
320         end
321
322         /* Generate PB7 output */
323         always@(posedge sysclk or posedge reset) begin
324                 if (reset)
325                   t1pb7 <= 1;
326                 else begin
327                         /* We are 0 when timer is armed and not fired yet */
328                         if (we && rs_t1ch)
329                           t1pb7 <= 0;
330                         /* We invert when fired */
331                         if (ckhalf && t1_fired)
332                           t1pb7 <= ~t1pb7;                      
333                 end
334         end
335
336         /* T1 interrupt */
337         assign t1irq = ckhalf & t1_fired;
338
339         /* Timer 2
340          *
341          * Either one shot or count PB6 pulses (ie. hblank)
342          */
343         always@(posedge sysclk or posedge reset) begin
344                 if (reset)
345                   pb6_old <= 1'b0;              
346                 else
347                   pb6_old <= pb_in6_3[6];
348         end
349         assign t2strobe = acr[5] ? (pb6_old & ~pb_in6_3[6]) : tstrobe;
350
351         /* Timer 2 latche (low only) */
352         always@(posedge sysclk or posedge reset) begin
353                 if (reset)
354                         t2l <= 0;
355                 else begin
356                         if (we && rs_t2cl)
357                           t2l <= wdata;               
358                 end
359         end
360
361         /* Timer 2 counter */
362         always@(posedge sysclk or posedge reset) begin
363                 if (reset)
364                         t2 <= 0;
365                 else begin
366                         /* Handle transfer from latch on write */
367                         if (we && rs_t2ch) begin
368                                 t2[7:0] <= t2l;
369                                 t2[15:8] <= wdata;
370                         end else if (t2strobe)
371                           t2 <= t2 - 1;
372                 end
373         end
374
375         /* T2 "armed" latch (see T1) */
376         always@(posedge sysclk or posedge reset) begin
377                 if (reset)
378                   t2_armed <= 0;
379                 else begin
380                         if (we && rs_t2ch)
381                           t2_armed <= 1;
382                         else if (t2_fired)
383                           t2_armed <= 0;
384                 end
385         end                     
386
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.
391          */
392         always@(posedge sysclk or posedge reset) begin
393                 if (reset)
394                   t2_fired <= 0;
395                 else begin
396                         if (t2strobe)
397                           t2_fired <= t2_armed && t2 == 0;
398                         if (acr[5] && t2_fired)
399                           t2_fired <= 0;                        
400                 end             
401         end
402
403         /* T2 Interrupt */
404         assign t2irq = acr[5] ? t2_fired : (t2_fired & ckhalf);
405         
406         /* Shift register
407          *
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
416          * 
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
423          * an interrupt
424          */
425
426         /* Write to SR (including external input) */
427         always@(posedge sysclk or posedge reset) begin
428                 if (reset)
429                   sr <= 8'b0;           
430                 else begin
431                         if (we && rs_sr)
432                           sr <= wdata;
433                         if (acr[4:2] == 3'b011 && sr_in_strobe)
434                           sr <= sr_in;
435                 end
436         end
437
438         /* Generate sr_out_strobe */
439         always@(posedge sysclk or posedge reset) begin
440                 if (reset)
441                   sr_out_strobe <= 1'b0;                
442                 else begin
443                         if (we && rs_sr && acr[4:2] == 3'b111)
444                           sr_out_strobe <= 1;
445                         else
446                           sr_out_strobe <= 0;   
447                 end
448         end
449
450         /* CA1 / CA2 edge detection */
451         always@(posedge sysclk or posedge reset) begin
452                 if (reset) begin
453                         ca1_old <= 0;
454                         ca2_old <= 0;           
455                 end else begin
456                         ca1_old <= ca1;
457                         ca2_old <= ca2;
458                 end
459         end
460
461
462         /* Interrupts */
463
464         
465         /* Write to IER */
466         always@(posedge sysclk or posedge reset) begin
467                 if (reset)
468                   ier <= 1'b0;          
469                 else if (we && rs_ier) begin
470                         if (wdata[7])
471                           ier <= ier | wdata[6:0];
472                         else
473                           ier <= ier & ~wdata[6:0];
474                 end
475         end
476
477         /* Handle IFR */
478         always@(posedge sysclk or posedge reset) begin
479                 if (reset)
480                   ifr <= 8'b0;          
481                 else begin
482                         /* First, write-1-to-clear */
483                         if (we && rs_ifr)
484                           ifr <= ifr & ~wdata[6:0];
485
486                         /* Now clear individual sources based on
487                          * register accesses
488                          */
489                         if (rs_ora && (pcr[3:1] == 3'b000 ||
490                                        pcr[3:1] == 3'b010))
491                           ifr[`CA2_IRQ] <= 0;
492                         if (rs_ora)
493                           ifr[`CA1_IRQ] <= 0;
494                         if (rs_sr)
495                           ifr[`SR_IRQ] <= 0;
496                         if (rs_orb && (pcr[7:5] == 3'b000 ||
497                                        pcr[7:5] == 3'b010))
498                           ifr[`CB2_IRQ] <= 0;
499                         if (rs_orb)
500                           ifr[`CB1_IRQ] <= 0;
501                         if (we && rs_t2ch)
502                           ifr[`T2_IRQ] <= 0;
503                         if ((!we) && rs_t2cl)
504                           ifr[`T2_IRQ] <= 0;
505                         if (we && (rs_t1ch || rs_t1lh))
506                           ifr[`T1_IRQ] <= 0;
507                         if ((!we) && rs_t1cl)
508                           ifr[`T1_IRQ] <= 0;
509
510                         /* Finally set sources based on relevant
511                          * events
512                          */
513
514                         /* -- SR interrupt --
515                          *
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.
520                           * 
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.
525                           */
526
527                         /* Shift out under control of external clock */
528                         if (we && rs_sr && acr[4:2] == 3'b111)
529                           ifr[`SR_IRQ] <= 1;
530
531                         /* Shift in under control of external clock */
532                         if (acr[4:2] == 3'b011 && sr_in_strobe)
533                           ifr[`SR_IRQ] <= 1;
534
535                         /* CA2 */
536                         if (pcr[3] == 0 &&
537                                     ((!pcr[2] &&  ca2_old && !ca2) ||
538                                      ( pcr[2] && !ca2_old &&  ca2)))
539                           ifr[`CA2_IRQ] <= 1;
540
541                         /* CA1 */
542                         if ((!pcr[0] &&  ca1_old && !ca1) ||
543                             ( pcr[0] && !ca1_old &&  ca1))
544                           ifr[`CA1_IRQ] <= 1;
545
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...
549                          */
550
551                         /* Timer IRQs */
552                         if (t1irq)
553                           ifr[`T1_IRQ] <= 1;
554                         if (t2irq)
555                           ifr[`T2_IRQ] <= 1;
556                 end
557         end
558 endmodule
559