grf_cc.c revision 1.4 1 1.1 mw #include "grf.h"
2 1.1 mw #if NGRF > 0
3 1.1 mw
4 1.1 mw /* Graphics routines for the AMIGA native custom chip set. */
5 1.1 mw
6 1.1 mw #include "sys/param.h"
7 1.1 mw #include "sys/errno.h"
8 1.1 mw #include "grfioctl.h"
9 1.1 mw #include "grfvar.h"
10 1.1 mw #include "grf_ccreg.h"
11 1.1 mw #include "../include/cpu.h"
12 1.1 mw #include "../amiga/custom.h"
13 1.3 mw #include "../amiga/cia.h"
14 1.1 mw
15 1.1 mw extern caddr_t CHIPMEMADDR;
16 1.1 mw extern caddr_t chipmem_steal ();
17 1.1 mw
18 1.1 mw struct ccfb ccfb = {
19 1.3 mw DEF_DISP_WIDTH,
20 1.3 mw DEF_DISP_HEIGHT,
21 1.3 mw DEF_DISP_X, DEF_DISP_Y,
22 1.3 mw DEF_DISP_Z,
23 1.3 mw 0,
24 1.3 mw DEF_FB_WIDTH,
25 1.3 mw DEF_FB_HEIGHT,
26 1.3 mw 0,
27 1.3 mw DEF_FB_X, DEF_FB_Y, DEF_FB_Z,
28 1.3 mw #if 0
29 1.3 mw DEF_DIWSTRT, DEF_DIWSTOP, DEF_DDFSTRT, DEF_DDFSTOP,
30 1.3 mw #endif
31 1.3 mw DEF_COL0, DEF_COL1, DEF_COL2, DEF_COL3, 0,0,0,0,0,0,0,0,0,0,0,0,
32 1.3 mw DEF_COL10, DEF_COL11, DEF_COL12, DEF_COL13, 0,0,0,0,0,0,0,0,0,0,0,0,
33 1.3 mw 0, /* chip ram for beep sample */
34 1.3 mw DEF_PERIOD, DEF_VOLUME, /* beep sample period and volume */
35 1.3 mw 0,DEF_ABEEP, /* beep timer, timer init value */
36 1.3 mw 0,DEF_DBEEP, /* beep timer, timer init value */
37 1.3 mw 0,0, /* cop1, cop2 */
38 1.3 mw 0, /* pointer */
39 1.3 mw 0,0, /* mouseH, mouseV */
40 1.3 mw 0,0, /* lastMouseH, lastMouseV */
41 1.3 mw 0,0, /* mouseX, mouseY */
42 1.3 mw 0,0,0, /* mouseb1, mouseb2, mouseb3 */
43 1.3 mw 0,0, /* joy1, joy2 */
44 1.3 mw DEF_SCREEN,DEF_MOUSE, /* screen/mouse blank timer init */
45 1.3 mw 0,0, /* screenblank, mouseblank */
46 1.3 mw 0,0, /* enableFlag, pad */
47 1.3 mw };
48 1.3 mw
49 1.3 mw /*
50 1.3 mw * custom copper list structure. It replaces the macro method of
51 1.3 mw * building copper lists for a good reason. You want to change
52 1.3 mw * diwstrt in an ioctl() handler? well, with this struct, it is
53 1.3 mw * trivial :-)
54 1.3 mw *
55 1.3 mw * YOU DON'T WANT! ioctl's to the console should NOT use any
56 1.3 mw * implementation dependant data format to set values, they
57 1.3 mw * should pass hi-level information that is processed by
58 1.3 mw * the different console drivers. This driver would recalculate
59 1.3 mw * diwstrt (for example) from given disp_* values.
60 1.3 mw */
61 1.3 mw typedef struct {
62 1.3 mw u_short planes[6][4]; /* move + hi word, move + lo word */
63 1.3 mw u_short bplcon0[2]; /* move + viewmode */
64 1.3 mw u_short bplcon1[2]; /* move + BPLCON1 */
65 1.3 mw u_short bpl1mod[2]; /* move + BPL1MOD */
66 1.3 mw u_short bpl2mod[2]; /* move + BPL2MOD */
67 1.3 mw u_short diwstrt[2]; /* move + DIWSTRT */
68 1.3 mw u_short diwstop[2]; /* move + DIWSTOP */
69 1.3 mw u_short ddfstrt[2]; /* move + DDFSTRT */
70 1.3 mw u_short ddfstop[2]; /* move + DDFSTOP */
71 1.3 mw u_short sprites[4*8]; /* 8 sprites (0 = mouseptr, 7 unused) */
72 1.3 mw u_short colors[32*2]; /* move + color, 32 color regs */
73 1.3 mw u_short copother[4]; /* move + COP1LC (to point to other copper list) */
74 1.3 mw u_short finish[6]; /* COPEND instruction, -or-
75 1.3 mw move + (COP2LC, COP2LC + 2, COPJMP2) */
76 1.3 mw } COPPERLIST;
77 1.3 mw
78 1.3 mw /*
79 1.3 mw * custom struct to describe the mousepointer sprite in chipram.
80 1.3 mw * the header is tweaked by the vbl handler to move the mouse sprite
81 1.3 mw * around. the image[] array can be modified by the ioctl() handler
82 1.3 mw * to change the image for the sprite!
83 1.3 mw *
84 1.3 mw * Again, we should probably have a much higher resolution, generic
85 1.3 mw * sprite, and scale that down if necessary in the invidial drivers.
86 1.3 mw */
87 1.3 mw typedef struct {
88 1.3 mw u_char header[4];
89 1.3 mw u_short image[16*2];
90 1.3 mw u_short footer[2];
91 1.3 mw } SPRITEPTR;
92 1.3 mw
93 1.3 mw /*
94 1.3 mw * initializer values for the pointer struct in chip ram. It is a stupid
95 1.3 mw * crosshair sprite, in just one color. Do NOT change the first 4 bytes!
96 1.3 mw */
97 1.3 mw static SPRITEPTR pointerInit = {
98 1.3 mw 0x50,0x50,0x60,0x00, /* header */
99 1.3 mw 0x0000,0x0000, /* image */
100 1.3 mw 0x0080,0x0000,
101 1.3 mw 0x0080,0x0000,
102 1.3 mw 0x0080,0x0000,
103 1.3 mw 0x0080,0x0000,
104 1.3 mw 0x0080,0x0000,
105 1.3 mw 0x0080,0x0000,
106 1.3 mw 0x0080,0x0000,
107 1.3 mw 0x7f7f,0x0000,
108 1.3 mw 0x0080,0x0000,
109 1.3 mw 0x0080,0x0000,
110 1.3 mw 0x0080,0x0000,
111 1.3 mw 0x0080,0x0000,
112 1.3 mw 0x0080,0x0000,
113 1.3 mw 0x0080,0x0000,
114 1.3 mw 0x0080,0x0000,
115 1.3 mw 0x0000,0x0000, /* footer */
116 1.1 mw };
117 1.1 mw
118 1.3 mw /*
119 1.3 mw * void initbeep(struct ccfb *fb);
120 1.3 mw *
121 1.3 mw * synopsis:
122 1.3 mw * allocates 20 bytes for a sine wave sample (in chip ram) and
123 1.3 mw * initializes it. The audio hardware is turned on to play
124 1.3 mw * the sine wave sample in an infinite loop! The volume is just
125 1.3 mw * set to zero so you don't hear it... The sample is played in
126 1.3 mw * channels 0 and 1 so it goes out left+right audio jacks in the
127 1.3 mw * back of the machine. The DMA is not enabled here... it is
128 1.3 mw * enabled in cc_init() below... To make an audible beep, all
129 1.3 mw * that is needed is to turn on the volume, and then have the
130 1.3 mw * vbl handler turn off the volume after the desired beep duration
131 1.3 mw * has elapsed.
132 1.3 mw *
133 1.3 mw * The custom chip console should really be broken down into a
134 1.3 mw * physical and logical layer. The physical layer should have things
135 1.3 mw * like the bitplanes, copper list, mousepointer chipram, and the
136 1.3 mw * audible beep. The logical layers should have their own private
137 1.3 mw * mousepointer image, color palette, and beep parameters. The logical
138 1.3 mw * layer can keep an image of chipram for its own context - layers of
139 1.3 mw * sorts, in amigaos parlance.
140 1.3 mw */
141 1.3 mw static inline void
142 1.3 mw initbeep (fb)
143 1.3 mw struct ccfb *fb;
144 1.3 mw {
145 1.3 mw static char sample[20] = {
146 1.3 mw 0,39,75,103,121,127,121,103,75,39,0,
147 1.3 mw -39,-75,-103,-121,-127,-121,-103,-75,-39
148 1.3 mw };
149 1.3 mw short i;
150 1.3 mw char *ptr = chipmem_steal(20);
151 1.3 mw
152 1.3 mw if (!ptr) panic("Can't chipmem_steal 20 bytes!\n");
153 1.3 mw fb->beepSample = ptr;
154 1.3 mw for (i=0; i<20; i++) *ptr++ = sample[i];
155 1.3 mw fb->beepTimer = fb->beepTime;
156 1.3 mw custom.aud[0].lc = custom.aud[1].lc =
157 1.3 mw (void *)((caddr_t)fb->beepSample - CHIPMEMADDR);
158 1.3 mw custom.aud[0].len = custom.aud[1].len = 10;
159 1.3 mw custom.aud[0].per = custom.aud[1].per = fb->beepPeriod;
160 1.3 mw custom.aud[0].vol = custom.aud[1].vol = 0;
161 1.3 mw fb->beepTimer = fb->dbeepTimer = 0;
162 1.3 mw /* make SURE to disallow any audio interrupts - we don't need them */
163 1.3 mw custom.intena = INTF_AUD0 | INTF_AUD1 | INTF_AUD2 | INTF_AUD3;
164 1.3 mw }
165 1.3 mw
166 1.3 mw /*
167 1.3 mw * void initpointer (struct ccfb *fb);
168 1.3 mw *
169 1.3 mw * synopsis:
170 1.3 mw * this routine initializes the mouse pointer part of the ccfb.
171 1.3 mw * currently, it only needs to copy the initializer data to the
172 1.3 mw * allocated chip ram.
173 1.3 mw */
174 1.3 mw static inline void
175 1.3 mw initpointer (fb)
176 1.3 mw struct ccfb *fb;
177 1.3 mw {
178 1.3 mw SPRITEPTR *pointer = (SPRITEPTR *)fb->pointer;
179 1.1 mw
180 1.3 mw /* initialize pointer structure */
181 1.3 mw *pointer = pointerInit;
182 1.3 mw }
183 1.1 mw
184 1.3 mw /*
185 1.3 mw * void initcop (COPPERLIST *cop, COPPERLIST *othercop, int shf,
186 1.3 mw * struct ccfb *fb);
187 1.3 mw *
188 1.3 mw * synopsis:
189 1.3 mw * this function initializes one copperlist, treated as short-
190 1.3 mw * frame list if SHF is TRUE.
191 1.3 mw * it is assumed that initpointer has been called by the time
192 1.3 mw * initcop() is called.
193 1.3 mw *
194 1.3 mw * This is REALLY basic stuff... even teenaged eurodemo coders
195 1.3 mw * understand it :-) Normally, I'd have done this in assembly
196 1.3 mw * as a bunch of dc.w statements... it is just translated into
197 1.3 mw * struct form here...
198 1.3 mw *
199 1.3 mw * (yep, since this *is no* eurodemo here :-)) Hey, and we
200 1.3 mw * even have symbolic names for registers too :-))
201 1.3 mw */
202 1.3 mw static void inline
203 1.3 mw initcop (cop, othercop, shf, fb)
204 1.3 mw COPPERLIST *cop, *othercop;
205 1.3 mw int shf;
206 1.3 mw struct ccfb *fb;
207 1.3 mw {
208 1.3 mw SPRITEPTR *pointer = (SPRITEPTR *)fb->pointer;
209 1.3 mw unsigned long screen;
210 1.3 mw unsigned long rowbytes = fb->fb_width >> 3; /* width of display, in bytes */
211 1.3 mw u_short *plptr;
212 1.3 mw u_short c, i, strt, stop;
213 1.1 mw
214 1.1 mw /* get PA of display area */
215 1.3 mw screen = (unsigned long) fb->fb - (unsigned long) CHIPMEMADDR;
216 1.3 mw fb->fb_planesize = fb->fb_height * rowbytes;
217 1.1 mw
218 1.1 mw /* account for possible interlaced half-frame */
219 1.1 mw if (shf)
220 1.3 mw screen += rowbytes;
221 1.3 mw
222 1.1 mw /* account for oversized framebuffers */
223 1.3 mw screen += (fb->fb_x >> 3) + (fb->fb_y * rowbytes);
224 1.1 mw
225 1.3 mw #define MOVE COP_MOVE
226 1.3 mw
227 1.1 mw /* initialize bitplane pointers for all planes */
228 1.3 mw for (plptr = &cop->planes[0][0], i = 0; i < fb->fb_z; i++)
229 1.3 mw {
230 1.3 mw MOVE (plptr, bplpth(i), HIADDR (screen));
231 1.3 mw plptr += 2;
232 1.3 mw MOVE (plptr, bplptl(i), LOADDR (screen));
233 1.3 mw plptr += 2;
234 1.3 mw screen += fb->fb_planesize;
235 1.3 mw }
236 1.3 mw /* set the other bitplane pointers to 0, I hate this fixed size array.. */
237 1.3 mw while (i < 6)
238 1.1 mw {
239 1.3 mw MOVE (plptr, bplpth(i), 0);
240 1.3 mw plptr += 2;
241 1.3 mw MOVE (plptr, bplptl(i), 0);
242 1.3 mw plptr += 2;
243 1.3 mw i++;
244 1.1 mw }
245 1.1 mw
246 1.1 mw c = 0x8000 /* HIRES */
247 1.3 mw | ((fb->fb_z & 7) << 12) /* bitplane use */
248 1.1 mw | 0x0200 /* composite COLOR enable (whatever this is..) */
249 1.1 mw | 0x0004; /* LACE */
250 1.3 mw MOVE (cop->bplcon0, bplcon0, c);
251 1.3 mw MOVE (cop->bplcon1, bplcon1, 0); /* nothing */
252 1.3 mw
253 1.3 mw /* modulo is one line for interlaced displays, plus difference between
254 1.3 mw virtual and effective framebuffer size */
255 1.3 mw MOVE (cop->bpl1mod, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
256 1.3 mw MOVE (cop->bpl2mod, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
257 1.3 mw
258 1.1 mw /* these use pre-ECS register interpretation. Might want to go ECS ? */
259 1.1 mw strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff);
260 1.3 mw MOVE (cop->diwstrt, diwstrt, strt);
261 1.1 mw stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8)
262 1.1 mw | (((fb->disp_x + fb->disp_width)>>1) & 0xff));
263 1.3 mw MOVE (cop->diwstop, diwstop, stop);
264 1.1 mw /* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */
265 1.1 mw
266 1.1 mw /* these are from from HW-manual.. */
267 1.1 mw strt = ((strt & 0xff) - 9) >> 1;
268 1.3 mw MOVE (cop->ddfstrt, ddfstrt, strt);
269 1.1 mw stop = strt + (((fb->disp_width >> 4) - 2) << 2);
270 1.3 mw MOVE (cop->ddfstop, ddfstop, stop);
271 1.3 mw
272 1.3 mw /* sprites */
273 1.3 mw {
274 1.3 mw /* some cleverness... footer[0] is a ZERO longword in chip */
275 1.3 mw u_short *spr = &cop->sprites[0];
276 1.3 mw u_short addr = CUSTOM_OFS(sprpt[0]);
277 1.3 mw u_short i;
278 1.3 mw for (i=0; i<8; i++) { /* for all sprites (8 of em) do */
279 1.3 mw *spr++ = addr; *spr++ = HIADDR(&pointer->footer[0]);
280 1.3 mw addr += 2;
281 1.3 mw *spr++ = addr; *spr++ = LOADDR(&pointer->footer[0]);
282 1.3 mw addr += 2;
283 1.3 mw }
284 1.3 mw }
285 1.3 mw cop->sprites[0*4+1] = HIADDR((caddr_t)pointer-CHIPMEMADDR);
286 1.3 mw cop->sprites[0*4+3] = LOADDR((caddr_t)pointer-CHIPMEMADDR);
287 1.3 mw
288 1.3 mw /* colors */
289 1.3 mw for (i = 0; i < 32; i++)
290 1.3 mw MOVE (cop->colors+i*2, color[i], fb->col[i]);
291 1.1 mw
292 1.1 mw /* setup interlaced display by constantly toggling between two copperlists */
293 1.3 mw MOVE (cop->copother, cop1lch, HIADDR ((unsigned long) othercop - (unsigned long) CHIPMEMADDR));
294 1.3 mw MOVE (cop->copother+2, cop1lcl, LOADDR ((unsigned long) othercop - (unsigned long) CHIPMEMADDR));
295 1.3 mw
296 1.3 mw /* terminate copper list */
297 1.3 mw COP_END (cop->finish);
298 1.3 mw }
299 1.3 mw
300 1.3 mw /*
301 1.3 mw * Install a sprite.
302 1.3 mw * The sprites to be loaded on the alternate frames
303 1.3 mw * can be specified separately,
304 1.3 mw * so interlaced sprites are possible.
305 1.3 mw */
306 1.3 mw cc_install_sprite(gp, num, spr1, spr2)
307 1.3 mw struct grf_softc *gp;
308 1.3 mw int num;
309 1.3 mw u_short *spr1, *spr2;
310 1.3 mw {
311 1.3 mw struct ccfb *fb = &ccfb;
312 1.3 mw COPPERLIST *cop;
313 1.1 mw
314 1.3 mw cop = (COPPERLIST*)fb->cop1;
315 1.3 mw cop->sprites[num*4+1] = HIADDR((caddr_t)spr1-CHIPMEMADDR);
316 1.3 mw cop->sprites[num*4+3] = LOADDR((caddr_t)spr1-CHIPMEMADDR);
317 1.3 mw
318 1.3 mw cop = (COPPERLIST*)fb->cop2;
319 1.3 mw cop->sprites[num*4+1] = HIADDR((caddr_t)spr2-CHIPMEMADDR);
320 1.3 mw cop->sprites[num*4+3] = LOADDR((caddr_t)spr2-CHIPMEMADDR);
321 1.3 mw }
322 1.1 mw
323 1.3 mw /*
324 1.3 mw * Uninstall a sprite.
325 1.3 mw */
326 1.3 mw cc_uninstall_sprite(gp, num)
327 1.3 mw struct grf_softc *gp;
328 1.3 mw int num;
329 1.3 mw {
330 1.3 mw struct ccfb *fb = &ccfb;
331 1.3 mw SPRITEPTR *pointer = (SPRITEPTR*)fb->pointer;
332 1.3 mw COPPERLIST *cop;
333 1.3 mw
334 1.3 mw /* some cleverness... footer[0] is a ZERO longword in chip */
335 1.3 mw cop = (COPPERLIST*)fb->cop1;
336 1.3 mw cop->sprites[num*4+1] = HIADDR(&pointer->footer[0]);
337 1.3 mw cop->sprites[num*4+3] = LOADDR(&pointer->footer[0]);
338 1.3 mw
339 1.3 mw cop = (COPPERLIST*)fb->cop2;
340 1.3 mw cop->sprites[num*4+1] = HIADDR(&pointer->footer[0]);
341 1.3 mw cop->sprites[num*4+3] = LOADDR(&pointer->footer[0]);
342 1.1 mw }
343 1.1 mw
344 1.3 mw /*
345 1.3 mw * Install a copper list extension.
346 1.3 mw */
347 1.3 mw cc_install_cop_ext(gp, cl1, cl2)
348 1.3 mw struct grf_softc *gp;
349 1.3 mw u_short *cl1, *cl2;
350 1.3 mw {
351 1.3 mw struct ccfb *fb = &ccfb;
352 1.3 mw COPPERLIST *cop;
353 1.1 mw
354 1.3 mw cop = (COPPERLIST*)fb->cop1;
355 1.3 mw COP_MOVE (cop->finish+0, cop2lch, HIADDR((caddr_t)cl1-CHIPMEMADDR));
356 1.3 mw COP_MOVE (cop->finish+2, cop2lcl, LOADDR((caddr_t)cl1-CHIPMEMADDR));
357 1.3 mw COP_MOVE (cop->finish+4, copjmp2, 0);
358 1.3 mw
359 1.3 mw cop = (COPPERLIST*)fb->cop2;
360 1.3 mw COP_MOVE (cop->finish+0, cop2lch, HIADDR((caddr_t)cl2-CHIPMEMADDR));
361 1.3 mw COP_MOVE (cop->finish+2, cop2lcl, LOADDR((caddr_t)cl2-CHIPMEMADDR));
362 1.3 mw COP_MOVE (cop->finish+4, copjmp2, 0);
363 1.3 mw }
364 1.3 mw
365 1.3 mw /*
366 1.3 mw * Uninstall a copper list extension.
367 1.3 mw */
368 1.3 mw cc_uninstall_cop_ext(gp, cl1, cl2)
369 1.3 mw struct grf_softc *gp;
370 1.3 mw u_short *cl1, *cl2;
371 1.1 mw {
372 1.3 mw register struct ccfb *fb = &ccfb;
373 1.3 mw COPPERLIST *cop;
374 1.3 mw
375 1.3 mw cop = (COPPERLIST*)fb->cop1;
376 1.3 mw COP_END (cop->finish);
377 1.3 mw
378 1.3 mw cop = (COPPERLIST*)fb->cop2;
379 1.3 mw COP_END (cop->finish);
380 1.3 mw }
381 1.1 mw
382 1.3 mw /*
383 1.3 mw * Call this function any time a key is hit to ensure screen blanker unblanks
384 1.3 mw */
385 1.3 mw void
386 1.3 mw cc_unblank ()
387 1.3 mw {
388 1.3 mw if (!ccfb.screenBlank) { /* screenblank timer 0 means blank! */
389 1.3 mw COPPERLIST *c1 = (COPPERLIST *)ccfb.cop1, *c2 = (COPPERLIST *)ccfb.cop2;
390 1.3 mw /* turn on sprite and raster DMA */
391 1.3 mw custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
392 1.3 mw ccfb.mouseBlank = ccfb.mouseTime; /* start mouseblank timer */
393 1.3 mw /* screen was black, reset background color to the one in ccfb! */
394 1.3 mw c1->colors[1] = c2->colors[1] = ccfb.col[0];
395 1.3 mw }
396 1.3 mw /* restart the screenblank timer */
397 1.3 mw ccfb.screenBlank = ccfb.screenTime;
398 1.1 mw }
399 1.1 mw
400 1.3 mw /*
401 1.3 mw * void cc_bell(void);
402 1.3 mw *
403 1.3 mw * Synopsis:
404 1.3 mw * trigger audible bell
405 1.3 mw * Description
406 1.3 mw * Call this function to start a beep tone. The beep lasts for
407 1.3 mw * ccfb.beepTime 60ths of a second (can adjust it in the ccfb structure
408 1.3 mw * in an ioctl(). The sample is playing in left+right aud0+aud1 hardware
409 1.3 mw * channels all the time, just the volume is off when the beep isn't
410 1.3 mw * heard. So here we just turn on the volume (ccfb.beepVolume, it can
411 1.3 mw * also be set by ioctl() call) and set the timer (ccfb.beepTime can
412 1.3 mw * be set by ioctl() as well). The cc_vbl() routine counts down the
413 1.3 mw * timer and shuts off the volume when it reaches zero.
414 1.3 mw */
415 1.3 mw void
416 1.3 mw cc_bell ()
417 1.3 mw {
418 1.3 mw custom.aud[0].vol = ccfb.beepVolume;
419 1.3 mw custom.aud[1].vol = ccfb.beepVolume;
420 1.3 mw ccfb.beepTimer = ccfb.beepTime;
421 1.3 mw }
422 1.1 mw
423 1.1 mw /*
424 1.3 mw * void cc_vbl(void);
425 1.3 mw *
426 1.3 mw * synopsis:
427 1.3 mw * vertical blank service routine for the console.
428 1.3 mw * provides the following:
429 1.3 mw * samples mouse counters and positions mouse sprite
430 1.3 mw * samples joystick inputs
431 1.3 mw * counts down mouseblanker timer and blanks mouse if it is time
432 1.3 mw * counts down screenblanker timer and blanks if it is time
433 1.3 mw * counts down audio beep timer and shuts of the volume if the beep is done
434 1.3 mw * unblanks mouse/screen if mouse is moved
435 1.3 mw * not implemented yet:
436 1.3 mw * it should adjust color palette in copper list over time to effect
437 1.3 mw * display beep.
438 1.3 mw *
439 1.3 mw * There's black magic going on here with assembly-in-C.. Since this
440 1.3 mw * is an interrupt handler, and it should be fast, ignore the obscure but
441 1.3 mw * probably fast processing of the mouse for now...
442 1.3 mw */
443 1.3 mw void
444 1.3 mw cc_vbl ()
445 1.3 mw {
446 1.3 mw u_short w0, w1;
447 1.3 mw u_char *b0 = (u_char *)&w0, *b1 = (u_char *)&w1;
448 1.3 mw SPRITEPTR *p = (SPRITEPTR *)ccfb.pointer;
449 1.3 mw
450 1.3 mw ccfb.lastMouseH = ccfb.mouseH;
451 1.3 mw ccfb.lastMouseV = ccfb.mouseV;
452 1.3 mw
453 1.3 mw /* horizontal mouse counter */
454 1.3 mw w1 = custom.joy0dat;
455 1.3 mw b0[1] = ccfb.mouseH; /* last counter val */
456 1.3 mw ccfb.mouseH = b1[1]; /* current is now last */
457 1.3 mw b1[1] -= b0[1]; /* current - last */
458 1.3 mw b1[0] = (b1[1] & 0x80) ? 0xff : 0x00; /* ext.w */
459 1.3 mw ccfb.mouseX += w1;
460 1.3 mw if (ccfb.mouseX < 0) ccfb.mouseX = 0;
461 1.3 mw if (ccfb.mouseX > ccfb.fb_width-1) ccfb.mouseX = ccfb.fb_width-1;
462 1.3 mw
463 1.3 mw /* vertical mouse counter */
464 1.3 mw w1 = custom.joy0dat;
465 1.3 mw b1[1] = b1[0];
466 1.3 mw b0[1] = ccfb.mouseV;
467 1.3 mw ccfb.mouseV = b1[1];
468 1.3 mw b1[1] -= b0[1];
469 1.3 mw b1[0] = (b1[1] & 0x80) ? 0xff : 0x00; /* ext.w */
470 1.3 mw ccfb.mouseY += w1;
471 1.3 mw if (ccfb.mouseY < 0) ccfb.mouseY = 0;
472 1.3 mw if (ccfb.mouseY > ccfb.fb_height-1) ccfb.mouseY = ccfb.fb_height-1;
473 1.3 mw
474 1.3 mw /* mouse buttons (should renumber them, middle button should be #2!) */
475 1.3 mw ccfb.mouseb1 = (ciaa.pra & (1<<6)) ? 0 : !0;
476 1.3 mw ccfb.mouseb2 = (custom.pot1dat & (1<<2)) ? 0 : !0;
477 1.3 mw ccfb.mouseb3 = (custom.pot1dat & (1<<0)) ? 0 : !0;
478 1.3 mw
479 1.3 mw /* position pointer sprite */
480 1.3 mw w0 = ccfb.mouseY >> 1;
481 1.3 mw b0[1] += 0x24;
482 1.3 mw p->header[0] = b0[1];
483 1.3 mw b0[1] += 16;
484 1.3 mw p->header[2] = b0[1];
485 1.3 mw
486 1.3 mw w0 = ccfb.mouseX >> 1;
487 1.3 mw w0 += 120;
488 1.3 mw if (w0 & 1) p->header[3] |= 1; else p->header[3] &= ~1;
489 1.3 mw w0 >>= 1;
490 1.3 mw p->header[1] = b0[1];
491 1.3 mw
492 1.3 mw /* joystick #1 */
493 1.3 mw ccfb.joy0 = 0;
494 1.3 mw w0 = custom.joy1dat;
495 1.3 mw w1 = w0 >> 1;
496 1.3 mw w1 ^= w0;
497 1.3 mw if (w1 & (1<<9)) ccfb.joy0 |= JOYLEFT;
498 1.3 mw if (w1 & (1<<1)) ccfb.joy0 |= JOYRIGHT;
499 1.3 mw if (w1 & (1<<8)) ccfb.joy0 |= JOYUP;
500 1.3 mw if (w1 & (1<<0)) ccfb.joy0 |= JOYDOWN;
501 1.3 mw if ( (ciaa.pra & (1<<7)) == 0 ) ccfb.joy0 |= JOYBUTTON;
502 1.3 mw
503 1.3 mw /* joystick #2 (normally mouse port) */
504 1.3 mw ccfb.joy1 = 0;
505 1.3 mw w0 = custom.joy0dat;
506 1.3 mw w1 = w0 >> 1;
507 1.3 mw w1 ^= w0;
508 1.3 mw if (w1 & (1<<9)) ccfb.joy1 |= JOYLEFT;
509 1.3 mw if (w1 & (1<<1)) ccfb.joy1 |= JOYRIGHT;
510 1.3 mw if (w1 & (1<<8)) ccfb.joy1 |= JOYUP;
511 1.3 mw if (w1 & (1<<0)) ccfb.joy1 |= JOYDOWN;
512 1.3 mw if ( (ciaa.pra & (1<<6)) == 0 ) ccfb.joy1 |= JOYBUTTON;
513 1.3 mw
514 1.3 mw /* only do screenblanker/mouseblanker/display beep if screen is enabled */
515 1.3 mw if (ccfb.enableFlag) {
516 1.3 mw /* handle screen blanker */
517 1.3 mw if (ccfb.screenBlank) {
518 1.3 mw COPPERLIST *c1 = (COPPERLIST *)ccfb.cop1, *c2 = (COPPERLIST *)ccfb.cop2;
519 1.3 mw ccfb.screenBlank--;
520 1.3 mw if (!ccfb.screenBlank) {
521 1.3 mw custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
522 1.3 mw c1->colors[1] = c2->colors[1] = 0; /* make screen BLACK */
523 1.3 mw }
524 1.3 mw }
525 1.3 mw
526 1.3 mw /* handle mouse blanker */
527 1.3 mw if (ccfb.mouseBlank) {
528 1.3 mw ccfb.mouseBlank--;
529 1.3 mw if (!ccfb.mouseBlank) custom.dmacon = DMAF_SPRITE;
530 1.3 mw }
531 1.3 mw else if (ccfb.lastMouseH != ccfb.mouseH || ccfb.lastMouseV != ccfb.mouseV) {
532 1.3 mw cc_unblank();
533 1.3 mw ccfb.mouseBlank = ccfb.mouseTime;
534 1.3 mw custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
535 1.3 mw }
536 1.3 mw
537 1.3 mw /* handle visual beep (not implemented yet) */
538 1.3 mw }
539 1.3 mw
540 1.3 mw /* handle audible beep */
541 1.3 mw if (ccfb.beepTimer) ccfb.beepTimer--;
542 1.3 mw if (!ccfb.beepTimer) custom.aud[0].vol = custom.aud[1].vol = 0;
543 1.3 mw }
544 1.3 mw
545 1.4 mw /* useful function for debugging.. */
546 1.4 mw int
547 1.4 mw amiga_mouse_button (num)
548 1.4 mw int num;
549 1.4 mw {
550 1.4 mw switch (num)
551 1.4 mw {
552 1.4 mw case 1:
553 1.4 mw return ccfb.mouseb1;
554 1.4 mw
555 1.4 mw case 2:
556 1.4 mw return ccfb.mouseb2;
557 1.4 mw
558 1.4 mw case 3:
559 1.4 mw return ccfb.mouseb3;
560 1.4 mw
561 1.4 mw default:
562 1.4 mw return 0;
563 1.4 mw }
564 1.4 mw }
565 1.4 mw
566 1.4 mw
567 1.3 mw /* Initialize hardware.
568 1.1 mw * Must point g_display at a grfinfo structure describing the hardware.
569 1.1 mw * Returns 0 if hardware not present, non-zero ow.
570 1.1 mw */
571 1.1 mw cc_init(gp, ad)
572 1.1 mw struct grf_softc *gp;
573 1.1 mw struct amiga_device *ad;
574 1.1 mw {
575 1.1 mw register struct ccfb *fb = &ccfb;
576 1.1 mw struct grfinfo *gi = &gp->g_display;
577 1.1 mw u_char *fbp, save;
578 1.1 mw int fboff, fbsize;
579 1.1 mw int s;
580 1.1 mw
581 1.1 mw /* if already initialized, fail */
582 1.3 mw if (fb->fb) return 0;
583 1.3 mw
584 1.3 mw /* disable dma */
585 1.3 mw custom.dmacon = DMAF_BLTDONE
586 1.3 mw | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER | DMAF_DISK
587 1.3 mw | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0;
588 1.3 mw
589 1.3 mw fb->mouseBlank = fb->mouseTime;
590 1.3 mw fb->screenBlank = fb->screenTime;
591 1.1 mw
592 1.1 mw /* testing for the result is really redundant because chipmem_steal
593 1.1 mw panics if it runs out of memory.. */
594 1.1 mw fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
595 1.1 mw if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
596 1.3 mw || !(fb->cop1 = (u_short *) chipmem_steal (sizeof(COPPERLIST)))
597 1.3 mw || !(fb->cop2 = (u_short *) chipmem_steal (sizeof(COPPERLIST)))
598 1.3 mw || !(fb->pointer = (u_short *)chipmem_steal (sizeof(SPRITEPTR)))
599 1.3 mw )
600 1.1 mw return 0;
601 1.1 mw
602 1.1 mw /* clear the display. bzero only likes regions up to 64k, so call multiple times */
603 1.1 mw for (fboff = 0; fboff < fbsize; fboff += 64*1024)
604 1.1 mw bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);
605 1.1 mw
606 1.3 mw /* init the audio beep */
607 1.3 mw initbeep(fb);
608 1.3 mw /* initialize the sprite pointer */
609 1.3 mw initpointer(fb);
610 1.3 mw
611 1.3 mw /* initialize the copper lists */
612 1.1 mw initcop (fb->cop1, fb->cop2, 0, fb);
613 1.1 mw initcop (fb->cop2, fb->cop1, 1, fb);
614 1.1 mw
615 1.1 mw /* start the new display */
616 1.1 mw
617 1.1 mw /* ok, this is a bit rough.. */
618 1.3 mw /* mtk: not any more! :-) */
619 1.3 mw /* mykes: phew, thanks :-) */
620 1.1 mw s = splhigh ();
621 1.3 mw
622 1.3 mw /* install dummy, to get display going (for vposr to count.. ) */
623 1.3 mw custom.cop1lc = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR);
624 1.1 mw custom.copjmp1 = 0;
625 1.3 mw
626 1.3 mw /* enable DMA (so the copperlists are executed and eventually
627 1.3 mw cause a switch to an interlaced display on system not already booting that
628 1.3 mw way. THANKS HAMISH for finding this bug!!) */
629 1.3 mw custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER |
630 1.3 mw DMAF_COPPER | DMAF_SPRITE | DMAF_AUD0 | DMAF_AUD1;
631 1.3 mw
632 1.3 mw /* this is real simple: wait for LOF bit of vposr to go high - then start
633 1.3 mw the copper list! :-) */
634 1.3 mw while (custom.vposr & 0x8000);
635 1.3 mw while (!(custom.vposr & 0x8000));
636 1.3 mw
637 1.3 mw custom.cop1lc = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR);
638 1.1 mw custom.copjmp1 = 0;
639 1.1 mw
640 1.1 mw custom.intreq = INTF_VERTB;
641 1.1 mw
642 1.1 mw splx (s);
643 1.1 mw
644 1.3 mw #if 0
645 1.1 mw /* tame the blitter. Copying one word onto itself should put it into
646 1.1 mw a consistent state. This is black magic... */
647 1.1 mw custom.bltapt =
648 1.1 mw custom.bltbpt =
649 1.1 mw custom.bltcpt =
650 1.1 mw custom.bltdpt = 0;
651 1.1 mw custom.bltamod =
652 1.1 mw custom.bltbmod =
653 1.1 mw custom.bltcmod =
654 1.1 mw custom.bltdmod = 0;
655 1.1 mw custom.bltafwm =
656 1.1 mw custom.bltalwn = 0xffff;
657 1.1 mw custom.bltcon0 = 0x09f0;
658 1.1 mw custom.bltcon1 = 0;
659 1.1 mw custom.bltsize = 1;
660 1.3 mw #endif
661 1.1 mw
662 1.1 mw /* enable VBR interrupts. This is also done in the serial driver, but it
663 1.1 mw really belongs here.. */
664 1.3 mw custom.intena = INTF_SETCLR | INTF_VERTB; /* under amigaos, INTF_INTEN is needed */
665 1.1 mw
666 1.1 mw #if 0
667 1.1 mw #ifdef DEBUG
668 1.1 mw /* prove the display is up.. */
669 1.1 mw for (fboff = 0; fboff < fbsize; fboff++)
670 1.1 mw {
671 1.1 mw fb->fb[fboff] = 0xff;
672 1.1 mw DELAY(10);
673 1.1 mw }
674 1.1 mw for (fboff = 0; fboff < fbsize; fboff++)
675 1.1 mw {
676 1.1 mw fb->fb[fboff] = 0;
677 1.1 mw DELAY(10);
678 1.1 mw }
679 1.1 mw #endif
680 1.1 mw #endif
681 1.1 mw
682 1.3 mw gi->gd_regaddr = (caddr_t) fb; /* XXX */
683 1.1 mw gi->gd_regsize = 0;
684 1.1 mw
685 1.1 mw gi->gd_fbaddr = fb->fb - (u_char *) CHIPMEMADDR;
686 1.3 mw #if 0
687 1.3 mw /* mykes kludges here to make gi look like 1 bitplane */
688 1.3 mw gi->gd_fbsize = fbsize/2;
689 1.3 mw #else
690 1.3 mw /* don't see why we should kludge here.. we have
691 1.3 mw disp_z to indicate the real depth of the display */
692 1.1 mw gi->gd_fbsize = fbsize;
693 1.3 mw #endif
694 1.1 mw
695 1.3 mw gi->gd_colors = 1 << fb->disp_z;
696 1.3 mw gi->gd_planes = fb->disp_z;
697 1.1 mw
698 1.1 mw gi->gd_fbwidth = fb->fb_width;
699 1.1 mw gi->gd_fbheight = fb->fb_height;
700 1.1 mw gi->gd_fbx = fb->fb_x;
701 1.1 mw gi->gd_fby = fb->fb_y;
702 1.1 mw gi->gd_dwidth = fb->disp_width;
703 1.1 mw gi->gd_dheight = fb->disp_height;
704 1.1 mw gi->gd_dx = fb->disp_x;
705 1.1 mw gi->gd_dy = fb->disp_y;
706 1.1 mw
707 1.3 mw gp->g_regkva = 0; /* builtin */
708 1.1 mw gp->g_fbkva = fb->fb;
709 1.1 mw
710 1.3 mw fb->enableFlag = !0;
711 1.1 mw return(1);
712 1.1 mw }
713 1.1 mw
714 1.1 mw cc_config(gp, di)
715 1.1 mw register struct grf_softc *gp;
716 1.1 mw struct grfdyninfo *di;
717 1.1 mw {
718 1.1 mw register struct ccfb *fb = &ccfb;
719 1.1 mw struct grfinfo *gi = &gp->g_display;
720 1.1 mw u_char *fbp, save;
721 1.1 mw int fboff, fbsize;
722 1.1 mw int s;
723 1.1 mw
724 1.1 mw /* bottom missing... */
725 1.1 mw
726 1.1 mw }
727 1.1 mw
728 1.1 mw /*
729 1.1 mw * Change the mode of the display.
730 1.1 mw * Right now all we can do is grfon/grfoff.
731 1.1 mw * Return a UNIX error number or 0 for success.
732 1.1 mw */
733 1.1 mw cc_mode(gp, cmd, arg)
734 1.1 mw register struct grf_softc *gp;
735 1.1 mw int cmd;
736 1.1 mw void *arg;
737 1.1 mw {
738 1.1 mw switch (cmd)
739 1.1 mw {
740 1.1 mw case GM_GRFON:
741 1.3 mw ccfb.enableFlag = !0;
742 1.3 mw ccfb.screenBlank = ccfb.screenTime;
743 1.3 mw ccfb.mouseBlank = ccfb.mouseTime;
744 1.3 mw custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
745 1.1 mw return 0;
746 1.1 mw
747 1.1 mw case GM_GRFOFF:
748 1.3 mw ccfb.enableFlag = 0;
749 1.3 mw custom.dmacon = DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
750 1.1 mw return 0;
751 1.1 mw
752 1.1 mw case GM_GRFCONFIG:
753 1.1 mw return cc_config (gp, (struct grfdyninfo *) arg);
754 1.1 mw
755 1.1 mw default:
756 1.1 mw break;
757 1.1 mw }
758 1.1 mw
759 1.1 mw return EINVAL;
760 1.1 mw }
761 1.1 mw
762 1.1 mw #endif
763 1.4 mw
764