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 }