Bringing flexcat 2.15 into the main branch (again)
[AROS.git] / arch / m68k-amiga / hidd / gfx / chipset.c
blob675b35807cbb38ab8ef261c30090f6fdbc2cc152
2 #include <proto/exec.h>
3 #include <proto/graphics.h>
4 #include <proto/cia.h>
6 #include <exec/libraries.h>
7 #include <hardware/custom.h>
8 #include <hardware/intbits.h>
9 #include <hardware/cia.h>
10 #include <hidd/graphics.h>
11 #include <graphics/modeid.h>
13 #include "amigavideogfx.h"
14 #include "amigavideobitmap.h"
15 #include "chipset.h"
17 #define DEBUG 0
18 #include <aros/debug.h>
20 static const UBYTE fetchunits[] = { 3,3,3,0, 4,3,3,0, 5,4,3,0 };
21 static const UBYTE fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
23 /* reset to OCS defaults */
24 void resetcustom(struct amigavideo_staticdata *data)
26 volatile struct Custom *custom = (struct Custom*)0xdff000;
27 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
29 custom->fmode = 0x0000;
30 custom->bplcon0 = 0x0200;
31 custom->bplcon1 = 0x0000;
32 custom->bplcon2 = 0x0000;
33 custom->bplcon3 = 0x0c00;
34 custom->bplcon4 = 0x0011;
35 custom->vposw = 0x8000;
36 custom->color[0] = 0x0444;
38 // Use AGA modes and create AGA copperlists only if AGA is "enabled"
39 data->aga_enabled = data->aga && GfxBase->ChipRevBits0 == SETCHIPREV_AA;
42 static void waitvblank(struct amigavideo_staticdata *data)
44 // ugly busy loop for now..
45 UWORD fc = data->framecounter;
46 while (fc == data->framecounter);
49 static void setnullsprite(struct amigavideo_staticdata *data)
51 if (data->copper1_spritept) {
52 UWORD *p = data->sprite_null;
53 data->copper1_spritept[0] = (UWORD)(((ULONG)p) >> 16);
54 data->copper1_spritept[2] = (UWORD)(((ULONG)p) >> 0);
58 void resetsprite(struct amigavideo_staticdata *data)
60 UWORD *sprite = data->sprite;
61 setnullsprite(data);
62 data->sprite = NULL;
63 FreeMem(sprite, data->spritedatasize);
64 data->sprite_width = data->sprite_height = 0;
67 static void setfmode(struct amigavideo_staticdata *data)
69 UWORD fmode;
70 fmode = data->fmode_bpl == 2 ? 3 : data->fmode_bpl;
71 fmode |= (data->fmode_spr == 2 ? 3 : data->fmode_spr) << 2;
72 if (data->copper2.copper2_fmode) {
73 *data->copper2.copper2_fmode = fmode;
74 if (data->interlace)
75 *data->copper2i.copper2_fmode = fmode;
79 static void setcoppercolors(struct amigavideo_staticdata *data)
81 UWORD i;
83 if (!data->copper2.copper2_palette)
84 return;
85 if (data->aga && data->aga_enabled) {
86 UWORD off = 1;
87 for (i = 0; i < data->use_colors; i++) {
88 UWORD vallo, valhi;
89 UBYTE r = data->palette[i * 3 + 0];
90 UBYTE g = data->palette[i * 3 + 1];
91 UBYTE b = data->palette[i * 3 + 2];
92 if ((i & 31) == 0)
93 off += 2;
94 valhi = ((r & 0xf0) << 4) | ((g & 0xf0)) | ((b & 0xf0) >> 4);
95 vallo = ((r & 0x0f) << 8) | ((g & 0x0f) << 4) | ((b & 0x0f));
96 data->copper2.copper2_palette[i * 2 + off] = valhi;
97 data->copper2.copper2_palette_aga_lo[i * 2 + off] = vallo;
98 if (data->interlace) {
99 data->copper2i.copper2_palette[i * 2 + off] = valhi;
100 data->copper2i.copper2_palette_aga_lo[i * 2 + off] = vallo;
103 } else if (data->res == 2 && !data->aga) {
104 /* ECS "scrambled" superhires */
105 for (i = 0; i < data->use_colors; i++) {
106 UBYTE offset = i < 16 ? 0 : 16;
107 UBYTE c1 = (i & 3) + offset;
108 UBYTE c2 = ((i >> 2) & 3) + offset;
109 UWORD val1 = ((data->palette[c1 * 3 + 0] >> 4) << 8) | ((data->palette[c1 * 3 + 1] >> 4) << 4) | ((data->palette[c1 * 3 + 2] >> 4) << 0);
110 UWORD val2 = ((data->palette[c2 * 3 + 0] >> 4) << 8) | ((data->palette[c2 * 3 + 1] >> 4) << 4) | ((data->palette[c2 * 3 + 2] >> 4) << 0);
111 UWORD val = (val1 & 0xccc) | ((val2 & 0xccc) >> 2);
112 data->copper2.copper2_palette[i * 2 + 1] = val;
113 if (data->interlace)
114 data->copper2i.copper2_palette[i * 2 + 1] = val;
117 } else {
118 for (i = 0; i < data->use_colors; i++) {
119 UWORD val = ((data->palette[i * 3 + 0] >> 4) << 8) | ((data->palette[i * 3 + 1] >> 4) << 4) | ((data->palette[i * 3 + 2] >> 4) << 0);
120 data->copper2.copper2_palette[i * 2 + 1] = val;
121 if (data->interlace)
122 data->copper2i.copper2_palette[i * 2 + 1] = val;
127 static void setpalntsc(struct amigavideo_staticdata *data, ULONG modeid)
129 volatile struct Custom *custom = (struct Custom*)0xdff000;
130 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
132 data->palmode = (GfxBase->DisplayFlags & NTSC) == 0;
133 if (!data->ecs_agnus)
134 return;
135 if ((modeid & MONITOR_ID_MASK) == PAL_MONITOR_ID) {
136 custom->beamcon0 = 0x0020;
137 data->palmode = TRUE;
138 } else if ((modeid & MONITOR_ID_MASK) == NTSC_MONITOR_ID) {
139 custom->beamcon0 = 0x0000;
140 data->palmode = FALSE;
141 } else {
142 custom->beamcon0 = (GfxBase->DisplayFlags & NTSC) ? 0x0000 : 0x0020;
146 void resetmode(struct amigavideo_staticdata *data)
148 volatile struct Custom *custom = (struct Custom*)0xdff000;
149 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
151 D(bug("resetmode\n"));
153 data->disp = NULL;
155 custom->dmacon = 0x0100;
156 setpalntsc(data, 0);
158 custom->cop2lc = (ULONG)data->copper2_backup;
159 custom->copjmp2 = 0;
161 waitvblank(data);
163 FreeVec(data->copper2.copper2);
164 data->copper2.copper2 = NULL;
165 FreeVec(data->copper2i.copper2);
166 data->copper2i.copper2 = NULL;
168 GfxBase->LOFlist = GfxBase->SHFlist = data->copper2_backup;
170 resetcustom(data);
172 data->depth = 0;
175 /* Use nominal screen height. Overscan is not supported yet. */
176 static WORD limitheight(struct amigavideo_staticdata *data, WORD y, BOOL lace, BOOL maxlimit)
178 if (lace)
179 y /= 2;
180 if (data->palmode) {
181 if (maxlimit && y > 311)
182 y = 311;
183 else if (!maxlimit && y > 256)
184 y = 256;
185 } else {
186 if (maxlimit && y > 261)
187 y = 261;
188 else if (!maxlimit && y > 200)
189 y = 200;
191 if (lace)
192 y *= 2;
193 return y;
196 static void setcopperscroll2(struct amigavideo_staticdata *data, struct amigabm_data *bm, struct copper2data *c2d, BOOL odd)
198 UWORD *copptr = c2d->copper2_scroll, *copbpl;
199 WORD xscroll, yscroll;
200 WORD x, y;
201 WORD ystart, yend, i, xdelay;
202 WORD xmaxscroll, modulo, ddfstrt, fmodewidth, minearly;
203 LONG offset;
205 fmodewidth = 16 << data->fmode_bpl;
206 x = bm->leftedge;
207 y = data->starty + (bm->topedge >> data->interlace);
209 yscroll = 0;
210 if (y < 10) {
211 yscroll = y - 10;
212 y = 10;
215 xmaxscroll = 1 << (1 + data->fmode_bpl);
216 xdelay = x & (fmodewidth - 1);
217 xscroll = -x;
219 yend = y + (bm->displayheight >> data->interlace);
220 yend = limitheight(data, yend, FALSE, TRUE);
221 ystart = y - data->extralines;
223 modulo = (data->interlace ? bm->bytesperrow : 0) + data->modulo;
224 ddfstrt = data->ddfstrt;
226 offset = ((xscroll + (xmaxscroll << 3) - 1) >> 3) & ~(xmaxscroll - 1);
227 offset -= (yscroll * bm->bytesperrow) << (data->interlace ? 1 : 0);
229 minearly = 1 << fetchunits[data->fmode_bpl * 4 + data->res];
230 if (xdelay) {
231 ddfstrt -= minearly;
232 modulo -= (minearly << data->res) / 4;
233 offset -= (minearly << data->res) / 4;
236 copptr[1] = (y << 8) | (data->startx); //(y << 8) + (x + 1);
237 copptr[3] = (yend << 8) | ((data->startx + 0x140) & 0xff); //((y + (bm->rows >> data->interlace)) << 8) + ((x + 1 + (bm->width >> data->res)) & 0x00ff);
238 copptr[5] = ((y >> 8) & 7) | (((yend >> 8) & 7) << 8) | 0x2000;
240 copbpl = c2d->copper2_bpl;
241 for (i = 0; i < bm->depth; i++) {
242 ULONG pptr = (ULONG)(bm->pbm->Planes[data->bploffsets[i]]);
243 if (data->interlace && odd)
244 pptr += bm->bytesperrow;
245 pptr += offset;
246 copbpl[1] = (UWORD)(pptr >> 16);
247 copbpl[3] = (UWORD)(pptr >> 0);
248 copbpl += 4;
251 xdelay <<= 2 - data->res;
252 copptr[11] =
253 (((xdelay >> 2) & 0x0f) << 0) | (((xdelay >> 2) & 0x0f) << 4)
254 | ((xdelay >> 6) << 10) | ((xdelay >> 6) << 14)
255 | ((xdelay & 3) << 8) | ((xdelay & 3) << 12);
257 copptr[7] = ddfstrt;
258 copptr[9] = data->ddfstop;
259 copptr[13] = modulo;
260 copptr[15] = modulo;
262 yend = y + bm->displayheight + yscroll;
263 yend = limitheight(data, yend, FALSE, TRUE);
264 copptr = c2d->copper2_bplcon0;
265 copptr[4] = (yend << 8) | 0x05;
266 if (yend < 256 || ystart >= 256) {
267 copptr[2] = 0x00df;
268 copptr[3] = 0x00fe;
269 } else {
270 copptr[2] = 0xffdf;
271 copptr[3] = 0xfffe;
274 copptr = c2d->copper2;
275 if (ystart >= 256)
276 copptr[0] = 0xffdf;
277 else
278 copptr[0] = 0x01fe;
279 copptr[2] = (ystart << 8) | 0x05;
280 copptr = c2d->copper2_bplcon0;
281 copptr[-2] = (y << 8) | 0x05;
284 static void setcopperscroll(struct amigavideo_staticdata *data, struct amigabm_data *bm)
286 setcopperscroll2(data, bm, &data->copper2, FALSE);
287 if (data->interlace)
288 setcopperscroll2(data, bm, &data->copper2i, TRUE);
291 static UWORD get_copper_list_length(struct amigavideo_staticdata *data, UBYTE depth)
293 UWORD v;
295 if (data->aga && data->aga_enabled) {
296 v = 1000 + ((1 << depth) + 1 + (1 << depth) / 32 + 1) * 2;
297 } else {
298 v = 1000;
300 return v * 2;
303 static void createcopperlist(struct amigavideo_staticdata *data, struct amigabm_data *bm, struct copper2data *c2d, BOOL lace)
305 UWORD *c;
306 UWORD i;
307 UWORD bplcon0, bplcon0_res;
308 ULONG pptr;
310 c = c2d->copper2;
311 D(bug("Copperlist%d %p\n", lace ? 2 : 1, c));
313 if (data->res == 1)
314 bplcon0_res = 0x8000;
315 else if (data->res == 2)
316 bplcon0_res = 0x0040;
317 else
318 bplcon0_res = 0;
320 data->bplcon0_null = 0x0201 | (data->interlace ? 4 : 0) | bplcon0_res;
321 data->bplcon3 = ((data->sprite_res + 1) << 6) | 2; // spriteres + bordersprite
323 *c++ = 0x01fe;
324 *c++ = 0xfffe;
325 *c++ = 0xffff;
326 *c++ = 0xfffe;
328 *c++ = 0x0100;
329 *c++ = data->bplcon0_null;
331 c2d->copper2_bpl = c;
332 for (i = 0; i < bm->depth; i++) {
333 pptr = (ULONG)(bm->pbm->Planes[data->bploffsets[i]]);
334 if (lace)
335 pptr += bm->bytesperrow;
336 *c++ = 0xe0 + i * 4;
337 *c++ = (UWORD)(pptr >> 16);
338 *c++ = 0xe2 + i * 4;
339 *c++ = (UWORD)(pptr >> 0);
342 data->use_colors = 1 << bm->depth;
343 // need to update sprite colors
344 if (data->use_colors < 16 + 4)
345 data->use_colors = 16 + 4;
346 if (data->res == 2 && !data->aga)
347 data->use_colors = 32; /* ECS "scrambled" superhires */
349 if (data->use_colors > 32 && (data->modeid & EXTRAHALFBRITE_KEY))
350 data->use_colors = 32;
351 if (data->modeid & HAM_KEY) {
352 if (bm->depth <= 6)
353 data->use_colors = 16 + 4;
354 else
355 data->use_colors = 64;
358 c2d->copper2_scroll = c;
359 *c++ = 0x008e;
360 *c++ = 0;
361 *c++ = 0x0090;
362 *c++ = 0;
363 *c++ = 0x01e4;
364 *c++ = 0;
365 *c++ = 0x0092;
366 *c++ = 0;
367 *c++ = 0x0094;
368 *c++ = 0;
369 *c++ = 0x0102;
370 *c++ = 0;
371 *c++ = 0x0108;
372 *c++ = 0;
373 *c++ = 0x010a;
374 *c++ = 0;
375 *c++ = 0x0104;
376 *c++ = 0x0024 | ((data->aga && !(data->modeid & EXTRAHALFBRITE_KEY)) ? 0x0200 : 0);
378 c2d->copper2_fmode = NULL;
379 if (data->aga && data->aga_enabled) {
380 *c++ = 0x010c;
381 *c++ = 0x0011;
382 *c++ = 0x01fc;
383 c2d->copper2_fmode = c;
384 *c++ = 0;
387 bplcon0 = data->bplcon0_null;
388 if (bm->depth > 7)
389 bplcon0 |= 0x0010;
390 else
391 bplcon0 |= bm->depth << 12;
392 if (data->modeid & HAM_KEY)
393 bplcon0 |= 0x0800;
395 c2d->copper2_palette = c;
396 if (data->aga && data->aga_enabled) {
397 // hi
398 for (i = 0; i < data->use_colors; i++) {
399 UBYTE agac = i & 31;
400 if (agac == 0) {
401 *c++ = 0x106;
402 *c++ = data->bplcon3 | ((i / 32) << 13);
404 *c++ = 0x180 + agac * 2;
405 *c++ = 0x000;
407 c2d->copper2_palette_aga_lo = c;
408 // lo
409 for (i = 0; i < data->use_colors; i++) {
410 UBYTE agac = i & 31;
411 if (agac == 0) {
412 *c++ = 0x106;
413 *c++ = data->bplcon3 | ((i / 32) << 13) | 0x0200;
415 *c++ = 0x180 + agac * 2;
416 *c++ = 0x000;
418 *c++ = 0x106;
419 *c++ = data->bplcon3;
420 } else {
421 // ocs/ecs
422 for (i = 0; i < data->use_colors; i++) {
423 *c++ = 0x180 + i * 2;
424 *c++ = 0x000;
428 data->extralines = (c - c2d->copper2) / 112 + 1;
430 *c++ = 0xffff;
431 *c++ = 0xfffe;
432 c2d->copper2_bplcon0 = c;
433 *c++ = 0x0100;
434 *c++ = bplcon0;
436 *c++ = 0xffff;
437 *c++ = 0xfffe;
438 *c++ = 0xffff;
439 *c++ = 0xfffe;
441 *c++ = 0x0100;
442 *c++ = data->bplcon0_null;
444 if (data->interlace) {
445 ULONG nextptr = (ULONG)(lace ? data->copper2.copper2 : data->copper2i.copper2);
446 *c++ = 0x0084;
447 *c++ = (UWORD)(nextptr >> 16);
448 *c++ = 0x0086;
449 *c++ = (UWORD)(nextptr >> 0);
451 *c++ = 0xffff;
452 *c++ = 0xfffe;
456 BOOL setbitmap(struct amigavideo_staticdata *data, struct amigabm_data *bm)
458 data->width = bm->width;
459 data->height = data->interlace ? (bm->height + 1) / 2 : bm->height;
460 data->modulo = bm->bytesperrow - data->modulopre / (4 >> data->res);
461 data->modulo &= ~((2 << data->fmode_bpl) - 1);
462 data->updatescroll = bm;
463 data->depth = bm->depth;
464 setcopperscroll(data, bm);
466 D(bug("setbitmap bm=%x mode=%08x w=%d h=%d d=%d bpr=%d\n",
467 bm, data->modeid, bm->width, bm->height, bm->depth, bm->bytesperrow));
468 return TRUE;
471 BOOL setmode(struct amigavideo_staticdata *data, struct amigabm_data *bm)
473 volatile struct Custom *custom = (struct Custom*)0xdff000;
474 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
475 UWORD ddfstrt, ddfstop;
476 UBYTE fetchunit, maxplanes;
477 UWORD bplwidth, viewwidth;
478 UBYTE i;
480 if (data->disp == bm)
481 return TRUE;
483 resetmode(data);
485 data->res = 0;
486 if ((data->modeid & SUPER_KEY) == SUPER_KEY)
487 data->res = 2;
488 else if ((data->modeid & SUPER_KEY) == HIRES_KEY)
489 data->res = 1;
490 data->interlace = (data->modeid & LORESLACE_KEY) ? 1 : 0;
491 data->fmode_bpl = data->aga && data->aga_enabled ? 2 : 0;
493 fetchunit = fetchunits[data->fmode_bpl * 4 + data->res];
494 maxplanes = fm_maxplanes[data->fmode_bpl * 4 + data->res];
496 D(bug("res %d fmode %d depth %d maxplanes %d aga %d agae %d\n",
497 data->res, data->fmode_bpl, bm->depth, maxplanes, data->aga, data->aga_enabled));
499 if (bm->depth > (1 << maxplanes)) {
500 if (data->aga && !data->aga_enabled) {
501 // Enable AGA if requesting AGA only mode.
502 // This is a compatibility hack because our display
503 // database currently contains all AGA modes even if AGA
504 // is "disabled".
505 GfxBase->ChipRevBits0 = SETCHIPREV_AA;
506 data->aga_enabled = TRUE;
507 data->fmode_bpl = data->aga && data->aga_enabled ? 2 : 0;
508 fetchunit = fetchunits[data->fmode_bpl * 4 + data->res];
509 maxplanes = fm_maxplanes[data->fmode_bpl * 4 + data->res];
511 if (bm->depth > (1 << maxplanes))
512 return FALSE;
515 viewwidth = bm->width;
516 // use nominal width for now
517 if ((viewwidth << data->res) > 320)
518 viewwidth = 320 << data->res;
520 D(bug("setmode bm=%x mode=%08x w=%d h=%d d=%d bpr=%d fu=%d\n",
521 bm, data->modeid, bm->width, bm->height, bm->depth, bm->bytesperrow, fetchunit));
523 bplwidth = viewwidth >> (data->res + 1);
524 ddfstrt = (data->startx / 2) & ~((1 << fetchunit) - 1);
525 ddfstop = ddfstrt + ((bplwidth + ((1 << fetchunit) - 1) - 2 * (1 << fetchunit)) & ~((1 << fetchunit) - 1));
526 data->modulopre = ddfstop + 2 * (1 << fetchunit) - ddfstrt;
527 ddfstrt -= 1 << maxplanes;
528 data->ddfstrt = ddfstrt;
529 data->ddfstop = ddfstop;
531 for (i = 0; i < 8; i++)
532 data->bploffsets[i] = i;
533 if ((data->modeid & HAM_KEY) && bm->depth > 6) {
534 data->bploffsets[0] = 6;
535 data->bploffsets[1] = 7;
536 for (i = 0; i < 6; i++)
537 data->bploffsets[i + 2] = i;
540 data->copper2.copper2 = AllocVec(get_copper_list_length(data, bm->depth), MEMF_CLEAR | MEMF_CHIP);
541 if (data->interlace)
542 data->copper2i.copper2 = AllocVec(get_copper_list_length(data, bm->depth), MEMF_CLEAR | MEMF_CHIP);
543 createcopperlist(data, bm, &data->copper2, FALSE);
544 if (data->interlace) {
545 createcopperlist(data, bm, &data->copper2i, TRUE);
548 setfmode(data);
549 setpalntsc(data, data->modeid);
550 custom->bplcon0 = data->bplcon0_null;
552 bm->displaywidth = viewwidth;
553 bm->displayheight = limitheight(data, bm->height, data->interlace, FALSE);
555 setbitmap(data, bm);
557 GfxBase->LOFlist = data->copper2.copper2;
558 GfxBase->SHFlist = data->interlace ? data->copper2i.copper2 : data->copper2.copper2;
559 custom->dmacon = 0x8100;
561 setcoppercolors(data);
562 setspritepos(data, data->spritex, data->spritey);
564 data->disp = bm;
565 return 1;
568 BOOL setsprite(struct amigavideo_staticdata *data, WORD width, WORD height, struct pHidd_Gfx_SetCursorShape *shape)
570 OOP_MethodID HiddBitMapBase = data->cs_HiddBitMapBase;
571 UWORD fetchsize;
572 UWORD bitmapwidth = width;
573 UWORD y, *p;
575 if (data->aga && data->aga_enabled && width > 16)
576 data->fmode_spr = 2;
577 else
578 data->fmode_spr = 0;
579 fetchsize = 2 << data->fmode_spr;
580 width = 16 << data->fmode_spr;
582 if (width != data->sprite_width || height != data->sprite_height) {
583 resetsprite(data);
584 data->spritedatasize = fetchsize * 2 + fetchsize * height * 2 + fetchsize * 2;
585 data->sprite = AllocMem(data->spritedatasize, MEMF_CHIP | MEMF_CLEAR);
586 if (!data->sprite)
587 return FALSE;
588 data->sprite_width = width;
589 data->sprite_height = height;
590 data->sprite_offset_x = shape->xoffset;
591 data->sprite_offset_y = shape->yoffset;
593 p = data->sprite;
594 p += fetchsize;
595 for(y = 0; y < height; y++) {
596 UWORD xx, xxx, x;
597 for (xx = 0, xxx = 0; xx < width; xx += 16, xxx++) {
598 UWORD pix1 = 0, pix2 = 0;
599 for(x = 0; x < 16; x++) {
600 UBYTE c = 0;
601 if (xx + x < bitmapwidth)
602 c = HIDD_BM_GetPixel(shape->shape, xx + x, y);
603 #if 0
604 /* Sprite alignment grid */
605 if (xx + x == 0 || xx + x == width - 1 || y == 0 || y == height - 1) {
606 c = 2;
607 } else if (0) {
608 c = 0;
610 #endif
611 pix1 <<= 1;
612 pix2 <<= 1;
613 pix1 |= (c & 1) ? 1 : 0;
614 pix2 |= (c & 2) ? 1 : 0;
616 p[xxx] = pix1;
617 p[xxx + fetchsize / 2] = pix2;
619 p += fetchsize;
621 setspritepos(data, data->spritex, data->spritey);
622 setspritevisible(data, data->cursorvisible);
623 return TRUE;
626 void setspritepos(struct amigavideo_staticdata *data, WORD x, WORD y)
628 UWORD ctl, pos;
630 data->spritex = x;
631 data->spritey = y;
632 if (!data->sprite || data->sprite_height == 0)
633 return;
635 x += data->sprite_offset_x << data->res;
636 x <<= (2 - data->res); // convert x to shres coordinates
637 x += (data->startx - 1) << 2; // display left edge offset
639 if (data->interlace)
640 y /= 2; // y is always in nonlaced
641 y += data->starty;
642 y += data->sprite_offset_y;
644 pos = (y << 8) | (x >> 3);
645 ctl = ((y + data->sprite_height) << 8);
646 ctl |= ((y >> 8) << 2) | (((y + data->sprite_height) >> 8) << 1) | ((x >> 2) & 1) | ((x & 3) << 3);
647 data->spritepos = pos;
648 data->spritectl = ctl;
651 void setspritevisible(struct amigavideo_staticdata *data, BOOL visible)
653 data->cursorvisible = visible;
654 if (visible) {
655 if (data->copper1_spritept) {
656 UWORD *p = data->sprite;
657 setfmode(data);
658 data->copper1_spritept[0] = (UWORD)(((ULONG)p) >> 16);
659 data->copper1_spritept[2] = (UWORD)(((ULONG)p) >> 0);
661 } else {
662 setnullsprite(data);
666 BOOL setcolors(struct amigavideo_staticdata *data, struct pHidd_BitMap_SetColors *msg, BOOL visible)
668 UWORD i, j;
669 if (msg->firstColor + msg->numColors > data->max_colors)
670 return FALSE;
671 j = 0;
672 for (i = msg->firstColor; j < msg->numColors; i++, j++) {
673 UBYTE red, green, blue;
674 red = msg->colors[j].red >> 8;
675 green = msg->colors[j].green >> 8;
676 blue = msg->colors[j].blue >> 8;
677 data->palette[i * 3 + 0] = red;
678 data->palette[i * 3 + 1] = green;
679 data->palette[i * 3 + 2] = blue;
680 //bug("%d: %02x %02x %02x\n", i, red, green, blue);
682 if (visible)
683 setcoppercolors(data);
684 return TRUE;
686 void setscroll(struct amigavideo_staticdata *data, struct amigabm_data *bm)
688 data->updatescroll = bm;
691 /* Convert Z flag to normal C-style return variable. Fun. */
692 UBYTE bltnode_wrapper(void)
694 UBYTE ret;
695 asm volatile (
696 " pea 1f\n"
697 " move.l 4(%%a1),-(%%sp)\n"
698 " rts\n"
699 "1: sne %d0\n"
700 " move.b %%d0,%0\n"
701 : "=g" (ret)
703 return ret;
706 #define BEAMSYNC_ALARM 0x0f00
707 /* AOS must use some GfxBase flags field for these. Later.. */
708 #define bqvar GfxBase->pad3
709 #define BQ_NEXT 1
710 #define BQ_BEAMSYNC 2
711 #define BQ_BEAMSYNCWAITING 4
712 #define BQ_MISSED 8
714 static AROS_INTH1(gfx_blit, struct GfxBase *, GfxBase)
716 AROS_INTFUNC_INIT
718 volatile struct Custom *custom = (struct Custom*)0xdff000;
719 struct bltnode *bn = NULL;
720 UBYTE v;
721 UWORD dmaconr;
723 dmaconr = custom->dmaconr;
724 dmaconr = custom->dmaconr;
725 if (dmaconr & 0x4000) {
726 /* Blitter still active? Wait for next interrupt. */
727 return 0;
730 if (GfxBase->blthd == NULL && GfxBase->bsblthd == NULL) {
731 custom->intena = INTF_BLIT;
732 return 0;
735 /* Was last blit in this node? */
736 if (bqvar & BQ_NEXT) {
737 bqvar &= ~(BQ_NEXT | BQ_MISSED);
738 if (bqvar & BQ_BEAMSYNC)
739 bn = GfxBase->bsblthd;
740 else
741 bn = GfxBase->blthd;
742 if (bn->stat == CLEANUP)
743 AROS_UFC2(UBYTE, bn->cleanup,
744 AROS_UFCA(struct Custom *, custom, A0),
745 AROS_UFCA(struct bltnode*, bn, A1));
746 /* Next node */
747 bn = bn->n;
748 if (bqvar & BQ_BEAMSYNC)
749 GfxBase->bsblthd = bn;
750 else
751 GfxBase->blthd = bn;
754 if (GfxBase->bsblthd) {
755 bn = GfxBase->bsblthd;
756 bqvar |= BQ_BEAMSYNC;
757 } else if (GfxBase->blthd) {
758 bn = GfxBase->blthd;
759 bqvar &= ~BQ_BEAMSYNC;
762 if (!bn) {
763 /* Last blit finished */
764 bqvar = 0;
765 custom->intena = INTF_BLIT;
766 GfxBase->blthd = GfxBase->bsblthd = NULL;
767 DisownBlitter();
768 return 0;
771 if (bqvar & BQ_BEAMSYNC) {
772 UWORD vpos = VBeamPos();
773 bqvar &= ~BQ_BEAMSYNCWAITING;
774 if (!(bqvar & BQ_MISSED) && bn->beamsync > vpos) {
775 volatile struct CIA *ciab = (struct CIA*)0xbfd000;
776 UWORD w = BEAMSYNC_ALARM - (bn->beamsync - vpos);
777 bqvar |= BQ_BEAMSYNCWAITING;
778 ciab->ciacrb &= ~0x80;
779 ciab->ciatodhi = 0;
780 ciab->ciatodmid = w >> 8;
781 ciab->ciatodlow = w;
782 return 0;
786 v = AROS_UFC2(UBYTE, bltnode_wrapper,
787 AROS_UFCA(struct Custom *, custom, A0),
788 AROS_UFCA(struct bltnode*, bn, A1));
790 dmaconr = custom->dmaconr;
791 dmaconr = custom->dmaconr;
792 if (!(dmaconr & 0x4000)) {
793 /* Eh? Blitter not active?, better fake the interrupt. */
794 custom->intreq = INTF_SETCLR | INTF_BLIT;
797 if (v) {
798 /* Handle same node again next time */
799 return 0;
802 bqvar |= BQ_NEXT;
804 return 0;
806 AROS_INTFUNC_EXIT
809 static AROS_INTH1(gfx_beamsync, struct amigavideo_staticdata*, data)
811 AROS_INTFUNC_INIT
813 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
815 if (bqvar & BQ_BEAMSYNCWAITING) {
816 /* We only need to trigger blitter interrupt */
817 volatile struct Custom *custom = (struct Custom*)0xdff000;
818 custom->intreq = INTF_SETCLR | INTF_BLIT;
821 return FALSE;
823 AROS_INTFUNC_EXIT
826 static AROS_INTH1(gfx_vblank, struct amigavideo_staticdata*, data)
828 AROS_INTFUNC_INIT
830 struct GfxBase *GfxBase = (APTR)data->cs_GfxBase;
831 volatile struct Custom *custom = (struct Custom*)0xdff000;
832 BOOL lof = (custom->vposr & 0x8000) != 0;
834 if (data->interlace) {
835 custom->cop2lc = (ULONG)(lof ? GfxBase->LOFlist : GfxBase->SHFlist);
836 } else {
837 custom->cop2lc = (ULONG)GfxBase->LOFlist;
838 /* We may be in SHF mode after switching interlace off. Fix it here. */
839 if (!lof)
840 custom->vposw = custom->vposr | 0x8000;
843 data->framecounter++;
844 if (data->sprite) {
845 UWORD *p = data->sprite;
846 p[0] = data->spritepos;
847 p[1 << data->fmode_spr] = data->spritectl;
850 if (data->updatescroll) {
851 setcopperscroll(data, data->updatescroll);
852 data->updatescroll = NULL;
855 if (bqvar & BQ_BEAMSYNC)
856 bqvar |= BQ_MISSED;
858 return FALSE;
860 AROS_INTFUNC_EXIT
863 void initcustom(struct amigavideo_staticdata *data)
865 UBYTE i;
866 UWORD *c;
867 UWORD vposr, val;
868 struct GfxBase *GfxBase;
869 struct Library *OOPBase;
870 volatile struct Custom *custom = (struct Custom*)0xdff000;
871 volatile struct CIA *ciab = (struct CIA*)0xbfd000;
873 /* Reset audio registers to values that help emulation
874 * if some program enables audio DMA without setting period
875 * or length. Very high period emulation is very CPU intensive.
877 for (i = 0; i < 4; i++) {
878 custom->aud[i].ac_vol = 0;
879 custom->aud[i].ac_per = 100;
880 custom->aud[i].ac_len = 1000;
883 resetcustom(data);
884 resetsprite(data);
886 /* data->cs_OOPBase was already set up.
887 * See amigavideo.conf's 'oopbase_field' config
889 OOPBase = data->cs_OOPBase;
890 data->cs_HiddBitMapBase = OOP_GetMethodID(IID_Hidd_BitMap, 0);
891 data->cs_HiddGfxBase = OOP_GetMethodID(IID_Hidd_Gfx, 0);
893 data->cs_UtilityBase = TaggedOpenLibrary(TAGGEDOPEN_UTILITY);
894 if (!data->cs_UtilityBase)
895 Alert(AT_DeadEnd | AN_Hidd | AG_OpenLib | AO_UtilityLib);
896 data->cs_GfxBase = TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS);
897 if (!data->cs_GfxBase)
898 Alert(AT_DeadEnd | AN_Hidd | AG_OpenLib | AO_GraphicsLib);
899 GfxBase = ((struct GfxBase *)data->cs_GfxBase);
900 GfxBase->cia = OpenResource("ciab.resource");
902 data->inter.is_Code = (APTR)gfx_vblank;
903 data->inter.is_Data = data;
904 data->inter.is_Node.ln_Name = "GFX VBlank server";
905 data->inter.is_Node.ln_Pri = 25;
906 data->inter.is_Node.ln_Type = NT_INTERRUPT;
907 AddIntServer(INTB_VERTB, &data->inter);
909 /* There are programs that take over the system and
910 * assume SysBase->IntVects[BLITTER].iv_Data = GfxBase!
912 GfxBase->bltsrv.is_Code = (APTR)gfx_blit;
913 GfxBase->bltsrv.is_Data = GfxBase;
914 GfxBase->bltsrv.is_Node.ln_Name = "Blitter";
915 GfxBase->bltsrv.is_Node.ln_Type = NT_INTERRUPT;
916 SetIntVector(INTB_BLIT, &GfxBase->bltsrv);
917 custom->intena = INTF_BLIT;
919 // CIA-B TOD counts scanlines */
920 GfxBase->timsrv.is_Code = (APTR)gfx_beamsync;
921 GfxBase->timsrv.is_Data = data;
922 GfxBase->timsrv.is_Node.ln_Name = "Beamsync";
923 GfxBase->timsrv.is_Node.ln_Type = NT_INTERRUPT;
924 Disable();
925 AddICRVector(GfxBase->cia, 2, &GfxBase->timsrv);
926 AbleICR(GfxBase->cia, 1 << 2);
927 ciab->ciacrb |= 0x80;
928 ciab->ciatodhi = 0;
929 /* TOD/ALARM CIA bug: http://eab.abime.net/showpost.php?p=277315&postcount=10 */
930 ciab->ciatodmid = BEAMSYNC_ALARM >> 8;
931 ciab->ciatodlow = BEAMSYNC_ALARM & 0xff;
932 ciab->ciacrb &= ~0x80;
933 ciab->ciatodhi = 0;
934 ciab->ciatodmid = 0;
935 ciab->ciatodlow = 0;
936 AbleICR(GfxBase->cia, 0x80 | (1 << 2));
937 Enable();
939 GfxBase->NormalDisplayColumns = 640;
940 GfxBase->NormalDisplayRows = (GfxBase->DisplayFlags & NTSC) ? 200 : 256;
941 GfxBase->MaxDisplayColumn = 640;
942 GfxBase->MaxDisplayRow = (GfxBase->DisplayFlags & NTSC) ? 200 : 256;
944 data->startx = 0x81;
945 data->starty = 0x28;
947 vposr = custom->vposr & 0x7f00;
948 data->aga = vposr >= 0x2200;
949 data->ecs_agnus = vposr >= 0x2000;
950 val = custom->deniseid;
951 custom->deniseid = custom->dmaconr;;
952 if (val == custom->deniseid) {
953 custom->deniseid = custom->dmaconr ^ 0x8000;
954 if (val == custom->deniseid) {
955 if ((val & (2 + 8)) == 8)
956 data->ecs_denise = TRUE;
959 data->max_colors = data->aga ? 256 : 32;
960 data->palette = AllocVec(data->max_colors * 3, MEMF_CLEAR);
961 data->copper1 = AllocVec(22 * 2 * sizeof(WORD), MEMF_CLEAR | MEMF_CHIP);
962 data->sprite_null = AllocMem(2 * 8, MEMF_CLEAR | MEMF_CHIP);
963 data->sprite_res = 0; /* lores */
964 c = data->copper1;
965 for (i = 0; i < 8; i++) {
966 *c++ = 0x0120 + i * 4;
967 if (i == 0)
968 data->copper1_spritept = c;
969 *c++ = (UWORD)(((ULONG)data->sprite_null) >> 16);
970 *c++ = 0x0122 + i * 4;
971 *c++ = (UWORD)(((ULONG)data->sprite_null) >> 0);
973 *c++ = 0x0c03;
974 *c++ = 0xfffe;
975 *c++ = 0x008a;
976 *c++ = 0x0000;
977 data->copper2_backup = c;
978 *c++ = 0xffff;
979 *c++ = 0xfffe;
980 custom->cop1lc = (ULONG)data->copper1;
981 custom->cop2lc = (ULONG)data->copper2_backup;
982 custom->dmacon = 0x8000 | 0x0080 | 0x0040 | 0x0020;
984 GfxBase->copinit = (struct copinit*)data->copper1;
986 D(bug("Copperlist0 %p\n", data->copper1));