fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 354 lines 6.8 kB view raw
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}