2
* c64dtvblitter.c - C64DTV blitter and DMA controller
5
* M.Kiesel <mayne@users.sourceforge.net>
6
* Hannu Nuotio <hannu.nuotio@tut.fi>
7
* Daniel Kahlin <daniel@kahlin.net>
9
* Marco van den Heuvel <blackystardust68@yahoo.com>
11
* This file is part of VICE, the Versatile Commodore Emulator.
12
* See README for copyright notice.
14
* This program is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation; either version 2 of the License, or
17
* (at your option) any later version.
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
36
#include "c64dtvmem.h"
37
#include "c64dtvflash.h"
38
#include "c64dtvblitter.h"
39
#include "c64dtvdma.h"
40
#include "vicii-mem.h"
45
#include "resources.h"
47
#include "interrupt.h"
50
#include "translate.h"
52
static log_t c64dtvblitter_log = LOG_ERR;
54
/* I/O of the blitter engine ($D3XX) */
55
BYTE c64dtvmem_blitter[0x20];
63
int blitter_log_enabled = 0;
66
static BYTE srca_data[4];
67
static int srca_data_offs;
68
static int srca_fetched;
69
static BYTE srcb_data[4];
70
static int srcb_data_offs;
71
static BYTE sourceA, sourceB;
72
static int blitter_count;
73
static enum { BLITTER_IDLE, BLITTER_READ_A, BLITTER_READ_B, BLITTER_WRITE } blitter_state;
74
static int sourceA_line_off;
75
static int sourceB_line_off;
76
static int dest_line_off;
81
static int dtvrevision;
82
static int have_blitter_bug;
85
#define GET_REG24(a) ((c64dtvmem_blitter[a+2]<<16) | (c64dtvmem_blitter[a+1]<<8) | c64dtvmem_blitter[a])
86
#define GET_REG16(a) ((c64dtvmem_blitter[a+1]<<8) | c64dtvmem_blitter[a])
87
#define GET_REG8(a) (c64dtvmem_blitter[a])
90
/* ------------------------------------------------------------------------- */
92
void c64dtvblitter_init(void)
94
if(c64dtvblitter_log == LOG_ERR)
95
c64dtvblitter_log = log_open("C64DTVBLITTER");
97
/* init Blitter IRQ */
98
c64dtv_blitter_irq_init();
102
void c64dtvblitter_shutdown(void)
106
void c64dtvblitter_reset(void)
109
if(blitter_log_enabled) log_message(c64dtvblitter_log, "reset");
110
/* TODO move register file initialization somewhere else? */
111
for (i=0;i<0x20;++i) c64dtvmem_blitter[i] = 0;
113
c64dtvmem_blitter[0x07] = 0x10;
114
c64dtvmem_blitter[0x0f] = 0x10;
115
c64dtvmem_blitter[0x17] = 0x10;
117
blit_sourceA_off = 0;
118
blit_sourceB_off = 0;
126
blitter_state = BLITTER_IDLE;
133
sourceA_line_off = 0;
134
sourceB_line_off = 0;
138
/* ------------------------------------------------------------------------- */
139
/* blitter transfer state machine */
141
static int do_blitter_read_a(void)
144
int offs = (blit_sourceA_off >> 4) & 0x1ffffc;
145
int loffs = (blit_sourceA_off >> 4) & 0x000003;
148
if (offs != srca_data_offs) {
149
memcpy(srca_data, &mem_ram[offs], 4);
150
srca_data_offs = offs;
154
sourceA = srca_data[loffs];
158
static int do_blitter_read_b(void)
160
int force_sourceB_zero = GET_REG8(0x1b) & 0x01;
163
int offs = (blit_sourceB_off >> 4) & 0x1ffffc;
164
int loffs = (blit_sourceB_off >> 4) & 0x000003;
166
if (force_sourceB_zero) {
171
if (offs != srcb_data_offs) {
172
memcpy(srcb_data, &mem_ram[offs], 4);
173
srcb_data_offs = offs;
176
sourceB = srcb_data[loffs];
181
static int do_blitter_write(void)
183
int sourceA_right_shift = GET_REG8(0x1e) & 0x07;
184
int mintermALU = (GET_REG8(0x1e) >> 3) & 0x07;
185
int write_if_sourceA_zero = GET_REG8(0x1b) & 0x02;
186
int write_if_sourceA_nonzero = GET_REG8(0x1b) & 0x04;
189
int offs = (blit_dest_off >> 4) & 0x1fffff;
192
if(!(write_if_sourceA_zero || write_if_sourceA_nonzero)) {
193
write_if_sourceA_zero = write_if_sourceA_nonzero = 1;
196
if ( (write_if_sourceA_zero && sourceA == 0) ||
197
(write_if_sourceA_nonzero && sourceA != 0) ||
198
(have_blitter_bug && srca_fetched) ) {
200
BYTE lastA_tmp = sourceA;
201
sourceA >>= sourceA_right_shift;
202
sourceA |= lastA << (8 - sourceA_right_shift);
207
case 0: dest = sourceA & sourceB; break;
208
case 1: dest = ~(sourceA & sourceB); break;
209
case 2: dest = ~(sourceA | sourceB); break;
210
case 3: dest = sourceA | sourceB; break;
211
case 4: dest = sourceA ^ sourceB; break;
212
case 5: dest = ~(sourceA ^ sourceB); break;
213
case 6: dest = sourceA + sourceB; break;
214
case 7: dest = sourceA - sourceB; break;
218
mem_ram[offs] = dest;
221
if(blitter_log_enabled) log_message(c64dtvblitter_log, "Blitter: %s %x.%x/%x.%x to %x.%x, %d to go, minterm %d", was_write ? "transferred" : "skipped", blit_sourceA_off >> 4, blit_sourceA_off & 15, blit_sourceB_off >> 4, blit_sourceB_off & 15, blit_dest_off >> 4, blit_dest_off & 15, blitter_count - 1, mintermALU);
225
static void update_counters(void)
227
int sourceA_modulo = GET_REG16(0x03);
228
int sourceA_line_length = GET_REG16(0x05);
229
int sourceA_step = GET_REG8(0x07);
230
int sourceB_modulo = GET_REG16(0x0b);
231
int sourceB_line_length = GET_REG16(0x0d);
232
int sourceB_step = GET_REG8(0x0f);
233
int dest_modulo = GET_REG16(0x13);
234
int dest_line_length = GET_REG16(0x15);
235
int dest_step = GET_REG8(0x17);
236
int sourceA_direction = (GET_REG8(0x1a)&0x02) ? +1 : -1;
237
int sourceB_direction = (GET_REG8(0x1a)&0x04) ? +1 : -1;
238
int dest_direction = (GET_REG8(0x1a)&0x08) ? +1 : -1;
240
if(sourceA_line_off >= sourceA_line_length) {
242
sourceA_line_off = 0;
243
blit_sourceA_off = ((blit_sourceA_off >> 4) + sourceA_modulo * sourceA_direction) << 4;
246
blit_sourceA_off += sourceA_step * sourceA_direction;
248
if(sourceB_line_off >= sourceB_line_length) {
249
sourceB_line_off = 0;
250
blit_sourceB_off = ((blit_sourceB_off >> 4) + sourceB_modulo * sourceB_direction) << 4;
253
blit_sourceB_off += sourceB_step * sourceB_direction;
255
if(dest_line_off >= dest_line_length) {
257
blit_dest_off = ((blit_dest_off >> 4) + dest_modulo * dest_direction) << 4;
260
blit_dest_off += dest_step * dest_direction;
264
/* 32 MHz processing clock */
266
static void perform_blitter_cycle(void)
269
while (subcycle < SUBCYCLES) {
270
switch (blitter_state) {
272
subcycle += SUBCYCLES;
275
if (blitter_count == 0) {
276
blitter_state = BLITTER_IDLE;
280
if ( do_blitter_read_a() )
281
subcycle += SUBCYCLES;
282
blitter_state=BLITTER_READ_B;
285
if ( do_blitter_read_b() )
286
subcycle += SUBCYCLES;
287
blitter_state=BLITTER_WRITE;
290
if ( do_blitter_write() )
291
subcycle += SUBCYCLES;
298
if (blitter_count==0)
299
blitter_state=BLITTER_IDLE;
301
blitter_state=BLITTER_READ_A;
304
log_message(c64dtvblitter_log, "invalid state in perform_blitter_cycle()");
305
blitter_state=BLITTER_IDLE;
312
/* ------------------------------------------------------------------------- */
314
/* These are the $D3xx Blitter register engine handlers */
316
/* Blitter IRQ code */
318
static unsigned int c64dtv_blitter_int_num;
319
struct alarm_s *c64dtv_blitter_irq_alarm;
321
void c64dtvblitter_trigger_blitter(void)
323
if(!blitter_active) {
324
int sourceA_continue = GET_REG8(0x1f) & 0x02;
325
int sourceB_continue = GET_REG8(0x1f) & 0x04;
326
int dest_continue = GET_REG8(0x1f) & 0x08;
328
/* last four bits of offsets are fractional */
329
if(!sourceA_continue) {
330
blit_sourceA_off = GET_REG24(0x00) & 0x3fffff;
331
blit_sourceA_off <<= 4;
333
if(!sourceB_continue) {
334
blit_sourceB_off = GET_REG24(0x08) & 0x3fffff;
335
blit_sourceB_off <<= 4;
338
blit_dest_off = GET_REG24(0x10) & 0x3fffff;
342
if(blitter_log_enabled && (sourceA_continue || sourceB_continue || dest_continue)) {
343
log_message(c64dtvblitter_log, "sourceA cont %s, sourceB cont %s, dest cont %s", sourceA_continue ? "on" : "off", sourceB_continue ? "on" : "off", dest_continue ? "on" : "off");
346
/* total number of bytes to transfer */
347
blitter_count = GET_REG16(0x18);
349
/* initialize state variables */
350
sourceA_line_off = 0;
351
sourceB_line_off = 0;
357
blitter_state = BLITTER_READ_A;
359
#ifndef CYCLE_EXACT_BLITTER
360
int blitter_time = 0;
363
perform_blitter_cycle();
365
} while (blitter_state != BLITTER_IDLE);
367
alarm_set(c64dtv_blitter_irq_alarm, maincpu_clk+blitter_time);
370
if (GET_REG8(0x1a) & 0x80) {
372
} else blitter_irq = 0;
379
void c64dtv_blitter_irq_alarm_handler(CLOCK offset, void *data)
381
if(blitter_log_enabled) log_message(c64dtvblitter_log, "IRQ/Done");
383
maincpu_set_irq(c64dtv_blitter_int_num, 1);
386
alarm_unset(c64dtv_blitter_irq_alarm);
387
blitter_busy &= 0xfe;
391
if (dma_on_irq & 0x20) {
392
c64dtvdma_trigger_dma();
396
void c64dtv_blitter_irq_init(void)
398
c64dtv_blitter_int_num = interrupt_cpu_status_int_new(maincpu_int_status, "C64DTVBLITTER");
400
c64dtv_blitter_irq_alarm = alarm_new(maincpu_alarm_context, "C64DTVBLITTERIrq",
401
c64dtv_blitter_irq_alarm_handler, NULL);
405
void c64dtv_blitter_store(WORD addr, BYTE value)
407
/* Store first, then check whether DMA access has been requested,
408
perform if necessary. */
409
c64dtvmem_blitter[addr] = value;
412
blitter_on_irq = GET_REG8(0x1a)&0x70;
414
/* Clear Blitter IRQ */
415
if((GET_REG8(0x1f)&0x01) && (blitter_busy==2)){
416
if(blitter_log_enabled) log_message(c64dtvblitter_log, "Clear IRQ (%i)", blitter_busy);
417
blitter_busy &= 0xfd;
418
maincpu_set_irq(c64dtv_blitter_int_num, 0);
420
/* reset clear IRQ strobe bit */
421
c64dtvmem_blitter[0x1f] &= 0xfe;
424
if(blitter_on_irq && (blitter_busy==0)) {
426
if(blitter_log_enabled) log_message(c64dtvblitter_log, "Scheduled Blitter (%02x)", blitter_on_irq);
430
/* Force Blitter start */
431
if(GET_REG8(0x1a)&0x01) {
432
c64dtvblitter_trigger_blitter();
433
/* reset force start strobe bit */
434
c64dtvmem_blitter[0x1a] &= 0xfe;
439
int c64dtvblitter_perform_blitter(void)
441
#ifdef CYCLE_EXACT_BLITTER
443
perform_blitter_cycle();
445
if(blitter_state == BLITTER_IDLE) {
446
c64dtv_blitter_irq_alarm_handler(0, NULL);
455
/* ------------------------------------------------------------------------- */
457
/* These are called on read/writes to $D3xx */
459
BYTE REGPARM1 c64dtv_dmablit_read(WORD addr)
461
if (!vicii_extended_regs())
462
return vicii_read(addr);
464
if((addr&0xff)==0x1f)
466
if((addr&0xff)==0x3f)
468
/* the default return value is 0x00 too but I have seen some strangeness
469
here. I've seen something that looks like DMAed data. - tlr */
474
void REGPARM2 c64dtv_dmablit_store(WORD addr, BYTE value)
476
if (!vicii_extended_regs()) {
477
vicii_store(addr, value);
483
if (addr & 0x20) c64dtv_blitter_store((WORD)(addr & 0x1f), value);
484
else c64dtv_dma_store(addr, value);
488
/* ------------------------------------------------------------------------- */
489
static int set_dtvrevision(int val, void *param)
500
have_blitter_bug = (dtvrevision == 2) ? 1 : 0;
504
static int set_blitter_log(int val, void *param)
506
blitter_log_enabled = val;
510
static const resource_int_t resources_int[] = {
511
{ "DtvRevision", 3, RES_EVENT_SAME, NULL,
512
&dtvrevision, set_dtvrevision, NULL },
513
{ "DtvBlitterLog", 0, RES_EVENT_NO, (resource_value_t)0,
514
&blitter_log_enabled, set_blitter_log, NULL },
518
int c64dtvblitter_resources_init(void)
520
return resources_register_int(resources_int);
523
void c64dtvblitter_resources_shutdown(void)
527
static const cmdline_option_t cmdline_options[] =
529
{ "-dtvrev", SET_RESOURCE, 1,
530
NULL, NULL, "DtvRevision", NULL,
531
USE_PARAM_ID, USE_DESCRIPTION_ID,
532
IDCLS_P_REVISION, IDCLS_SPECIFY_DTV_REVISION,
534
{ "-dtvblitterlog", SET_RESOURCE, 0,
535
NULL, NULL, "DtvBlitterLog", (resource_value_t)1,
536
USE_PARAM_STRING, USE_DESCRIPTION_ID,
537
IDCLS_UNUSED, IDCLS_ENABLE_DTV_BLITTER_LOG,
539
{ "+dtvblitterlog", SET_RESOURCE, 0,
540
NULL, NULL, "DtvBlitterLog", (resource_value_t)0,
541
USE_PARAM_STRING, USE_DESCRIPTION_ID,
542
IDCLS_UNUSED, IDCLS_DISABLE_DTV_BLITTER_LOG,
547
int c64dtvblitter_cmdline_options_init(void)
549
return cmdline_register_options(cmdline_options);
552
/* ------------------------------------------------------------------------- */
557
static log_t c64_snapshot_log = LOG_ERR;
559
static const char snap_blitter_module_name[] = "C64DTVBLITTER";
561
int c64dtvblitter_snapshot_write_module(snapshot_t *s)
563
snapshot_module_t *m;
565
/* Blitter module. */
566
m = snapshot_module_create(s, snap_blitter_module_name, SNAP_MAJOR, SNAP_MINOR);
570
if (SMW_BA(m, c64dtvmem_blitter, 0x20) < 0
571
|| SMW_DW(m, blit_sourceA_off) < 0
572
|| SMW_DW(m, blit_sourceB_off) < 0
573
|| SMW_DW(m, blit_dest_off) < 0
574
|| SMW_DW(m, blitter_busy) < 0
575
|| SMW_DW(m, blitter_irq) < 0
576
|| SMW_DW(m, blitter_on_irq) < 0
577
|| SMW_DW(m, blitter_active) < 0
578
|| SMW_BA(m, srca_data, 4) < 0
579
|| SMW_DW(m, srca_data_offs) < 0
580
|| SMW_DW(m, srca_fetched) < 0
581
|| SMW_BA(m, srcb_data, 4) < 0
582
|| SMW_DW(m, srcb_data_offs) < 0
583
|| SMW_B(m, sourceA) < 0
584
|| SMW_B(m, sourceB) < 0
585
|| SMW_DW(m, blitter_count) < 0
586
|| SMW_DW(m, blitter_state) < 0
587
|| SMW_DW(m, sourceA_line_off) < 0
588
|| SMW_DW(m, sourceB_line_off) < 0
589
|| SMW_DW(m, dest_line_off) < 0
590
|| SMW_B(m, lastA) < 0)
593
if (snapshot_module_close(m) < 0)
601
snapshot_module_close(m);
606
int c64dtvblitter_snapshot_read_module(snapshot_t *s)
608
BYTE major_version, minor_version;
609
snapshot_module_t *m;
610
int temp_blitter_state;
612
/* Blitter module. */
613
m = snapshot_module_open(s, snap_blitter_module_name,
614
&major_version, &minor_version);
618
if (major_version > SNAP_MAJOR || minor_version > SNAP_MINOR) {
619
log_error(c64_snapshot_log,
620
"Snapshot module version (%d.%d) newer than %d.%d.",
621
major_version, minor_version,
622
SNAP_MAJOR, SNAP_MINOR);
626
if (SMR_BA(m, c64dtvmem_blitter, 0x20) < 0
627
|| SMR_DW_INT(m, &blit_sourceA_off) < 0
628
|| SMR_DW_INT(m, &blit_sourceB_off) < 0
629
|| SMR_DW_INT(m, &blit_dest_off) < 0
630
|| SMR_DW_INT(m, &blitter_busy) < 0
631
|| SMR_DW_INT(m, &blitter_irq) < 0
632
|| SMR_DW_INT(m, &blitter_on_irq) < 0
633
|| SMR_DW_INT(m, &blitter_active) < 0
634
|| SMR_BA(m, srca_data, 4) < 0
635
|| SMR_DW_INT(m, &srca_data_offs) < 0
636
|| SMR_DW_INT(m, &srca_fetched) < 0
637
|| SMR_BA(m, srcb_data, 4) < 0
638
|| SMR_DW_INT(m, &srcb_data_offs) < 0
639
|| SMR_B(m, &sourceA) < 0
640
|| SMR_B(m, &sourceB) < 0
641
|| SMR_DW_INT(m, &blitter_count) < 0
642
|| SMR_DW_INT(m, &temp_blitter_state) < 0
643
|| SMR_DW_INT(m, &sourceA_line_off) < 0
644
|| SMR_DW_INT(m, &sourceB_line_off) < 0
645
|| SMR_DW_INT(m, &dest_line_off) < 0
646
|| SMR_B(m, &lastA) < 0)
649
blitter_state = temp_blitter_state;
651
if (snapshot_module_close(m) < 0)
659
snapshot_module_close(m);