Mercurial > repos > blastem
comparison i8255.c @ 2521:8cf7cadc17ee
Initial SC-3000 support
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 11 Oct 2024 00:46:53 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2520:0e9d7ef03983 | 2521:8cf7cadc17ee |
---|---|
1 #include "i8255.h" | |
2 | |
3 #include <string.h> | |
4 | |
5 #define BIT_OBFA 0x80 | |
6 #define BIT_ACKA 0x40 | |
7 #define BIT_IBFA 0x20 | |
8 #define BIT_STBA 0x10 | |
9 #define BIT_INTRA 0x08 | |
10 #define BIT_STB_ACKB 0x04 | |
11 #define BIT_IBF_OBFB 0x02 | |
12 #define BIT_INTRB 0x01 | |
13 | |
14 #define BIT_INTE1 BIT_ACKA | |
15 #define BIT_INTE2 BIT_STBA | |
16 #define BIT_INTEB BIT_STB_ACKB | |
17 | |
18 void i8255_init(i8255 *ppi, i8255_out_update out, i8255_in_sample in) | |
19 { | |
20 memset(ppi->latches, 0, sizeof(ppi->latches)); | |
21 ppi->control = 0x1B; //all ports start as input | |
22 ppi->portc_write_mask = 0xFF; | |
23 ppi->portc_out_mask = 0; | |
24 ppi->out_handler = out; | |
25 ppi->in_handler = in; | |
26 } | |
27 | |
28 static uint8_t porta_out_enabled(i8255 *ppi) | |
29 { | |
30 return (ppi->control & 0x40) || !(ppi->control & 0x10); | |
31 } | |
32 | |
33 void i8255_write(uint32_t address, i8255 *ppi, uint8_t value, uint32_t cycle) | |
34 { | |
35 switch(address) | |
36 { | |
37 case 0: | |
38 ppi->latches[0] = value; | |
39 if (porta_out_enabled(ppi)) { | |
40 if (ppi->control & 0x60) { | |
41 //Mode 1 or 2 | |
42 ppi->latches[2] &= ~BIT_OBFA; | |
43 if ((ppi->control & 0x60) == 0x20 || !(ppi->latches[2] & BIT_IBFA)) { | |
44 ppi->latches[2] &= ~BIT_INTRA; | |
45 } | |
46 if (ppi->out_handler) { | |
47 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
48 } | |
49 } | |
50 if (ppi->out_handler && !(ppi->control & 0x40)) { | |
51 ppi->out_handler(ppi, cycle, address, value); | |
52 } | |
53 } | |
54 break; | |
55 case 1: | |
56 if (!(ppi->control & 0x02)) { | |
57 ppi->latches[1] = value; | |
58 if (ppi->control & 0x04) { | |
59 //Mode 1 | |
60 ppi->latches[2] &= ~(BIT_IBF_OBFB|BIT_INTRB); | |
61 if (ppi->out_handler) { | |
62 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
63 } | |
64 } | |
65 if (ppi->out_handler) { | |
66 ppi->out_handler(ppi, cycle, address, value); | |
67 } | |
68 } | |
69 break; | |
70 case 2: | |
71 ppi->latches[2] &= ~ppi->portc_write_mask; | |
72 ppi->latches[2] |= value & ppi->portc_write_mask; | |
73 if (ppi->out_handler && ppi->portc_out_mask) { | |
74 ppi->out_handler(ppi, cycle, address, ppi->latches[2] & ppi->portc_out_mask); | |
75 } | |
76 break; | |
77 case 3: | |
78 if (value & 0x80) { | |
79 uint8_t changed = ppi->control ^ value; | |
80 //datasheet says "output" state is cleared on mode changes | |
81 if (changed & 0x60) { | |
82 //group A mode changed | |
83 ppi->latches[0] = 0; | |
84 ppi->latches[2] &= 0x0F; | |
85 } | |
86 if (changed & 4) { | |
87 //group B mode changed | |
88 ppi->latches[1] = 0; | |
89 if (value & 0x60) { | |
90 //PC4 is INTRa | |
91 ppi->latches[2] &= 0xF8; | |
92 } else { | |
93 ppi->latches[2] &= 0xF0; | |
94 } | |
95 } | |
96 ppi->control = value; | |
97 ppi->portc_write_mask = ppi->portc_out_mask = 0; | |
98 if (value & 0x40) { | |
99 //Port A Mode 2 | |
100 ppi->portc_out_mask |= BIT_OBFA | BIT_IBFA | BIT_INTRA; | |
101 ppi->portc_write_mask |= BIT_INTE1 | BIT_INTE2; | |
102 } else if (value & 0x20) { | |
103 //Port A Mode 1 | |
104 ppi->portc_out_mask |= BIT_INTRA; | |
105 if (value & 0x10) { | |
106 //Input | |
107 ppi->portc_out_mask |= BIT_IBFA; | |
108 ppi->portc_write_mask |= BIT_INTE2 | 0xC0; | |
109 if (!(value & 0x08)) { | |
110 //Port C upper Output | |
111 ppi->portc_out_mask |= 0xC0; | |
112 } | |
113 } else { | |
114 //Output | |
115 ppi->portc_out_mask |= BIT_OBFA; | |
116 ppi->portc_out_mask |= BIT_INTE1 | 0x30; | |
117 if (!(value & 0x08)) { | |
118 //Port C upper Output | |
119 ppi->portc_out_mask |= 0x30; | |
120 } | |
121 } | |
122 } else { | |
123 ppi->portc_write_mask |= 0xF0; | |
124 if (!(value & 0x08)) { | |
125 //Port C upper Output | |
126 ppi->portc_out_mask |= 0xF0; | |
127 } | |
128 } | |
129 if (value & 0x04) { | |
130 //Port B Mode 1 | |
131 ppi->portc_out_mask |= BIT_IBF_OBFB | BIT_INTRB; | |
132 ppi->portc_write_mask |= BIT_INTEB; | |
133 if (!(ppi->portc_out_mask & BIT_INTRA) && !(value & 1)) { | |
134 //Port C lower Output | |
135 ppi->portc_out_mask |= 0x08; | |
136 ppi->portc_write_mask |= 0x08; | |
137 } | |
138 } else { | |
139 if (!(value & 1)) { | |
140 //Port C lower Output | |
141 ppi->portc_out_mask |= 0x07; | |
142 ppi->portc_write_mask |= 0x07; | |
143 if (!(ppi->portc_out_mask & BIT_INTRA)) { | |
144 ppi->portc_out_mask |= 0x08; | |
145 ppi->portc_write_mask |= 0x08; | |
146 } | |
147 } | |
148 } | |
149 } else { | |
150 uint8_t bit = 1 << ((value >> 1) & 7); | |
151 if (ppi->portc_write_mask & bit) { | |
152 if (value & 1) { | |
153 ppi->latches[2] |= bit; | |
154 } else { | |
155 ppi->latches[2] &= bit; | |
156 } | |
157 if (ppi->out_handler && ppi->portc_out_mask) { | |
158 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
159 } | |
160 } | |
161 } | |
162 | |
163 } | |
164 } | |
165 | |
166 uint8_t i8255_read(uint32_t address, i8255 *ppi, uint32_t cycle) | |
167 { | |
168 switch(address) | |
169 { | |
170 case 0: | |
171 if (ppi->control & 0x60) { | |
172 //Mode 1 or 2 | |
173 if (ppi->control & 0x50) { | |
174 //Mode 2 or Mode 1 input | |
175 ppi->latches[2] &= ~BIT_IBFA; | |
176 if (!(ppi->control & 0x40) || (ppi->latches[2] & BIT_OBFA)) { | |
177 ppi->latches[2] &= ~BIT_INTRA; | |
178 } | |
179 if (ppi->out_handler) { | |
180 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
181 } | |
182 } | |
183 return ppi->latches[3]; | |
184 } | |
185 if (ppi->control & 0x10) { | |
186 if (ppi->in_handler) { | |
187 return ppi->in_handler(ppi, cycle, address); | |
188 } | |
189 return 0xFF; | |
190 } | |
191 return ppi->latches[0]; | |
192 case 1: | |
193 if (ppi->control & 0x40) { | |
194 //Mode 1 | |
195 if (ppi->control & 0x2) { | |
196 //input | |
197 ppi->latches[2] &= ~(BIT_IBF_OBFB|BIT_INTRB); | |
198 if (ppi->out_handler) { | |
199 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
200 } | |
201 } | |
202 return ppi->latches[1]; | |
203 } | |
204 if (ppi->control & 0x2) { | |
205 //input | |
206 if (ppi->in_handler) { | |
207 return ppi->in_handler(ppi, cycle, address); | |
208 } | |
209 return 0xFF; | |
210 } | |
211 return ppi->latches[1]; | |
212 case 2: | |
213 return ppi->latches[2]; | |
214 case 3: | |
215 default: | |
216 return 0xFF;//described as illegal in datasheet | |
217 } | |
218 } | |
219 | |
220 void i8255_input_strobe_a(i8255 *ppi, uint8_t value, uint32_t cycle) | |
221 { | |
222 if ((ppi->control & 0x70) == 0x30 || (ppi->control & 0x40)) { | |
223 //Mode 2 or Mode 1 input | |
224 ppi->latches[3] = value; | |
225 ppi->latches[2] |= BIT_IBFA; | |
226 if (ppi->latches[2] & BIT_INTE2) { | |
227 ppi->latches[2] |= BIT_INTRA; | |
228 } | |
229 if (ppi->out_handler) { | |
230 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
231 } | |
232 } | |
233 } | |
234 | |
235 void i8255_input_strobe_b(i8255 *ppi, uint8_t value, uint32_t cycle) | |
236 { | |
237 if ((ppi->control & 6) == 6) { | |
238 //Mode 1 input | |
239 ppi->latches[1] = value; | |
240 ppi->latches[2] |= BIT_IBF_OBFB; | |
241 if (ppi->latches[2] & BIT_INTEB) { | |
242 ppi->latches[2] |= BIT_INTRB; | |
243 } | |
244 if (ppi->out_handler) { | |
245 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
246 } | |
247 } | |
248 } | |
249 | |
250 uint8_t i8255_output_ack_a(i8255 *ppi, uint32_t cycle) | |
251 { | |
252 if ((ppi->control & 0x70) == 0x20 || (ppi->control & 0x40)) { | |
253 //Mode 2 or Mode 1 output | |
254 ppi->latches[2] |= BIT_OBFA; | |
255 if (ppi->latches[2] & BIT_INTE1) { | |
256 ppi->latches[2] |= BIT_INTRA; | |
257 } | |
258 if (ppi->out_handler) { | |
259 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
260 } | |
261 return ppi->latches[0]; | |
262 } | |
263 if (ppi->control & 0x10) { | |
264 //input mode | |
265 return 0xFF; | |
266 } | |
267 //Mode 0 output | |
268 return ppi->latches[0]; | |
269 } | |
270 | |
271 uint8_t i8255_output_ack_b(i8255 *ppi, uint32_t cycle) | |
272 { | |
273 if ((ppi->control & 0x06) == 0x04) { | |
274 //Mode 1 output | |
275 ppi->latches[2] |= BIT_IBF_OBFB; | |
276 if (ppi->latches[2] & BIT_INTEB) { | |
277 ppi->latches[2] |= BIT_INTRB; | |
278 } | |
279 if (ppi->out_handler) { | |
280 ppi->out_handler(ppi, cycle, 2, ppi->latches[2] & ppi->portc_out_mask); | |
281 } | |
282 return ppi->latches[1]; | |
283 } | |
284 if (ppi->control & 2) { | |
285 //input mode | |
286 return 0xFF; | |
287 } | |
288 //Mode 0 output | |
289 return ppi->latches[1]; | |
290 } |