wip prep commit in lieu of gfx subsystem update changes.
[AROS.git] / arch / m68k-amiga / hidd / amigavideo / chipset.c
blob6b46e89e982c215d5a893b2b26c86d46d7327585
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <proto/exec.h>
7 #include <proto/graphics.h>
8 #include <proto/cia.h>
10 #include <exec/libraries.h>
11 #include <hardware/custom.h>
12 #include <hardware/intbits.h>
13 #include <hardware/cia.h>
14 #include <hidd/gfx.h>
15 #include <graphics/modeid.h>
17 #include "amigavideo_hidd.h"
18 #include "amigavideo_bitmap.h"
19 #include "chipset.h"
21 #define DEBUG 0
22 #include <aros/debug.h>
24 static const UBYTE fetchunits[] = { 3,3,3,0, 4,3,3,0, 5,4,3,0 };
25 static const UBYTE fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
27 /* reset to OCS defaults */
28 void resetcustom(struct amigavideo_staticdata *data)
30 volatile struct Custom *custom = (struct Custom*)0xdff000;
31 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
33 custom->fmode = 0x0000;
34 custom->bplcon0 = 0x0200;
35 custom->bplcon1 = 0x0000;
36 custom->bplcon2 = 0x0024;
37 custom->bplcon3 = 0x0c00;
38 custom->bplcon4 = 0x0011;
39 custom->vposw = 0x8000;
40 custom->color[0] = 0x0444;
42 // Use AGA modes and create AGA copperlists only if AGA is "enabled"
43 data->aga_enabled = data->aga && GfxBase->ChipRevBits0 == SETCHIPREV_AA;
46 static void waitvblank(struct amigavideo_staticdata *data)
48 // ugly busy loop for now..
49 UWORD fc = data->framecounter;
50 while (fc == data->framecounter);
53 static void setnullsprite(struct amigavideo_staticdata *data)
55 if (data->copper1_spritept) {
56 UWORD *p = data->sprite_null;
57 data->copper1_spritept[0] = (UWORD)(((ULONG)p) >> 16);
58 data->copper1_spritept[2] = (UWORD)(((ULONG)p) >> 0);
62 void resetsprite(struct amigavideo_staticdata *data)
64 UWORD *sprite = data->sprite;
65 setnullsprite(data);
66 data->sprite = NULL;
67 FreeMem(sprite, data->spritedatasize);
68 data->sprite_width = data->sprite_height = 0;
71 static void setfmode(struct amigavideo_staticdata *data)
73 UWORD fmode;
74 fmode = data->fmode_bpl == 2 ? 3 : data->fmode_bpl;
75 fmode |= (data->fmode_spr == 2 ? 3 : data->fmode_spr) << 2;
76 if (data->copper2.copper2_fmode) {
77 *data->copper2.copper2_fmode = fmode;
78 if (data->interlace)
79 *data->copper2i.copper2_fmode = fmode;
83 static void setcoppercolors(struct amigavideo_staticdata *data)
85 UWORD i;
87 if (!data->copper2.copper2_palette)
88 return;
89 if (data->aga && data->aga_enabled) {
90 UWORD off = 1;
91 for (i = 0; i < data->use_colors; i++) {
92 UWORD vallo, valhi;
93 UBYTE r = data->palette[i * 3 + 0];
94 UBYTE g = data->palette[i * 3 + 1];
95 UBYTE b = data->palette[i * 3 + 2];
96 if ((i & 31) == 0)
97 off += 2;
98 valhi = ((r & 0xf0) << 4) | ((g & 0xf0)) | ((b & 0xf0) >> 4);
99 vallo = ((r & 0x0f) << 8) | ((g & 0x0f) << 4) | ((b & 0x0f));
100 data->copper2.copper2_palette[i * 2 + off] = valhi;
101 data->copper2.copper2_palette_aga_lo[i * 2 + off] = vallo;
102 if (data->interlace) {
103 data->copper2i.copper2_palette[i * 2 + off] = valhi;
104 data->copper2i.copper2_palette_aga_lo[i * 2 + off] = vallo;
107 } else if (data->res == 2 && !data->aga) {
108 /* ECS "scrambled" superhires */
109 for (i = 0; i < data->use_colors; i++) {
110 UBYTE offset = i < 16 ? 0 : 16;
111 UBYTE c1 = (i & 3) + offset;
112 UBYTE c2 = ((i >> 2) & 3) + offset;
113 UWORD val1 = ((data->palette[c1 * 3 + 0] >> 4) << 8) | ((data->palette[c1 * 3 + 1] >> 4) << 4) | ((data->palette[c1 * 3 + 2] >> 4) << 0);
114 UWORD val2 = ((data->palette[c2 * 3 + 0] >> 4) << 8) | ((data->palette[c2 * 3 + 1] >> 4) << 4) | ((data->palette[c2 * 3 + 2] >> 4) << 0);
115 UWORD val = (val1 & 0xccc) | ((val2 & 0xccc) >> 2);
116 data->copper2.copper2_palette[i * 2 + 1] = val;
117 if (data->interlace)
118 data->copper2i.copper2_palette[i * 2 + 1] = val;
121 } else {
122 for (i = 0; i < data->use_colors; i++) {
123 UWORD val = ((data->palette[i * 3 + 0] >> 4) << 8) | ((data->palette[i * 3 + 1] >> 4) << 4) | ((data->palette[i * 3 + 2] >> 4) << 0);
124 data->copper2.copper2_palette[i * 2 + 1] = val;
125 if (data->interlace)
126 data->copper2i.copper2_palette[i * 2 + 1] = val;
131 static void setpalntsc(struct amigavideo_staticdata *data, ULONG modeid)
133 volatile struct Custom *custom = (struct Custom*)0xdff000;
134 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
136 data->palmode = (GfxBase->DisplayFlags & NTSC) == 0;
137 if (!data->ecs_agnus)
138 return;
139 if ((modeid & MONITOR_ID_MASK) == PAL_MONITOR_ID) {
140 custom->beamcon0 = 0x0020;
141 data->palmode = TRUE;
142 } else if ((modeid & MONITOR_ID_MASK) == NTSC_MONITOR_ID) {
143 custom->beamcon0 = 0x0000;
144 data->palmode = FALSE;
145 } else {
146 custom->beamcon0 = (GfxBase->DisplayFlags & NTSC) ? 0x0000 : 0x0020;
150 void resetmode(struct amigavideo_staticdata *data)
152 volatile struct Custom *custom = (struct Custom*)0xdff000;
153 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
155 D(bug("resetmode\n"));
157 data->disp = NULL;
159 custom->dmacon = 0x0100;
160 setpalntsc(data, 0);
162 custom->cop2lc = (ULONG)data->copper2_backup;
163 custom->copjmp2 = 0;
165 waitvblank(data);
167 FreeVec(data->copper2.copper2);
168 data->copper2.copper2 = NULL;
169 FreeVec(data->copper2i.copper2);
170 data->copper2i.copper2 = NULL;
172 GfxBase->LOFlist = GfxBase->SHFlist = data->copper2_backup;
174 resetcustom(data);
176 data->depth = 0;
179 /* Use nominal screen height. Overscan is not supported yet. */
180 static WORD limitheight(struct amigavideo_staticdata *data, WORD y, BOOL lace, BOOL maxlimit)
182 if (lace)
183 y /= 2;
184 if (data->palmode) {
185 if (maxlimit && y > 311)
186 y = 311;
187 else if (!maxlimit && y > 256)
188 y = 256;
189 } else {
190 if (maxlimit && y > 261)
191 y = 261;
192 else if (!maxlimit && y > 200)
193 y = 200;
195 if (lace)
196 y *= 2;
197 return y;
200 static void setcopperscroll2(struct amigavideo_staticdata *data, struct amigabm_data *bm, struct copper2data *c2d, BOOL odd)
202 UWORD *copptr = c2d->copper2_scroll, *copbpl;
203 WORD xscroll, yscroll;
204 WORD x, y;
205 WORD ystart, yend, i, xdelay;
206 WORD xmaxscroll, modulo, ddfstrt, fmodewidth, minearly;
207 LONG offset;
209 fmodewidth = 16 << data->fmode_bpl;
210 x = bm->leftedge;
211 y = data->starty + (bm->topedge >> data->interlace);
213 yscroll = 0;
214 if (y < 10) {
215 yscroll = y - 10;
216 y = 10;
219 xmaxscroll = 1 << (1 + data->fmode_bpl);
220 xdelay = x & (fmodewidth - 1);
221 xscroll = -x;
223 yend = y + (bm->displayheight >> data->interlace);
224 yend = limitheight(data, yend, FALSE, TRUE);
225 ystart = y - data->extralines;
227 modulo = (data->interlace ? bm->bytesperrow : 0) + data->modulo;
228 ddfstrt = data->ddfstrt;
230 offset = ((xscroll + (xmaxscroll << 3) - 1) >> 3) & ~(xmaxscroll - 1);
231 offset -= (yscroll * bm->bytesperrow) << (data->interlace ? 1 : 0);
233 minearly = 1 << fetchunits[data->fmode_bpl * 4 + data->res];
234 if (xdelay) {
235 ddfstrt -= minearly;
236 modulo -= (minearly << data->res) / 4;
237 offset -= (minearly << data->res) / 4;
240 copptr[1] = (y << 8) | (data->startx); //(y << 8) + (x + 1);
241 copptr[3] = (yend << 8) | ((data->startx + 0x140) & 0xff); //((y + (bm->rows >> data->interlace)) << 8) + ((x + 1 + (bm->width >> data->res)) & 0x00ff);
242 copptr[5] = ((y >> 8) & 7) | (((yend >> 8) & 7) << 8) | 0x2000;
244 copbpl = c2d->copper2_bpl;
245 for (i = 0; i < bm->depth; i++) {
246 ULONG pptr = (ULONG)(bm->pbm->Planes[data->bploffsets[i]]);
247 if (data->interlace && odd)
248 pptr += bm->bytesperrow;
249 pptr += offset;
250 copbpl[1] = (UWORD)(pptr >> 16);
251 copbpl[3] = (UWORD)(pptr >> 0);
252 copbpl += 4;
255 xdelay <<= 2 - data->res;
256 copptr[11] =
257 (((xdelay >> 2) & 0x0f) << 0) | (((xdelay >> 2) & 0x0f) << 4)
258 | ((xdelay >> 6) << 10) | ((xdelay >> 6) << 14)
259 | ((xdelay & 3) << 8) | ((xdelay & 3) << 12);
261 copptr[7] = ddfstrt;
262 copptr[9] = data->ddfstop;
263 copptr[13] = modulo;
264 copptr[15] = modulo;
266 yend = y + bm->displayheight + yscroll;
267 yend = limitheight(data, yend, FALSE, TRUE);
268 copptr = c2d->copper2_bplcon0;
269 copptr[4] = (yend << 8) | 0x05;
270 if (yend < 256 || ystart >= 256) {
271 copptr[2] = 0x00df;
272 copptr[3] = 0x00fe;
273 } else {
274 copptr[2] = 0xffdf;
275 copptr[3] = 0xfffe;
278 copptr = c2d->copper2;
279 if (ystart >= 256)
280 copptr[0] = 0xffdf;
281 else
282 copptr[0] = 0x01fe;
283 copptr[2] = (ystart << 8) | 0x05;
284 copptr = c2d->copper2_bplcon0;
285 copptr[-2] = (y << 8) | 0x05;
288 static void setcopperscroll(struct amigavideo_staticdata *data, struct amigabm_data *bm)
290 setcopperscroll2(data, bm, &data->copper2, FALSE);
291 if (data->interlace)
292 setcopperscroll2(data, bm, &data->copper2i, TRUE);
295 static UWORD get_copper_list_length(struct amigavideo_staticdata *data, UBYTE depth)
297 UWORD v;
299 if (data->aga && data->aga_enabled) {
300 v = 1000 + ((1 << depth) + 1 + (1 << depth) / 32 + 1) * 2;
301 } else {
302 v = 1000;
304 return v * 2;
307 static void createcopperlist(struct amigavideo_staticdata *data, struct amigabm_data *bm, struct copper2data *c2d, BOOL lace)
309 UWORD *c;
310 UWORD i;
311 UWORD bplcon0, bplcon0_res;
312 ULONG pptr;
314 c = c2d->copper2;
315 D(bug("Copperlist%d %p\n", lace ? 2 : 1, c));
317 if (data->res == 1)
318 bplcon0_res = 0x8000;
319 else if (data->res == 2)
320 bplcon0_res = 0x0040;
321 else
322 bplcon0_res = 0;
324 data->bplcon0_null = 0x0201 | (data->interlace ? 4 : 0) | bplcon0_res;
325 data->bplcon3 = ((data->sprite_res + 1) << 6) | 2; // spriteres + bordersprite
327 *c++ = 0x01fe;
328 *c++ = 0xfffe;
329 *c++ = 0xffff;
330 *c++ = 0xfffe;
332 *c++ = 0x0100;
333 *c++ = data->bplcon0_null;
335 c2d->copper2_bpl = c;
336 for (i = 0; i < bm->depth; i++) {
337 pptr = (ULONG)(bm->pbm->Planes[data->bploffsets[i]]);
338 if (lace)
339 pptr += bm->bytesperrow;
340 *c++ = 0xe0 + i * 4;
341 *c++ = (UWORD)(pptr >> 16);
342 *c++ = 0xe2 + i * 4;
343 *c++ = (UWORD)(pptr >> 0);
346 data->use_colors = 1 << bm->depth;
347 // need to update sprite colors
348 if (data->use_colors < 16 + 4)
349 data->use_colors = 16 + 4;
350 if (data->res == 2 && !data->aga)
351 data->use_colors = 32; /* ECS "scrambled" superhires */
353 if (data->use_colors > 32 && (data->modeid & EXTRAHALFBRITE_KEY))
354 data->use_colors = 32;
355 if (data->modeid & HAM_KEY) {
356 if (bm->depth <= 6)
357 data->use_colors = 16 + 4;
358 else
359 data->use_colors = 64;
362 c2d->copper2_scroll = c;
363 *c++ = 0x008e;
364 *c++ = 0;
365 *c++ = 0x0090;
366 *c++ = 0;
367 *c++ = 0x01e4;
368 *c++ = 0;
369 *c++ = 0x0092;
370 *c++ = 0;
371 *c++ = 0x0094;
372 *c++ = 0;
373 *c++ = 0x0102;
374 *c++ = 0;
375 *c++ = 0x0108;
376 *c++ = 0;
377 *c++ = 0x010a;
378 *c++ = 0;
379 *c++ = 0x0104;
380 *c++ = 0x0024 | ((data->aga && !(data->modeid & EXTRAHALFBRITE_KEY)) ? 0x0200 : 0);
382 c2d->copper2_fmode = NULL;
383 if (data->aga && data->aga_enabled) {
384 *c++ = 0x010c;
385 *c++ = 0x0011;
386 *c++ = 0x01fc;
387 c2d->copper2_fmode = c;
388 *c++ = 0;
391 bplcon0 = data->bplcon0_null;
392 if (bm->depth > 7)
393 bplcon0 |= 0x0010;
394 else
395 bplcon0 |= bm->depth << 12;
396 if (data->modeid & HAM_KEY)
397 bplcon0 |= 0x0800;
399 c2d->copper2_palette = c;
400 if (data->aga && data->aga_enabled) {
401 // hi
402 for (i = 0; i < data->use_colors; i++) {
403 UBYTE agac = i & 31;
404 if (agac == 0) {
405 *c++ = 0x106;
406 *c++ = data->bplcon3 | ((i / 32) << 13);
408 *c++ = 0x180 + agac * 2;
409 *c++ = 0x000;
411 c2d->copper2_palette_aga_lo = c;
412 // lo
413 for (i = 0; i < data->use_colors; i++) {
414 UBYTE agac = i & 31;
415 if (agac == 0) {
416 *c++ = 0x106;
417 *c++ = data->bplcon3 | ((i / 32) << 13) | 0x0200;
419 *c++ = 0x180 + agac * 2;
420 *c++ = 0x000;
422 *c++ = 0x106;
423 *c++ = data->bplcon3;
424 } else {
425 // ocs/ecs
426 for (i = 0; i < data->use_colors; i++) {
427 *c++ = 0x180 + i * 2;
428 *c++ = 0x000;
432 data->extralines = (c - c2d->copper2) / 112 + 1;
434 *c++ = 0xffff;
435 *c++ = 0xfffe;
436 c2d->copper2_bplcon0 = c;
437 *c++ = 0x0100;
438 *c++ = bplcon0;
440 *c++ = 0xffff;
441 *c++ = 0xfffe;
442 *c++ = 0xffff;
443 *c++ = 0xfffe;
445 *c++ = 0x0100;
446 *c++ = data->bplcon0_null;
448 if (data->interlace) {
449 ULONG nextptr = (ULONG)(lace ? data->copper2.copper2 : data->copper2i.copper2);
450 *c++ = 0x0084;
451 *c++ = (UWORD)(nextptr >> 16);
452 *c++ = 0x0086;
453 *c++ = (UWORD)(nextptr >> 0);
455 *c++ = 0xffff;
456 *c++ = 0xfffe;
460 BOOL setbitmap(struct amigavideo_staticdata *data, struct amigabm_data *bm)
462 data->width = bm->width;
463 data->height = data->interlace ? (bm->height + 1) / 2 : bm->height;
464 data->modulo = bm->bytesperrow - data->modulopre / (4 >> data->res);
465 data->modulo &= ~((2 << data->fmode_bpl) - 1);
466 data->updatescroll = bm;
467 data->depth = bm->depth;
468 setcopperscroll(data, bm);
470 D(bug("setbitmap bm=%x mode=%08x w=%d h=%d d=%d bpr=%d\n",
471 bm, data->modeid, bm->width, bm->height, bm->depth, bm->bytesperrow));
472 return TRUE;
475 BOOL setmode(struct amigavideo_staticdata *data, struct amigabm_data *bm)
477 volatile struct Custom *custom = (struct Custom*)0xdff000;
478 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
479 UWORD ddfstrt, ddfstop;
480 UBYTE fetchunit, maxplanes;
481 UWORD bplwidth, viewwidth;
482 UBYTE i;
484 if (data->disp == bm)
485 return TRUE;
487 resetmode(data);
489 data->res = 0;
490 if ((data->modeid & SUPER_KEY) == SUPER_KEY)
491 data->res = 2;
492 else if ((data->modeid & SUPER_KEY) == HIRES_KEY)
493 data->res = 1;
494 data->interlace = (data->modeid & LORESLACE_KEY) ? 1 : 0;
495 data->fmode_bpl = data->aga && data->aga_enabled ? 2 : 0;
497 fetchunit = fetchunits[data->fmode_bpl * 4 + data->res];
498 maxplanes = fm_maxplanes[data->fmode_bpl * 4 + data->res];
500 D(bug("res %d fmode %d depth %d maxplanes %d aga %d agae %d\n",
501 data->res, data->fmode_bpl, bm->depth, maxplanes, data->aga, data->aga_enabled));
503 if (bm->depth > (1 << maxplanes)) {
504 if (data->aga && !data->aga_enabled) {
505 // Enable AGA if requesting AGA only mode.
506 // This is a compatibility hack because our display
507 // database currently contains all AGA modes even if AGA
508 // is "disabled".
509 GfxBase->ChipRevBits0 = SETCHIPREV_AA;
510 data->aga_enabled = TRUE;
511 data->fmode_bpl = data->aga && data->aga_enabled ? 2 : 0;
512 fetchunit = fetchunits[data->fmode_bpl * 4 + data->res];
513 maxplanes = fm_maxplanes[data->fmode_bpl * 4 + data->res];
515 if (bm->depth > (1 << maxplanes))
516 return FALSE;
519 viewwidth = bm->width;
520 // use nominal width for now
521 if ((viewwidth << data->res) > 320)
522 viewwidth = 320 << data->res;
524 D(bug("setmode bm=%x mode=%08x w=%d h=%d d=%d bpr=%d fu=%d\n",
525 bm, data->modeid, bm->width, bm->height, bm->depth, bm->bytesperrow, fetchunit));
527 bplwidth = viewwidth >> (data->res + 1);
528 ddfstrt = (data->startx / 2) & ~((1 << fetchunit) - 1);
529 ddfstop = ddfstrt + ((bplwidth + ((1 << fetchunit) - 1) - 2 * (1 << fetchunit)) & ~((1 << fetchunit) - 1));
530 data->modulopre = ddfstop + 2 * (1 << fetchunit) - ddfstrt;
531 ddfstrt -= 1 << maxplanes;
532 data->ddfstrt = ddfstrt;
533 data->ddfstop = ddfstop;
535 for (i = 0; i < 8; i++)
536 data->bploffsets[i] = i;
537 if ((data->modeid & HAM_KEY) && bm->depth > 6) {
538 data->bploffsets[0] = 6;
539 data->bploffsets[1] = 7;
540 for (i = 0; i < 6; i++)
541 data->bploffsets[i + 2] = i;
544 data->copper2.copper2 = AllocVec(get_copper_list_length(data, bm->depth), MEMF_CLEAR | MEMF_CHIP);
545 if (data->interlace)
546 data->copper2i.copper2 = AllocVec(get_copper_list_length(data, bm->depth), MEMF_CLEAR | MEMF_CHIP);
547 createcopperlist(data, bm, &data->copper2, FALSE);
548 if (data->interlace) {
549 createcopperlist(data, bm, &data->copper2i, TRUE);
552 setfmode(data);
553 setpalntsc(data, data->modeid);
554 custom->bplcon0 = data->bplcon0_null;
556 bm->displaywidth = viewwidth;
557 bm->displayheight = limitheight(data, bm->height, data->interlace, FALSE);
559 setbitmap(data, bm);
561 GfxBase->LOFlist = data->copper2.copper2;
562 GfxBase->SHFlist = data->interlace ? data->copper2i.copper2 : data->copper2.copper2;
563 custom->dmacon = 0x8100;
565 setcoppercolors(data);
566 setspritepos(data, data->spritex, data->spritey);
568 data->disp = bm;
569 return 1;
572 BOOL setsprite(struct amigavideo_staticdata *data, WORD width, WORD height, struct pHidd_Gfx_SetCursorShape *shape)
574 OOP_MethodID HiddBitMapBase = data->cs_HiddBitMapBase;
575 UWORD fetchsize;
576 UWORD bitmapwidth = width;
577 UWORD y, *p;
579 if (data->aga && data->aga_enabled && width > 16)
580 data->fmode_spr = 2;
581 else
582 data->fmode_spr = 0;
583 fetchsize = 2 << data->fmode_spr;
584 width = 16 << data->fmode_spr;
586 if (width != data->sprite_width || height != data->sprite_height) {
587 resetsprite(data);
588 data->spritedatasize = fetchsize * 2 + fetchsize * height * 2 + fetchsize * 2;
589 data->sprite = AllocMem(data->spritedatasize, MEMF_CHIP | MEMF_CLEAR);
590 if (!data->sprite)
591 return FALSE;
592 data->sprite_width = width;
593 data->sprite_height = height;
594 data->sprite_offset_x = shape->xoffset;
595 data->sprite_offset_y = shape->yoffset;
597 p = data->sprite;
598 p += fetchsize;
599 for(y = 0; y < height; y++) {
600 UWORD xx, xxx, x;
601 for (xx = 0, xxx = 0; xx < width; xx += 16, xxx++) {
602 UWORD pix1 = 0, pix2 = 0;
603 for(x = 0; x < 16; x++) {
604 UBYTE c = 0;
605 if (xx + x < bitmapwidth)
606 c = HIDD_BM_GetPixel(shape->shape, xx + x, y);
607 #if 0
608 /* Sprite alignment grid */
609 if (xx + x == 0 || xx + x == width - 1 || y == 0 || y == height - 1) {
610 c = 2;
611 } else if (0) {
612 c = 0;
614 #endif
615 pix1 <<= 1;
616 pix2 <<= 1;
617 pix1 |= (c & 1) ? 1 : 0;
618 pix2 |= (c & 2) ? 1 : 0;
620 p[xxx] = pix1;
621 p[xxx + fetchsize / 2] = pix2;
623 p += fetchsize;
625 setspritepos(data, data->spritex, data->spritey);
626 setspritevisible(data, data->cursorvisible);
627 return TRUE;
630 void setspritepos(struct amigavideo_staticdata *data, WORD x, WORD y)
632 UWORD ctl, pos;
634 data->spritex = x;
635 data->spritey = y;
636 if (!data->sprite || data->sprite_height == 0)
637 return;
639 x += data->sprite_offset_x << data->res;
640 x <<= (2 - data->res); // convert x to shres coordinates
641 x += (data->startx - 1) << 2; // display left edge offset
643 if (data->interlace)
644 y /= 2; // y is always in nonlaced
645 y += data->starty;
646 y += data->sprite_offset_y;
648 pos = (y << 8) | (x >> 3);
649 ctl = ((y + data->sprite_height) << 8);
650 ctl |= ((y >> 8) << 2) | (((y + data->sprite_height) >> 8) << 1) | ((x >> 2) & 1) | ((x & 3) << 3);
651 data->spritepos = pos;
652 data->spritectl = ctl;
655 void setspritevisible(struct amigavideo_staticdata *data, BOOL visible)
657 data->cursorvisible = visible;
658 if (visible) {
659 if (data->copper1_spritept) {
660 UWORD *p = data->sprite;
661 setfmode(data);
662 data->copper1_spritept[0] = (UWORD)(((ULONG)p) >> 16);
663 data->copper1_spritept[2] = (UWORD)(((ULONG)p) >> 0);
665 } else {
666 setnullsprite(data);
670 BOOL setcolors(struct amigavideo_staticdata *data, struct pHidd_BitMap_SetColors *msg, BOOL visible)
672 UWORD i, j;
673 if (msg->firstColor + msg->numColors > data->max_colors)
674 return FALSE;
675 j = 0;
676 for (i = msg->firstColor; j < msg->numColors; i++, j++) {
677 UBYTE red, green, blue;
678 red = msg->colors[j].red >> 8;
679 green = msg->colors[j].green >> 8;
680 blue = msg->colors[j].blue >> 8;
681 data->palette[i * 3 + 0] = red;
682 data->palette[i * 3 + 1] = green;
683 data->palette[i * 3 + 2] = blue;
684 //bug("%d: %02x %02x %02x\n", i, red, green, blue);
686 if (visible)
687 setcoppercolors(data);
688 return TRUE;
690 void setscroll(struct amigavideo_staticdata *data, struct amigabm_data *bm)
692 data->updatescroll = bm;
695 /* Convert Z flag to normal C-style return variable. Fun. */
696 UBYTE bltnode_wrapper(void)
698 UBYTE ret;
699 asm volatile (
700 " pea 1f\n"
701 " move.l 4(%%a1),-(%%sp)\n"
702 " rts\n"
703 "1: sne %d0\n"
704 " move.b %%d0,%0\n"
705 : "=g" (ret)
707 return ret;
710 #define BEAMSYNC_ALARM 0x0f00
711 /* AOS must use some GfxBase flags field for these. Later.. */
712 #define bqvar GfxBase->pad3
713 #define BQ_NEXT 1
714 #define BQ_BEAMSYNC 2
715 #define BQ_BEAMSYNCWAITING 4
716 #define BQ_MISSED 8
718 static AROS_INTH1(gfx_blit, struct GfxBase *, GfxBase)
720 AROS_INTFUNC_INIT
722 volatile struct Custom *custom = (struct Custom*)0xdff000;
723 struct bltnode *bn = NULL;
724 UBYTE v;
725 UWORD dmaconr;
727 dmaconr = custom->dmaconr;
728 dmaconr = custom->dmaconr;
729 if (dmaconr & 0x4000) {
730 /* Blitter still active? Wait for next interrupt. */
731 return 0;
734 if (GfxBase->blthd == NULL && GfxBase->bsblthd == NULL) {
735 custom->intena = INTF_BLIT;
736 return 0;
739 /* Was last blit in this node? */
740 if (bqvar & BQ_NEXT) {
741 bqvar &= ~(BQ_NEXT | BQ_MISSED);
742 if (bqvar & BQ_BEAMSYNC)
743 bn = GfxBase->bsblthd;
744 else
745 bn = GfxBase->blthd;
746 if (bn->stat == CLEANUP)
747 AROS_UFC2(UBYTE, bn->cleanup,
748 AROS_UFCA(struct Custom *, custom, A0),
749 AROS_UFCA(struct bltnode*, bn, A1));
750 /* Next node */
751 bn = bn->n;
752 if (bqvar & BQ_BEAMSYNC)
753 GfxBase->bsblthd = bn;
754 else
755 GfxBase->blthd = bn;
758 if (GfxBase->bsblthd) {
759 bn = GfxBase->bsblthd;
760 bqvar |= BQ_BEAMSYNC;
761 } else if (GfxBase->blthd) {
762 bn = GfxBase->blthd;
763 bqvar &= ~BQ_BEAMSYNC;
766 if (!bn) {
767 /* Last blit finished */
768 bqvar = 0;
769 custom->intena = INTF_BLIT;
770 GfxBase->blthd = GfxBase->bsblthd = NULL;
771 DisownBlitter();
772 return 0;
775 if (bqvar & BQ_BEAMSYNC) {
776 UWORD vpos = VBeamPos();
777 bqvar &= ~BQ_BEAMSYNCWAITING;
778 if (!(bqvar & BQ_MISSED) && bn->beamsync > vpos) {
779 volatile struct CIA *ciab = (struct CIA*)0xbfd000;
780 UWORD w = BEAMSYNC_ALARM - (bn->beamsync - vpos);
781 bqvar |= BQ_BEAMSYNCWAITING;
782 ciab->ciacrb &= ~0x80;
783 ciab->ciatodhi = 0;
784 ciab->ciatodmid = w >> 8;
785 ciab->ciatodlow = w;
786 return 0;
790 v = AROS_UFC2(UBYTE, bltnode_wrapper,
791 AROS_UFCA(struct Custom *, custom, A0),
792 AROS_UFCA(struct bltnode*, bn, A1));
794 dmaconr = custom->dmaconr;
795 dmaconr = custom->dmaconr;
796 if (!(dmaconr & 0x4000)) {
797 /* Eh? Blitter not active?, better fake the interrupt. */
798 custom->intreq = INTF_SETCLR | INTF_BLIT;
801 if (v) {
802 /* Handle same node again next time */
803 return 0;
806 bqvar |= BQ_NEXT;
808 return 0;
810 AROS_INTFUNC_EXIT
813 static AROS_INTH1(gfx_beamsync, struct amigavideo_staticdata*, data)
815 AROS_INTFUNC_INIT
817 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
819 if (bqvar & BQ_BEAMSYNCWAITING) {
820 /* We only need to trigger blitter interrupt */
821 volatile struct Custom *custom = (struct Custom*)0xdff000;
822 custom->intreq = INTF_SETCLR | INTF_BLIT;
825 return FALSE;
827 AROS_INTFUNC_EXIT
830 static AROS_INTH1(gfx_vblank, struct amigavideo_staticdata*, data)
832 AROS_INTFUNC_INIT
834 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
835 volatile struct Custom *custom = (struct Custom*)0xdff000;
836 BOOL lof = (custom->vposr & 0x8000) != 0;
838 if (data->interlace) {
839 custom->cop2lc = (ULONG)(lof ? GfxBase->LOFlist : GfxBase->SHFlist);
840 } else {
841 custom->cop2lc = (ULONG)GfxBase->LOFlist;
842 /* We may be in SHF mode after switching interlace off. Fix it here. */
843 if (!lof)
844 custom->vposw = custom->vposr | 0x8000;
847 data->framecounter++;
848 if (data->sprite) {
849 UWORD *p = data->sprite;
850 p[0] = data->spritepos;
851 p[1 << data->fmode_spr] = data->spritectl;
854 if (data->updatescroll) {
855 setcopperscroll(data, data->updatescroll);
856 data->updatescroll = NULL;
859 if (bqvar & BQ_BEAMSYNC)
860 bqvar |= BQ_MISSED;
862 return FALSE;
864 AROS_INTFUNC_EXIT
867 void initcustom(struct amigavideo_staticdata *data)
869 UBYTE i;
870 UWORD *c;
871 UWORD vposr, val;
872 struct GfxBase *GfxBase;
873 struct Library *OOPBase;
874 volatile struct Custom *custom = (struct Custom*)0xdff000;
875 volatile struct CIA *ciab = (struct CIA*)0xbfd000;
877 /* Reset audio registers to values that help emulation
878 * if some program enables audio DMA without setting period
879 * or length. Very high period emulation is very CPU intensive.
881 for (i = 0; i < 4; i++) {
882 custom->aud[i].ac_vol = 0;
883 custom->aud[i].ac_per = 100;
884 custom->aud[i].ac_len = 1000;
887 resetcustom(data);
888 resetsprite(data);
890 /* data->cs_OOPBase was already set up.
891 * See amigavideo.conf's 'oopbase_field' config
893 OOPBase = data->cs_OOPBase;
894 data->cs_HiddBitMapBase = OOP_GetMethodID(IID_Hidd_BitMap, 0);
895 data->cs_HiddGfxBase = OOP_GetMethodID(IID_Hidd_Gfx, 0);
897 data->cs_UtilityBase = TaggedOpenLibrary(TAGGEDOPEN_UTILITY);
898 if (!data->cs_UtilityBase)
899 Alert(AT_DeadEnd | AN_Hidd | AG_OpenLib | AO_UtilityLib);
900 data->cs_GfxBase = TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS);
901 if (!data->cs_GfxBase)
902 Alert(AT_DeadEnd | AN_Hidd | AG_OpenLib | AO_GraphicsLib);
903 GfxBase = ((struct GfxBase *)data->cs_GfxBase);
904 GfxBase->cia = OpenResource("ciab.resource");
906 data->inter.is_Code = (APTR)gfx_vblank;
907 data->inter.is_Data = data;
908 data->inter.is_Node.ln_Name = "GFX VBlank server";
909 data->inter.is_Node.ln_Pri = 25;
910 data->inter.is_Node.ln_Type = NT_INTERRUPT;
911 AddIntServer(INTB_VERTB, &data->inter);
913 /* There are programs that take over the system and
914 * assume SysBase->IntVects[BLITTER].iv_Data = GfxBase!
916 GfxBase->bltsrv.is_Code = (APTR)gfx_blit;
917 GfxBase->bltsrv.is_Data = GfxBase;
918 GfxBase->bltsrv.is_Node.ln_Name = "Blitter";
919 GfxBase->bltsrv.is_Node.ln_Type = NT_INTERRUPT;
920 SetIntVector(INTB_BLIT, &GfxBase->bltsrv);
921 custom->intena = INTF_BLIT;
923 // CIA-B TOD counts scanlines */
924 GfxBase->timsrv.is_Code = (APTR)gfx_beamsync;
925 GfxBase->timsrv.is_Data = data;
926 GfxBase->timsrv.is_Node.ln_Name = "Beamsync";
927 GfxBase->timsrv.is_Node.ln_Type = NT_INTERRUPT;
928 Disable();
929 AddICRVector(GfxBase->cia, 2, &GfxBase->timsrv);
930 AbleICR(GfxBase->cia, 1 << 2);
931 ciab->ciacrb |= 0x80;
932 ciab->ciatodhi = 0;
933 /* TOD/ALARM CIA bug: http://eab.abime.net/showpost.php?p=277315&postcount=10 */
934 ciab->ciatodmid = BEAMSYNC_ALARM >> 8;
935 ciab->ciatodlow = BEAMSYNC_ALARM & 0xff;
936 ciab->ciacrb &= ~0x80;
937 ciab->ciatodhi = 0;
938 ciab->ciatodmid = 0;
939 ciab->ciatodlow = 0;
940 AbleICR(GfxBase->cia, 0x80 | (1 << 2));
941 Enable();
943 GfxBase->NormalDisplayColumns = 640;
944 GfxBase->NormalDisplayRows = (GfxBase->DisplayFlags & NTSC) ? 200 : 256;
945 GfxBase->MaxDisplayColumn = 640;
946 GfxBase->MaxDisplayRow = (GfxBase->DisplayFlags & NTSC) ? 200 : 256;
948 data->startx = 0x81;
949 data->starty = 0x28;
951 vposr = custom->vposr & 0x7f00;
952 data->aga = vposr >= 0x2200;
953 data->ecs_agnus = vposr >= 0x2000;
954 val = custom->deniseid;
955 custom->deniseid = custom->dmaconr;;
956 if (val == custom->deniseid) {
957 custom->deniseid = custom->dmaconr ^ 0x8000;
958 if (val == custom->deniseid) {
959 if ((val & (2 + 8)) == 8)
960 data->ecs_denise = TRUE;
963 data->max_colors = data->aga ? 256 : 32;
964 data->palette = AllocVec(data->max_colors * 3, MEMF_CLEAR);
965 data->copper1 = AllocVec(22 * 2 * sizeof(WORD), MEMF_CLEAR | MEMF_CHIP);
966 data->sprite_null = AllocMem(2 * 8, MEMF_CLEAR | MEMF_CHIP);
967 data->sprite_res = 0; /* lores */
968 c = data->copper1;
969 for (i = 0; i < 8; i++) {
970 *c++ = 0x0120 + i * 4;
971 if (i == 0)
972 data->copper1_spritept = c;
973 *c++ = (UWORD)(((ULONG)data->sprite_null) >> 16);
974 *c++ = 0x0122 + i * 4;
975 *c++ = (UWORD)(((ULONG)data->sprite_null) >> 0);
977 *c++ = 0x0c03;
978 *c++ = 0xfffe;
979 *c++ = 0x008a;
980 *c++ = 0x0000;
981 data->copper2_backup = c;
982 *c++ = 0xffff;
983 *c++ = 0xfffe;
984 custom->cop1lc = (ULONG)data->copper1;
985 custom->cop2lc = (ULONG)data->copper2_backup;
986 custom->dmacon = 0x8000 | 0x0080 | 0x0040 | 0x0020;
988 GfxBase->copinit = (struct copinit*)data->copper1;
990 D(bug("Copperlist0 %p\n", data->copper1));