fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 555 lines 9.9 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/chipset/e6560.c * 7 * Created: 2020-04-18 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2020 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 "e6560.h" 27 28 29void e6560_init (e6560_t *vic) 30{ 31 unsigned i; 32 33 vic->hsync_ext = NULL; 34 vic->hsync = NULL; 35 36 vic->vsync_ext = NULL; 37 vic->vsync = NULL; 38 39 vic->sound_ext = NULL; 40 vic->sound = NULL; 41 42 for (i = 0; i < 64; i++) { 43 vic->memmap[i] = NULL; 44 } 45 46 vic->colram = NULL; 47 48 vic->w = 260; 49 vic->h = 261; 50 51 vic->frame = 0; 52 53 vic->ptr = vic->buf; 54 55 vic->snd_enable = 0; 56 vic->snd_rem = 0; 57 58 vic->snd_clk_inp = 1000000; 59 vic->snd_clk_out = 44100; 60 vic->snd_clk_cnt = 0; 61 62 vic->snd_buf_cnt = 0; 63 vic->snd_buf_max = 256; 64} 65 66void e6560_free (e6560_t *vic) 67{ 68 if (vic->sound != NULL) { 69 vic->sound (vic->sound_ext, vic->snd_buf, 0, 1); 70 } 71} 72 73void e6560_set_hsync_fct (e6560_t *vic, void *ext, void *fct) 74{ 75 vic->hsync_ext = ext; 76 vic->hsync = fct; 77} 78 79void e6560_set_vsync_fct (e6560_t *vic, void *ext, void *fct) 80{ 81 vic->vsync_ext = ext; 82 vic->vsync = fct; 83} 84 85void e6560_set_sound_fct (e6560_t *vic, void *ext, void *fct) 86{ 87 vic->sound_ext = ext; 88 vic->sound = fct; 89} 90 91void e6560_set_memmap (e6560_t *vic, unsigned pa, unsigned pn, const unsigned char *ptr) 92{ 93 while ((pa < 64) && (pn > 0)) { 94 vic->memmap[pa] = ptr; 95 96 pa += 1; 97 pn -= 1; 98 99 if (ptr != NULL) { 100 ptr += 256; 101 } 102 } 103} 104 105void e6560_set_colram (e6560_t *vic, const unsigned char *ptr) 106{ 107 vic->colram = ptr; 108} 109 110void e6560_set_pal (e6560_t *vic, int val) 111{ 112 if (val) { 113 vic->w = 284; 114 vic->h = 312; 115 } 116 else { 117 vic->w = 260; 118 vic->h = 261; 119 } 120} 121 122void e6560_set_clock (e6560_t *vic, unsigned long val) 123{ 124 vic->snd_clk_inp = val; 125} 126 127void e6560_set_srate (e6560_t *vic, unsigned long val) 128{ 129 if (val == 0) { 130 return; 131 } 132 133 vic->snd_clk_out = val; 134 vic->snd_clk_cnt = 0; 135} 136 137static 138void vic_sound_start (e6560_t *vic) 139{ 140 unsigned i; 141 142 vic->snd_buf_cnt = 0; 143 vic->snd_rem = 2 * vic->snd_clk_out; 144 vic->snd_clk_cnt = 0; 145 146 if (vic->sound == NULL) { 147 return; 148 } 149 150 for (i = 0; i < vic->snd_buf_max; i++) { 151 vic->snd_buf[i] = 0x8000; 152 } 153 154 vic->sound (vic->sound_ext, vic->snd_buf, vic->snd_buf_max, 0); 155 vic->sound (vic->sound_ext, vic->snd_buf, vic->snd_buf_max, 0); 156} 157 158static 159void vic_sound_stop (e6560_t *vic) 160{ 161 if (vic->sound != NULL) { 162 vic->sound (vic->sound_ext, vic->snd_buf, vic->snd_buf_cnt, 1); 163 } 164 165 vic->snd_buf_cnt = 0; 166} 167 168static 169void vic_sound_enable (e6560_t *vic, unsigned chn, unsigned char val) 170{ 171 e6560_chn_t *c; 172 173 c = vic->chn + (chn & 3); 174 175 if (val & 0x80) { 176 vic->snd_enable |= 1 << chn; 177 178 c->div = (128 - ((val + 1) & 0x7f)) << (7 - chn); 179 c->cnt = c->div; 180 c->smp = -64; 181 182 if (vic->snd_rem == 0) { 183 vic_sound_start (vic); 184 } 185 } 186 else { 187 vic->snd_enable &= ~(1 << chn); 188 189 c->smp = 0; 190 } 191} 192 193static 194void vic_sound_out (e6560_t *vic) 195{ 196 int val; 197 uint16_t tmp; 198 e6560_chn_t *chn; 199 200 if (vic->snd_rem == 0) { 201 return; 202 } 203 204 vic->snd_clk_cnt += vic->snd_clk_out; 205 206 if (vic->snd_clk_cnt < vic->snd_clk_inp) { 207 return; 208 } 209 210 vic->snd_clk_cnt -= vic->snd_clk_inp; 211 212 chn = vic->chn; 213 214 val = (chn[0].smp + chn[1].smp + chn[2].smp + chn[3].smp); 215 val *= ((vic->reg[14] & 15) + 1) * 4; 216 tmp = val; 217 218 vic->snd_buf[vic->snd_buf_cnt++] = tmp ^ 0x8000; 219 220 if (vic->snd_buf_cnt >= vic->snd_buf_max) { 221 if (vic->sound != NULL) { 222 vic->sound (vic->sound_ext, vic->snd_buf, vic->snd_buf_max, 0); 223 } 224 225 vic->snd_buf_cnt = 0; 226 } 227 228 if (--vic->snd_rem == 0) { 229 vic_sound_stop (vic); 230 } 231} 232 233static 234void vic_sound_clock (e6560_t *vic) 235{ 236 unsigned i; 237 e6560_chn_t *chn; 238 239 if (vic->snd_enable == 0) { 240 return; 241 } 242 243 vic->snd_rem = 2 * vic->snd_clk_out; 244 245 for (i = 0; i < 4; i++) { 246 if (~vic->snd_enable & (1 << i)) { 247 continue; 248 } 249 250 chn = vic->chn + i; 251 252 if (--chn->cnt > 0) { 253 continue; 254 } 255 256 chn->cnt = chn->div; 257 chn->smp = -chn->smp; 258 259 if (i == 3) { 260 if (vic->snd_lfsr & 1) { 261 vic->snd_lfsr = (vic->snd_lfsr >> 1) ^ 0x80000057; 262 chn->smp = -chn->smp; 263 } 264 else { 265 vic->snd_lfsr = vic->snd_lfsr >> 1; 266 } 267 } 268 } 269} 270 271static 272void vic_update_line (e6560_t *vic) 273{ 274 vic->reg[3] = (vic->reg[3] & 0x7f) | ((vic->y & 1) << 7); 275 vic->reg[4] = vic->y >> 1; 276} 277 278static 279void vic_update_colmap (e6560_t *vic) 280{ 281 vic->reverse = (vic->reg[15] >> 3) & 1; 282 283 vic->colmap1[vic->reverse] = 0; 284 vic->colmap1[vic->reverse ^ 1] = (vic->reg[15] >> 4) & 0x0f; 285 286 vic->colmap2[0] = (vic->reg[15] >> 4) & 0x0f; 287 vic->colmap2[1] = vic->reg[15] & 0x07; 288 vic->colmap2[2] = 0; 289 vic->colmap2[3] = (vic->reg[14] >> 4) & 0x0f; 290} 291 292static 293void vic_update_vaddr (e6560_t *vic) 294{ 295 vic->vbase = (vic->reg[5] << 6) & 0x3c00; 296 vic->vbase |= (vic->reg[2] << 2) & 0x200; 297 vic->cbase = (vic->reg[5] << 10) & 0x3c00; 298} 299 300unsigned char e6560_get_reg (e6560_t *vic, unsigned long addr) 301{ 302 if ((addr == 3) || (addr == 4)) { 303 vic_update_line (vic); 304 } 305 306 if (addr < 16) { 307 return (vic->reg[addr]); 308 } 309 310 return (0xaa); 311} 312 313void e6560_set_reg (e6560_t *vic, unsigned long addr, unsigned char val) 314{ 315 if (addr >= 16) { 316 return; 317 } 318 319 vic->reg[addr] = val; 320 321 if (addr == 0) { 322 vic->start_x = (val & 0x7f) << 2; 323 } 324 325 if (addr == 1) { 326 vic->start_y = (val & 0xff) << 1; 327 } 328 329 if ((addr == 2) || (addr == 5)) { 330 vic_update_vaddr (vic); 331 } 332 333 if (addr == 3) { 334 vic->line_shift = 3 + (val & 1); 335 vic->line_cnt = 1 << vic->line_shift; 336 } 337 338 if ((addr == 14) || (addr == 15)) { 339 vic_update_colmap (vic); 340 } 341 342 if ((addr >= 10) && (addr <= 13)) { 343 vic_sound_enable (vic, addr - 10, vic->reg[addr]); 344 } 345} 346 347void e6560_reset (e6560_t *vic) 348{ 349 unsigned i; 350 351 for (i = 0; i < 16; i++) { 352 vic->reg[i] = 0; 353 } 354 355 vic->x = 0; 356 vic->y = 0; 357 358 vic->start_x = 0; 359 vic->start_y = 0; 360 361 vic->col = 0; 362 vic->row = 0; 363 vic->col_cnt = 0; 364 vic->row_cnt = 0; 365 366 vic->line = 0; 367 vic->line_cnt = 8; 368 vic->line_shift = 3; 369 370 vic->vbase = 0; 371 vic->cbase = 0; 372 373 vic->addr1 = 0; 374 vic->addr2 = 0; 375 376 vic->next = 0; 377 378 vic->ptr = vic->buf; 379 380 vic->colmap1[0] = 0; 381 vic->colmap1[1] = 0; 382 383 for (i = 0; i < 4; i++) { 384 vic->colmap2[i] = 0; 385 } 386 387 vic->snd_enable = 0; 388 vic->snd_lfsr = 1; 389 vic->snd_clk_cnt = 0; 390 391 for (i = 0; i < 4; i++) { 392 vic->chn[i].cnt = 0; 393 vic->chn[i].div = 0; 394 vic->chn[i].smp = 0; 395 } 396} 397 398static 399unsigned char vic_fetch_data (e6560_t *vic, unsigned addr) 400{ 401 const unsigned char *ptr; 402 403 ptr = vic->memmap[(addr & 16383) >> 8]; 404 405 if (ptr != NULL) { 406 return (ptr[addr & 0xff]); 407 } 408 409 return (0); 410} 411 412static 413unsigned char vic_fetch_color (e6560_t *vic, unsigned addr) 414{ 415 if (vic->colram == NULL) { 416 return (0); 417 } 418 419 return (vic->colram[addr & 0x3ff]); 420} 421 422static 423void e6560_clock_char (e6560_t *vic) 424{ 425 unsigned i; 426 unsigned addr; 427 unsigned char val, col; 428 unsigned char *map; 429 430 if ((vic->col_cnt == 0) || (vic->row_cnt == 0)) { 431 /* in border */ 432 433 val = vic->reg[15] & 7; 434 435 for (i = 0; i < 4; i++) { 436 *(vic->ptr++) = val; 437 } 438 439 return; 440 } 441 442 if (vic->next == 0) { 443 /* fetch character code */ 444 445 vic->chr = vic_fetch_data (vic, vic->vbase + vic->addr2); 446 vic->color = vic_fetch_color (vic, vic->vbase + vic->addr2); 447 448 vic->next = 1; 449 vic->addr2 += 1; 450 451 return; 452 } 453 454 /* update one line of one character */ 455 456 addr = vic->cbase + (vic->chr << vic->line_shift) + vic->line; 457 val = vic_fetch_data (vic, addr); 458 459 vic->next = 0; 460 vic->col += 1; 461 vic->col_cnt -= 1; 462 463 if (vic->color & 0x08) { 464 map = vic->colmap2; 465 map[2] = vic->color & 7; 466 467 for (i = 0; i < 4; i++) { 468 col = map[(val >> 6) & 3]; 469 *(vic->ptr++) = col; 470 *(vic->ptr++) = col; 471 val <<= 2; 472 } 473 } 474 else { 475 map = vic->colmap1; 476 map[vic->reverse] = vic->color & 7; 477 478 for (i = 0; i < 8; i++) { 479 *(vic->ptr++) = map[(val >> 7) & 1]; 480 val <<= 1; 481 } 482 } 483} 484 485void e6560_clock (e6560_t *vic) 486{ 487 if (vic->snd_rem > 0) { 488 vic_sound_clock (vic); 489 vic_sound_out (vic); 490 } 491 492 if (vic->x == vic->start_x) { 493 vic->col_cnt = vic->reg[2] & 0x7f; 494 } 495 496 e6560_clock_char (vic); 497 498 vic->x += 4; 499 500 if (vic->x < vic->w) { 501 return; 502 } 503 504 if (vic->hsync != NULL) { 505 vic->hsync (vic->hsync_ext, vic->y, vic->w, vic->buf); 506 } 507 508 vic->x = 0; 509 vic->next = 0; 510 vic->ptr = vic->buf; 511 vic->col = 0; 512 vic->col_cnt = 0; 513 514 vic->line += 1; 515 516 if (vic->line >= vic->line_cnt) { 517 vic->line = 0; 518 519 if (vic->row_cnt > 0) { 520 vic->row += 1; 521 vic->row_cnt -= 1; 522 } 523 524 vic->addr1 = vic->addr2; 525 } 526 else { 527 vic->addr2 = vic->addr1; 528 } 529 530 vic->y += 1; 531 532 if (vic->y == vic->start_y) { 533 vic->row = 0; 534 vic->line = 0; 535 vic->row_cnt = (vic->reg[3] >> 1) & 0x3f; 536 vic->addr1 = 0; 537 vic->addr2 = 0; 538 } 539 540 if (vic->y < vic->h) { 541 return; 542 } 543 544 if (vic->vsync != NULL) { 545 vic->vsync (vic->vsync_ext); 546 } 547 548 vic->y = 0; 549 vic->row = 0; 550 vic->line = 0; 551 vic->row_cnt = 0; 552 vic->addr1 = 0; 553 vic->addr2 = 0; 554 vic->frame += 1; 555}