bit shift was left, of course, write in comment what code really does!
[AROS.git] / arch / m68k-amiga / hidd / amigavideo / chipset.c
blob84ec9b58a94c262617c23b1a073520beec044e2a
1 /*
2 Copyright © 1995-2019, 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 #include <aros/debug.h>
23 #define BPLCONMASK 0x8a55
25 static const UBYTE fetchunits[] = { 3,3,3,0, 4,3,3,0, 5,4,3,0 };
26 static const UBYTE fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
28 /* reset to OCS defaults */
29 void resetcustom(struct amigavideo_staticdata *csd)
31 volatile struct Custom *custom = (struct Custom*)0xdff000;
32 struct GfxBase *GfxBase = (APTR)csd->cs_GfxBase;
35 bug("[AmigaVideo] %s()\n", __func__);
36 bug("[AmigaVideo] %s: GfxBase @ 0x%p\n", __func__, GfxBase);
39 GfxBase->system_bplcon0 &= ~BPLCONMASK;
40 GfxBase->system_bplcon0 |= 0x0200;
41 D(bug("[AmigaVideo] %s: bplcon0 = %04x\n", __func__, GfxBase->system_bplcon0));
43 custom->fmode = 0x0000;
44 custom->bplcon0 = GfxBase->system_bplcon0;
45 custom->bplcon1 = 0x0000;
46 custom->bplcon2 = 0x0024;
47 custom->bplcon3 = 0x0c00;
48 custom->bplcon4 = 0x0011;
49 custom->vposw = 0x8000;
50 custom->color[0] = 0x0444;
52 // Use AGA modes and create AGA copperlists only if AGA is "enabled"
53 csd->aga_enabled = csd->aga && GfxBase->ChipRevBits0 == SETCHIPREV_AA;
56 static void waitvblank(struct amigavideo_staticdata *csd)
58 // ugly busy loop for now..
59 UWORD fc = csd->framecounter;
60 while (fc == csd->framecounter);
63 static void setnullsprite(struct amigavideo_staticdata *csd)
65 if (csd->copper1_spritept) {
66 UWORD *p = csd->sprite_null;
67 csd->copper1_spritept[0] = (UWORD)(((ULONG)p) >> 16);
68 csd->copper1_spritept[2] = (UWORD)(((ULONG)p) >> 0);
72 void resetsprite(struct amigavideo_staticdata *csd)
74 UWORD *sprite = csd->sprite;
75 setnullsprite(csd);
76 csd->sprite = NULL;
77 FreeMem(sprite, csd->spritedatasize);
78 csd->sprite_width = csd->sprite_height = 0;
81 static void setfmode(struct amigavideo_staticdata *csd)
83 UWORD fmode;
84 fmode = csd->fmode_bpl == 2 ? 3 : csd->fmode_bpl;
85 fmode |= (csd->fmode_spr == 2 ? 3 : csd->fmode_spr) << 2;
86 if (csd->copper2.copper2_fmode) {
87 *csd->copper2.copper2_fmode = fmode;
88 if (csd->interlace)
89 *csd->copper2i.copper2_fmode = fmode;
93 static void setcoppercolors(struct amigavideo_staticdata *csd)
95 UWORD i;
97 if (!csd->copper2.copper2_palette)
98 return;
99 if (csd->aga && csd->aga_enabled) {
100 UWORD off = 1;
101 for (i = 0; i < csd->use_colors; i++) {
102 UWORD vallo, valhi;
103 UBYTE r = csd->palette[i * 3 + 0];
104 UBYTE g = csd->palette[i * 3 + 1];
105 UBYTE b = csd->palette[i * 3 + 2];
106 if ((i & 31) == 0)
107 off += 2;
108 valhi = ((r & 0xf0) << 4) | ((g & 0xf0)) | ((b & 0xf0) >> 4);
109 vallo = ((r & 0x0f) << 8) | ((g & 0x0f) << 4) | ((b & 0x0f));
110 csd->copper2.copper2_palette[i * 2 + off] = valhi;
111 csd->copper2.copper2_palette_aga_lo[i * 2 + off] = vallo;
112 if (csd->interlace) {
113 csd->copper2i.copper2_palette[i * 2 + off] = valhi;
114 csd->copper2i.copper2_palette_aga_lo[i * 2 + off] = vallo;
117 } else if (csd->res == 2 && !csd->aga) {
118 /* ECS "scrambled" superhires */
119 for (i = 0; i < csd->use_colors; i++) {
120 UBYTE offset = i < 16 ? 0 : 16;
121 UBYTE c1 = (i & 3) + offset;
122 UBYTE c2 = ((i >> 2) & 3) + offset;
123 UWORD val1 = ((csd->palette[c1 * 3 + 0] >> 4) << 8) | ((csd->palette[c1 * 3 + 1] >> 4) << 4) | ((csd->palette[c1 * 3 + 2] >> 4) << 0);
124 UWORD val2 = ((csd->palette[c2 * 3 + 0] >> 4) << 8) | ((csd->palette[c2 * 3 + 1] >> 4) << 4) | ((csd->palette[c2 * 3 + 2] >> 4) << 0);
125 UWORD val = (val1 & 0xccc) | ((val2 & 0xccc) >> 2);
126 csd->copper2.copper2_palette[i * 2 + 1] = val;
127 if (csd->interlace)
128 csd->copper2i.copper2_palette[i * 2 + 1] = val;
131 } else {
132 for (i = 0; i < csd->use_colors; i++) {
133 UWORD val = ((csd->palette[i * 3 + 0] >> 4) << 8) | ((csd->palette[i * 3 + 1] >> 4) << 4) | ((csd->palette[i * 3 + 2] >> 4) << 0);
134 csd->copper2.copper2_palette[i * 2 + 1] = val;
135 if (csd->interlace)
136 csd->copper2i.copper2_palette[i * 2 + 1] = val;
141 static void setpalntsc(struct amigavideo_staticdata *csd, ULONG modeid)
143 volatile struct Custom *custom = (struct Custom*)0xdff000;
144 struct GfxBase *GfxBase = (APTR)csd->cs_GfxBase;
146 csd->palmode = (GfxBase->DisplayFlags & NTSC) == 0;
147 if (!csd->ecs_agnus)
148 return;
149 if ((modeid & MONITOR_ID_MASK) == PAL_MONITOR_ID) {
150 custom->beamcon0 = 0x0020;
151 csd->palmode = TRUE;
152 } else if ((modeid & MONITOR_ID_MASK) == NTSC_MONITOR_ID) {
153 custom->beamcon0 = 0x0000;
154 csd->palmode = FALSE;
155 } else {
156 custom->beamcon0 = (GfxBase->DisplayFlags & NTSC) ? 0x0000 : 0x0020;
160 void resetmode(struct amigavideo_staticdata *csd)
162 volatile struct Custom *custom = (struct Custom*)0xdff000;
163 struct GfxBase *GfxBase = (APTR)csd->cs_GfxBase;
165 D(bug("[AmigaVideo] %s()\n", __func__));
167 csd->disp = NULL;
169 custom->dmacon = 0x0100;
170 setpalntsc(csd, 0);
172 custom->cop2lc = (ULONG)csd->copper2_backup;
173 custom->copjmp2 = 0;
175 waitvblank(csd);
177 FreeVec(csd->copper2.copper2);
178 csd->copper2.copper2 = NULL;
179 FreeVec(csd->copper2i.copper2);
180 csd->copper2i.copper2 = NULL;
182 GfxBase->LOFlist = GfxBase->SHFlist = csd->copper2_backup;
184 resetcustom(csd);
186 csd->depth = 0;
189 /* Use nominal screen height. Overscan is not supported yet. */
190 static WORD limitheight(struct amigavideo_staticdata *csd, WORD y, BOOL lace, BOOL maxlimit)
192 if (lace)
193 y /= 2;
194 if (csd->palmode) {
195 if (maxlimit && y > 311)
196 y = 311;
197 else if (!maxlimit && y > 256)
198 y = 256;
199 } else {
200 if (maxlimit && y > 261)
201 y = 261;
202 else if (!maxlimit && y > 200)
203 y = 200;
205 if (lace)
206 y *= 2;
207 return y;
210 static void setcopperscroll2(struct amigavideo_staticdata *csd, struct amigabm_data *bm, struct copper2data *c2d, BOOL odd)
212 UWORD *copptr = c2d->copper2_scroll, *copbpl;
213 WORD xscroll, yscroll;
214 WORD x, y;
215 WORD ystart, yend, i, xdelay;
216 WORD xmaxscroll, modulo, ddfstrt, fmodewidth, minearly;
217 LONG offset;
219 fmodewidth = 16 << csd->fmode_bpl;
220 x = bm->leftedge;
221 y = csd->starty + (bm->topedge >> csd->interlace);
223 yscroll = 0;
224 if (y < 10) {
225 yscroll = y - 10;
226 y = 10;
229 xmaxscroll = 1 << (1 + csd->fmode_bpl);
230 xdelay = x & (fmodewidth - 1);
231 xscroll = -x;
233 yend = y + (bm->displayheight >> csd->interlace);
234 yend = limitheight(csd, yend, FALSE, TRUE);
235 ystart = y - csd->extralines;
237 modulo = (csd->interlace ? bm->bytesperrow : 0) + csd->modulo;
238 ddfstrt = csd->ddfstrt;
240 offset = ((xscroll + (xmaxscroll << 3) - 1) >> 3) & ~(xmaxscroll - 1);
241 offset -= (yscroll * bm->bytesperrow) << (csd->interlace ? 1 : 0);
243 minearly = 1 << fetchunits[csd->fmode_bpl * 4 + csd->res];
244 if (xdelay) {
245 ddfstrt -= minearly;
246 modulo -= (minearly << csd->res) / 4;
247 offset -= (minearly << csd->res) / 4;
250 copptr[1] = (y << 8) | (csd->startx); //(y << 8) + (x + 1);
251 copptr[3] = (yend << 8) | ((csd->startx + 0x140) & 0xff); //((y + (bm->rows >> csd->interlace)) << 8) + ((x + 1 + (bm->width >> csd->res)) & 0x00ff);
252 copptr[5] = ((y >> 8) & 7) | (((yend >> 8) & 7) << 8) | 0x2000;
254 copbpl = c2d->copper2_bpl;
255 for (i = 0; i < bm->depth; i++) {
256 ULONG pptr = (ULONG)(bm->pbm->Planes[csd->bploffsets[i]]);
257 if (csd->interlace && odd)
258 pptr += bm->bytesperrow;
259 pptr += offset;
260 copbpl[1] = (UWORD)(pptr >> 16);
261 copbpl[3] = (UWORD)(pptr >> 0);
262 copbpl += 4;
265 xdelay <<= 2 - csd->res;
266 copptr[11] =
267 (((xdelay >> 2) & 0x0f) << 0) | (((xdelay >> 2) & 0x0f) << 4)
268 | ((xdelay >> 6) << 10) | ((xdelay >> 6) << 14)
269 | ((xdelay & 3) << 8) | ((xdelay & 3) << 12);
271 copptr[7] = ddfstrt;
272 copptr[9] = csd->ddfstop;
273 copptr[13] = modulo;
274 copptr[15] = modulo;
276 yend = y + bm->displayheight + yscroll;
277 yend = limitheight(csd, yend, FALSE, TRUE);
278 copptr = c2d->copper2_bplcon0;
279 copptr[4] = (yend << 8) | 0x05;
280 if (yend < 256 || ystart >= 256) {
281 copptr[2] = 0x00df;
282 copptr[3] = 0x00fe;
283 } else {
284 copptr[2] = 0xffdf;
285 copptr[3] = 0xfffe;
288 copptr = c2d->copper2;
289 if (ystart >= 256)
290 copptr[0] = 0xffdf;
291 else
292 copptr[0] = 0x01fe;
293 copptr[2] = (ystart << 8) | 0x05;
294 copptr = c2d->copper2_bplcon0;
295 copptr[-2] = (y << 8) | 0x05;
298 static void setcopperscroll(struct amigavideo_staticdata *csd, struct amigabm_data *bm)
300 setcopperscroll2(csd, bm, &csd->copper2, FALSE);
301 if (csd->interlace)
302 setcopperscroll2(csd, bm, &csd->copper2i, TRUE);
305 static UWORD get_copper_list_length(struct amigavideo_staticdata *csd, UBYTE depth)
307 UWORD v;
309 if (csd->aga && csd->aga_enabled) {
310 v = 1000 + ((1 << depth) + 1 + (1 << depth) / 32 + 1) * 2;
311 } else {
312 v = 1000;
314 return v * 2;
317 static void createcopperlist(struct amigavideo_staticdata *csd, struct amigabm_data *bm, struct copper2data *c2d, BOOL lace)
319 struct GfxBase *GfxBase = (struct GfxBase *)csd->cs_GfxBase;
320 volatile WORD *system_bplcon0 = (volatile WORD *)&GfxBase->system_bplcon0;
321 UWORD *c;
322 UWORD i;
323 UWORD bplcon0, bplcon0_res;
324 ULONG pptr;
326 D(bug("[AmigaVideo] %s()\n", __func__));
327 D(bug("[AmigaVideo] %s: GfxBase @ 0x%p\n", __func__, GfxBase));
328 D(bug("[AmigaVideo] %s: system_bplcon0 @ 0x%p\n", __func__, system_bplcon0));
330 c = c2d->copper2;
331 D(bug("[AmigaVideo] %s: Copperlist%d %p\n", __func__, lace ? 2 : 1, c));
333 bplcon0_res = *system_bplcon0 & ~BPLCONMASK;
334 D(bug("[AmigaVideo] %s: bplcon0_res = %04x\n", __func__, bplcon0_res));
336 if (csd->res == 1)
337 bplcon0_res |= 0x8000;
338 else if (csd->res == 2)
339 bplcon0_res |= 0x0040;
340 else
341 bplcon0_res = 0;
343 csd->bplcon0_null = 0x0201 | (csd->interlace ? 4 : 0) | bplcon0_res;
344 csd->bplcon3 = ((csd->sprite_res + 1) << 6) | 2; // spriteres + bordersprite
346 *c++ = 0x01fe;
347 *c++ = 0xfffe;
348 *c++ = 0xffff;
349 *c++ = 0xfffe;
351 *c++ = 0x0100;
352 *c++ = csd->bplcon0_null;
354 c2d->copper2_bpl = c;
355 for (i = 0; i < bm->depth; i++) {
356 pptr = (ULONG)(bm->pbm->Planes[csd->bploffsets[i]]);
357 if (lace)
358 pptr += bm->bytesperrow;
359 *c++ = 0xe0 + i * 4;
360 *c++ = (UWORD)(pptr >> 16);
361 *c++ = 0xe2 + i * 4;
362 *c++ = (UWORD)(pptr >> 0);
365 csd->use_colors = 1 << bm->depth;
366 // need to update sprite colors
367 if (csd->use_colors < 16 + 4)
368 csd->use_colors = 16 + 4;
369 if (csd->res == 2 && !csd->aga)
370 csd->use_colors = 32; /* ECS "scrambled" superhires */
372 if (csd->use_colors > 32 && (csd->modeid & EXTRAHALFBRITE_KEY))
373 csd->use_colors = 32;
374 if (csd->modeid & HAM_KEY) {
375 if (bm->depth <= 6)
376 csd->use_colors = 16 + 4;
377 else
378 csd->use_colors = 64;
381 c2d->copper2_scroll = c;
382 *c++ = 0x008e;
383 *c++ = 0;
384 *c++ = 0x0090;
385 *c++ = 0;
386 *c++ = 0x01e4;
387 *c++ = 0;
388 *c++ = 0x0092;
389 *c++ = 0;
390 *c++ = 0x0094;
391 *c++ = 0;
392 *c++ = 0x0102;
393 *c++ = 0;
394 *c++ = 0x0108;
395 *c++ = 0;
396 *c++ = 0x010a;
397 *c++ = 0;
398 *c++ = 0x0104;
399 *c++ = 0x0024 | ((csd->aga && !(csd->modeid & EXTRAHALFBRITE_KEY)) ? 0x0200 : 0);
401 c2d->copper2_fmode = NULL;
402 if (csd->aga && csd->aga_enabled) {
403 *c++ = 0x010c;
404 *c++ = 0x0011;
405 *c++ = 0x01fc;
406 c2d->copper2_fmode = c;
407 *c++ = 0;
410 bplcon0 = csd->bplcon0_null;
411 if (bm->depth > 7)
412 bplcon0 |= 0x0010;
413 else
414 bplcon0 |= bm->depth << 12;
415 if (csd->modeid & HAM_KEY)
416 bplcon0 |= 0x0800;
418 *system_bplcon0 = (*system_bplcon0 & ~BPLCONMASK) | bplcon0;
419 D(bug("[AmigaVideo] %s: system_bplcon0 = %04x\n", __func__, *system_bplcon0));
421 c2d->copper2_palette = c;
422 if (csd->aga && csd->aga_enabled) {
423 // hi
424 for (i = 0; i < csd->use_colors; i++) {
425 UBYTE agac = i & 31;
426 if (agac == 0) {
427 *c++ = 0x106;
428 *c++ = csd->bplcon3 | ((i / 32) << 13);
430 *c++ = 0x180 + agac * 2;
431 *c++ = 0x000;
433 c2d->copper2_palette_aga_lo = c;
434 // lo
435 for (i = 0; i < csd->use_colors; i++) {
436 UBYTE agac = i & 31;
437 if (agac == 0) {
438 *c++ = 0x106;
439 *c++ = csd->bplcon3 | ((i / 32) << 13) | 0x0200;
441 *c++ = 0x180 + agac * 2;
442 *c++ = 0x000;
444 *c++ = 0x106;
445 *c++ = csd->bplcon3;
446 } else {
447 // ocs/ecs
448 for (i = 0; i < csd->use_colors; i++) {
449 *c++ = 0x180 + i * 2;
450 *c++ = 0x000;
454 csd->extralines = (c - c2d->copper2) / 112 + 1;
456 *c++ = 0xffff;
457 *c++ = 0xfffe;
458 c2d->copper2_bplcon0 = c;
459 *c++ = 0x0100;
460 *c++ = bplcon0;
462 *c++ = 0xffff;
463 *c++ = 0xfffe;
464 *c++ = 0xffff;
465 *c++ = 0xfffe;
467 *c++ = 0x0100;
468 *c++ = csd->bplcon0_null;
470 if (csd->interlace) {
471 ULONG nextptr = (ULONG)(lace ? csd->copper2.copper2 : csd->copper2i.copper2);
472 *c++ = 0x0084;
473 *c++ = (UWORD)(nextptr >> 16);
474 *c++ = 0x0086;
475 *c++ = (UWORD)(nextptr >> 0);
477 *c++ = 0xffff;
478 *c++ = 0xfffe;
482 BOOL setbitmap(struct amigavideo_staticdata *csd, struct amigabm_data *bm)
484 csd->width = bm->width;
485 csd->height = csd->interlace ? (bm->height + 1) / 2 : bm->height;
486 csd->modulo = bm->bytesperrow - csd->modulopre / (4 >> csd->res);
487 csd->modulo &= ~((2 << csd->fmode_bpl) - 1);
488 csd->updatescroll = bm;
489 csd->depth = bm->depth;
490 setcopperscroll(csd, bm);
492 D(bug("setbitmap bm=%x mode=%08x w=%d h=%d d=%d bpr=%d\n",
493 bm, csd->modeid, bm->width, bm->height, bm->depth, bm->bytesperrow));
494 return TRUE;
497 BOOL setmode(struct amigavideo_staticdata *csd, struct amigabm_data *bm)
499 volatile struct Custom *custom = (struct Custom*)0xdff000;
500 struct GfxBase *GfxBase = (APTR)csd->cs_GfxBase;
501 UWORD ddfstrt, ddfstop;
502 UBYTE fetchunit, maxplanes;
503 UWORD bplwidth, viewwidth;
504 UBYTE i;
506 if (csd->disp == bm)
507 return TRUE;
509 resetmode(csd);
511 csd->res = 0;
512 if ((csd->modeid & SUPER_KEY) == SUPER_KEY)
513 csd->res = 2;
514 else if ((csd->modeid & SUPER_KEY) == HIRES_KEY)
515 csd->res = 1;
516 csd->interlace = (csd->modeid & LORESLACE_KEY) ? 1 : 0;
517 csd->fmode_bpl = csd->aga && csd->aga_enabled ? 2 : 0;
519 fetchunit = fetchunits[csd->fmode_bpl * 4 + csd->res];
520 maxplanes = fm_maxplanes[csd->fmode_bpl * 4 + csd->res];
522 D(bug("res %d fmode %d depth %d maxplanes %d aga %d agae %d\n",
523 csd->res, csd->fmode_bpl, bm->depth, maxplanes, csd->aga, csd->aga_enabled));
525 if (bm->depth > (1 << maxplanes)) {
526 if (csd->aga && !csd->aga_enabled) {
527 // Enable AGA if requesting AGA only mode.
528 // This is a compatibility hack because our display
529 // database currently contains all AGA modes even if AGA
530 // is "disabled".
531 GfxBase->ChipRevBits0 = SETCHIPREV_AA;
532 csd->aga_enabled = TRUE;
533 csd->fmode_bpl = csd->aga && csd->aga_enabled ? 2 : 0;
534 fetchunit = fetchunits[csd->fmode_bpl * 4 + csd->res];
535 maxplanes = fm_maxplanes[csd->fmode_bpl * 4 + csd->res];
537 if (bm->depth > (1 << maxplanes))
538 return FALSE;
541 viewwidth = bm->width;
542 // use nominal width for now
543 if ((viewwidth << csd->res) > 320)
544 viewwidth = 320 << csd->res;
546 D(bug("setmode bm=%x mode=%08x w=%d h=%d d=%d bpr=%d fu=%d\n",
547 bm, csd->modeid, bm->width, bm->height, bm->depth, bm->bytesperrow, fetchunit));
549 bplwidth = viewwidth >> (csd->res + 1);
550 ddfstrt = (csd->startx / 2) & ~((1 << fetchunit) - 1);
551 ddfstop = ddfstrt + ((bplwidth + ((1 << fetchunit) - 1) - 2 * (1 << fetchunit)) & ~((1 << fetchunit) - 1));
552 csd->modulopre = ddfstop + 2 * (1 << fetchunit) - ddfstrt;
553 ddfstrt -= 1 << maxplanes;
554 csd->ddfstrt = ddfstrt;
555 csd->ddfstop = ddfstop;
557 for (i = 0; i < 8; i++)
558 csd->bploffsets[i] = i;
559 if ((csd->modeid & HAM_KEY) && bm->depth > 6) {
560 csd->bploffsets[0] = 6;
561 csd->bploffsets[1] = 7;
562 for (i = 0; i < 6; i++)
563 csd->bploffsets[i + 2] = i;
566 csd->copper2.copper2 = AllocVec(get_copper_list_length(csd, bm->depth), MEMF_CLEAR | MEMF_CHIP);
567 if (csd->interlace)
568 csd->copper2i.copper2 = AllocVec(get_copper_list_length(csd, bm->depth), MEMF_CLEAR | MEMF_CHIP);
569 createcopperlist(csd, bm, &csd->copper2, FALSE);
570 if (csd->interlace) {
571 createcopperlist(csd, bm, &csd->copper2i, TRUE);
574 setfmode(csd);
575 setpalntsc(csd, csd->modeid);
576 custom->bplcon0 = csd->bplcon0_null;
578 bm->displaywidth = viewwidth;
579 bm->displayheight = limitheight(csd, bm->height, csd->interlace, FALSE);
581 setbitmap(csd, bm);
583 GfxBase->LOFlist = csd->copper2.copper2;
584 GfxBase->SHFlist = csd->interlace ? csd->copper2i.copper2 : csd->copper2.copper2;
585 custom->dmacon = 0x8100;
587 setcoppercolors(csd);
588 setspritepos(csd, csd->spritex, csd->spritey);
590 csd->disp = bm;
591 return 1;
594 UBYTE av__PickPen(struct amigavideo_staticdata *csd, ULONG pixel)
596 UBYTE retval = 1;
597 return retval;
600 BOOL setsprite(OOP_Class *cl, OOP_Object *o, WORD width, WORD height, struct pHidd_Gfx_SetCursorShape *msg)
602 struct amigavideo_staticdata *csd = CSD(cl);
603 struct Library *OOPBase = csd->cs_OOPBase;
604 OOP_MethodID HiddGfxBase = csd->cs_HiddGfxBase;
605 OOP_MethodID HiddBitMapBase = csd->cs_HiddBitMapBase;
606 OOP_Object *bmPFObj = NULL;
607 HIDDT_PixelFormat *bmPF;
608 IPTR pf, bmcmod;
609 UWORD fetchsize;
610 UWORD bitmapwidth = width;
611 UWORD y, *p;
613 OOP_GetAttr(msg->shape, aHidd_BitMap_PixFmt, (IPTR*)&bmPFObj);
614 OOP_GetAttr(bmPFObj, aHidd_PixFmt_ColorModel, &bmcmod);
615 if (bmcmod == vHidd_ColorModel_TrueColor)
617 OOP_GetAttr(bmPFObj, aHidd_PixFmt_StdPixFmt, (IPTR*)&pf);
618 bmPF = (HIDDT_PixelFormat *)HIDD_Gfx_GetPixFmt(o, pf);
621 if (csd->aga && csd->aga_enabled && width > 16)
622 csd->fmode_spr = 2;
623 else
624 csd->fmode_spr = 0;
625 fetchsize = 2 << csd->fmode_spr;
626 width = 16 << csd->fmode_spr;
628 if (width != csd->sprite_width || height != csd->sprite_height) {
629 resetsprite(csd);
630 csd->spritedatasize = fetchsize * 2 + fetchsize * height * 2 + fetchsize * 2;
631 csd->sprite = AllocMem(csd->spritedatasize, MEMF_CHIP | MEMF_CLEAR);
632 if (!csd->sprite)
633 return FALSE;
634 csd->sprite_width = width;
635 csd->sprite_height = height;
636 csd->sprite_offset_x = msg->xoffset;
637 csd->sprite_offset_y = msg->yoffset;
639 p = csd->sprite;
640 p += fetchsize;
641 for(y = 0; y < height; y++) {
642 UWORD xx, xxx, x;
643 for (xx = 0, xxx = 0; xx < width; xx += 16, xxx++) {
644 UWORD pix1 = 0, pix2 = 0;
645 for(x = 0; x < 16; x++) {
646 UBYTE c = 0;
647 if (xx + x < bitmapwidth)
649 if (bmcmod != vHidd_ColorModel_TrueColor)
650 c = HIDD_BM_GetPixel(msg->shape, x, y);
651 else
653 HIDDT_Pixel pix = HIDD_BM_GetPixel(msg->shape, x, y);
654 c = 0;
655 if ((ALPHA_COMP(pix, bmPF) & 0xFF00) == 0xFF00)
656 c = av__PickPen(csd, ((RED_COMP(pix, bmPF) & 0xFF00) << 8) | (GREEN_COMP(pix, bmPF) & 0xFF00) | ((BLUE_COMP(pix, bmPF) >> 8) & 0xFF));
657 else c = 0;
660 pix1 <<= 1;
661 pix2 <<= 1;
662 pix1 |= (c & 1) ? 1 : 0;
663 pix2 |= (c & 2) ? 1 : 0;
665 p[xxx] = pix1;
666 p[xxx + fetchsize / 2] = pix2;
668 p += fetchsize;
670 setspritepos(csd, csd->spritex, csd->spritey);
671 setspritevisible(csd, csd->cursorvisible);
672 return TRUE;
675 void setspritepos(struct amigavideo_staticdata *csd, WORD x, WORD y)
677 UWORD ctl, pos;
679 csd->spritex = x;
680 csd->spritey = y;
681 if (!csd->sprite || csd->sprite_height == 0)
682 return;
684 x += csd->sprite_offset_x << csd->res;
685 x <<= (2 - csd->res); // convert x to shres coordinates
686 x += (csd->startx - 1) << 2; // display left edge offset
688 if (csd->interlace)
689 y /= 2; // y is always in nonlaced
690 y += csd->starty;
691 y += csd->sprite_offset_y;
693 pos = (y << 8) | (x >> 3);
694 ctl = ((y + csd->sprite_height) << 8);
695 ctl |= ((y >> 8) << 2) | (((y + csd->sprite_height) >> 8) << 1) | ((x >> 2) & 1) | ((x & 3) << 3);
696 csd->spritepos = pos;
697 csd->spritectl = ctl;
700 void setspritevisible(struct amigavideo_staticdata *csd, BOOL visible)
702 csd->cursorvisible = visible;
703 if (visible) {
704 if (csd->copper1_spritept) {
705 UWORD *p = csd->sprite;
706 setfmode(csd);
707 csd->copper1_spritept[0] = (UWORD)(((ULONG)p) >> 16);
708 csd->copper1_spritept[2] = (UWORD)(((ULONG)p) >> 0);
710 } else {
711 setnullsprite(csd);
715 BOOL setcolors(struct amigavideo_staticdata *csd, struct pHidd_BitMap_SetColors *msg, BOOL visible)
717 UWORD i, j;
718 if (msg->firstColor + msg->numColors > csd->max_colors)
719 return FALSE;
720 j = 0;
721 for (i = msg->firstColor; j < msg->numColors; i++, j++) {
722 UBYTE red, green, blue;
723 red = msg->colors[j].red >> 8;
724 green = msg->colors[j].green >> 8;
725 blue = msg->colors[j].blue >> 8;
726 csd->palette[i * 3 + 0] = red;
727 csd->palette[i * 3 + 1] = green;
728 csd->palette[i * 3 + 2] = blue;
729 //bug("%d: %02x %02x %02x\n", i, red, green, blue);
731 if (visible)
732 setcoppercolors(csd);
733 return TRUE;
735 void setscroll(struct amigavideo_staticdata *csd, struct amigabm_data *bm)
737 csd->updatescroll = bm;
740 /* Convert Z flag to normal C-style return variable. Fun. */
741 UBYTE bltnode_wrapper(void)
743 UBYTE ret;
744 asm volatile (
745 " pea 1f\n"
746 " move.l 4(%%a1),-(%%sp)\n"
747 " rts\n"
748 "1: sne %d0\n"
749 " move.b %%d0,%0\n"
750 : "=g" (ret)
752 return ret;
755 #define BEAMSYNC_ALARM 0x0f00
756 /* AOS must use some GfxBase flags field for these. Later.. */
757 #define bqvar GfxBase->pad3
758 #define BQ_NEXT 1
759 #define BQ_BEAMSYNC 2
760 #define BQ_BEAMSYNCWAITING 4
761 #define BQ_MISSED 8
763 static AROS_INTH1(gfx_blit, struct GfxBase *, GfxBase)
765 AROS_INTFUNC_INIT
767 volatile struct Custom *custom = (struct Custom*)0xdff000;
768 struct bltnode *bn = NULL;
769 UBYTE v;
770 UWORD dmaconr;
772 dmaconr = custom->dmaconr;
773 dmaconr = custom->dmaconr;
774 if (dmaconr & 0x4000) {
775 /* Blitter still active? Wait for next interrupt. */
776 return 0;
779 if (GfxBase->blthd == NULL && GfxBase->bsblthd == NULL) {
780 custom->intena = INTF_BLIT;
781 return 0;
784 /* Was last blit in this node? */
785 if (bqvar & BQ_NEXT) {
786 bqvar &= ~(BQ_NEXT | BQ_MISSED);
787 if (bqvar & BQ_BEAMSYNC)
788 bn = GfxBase->bsblthd;
789 else
790 bn = GfxBase->blthd;
791 if (bn->stat == CLEANUP)
792 AROS_UFC2(UBYTE, bn->cleanup,
793 AROS_UFCA(struct Custom *, custom, A0),
794 AROS_UFCA(struct bltnode*, bn, A1));
795 /* Next node */
796 bn = bn->n;
797 if (bqvar & BQ_BEAMSYNC)
798 GfxBase->bsblthd = bn;
799 else
800 GfxBase->blthd = bn;
803 if (GfxBase->bsblthd) {
804 bn = GfxBase->bsblthd;
805 bqvar |= BQ_BEAMSYNC;
806 } else if (GfxBase->blthd) {
807 bn = GfxBase->blthd;
808 bqvar &= ~BQ_BEAMSYNC;
811 if (!bn) {
812 /* Last blit finished */
813 bqvar = 0;
814 custom->intena = INTF_BLIT;
815 GfxBase->blthd = GfxBase->bsblthd = NULL;
816 DisownBlitter();
817 return 0;
820 if (bqvar & BQ_BEAMSYNC) {
821 UWORD vpos = VBeamPos();
822 bqvar &= ~BQ_BEAMSYNCWAITING;
823 if (!(bqvar & BQ_MISSED) && bn->beamsync > vpos) {
824 volatile struct CIA *ciab = (struct CIA*)0xbfd000;
825 UWORD w = BEAMSYNC_ALARM - (bn->beamsync - vpos);
826 bqvar |= BQ_BEAMSYNCWAITING;
827 ciab->ciacrb &= ~0x80;
828 ciab->ciatodhi = 0;
829 ciab->ciatodmid = w >> 8;
830 ciab->ciatodlow = w;
831 return 0;
835 v = AROS_UFC2(UBYTE, bltnode_wrapper,
836 AROS_UFCA(struct Custom *, custom, A0),
837 AROS_UFCA(struct bltnode*, bn, A1));
839 dmaconr = custom->dmaconr;
840 dmaconr = custom->dmaconr;
841 if (!(dmaconr & 0x4000)) {
842 /* Eh? Blitter not active?, better fake the interrupt. */
843 custom->intreq = INTF_SETCLR | INTF_BLIT;
846 if (v) {
847 /* Handle same node again next time */
848 return 0;
851 bqvar |= BQ_NEXT;
853 return 0;
855 AROS_INTFUNC_EXIT
858 static AROS_INTH1(gfx_beamsync, struct amigavideo_staticdata*, csd)
860 AROS_INTFUNC_INIT
862 struct GfxBase *GfxBase = (APTR)csd->cs_GfxBase;
864 if (bqvar & BQ_BEAMSYNCWAITING) {
865 /* We only need to trigger blitter interrupt */
866 volatile struct Custom *custom = (struct Custom*)0xdff000;
867 custom->intreq = INTF_SETCLR | INTF_BLIT;
870 return FALSE;
872 AROS_INTFUNC_EXIT
875 static AROS_INTH1(gfx_vblank, struct amigavideo_staticdata*, csd)
877 AROS_INTFUNC_INIT
879 struct GfxBase *GfxBase = (APTR)csd->cs_GfxBase;
880 volatile struct Custom *custom = (struct Custom*)0xdff000;
881 BOOL lof = (custom->vposr & 0x8000) != 0;
883 if (csd->interlace) {
884 custom->cop2lc = (ULONG)(lof ? GfxBase->LOFlist : GfxBase->SHFlist);
885 } else {
886 custom->cop2lc = (ULONG)GfxBase->LOFlist;
887 /* We may be in SHF mode after switching interlace off. Fix it here. */
888 if (!lof)
889 custom->vposw = custom->vposr | 0x8000;
892 csd->framecounter++;
893 if (csd->sprite) {
894 UWORD *p = csd->sprite;
895 p[0] = csd->spritepos;
896 p[1 << csd->fmode_spr] = csd->spritectl;
899 if (csd->updatescroll) {
900 setcopperscroll(csd, csd->updatescroll);
901 csd->updatescroll = NULL;
904 if (bqvar & BQ_BEAMSYNC)
905 bqvar |= BQ_MISSED;
907 return FALSE;
909 AROS_INTFUNC_EXIT
912 void initcustom(struct amigavideo_staticdata *csd)
914 UBYTE i;
915 UWORD *c;
916 UWORD vposr, val;
917 struct GfxBase *GfxBase;
918 struct Library *OOPBase;
919 volatile struct Custom *custom = (struct Custom*)0xdff000;
920 volatile struct CIA *ciab = (struct CIA*)0xbfd000;
922 D(bug("[AmigaVideo] %s()\n", __func__));
924 /* Reset audio registers to values that help emulation
925 * if some program enables audio DMA without setting period
926 * or length. Very high period emulation is very CPU intensive.
928 for (i = 0; i < 4; i++) {
929 custom->aud[i].ac_vol = 0;
930 custom->aud[i].ac_per = 100;
931 custom->aud[i].ac_len = 1000;
934 /* csd->cs_OOPBase was already set up.
935 * See amigavideo.conf's 'oopbase_field' config
937 OOPBase = csd->cs_OOPBase;
938 csd->cs_HiddBitMapBase = OOP_GetMethodID(IID_Hidd_BitMap, 0);
939 csd->cs_HiddGfxBase = OOP_GetMethodID(IID_Hidd_Gfx, 0);
941 csd->cs_UtilityBase = TaggedOpenLibrary(TAGGEDOPEN_UTILITY);
942 if (!csd->cs_UtilityBase)
943 Alert(AT_DeadEnd | AN_Hidd | AG_OpenLib | AO_UtilityLib);
944 csd->cs_GfxBase = TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS);
945 if (!csd->cs_GfxBase)
946 Alert(AT_DeadEnd | AN_Hidd | AG_OpenLib | AO_GraphicsLib);
947 GfxBase = ((struct GfxBase *)csd->cs_GfxBase);
948 GfxBase->cia = OpenResource("ciab.resource");
950 /* Reset now we have the bases */
951 resetcustom(csd);
952 resetsprite(csd);
954 csd->inter.is_Code = (APTR)gfx_vblank;
955 csd->inter.is_Data = csd;
956 csd->inter.is_Node.ln_Name = "GFX VBlank server";
957 csd->inter.is_Node.ln_Pri = 25;
958 csd->inter.is_Node.ln_Type = NT_INTERRUPT;
959 AddIntServer(INTB_VERTB, &csd->inter);
961 /* There are programs that take over the system and
962 * assume SysBase->IntVects[BLITTER].iv_Data = GfxBase!
964 GfxBase->bltsrv.is_Code = (APTR)gfx_blit;
965 GfxBase->bltsrv.is_Data = GfxBase;
966 GfxBase->bltsrv.is_Node.ln_Name = "Blitter";
967 GfxBase->bltsrv.is_Node.ln_Type = NT_INTERRUPT;
968 SetIntVector(INTB_BLIT, &GfxBase->bltsrv);
969 custom->intena = INTF_BLIT;
971 // CIA-B TOD counts scanlines */
972 GfxBase->timsrv.is_Code = (APTR)gfx_beamsync;
973 GfxBase->timsrv.is_Data = csd;
974 GfxBase->timsrv.is_Node.ln_Name = "Beamsync";
975 GfxBase->timsrv.is_Node.ln_Type = NT_INTERRUPT;
976 Disable();
977 AddICRVector(GfxBase->cia, 2, &GfxBase->timsrv);
978 AbleICR(GfxBase->cia, 1 << 2);
979 ciab->ciacrb |= 0x80;
980 ciab->ciatodhi = 0;
981 /* TOD/ALARM CIA bug: http://eab.abime.net/showpost.php?p=277315&postcount=10 */
982 ciab->ciatodmid = BEAMSYNC_ALARM >> 8;
983 ciab->ciatodlow = BEAMSYNC_ALARM & 0xff;
984 ciab->ciacrb &= ~0x80;
985 ciab->ciatodhi = 0;
986 ciab->ciatodmid = 0;
987 ciab->ciatodlow = 0;
988 AbleICR(GfxBase->cia, 0x80 | (1 << 2));
989 Enable();
991 GfxBase->NormalDisplayColumns = 640;
992 GfxBase->NormalDisplayRows = (GfxBase->DisplayFlags & NTSC) ? 200 : 256;
993 GfxBase->MaxDisplayColumn = 640;
994 GfxBase->MaxDisplayRow = (GfxBase->DisplayFlags & NTSC) ? 200 : 256;
996 csd->startx = 0x81;
997 csd->starty = 0x28;
999 vposr = custom->vposr & 0x7f00;
1000 csd->aga = vposr >= 0x2200;
1001 csd->ecs_agnus = vposr >= 0x2000;
1002 val = custom->deniseid;
1003 custom->deniseid = custom->dmaconr;;
1004 if (val == custom->deniseid) {
1005 custom->deniseid = custom->dmaconr ^ 0x8000;
1006 if (val == custom->deniseid) {
1007 if ((val & (2 + 8)) == 8)
1008 csd->ecs_denise = TRUE;
1011 csd->max_colors = csd->aga ? 256 : 32;
1012 csd->palette = AllocVec(csd->max_colors * 3, MEMF_CLEAR);
1013 csd->copper1 = AllocVec(22 * 2 * sizeof(WORD), MEMF_CLEAR | MEMF_CHIP);
1014 csd->sprite_null = AllocMem(2 * 8, MEMF_CLEAR | MEMF_CHIP);
1015 csd->sprite_res = 0; /* lores */
1016 c = csd->copper1;
1017 for (i = 0; i < 8; i++) {
1018 *c++ = 0x0120 + i * 4;
1019 if (i == 0)
1020 csd->copper1_spritept = c;
1021 *c++ = (UWORD)(((ULONG)csd->sprite_null) >> 16);
1022 *c++ = 0x0122 + i * 4;
1023 *c++ = (UWORD)(((ULONG)csd->sprite_null) >> 0);
1025 *c++ = 0x0c03;
1026 *c++ = 0xfffe;
1027 *c++ = 0x008a;
1028 *c++ = 0x0000;
1029 csd->copper2_backup = c;
1030 *c++ = 0xffff;
1031 *c++ = 0xfffe;
1032 custom->cop1lc = (ULONG)csd->copper1;
1033 custom->cop2lc = (ULONG)csd->copper2_backup;
1034 custom->dmacon = 0x8000 | 0x0080 | 0x0040 | 0x0020;
1036 GfxBase->copinit = (struct copinit*)csd->copper1;
1038 D(bug("Copperlist0 %p\n", csd->copper1));