]> Shamusworld >> Repos - apple2/blob - src/v6522via.cpp
Fix trash on sides of screen in full screen mode.
[apple2] / src / v6522via.cpp
1 //
2 // Virtual 6522 Versatile Interface Adapter
3 //
4 // by James Hammons
5 // (C) 2018 Underground Software
6 //
7
8 #include "v6522via.h"
9
10 #include <string.h>             // for memset()
11 #include "log.h"
12
13
14 /*
15 Register  Function
16 --------  -------------------------
17 0         Output Register B
18 1         Output Register A
19 2         Data Direction Register B
20 3         Data Direction Register A
21 4         Timer 1 Low byte counter (& latch)
22 5         Timer 1 Hgh byte counter (& latch)
23 6         Timer 1 Low byte latch
24 7         Timer 1 Hgh byte latch (& reset IRQ flag)
25 B         Aux Control Register
26 D         Interrupt Flag Register
27 E         Interrupt Enable Register
28
29 bit 6 of ACR:
30 0: Timed interrupt each time Timer 1 is loaded
31 1: Continuous interrupts
32
33 bit 7 enables PB7 (bit 6 controls output type):
34 0: One shot output
35 1: Square wave output
36 */
37
38
39 V6522VIA::V6522VIA(): orb(0), ora(0), ddrb(0), ddra(0),
40         timer1counter(0), timer1latch(0), timer2counter(0),
41         acr(0), ifr(0), ier(0)
42 {
43 }
44
45
46 void V6522VIA::Reset(void)
47 {
48         memset(this, 0, sizeof(V6522VIA));
49 }
50
51
52 uint8_t V6522VIA::Read(uint8_t regNum)
53 {
54         switch (regNum)
55         {
56         case 0x00:
57 //For some reason, this prevents Ankh from loading.  Need to figure out what the MB *really* returns in its uninitialized state...
58 //              return orb & ddrb;
59                 return 0xFF;
60
61         case 0x01:
62                 return ora & ddra;
63
64         case 0x02:
65                 return ddrb;
66
67         case 0x03:
68                 return ddra;
69
70         case 0x04:
71                 return timer1counter & 0xFF;
72
73         case 0x05:
74                 return (timer1counter & 0xFF00) >> 8;
75
76         case 0x06:
77                 return timer1latch & 0xFF;
78
79         case 0x07:
80                 return (timer1latch & 0xFF00) >> 8;
81
82         case 0x08:
83                 return timer2counter & 0xFF;
84
85         case 0x09:
86                 return (timer2counter & 0xFF00) >> 8;
87
88         case 0x0B:
89                 return acr;
90
91         case 0x0D:
92                 return (ifr & 0x7F) | (ifr & 0x7F ? 0x80 : 0);
93
94         case 0x0E:
95                 return ier | 0x80;
96
97         default:
98                 WriteLog("Unhandled 6522 register %X read (chip %d)\n", regNum, id);
99         }
100
101         return 0;
102 }
103
104
105 void V6522VIA::Write(uint8_t regNum, uint8_t byte)
106 {
107         switch (regNum)
108         {
109         case 0x00:
110                 orb = byte;
111                 break;
112
113         case 0x01:
114                 ora = byte;
115                 break;
116
117         case 0x02:
118                 ddrb = byte;
119                 break;
120
121         case 0x03:
122                 ddra = byte;
123                 break;
124
125         case 0x04:
126                 timer1latch = (timer1latch & 0xFF00) | byte;
127                 break;
128
129         case 0x05:
130                 timer1latch = (timer1latch & 0x00FF) | (((uint16_t)byte) << 8);
131                 timer1counter = timer1latch;
132                 ifr &= 0x3F; // Clear T1 interrupt flag
133                 break;
134
135         case 0x06:
136                 timer1latch = (timer1latch & 0xFF00)
137                         | byte;
138                 break;
139
140         case 0x07:
141                 timer1latch = (timer1latch & 0x00FF) | (((uint16_t)byte) << 8);
142                 ifr &= 0x3F; // Clear T1 interrupt flag
143                 break;
144
145         case 0x0B:
146                 acr = byte;
147                 break;
148
149         case 0x0D:
150                 ifr &= ~byte;
151                 break;
152
153         case 0x0E:
154                 if (byte & 0x80)
155                         // Setting bits in the IER
156                         ier |= byte;
157                 else
158                         // Clearing bits in the IER
159                         ier &= ~byte;
160
161                 break;
162         default:
163                 WriteLog("Unhandled 6522 register $%X write $%02X (chip %d)\n", regNum, byte, id);
164         }
165 }
166
167
168 bool V6522VIA::Run(uint16_t cycles)
169 {
170         // This is to signal to the caller that we hit an IRQ condition
171         bool response = false;
172         bool viaT1HitZero = (timer1counter <= cycles ? true : false);
173
174         timer1counter -= cycles;
175         timer2counter -= cycles;
176
177         if (viaT1HitZero)
178         {
179                 if (acr & 0x40)
180                 {
181                         timer1counter += timer1latch;
182
183                         if (ier & 0x40)
184                         {
185                                 ifr |= (0x80 | 0x40);
186                                 response = true;
187                         }
188                 }
189                 else
190                 {
191                         // Disable T1 interrupt
192                         ier &= 0x3F;
193                 }
194         }
195
196         return response;
197 }
198