fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/chipset/e6850.c *
7 * Created: 2013-05-31 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2013-2015 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <stdlib.h>
24#include <stdio.h>
25
26#include "e6850.h"
27
28
29#ifndef DEBUG_ACIA
30#define DEBUG_ACIA 0
31#endif
32
33
34#define E6850_SR_RDRF 0x01
35#define E6850_SR_TDRE 0x02
36#define E6850_SR_DCD 0x04
37#define E6850_SR_CTS 0x08
38#define E6850_SR_FE 0x10
39#define E6850_SR_OVRN 0x20
40#define E6850_SR_PE 0x40
41#define E6850_SR_IRQ 0x80
42
43
44void e6850_init (e6850_t *acia)
45{
46 acia->send_ext = NULL;
47 acia->send_fct = NULL;
48
49 acia->recv_ext = NULL;
50 acia->recv_fct = NULL;
51
52 acia->irq_val = 0;
53 acia->irq_ext = NULL;
54 acia->irq_fct = NULL;
55}
56
57void e6850_free (e6850_t *acia)
58{
59}
60
61void e6850_set_irq_fct (e6850_t *acia, void *ext, void *fct)
62{
63 acia->irq_ext = ext;
64 acia->irq_fct = fct;
65}
66
67void e6850_set_send_fct (e6850_t *acia, void *ext, void *fct)
68{
69 acia->send_ext = ext;
70 acia->send_fct = fct;
71}
72
73void e6850_set_recv_fct (e6850_t *acia, void *ext, void *fct)
74{
75 acia->recv_ext = ext;
76 acia->recv_fct = fct;
77}
78
79static
80void e6850_set_irq (e6850_t *acia, int val)
81{
82 val = (val != 0);
83
84 if (acia->irq_val != val) {
85 acia->irq_val = val;
86
87#if DEBUG_ACIA >= 2
88 fprintf (stderr, "ACIA: irq = %d\n", val);
89#endif
90
91 if (acia->irq_fct != NULL) {
92 acia->irq_fct (acia->irq_ext, acia->irq_val);
93 }
94 }
95}
96
97static
98void e6850_check_int (e6850_t *acia)
99{
100 acia->sr &= ~E6850_SR_IRQ;
101
102 if ((acia->cr & 0x80) && (acia->sr & E6850_SR_RDRF)) {
103 acia->sr |= E6850_SR_IRQ;
104 }
105 else if (((acia->cr & 0x60) == 0x20) && (acia->sr & E6850_SR_TDRE)) {
106 acia->sr |= E6850_SR_IRQ;
107 }
108
109 if ((acia->cr & 3) == 3) {
110 /* master reset */
111 acia->sr &= ~E6850_SR_IRQ;
112 }
113
114 e6850_set_irq (acia, acia->sr & E6850_SR_IRQ);
115}
116
117static
118void e6850_send_tdr (e6850_t *acia)
119{
120 acia->tsr = acia->tdr;
121 acia->sr |= E6850_SR_TDRE;
122 acia->send_timer = (unsigned long) acia->char_bits << acia->clock_div;
123
124 e6850_check_int (acia);
125}
126
127static
128void e6850_send_tsr (e6850_t *acia)
129{
130 if (acia->send_fct != NULL) {
131 acia->send_fct (acia->send_ext, acia->tsr);
132 }
133
134 if ((acia->sr & E6850_SR_TDRE) == 0) {
135 e6850_send_tdr (acia);
136 }
137}
138
139static
140void e6850_receive_rsr (e6850_t *acia)
141{
142 unsigned char val;
143
144 if (acia->recv_fct == NULL) {
145 return;
146 }
147
148 if (acia->recv_fct (acia->recv_ext, &val)) {
149 return;
150 }
151
152 acia->rsr = val;
153 acia->recv_timer = (unsigned long) acia->char_bits << acia->clock_div;
154}
155
156static
157void e6850_receive_rdr (e6850_t *acia)
158{
159 acia->rdr = acia->rsr;
160 acia->sr |= E6850_SR_RDRF;
161
162 e6850_receive_rsr (acia);
163 e6850_check_int (acia);
164}
165
166unsigned char e6850_get_status (e6850_t *acia)
167{
168 return (acia->sr);
169}
170
171unsigned char e6850_get_data (e6850_t *acia)
172{
173 e6850_set_irq (acia, 0);
174
175 acia->sr &= ~E6850_SR_RDRF;
176
177 e6850_check_int (acia);
178
179#if DEBUG_ACIA >= 2
180 fprintf (stderr, "ACIA: read data %02X\n", acia->rdr);
181#endif
182
183 return (acia->rdr);
184}
185
186void e6850_set_control (e6850_t *acia, unsigned char val)
187{
188 unsigned char ws;
189
190 if (acia->cr == val) {
191 return;
192 }
193
194#if DEBUG_ACIA >= 1
195 fprintf (stderr, "ACIA: set cr %02X\n", val);
196#endif
197
198 acia->cr = val;
199
200 switch (val & 3) {
201 case 0:
202 acia->clock_div = 0;
203 break;
204
205 case 1:
206 acia->clock_div = 4;
207 break;
208
209 case 2:
210 acia->clock_div = 6;
211 break;
212
213 default:
214 acia->clock_div = 0;
215 acia->recv_timer = 0;
216#if DEBUG_ACIA >= 1
217 fprintf (stderr, "ACIA: master reset\n");
218#endif
219 return;
220 }
221
222 ws = (val >> 2) & 7;
223
224 acia->data_bits = (ws & 2) ? 8 : 7;
225 acia->stop_bits = (ws & 1) ? 1 : 2;
226
227 if (ws == 4) {
228 acia->stop_bits = 2;
229 }
230
231 acia->char_bits = acia->data_bits + acia->stop_bits;
232
233 if ((ws != 4) && (ws != 5)) {
234 acia->char_bits += 1;
235 }
236
237 e6850_check_int (acia);
238}
239
240void e6850_set_data (e6850_t *acia, unsigned char val)
241{
242 e6850_set_irq (acia, 0);
243
244 acia->tdr = val;
245 acia->sr &= ~E6850_SR_TDRE;
246
247 e6850_check_int (acia);
248
249 if (acia->send_timer == 0) {
250 e6850_send_tdr (acia);
251 }
252
253 e6850_check_int (acia);
254}
255
256unsigned char e6850_get_uint8 (e6850_t *acia, unsigned long addr)
257{
258 switch (addr) {
259 case 0:
260 return (e6850_get_status (acia));
261
262 case 1:
263 return (e6850_get_data (acia));
264 }
265
266 return (0);
267}
268
269unsigned short e6850_get_uint16 (e6850_t *acia, unsigned long addr)
270{
271 return (0);
272}
273
274unsigned long e6850_get_uint32 (e6850_t *acia, unsigned long addr)
275{
276 return (0);
277}
278
279void e6850_set_uint8 (e6850_t *acia, unsigned long addr, unsigned char val)
280{
281 switch (addr) {
282 case 0:
283 e6850_set_control (acia, val);
284 break;
285
286 case 1:
287 e6850_set_data (acia, val);
288 break;
289 }
290}
291
292void e6850_set_uint16 (e6850_t *acia, unsigned long addr, unsigned short val)
293{
294}
295
296void e6850_set_uint32 (e6850_t *acia, unsigned long addr, unsigned long val)
297{
298}
299
300int e6850_receive_ready (const e6850_t *acia)
301{
302 return ((acia->sr & E6850_SR_RDRF) == 0);
303}
304
305void e6850_receive (e6850_t *acia, unsigned char val)
306{
307 acia->rsr = val;
308 acia->recv_timer = (unsigned long) acia->char_bits << acia->clock_div;
309}
310
311void e6850_reset (e6850_t *acia)
312{
313 acia->cr = 0;
314 acia->sr = E6850_SR_TDRE;
315 acia->rdr = 0;
316 acia->tdr = 0;
317 acia->rsr = 0;
318 acia->tsr = 0;
319
320 acia->clock_div = 0;
321 acia->data_bits = 0;
322 acia->stop_bits = 0;
323 acia->char_bits = 0;
324
325 acia->recv_timer = 0;
326 acia->send_timer = 0;
327
328 e6850_check_int (acia);
329}
330
331void e6850_clock (e6850_t *acia, unsigned cnt)
332{
333 if (acia->recv_timer > 0) {
334 if (cnt < acia->recv_timer) {
335 acia->recv_timer -= cnt;
336 }
337 else {
338 acia->recv_timer = 0;
339
340 e6850_receive_rdr (acia);
341 }
342 }
343
344 if (acia->send_timer > 0) {
345 if (cnt < acia->send_timer) {
346 acia->send_timer -= cnt;
347 }
348 else {
349 acia->send_timer = 0;
350
351 e6850_send_tsr (acia);
352 }
353 }
354}