1 /*
2 * Copyright (C) 2004-2020 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: TURBOchannel Pixelstamp graphics card
29 *
30 * PMAG-CA = PX
31 * PMAG-DA = PXG
32 * PMAG-EA = PXG+
33 * PMAG-FA = PXG+ TURBO
34 *
35 * See include/pxreg.h (and NetBSD's arch/pmax/dev/px.c) for more information.
36 *
37 * The emulation of this device is far from complete. Different pixelstamp
38 * boards are recognizes under different names depending on operating system:
39 *
40 * NetBSD/pmax: (works fine both with and without console on framebuffer)
41 * PMAG-CA: px0 at tc0 slot 0 offset 0x0: 2D, 4x1 stamp,
42 * 8 plane
43 * PMAG-DA: px0 at tc0 slot 0 offset 0x0: 3D, 4x1 stamp,
44 * 8 plane, 128KB SRAM
45 * PMAG-EA: (not supported)
46 * PMAG-FA: px0 at tc0 slot 0 offset 0x0: 3D, 5x2 stamp,
47 * 24 plane, 128KB SRAM
48 *
49 * Ultrix 4.2A rev 47: (usually crashes if the device is installed, but
50 * serial console is used)
51 * PMAG-CA: px0 at ibus0, pa0 (5x1 8+8+0+0)
52 * PMAG-DA: px0 at ibus0, pq0 (5x1 16+16+16+0 128KB)
53 * or (5x1 0+0+16+0 128KB)
54 * PMAG-EA: (not supported)
55 * PMAG-FA: px0 at ibus0, pq0 (5x2 24+24+16+16 128KB)
56 *
57 * Ultrix 4.2 rev 85: (usually crashes if the device is installed,
58 * but serial console is used)
59 * PMAG-CA: ga0 at ibus0, ga0 ( 8 planes 4x1 stamp )
60 * PMAG-DA: gq0 at ibus0, gq0 ( 8+8+16Z+0X plane 4x1 stamp )
61 * PMAG-EA: (not supported)
62 * PMAG-FA: gq0 at ibus0, gq0 ( 24+24+24Z+24X plane
63 * 5x2 stamp ) (crashes in serial console mode)
64 *
65 * TODO: A lot of stuff:
66 *
67 * Read http://www.mit.edu/afs/athena/system/pmax_ul3/srvd.73/sys/
68 * io/tc/gq.h
69 * and try to figure out the interrupt and memory management stuff.
70 *
71 * Color support: foreground, background, 8-bit palette?
72 * 2D and 3D stuff: polygons? shading?
73 * Don't use so many hardcoded values.
74 * Actually interpret the values in each command, don't just
75 * assume NetBSD/Ultrix usage.
76 * Factor out the DMA read (main memory vs sram).
77 * Interrupts?
78 * Make sure that everything works with both NetBSD and Ultrix.
79 */
80
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84
85 #include "cpu.h"
86 #include "devices.h"
87 #include "machine.h"
88 #include "memory.h"
89 #include "misc.h"
90
91 #include "thirdparty/pxreg.h"
92
93 #define PX_XSIZE 1280
94 #define PX_YSIZE 1024
95
96 static bool px_debug = false;
97
98
DEVICE_TICK(px)99 DEVICE_TICK(px)
100 {
101 #if 0
102 struct px_data *d = extra;
103
104 if (d->intr & STIC_INT_P_EN) /* or _WE ? */
105 INTERRUPT_ASSERT(d->irq);
106 #endif
107 }
108
109
110 /*
111 * px_readword():
112 *
113 * Helper function to read 32-bit words from DMA memory,
114 * to allow both little and big endian accesses.
115 * (DECstations probably only use little endian access,
116 * but endianness-independance is probably nice to have anyway.)
117 */
px_readword(struct cpu * cpu,unsigned char * dma_buf,int ofs)118 uint32_t px_readword(struct cpu *cpu, unsigned char *dma_buf, int ofs)
119 {
120 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
121 return dma_buf[ofs+0] + (dma_buf[ofs+1] << 8) +
122 (dma_buf[ofs+2] << 16) + (dma_buf[ofs+3] << 24);
123 else
124 return dma_buf[ofs+3] + (dma_buf[ofs+2] << 8) +
125 (dma_buf[ofs+1] << 16) + (dma_buf[ofs+0] << 24);
126 }
127
128
129 /*
130 * dev_px_dma():
131 *
132 * This routine performs a (fake) DMA transfer of STAMP commands
133 * and executes them.
134 *
135 * For the "PX" board, read from main memory (cpu->mem). For all other
136 * boards, read from the i860 SRAM portion of the device (d->sram).
137 */
dev_px_dma(struct cpu * cpu,uint32_t sys_addr,struct px_data * d)138 void dev_px_dma(struct cpu *cpu, uint32_t sys_addr, struct px_data *d)
139 {
140 unsigned char dma_buf[32768];
141 size_t dma_len = sizeof(dma_buf);
142 int bytesperpixel;
143 uint32_t cmdword;
144
145 bytesperpixel = d->bitdepth >> 3;
146
147 dma_len = 56 * 4; /* TODO: this is just enough for NetBSD's
148 putchar */
149
150 if (d->type == DEV_PX_TYPE_PX) {
151 cpu->memory_rw(cpu, cpu->mem, sys_addr, dma_buf,
152 dma_len, MEM_READ, NO_EXCEPTIONS | PHYSICAL);
153 } else {
154 /* TODO: past end of sram? */
155 memmove(dma_buf, &d->sram[sys_addr & 0x1ffff], dma_len);
156 }
157
158 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
159 cmdword = dma_buf[0] + (dma_buf[1] << 8) +
160 (dma_buf[2] << 16) + (dma_buf[3] << 24);
161 else
162 cmdword = dma_buf[3] + (dma_buf[2] << 8) +
163 (dma_buf[1] << 16) + (dma_buf[0] << 24);
164
165 if (px_debug) {
166 debug("[ px: dma from 0x%08x: ", (int)sys_addr);
167
168 debug("cmd=");
169 switch (cmdword & 0xf) {
170 case STAMP_CMD_POINTS: debug("points"); break;
171 case STAMP_CMD_LINES: debug("lines"); break;
172 case STAMP_CMD_TRIANGLES: debug("triangles"); break;
173 case STAMP_CMD_COPYSPANS: debug("copyspans"); break;
174 case STAMP_CMD_READSPANS: debug("readspans"); break;
175 case STAMP_CMD_WRITESPANS: debug("writespans"); break;
176 case STAMP_CMD_VIDEO: debug("video"); break;
177 default:
178 debug("0x%x (?)", cmdword & 0xf);
179 }
180
181 debug(",rgb=");
182 switch (cmdword & 0x30) {
183 case STAMP_RGB_NONE: debug("none"); break;
184 case STAMP_RGB_CONST: debug("const"); break;
185 case STAMP_RGB_FLAT: debug("flat"); break;
186 case STAMP_RGB_SMOOTH: debug("smooth"); break;
187 default:
188 debug("0x%x (?)", cmdword & 0x30);
189 }
190
191 debug(",z=");
192 switch (cmdword & 0xc0) {
193 case STAMP_Z_NONE: debug("none"); break;
194 case STAMP_Z_CONST: debug("const"); break;
195 case STAMP_Z_FLAT: debug("flat"); break;
196 case STAMP_Z_SMOOTH: debug("smooth"); break;
197 default:
198 debug("0x%x (?)", cmdword & 0xc0);
199 }
200
201 debug(",xy=");
202 switch (cmdword & 0x300) {
203 case STAMP_XY_NONE: debug("none"); break;
204 case STAMP_XY_PERPACKET: debug("perpacket"); break;
205 case STAMP_XY_PERPRIMATIVE: debug("perprimative"); break;
206 default:
207 debug("0x%x (?)", cmdword & 0x300);
208 }
209
210 debug(",lw=");
211 switch (cmdword & 0xc00) {
212 case STAMP_LW_NONE: debug("none"); break;
213 case STAMP_LW_PERPACKET: debug("perpacket"); break;
214 case STAMP_LW_PERPRIMATIVE: debug("perprimative"); break;
215 default:
216 debug("0x%x (?)", cmdword & 0xc00);
217 }
218
219 if (cmdword & STAMP_CLIPRECT)
220 debug(",CLIPRECT");
221 if (cmdword & STAMP_MESH)
222 debug(",MESH");
223 if (cmdword & STAMP_AALINE)
224 debug(",AALINE");
225 if (cmdword & STAMP_HS_EQUALS)
226 debug(",HS_EQUALS");
227
228 for (size_t i=0; i<dma_len; i++)
229 debug(" %02x", dma_buf[i]);
230
231 debug(" ]\n");
232 }
233
234 /* NetBSD and Ultrix copyspans */
235 if (cmdword == 0x405) {
236 uint32_t nspans, lw;
237 uint32_t spannr, ofs;
238 uint32_t span_len, span_src, span_dst;
239 /* unsigned char pixels[PX_XSIZE * 3]; */
240
241 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
242 nspans = dma_buf[4] + (dma_buf[5] << 8) +
243 (dma_buf[6] << 16) + (dma_buf[7] << 24);
244 else
245 nspans = dma_buf[7] + (dma_buf[6] << 8) +
246 (dma_buf[5] << 16) + (dma_buf[4] << 24);
247
248 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
249 lw = dma_buf[16] + (dma_buf[17] << 8) +
250 (dma_buf[18] << 16) + (dma_buf[19] << 24);
251 else
252 lw = dma_buf[19] + (dma_buf[18] << 8) +
253 (dma_buf[17] << 16) + (dma_buf[16] << 24);
254
255 nspans >>= 24;
256 /* Why not this? lw = (lw + 1) >> 2; */
257
258 if (px_debug)
259 debug("[ px: copyspans: nspans = %i, lw = %i ]\n", nspans, lw);
260
261 /* Reread copyspans command if it wasn't completely read: */
262 if (dma_len < 4*(5 + nspans*3)) {
263 dma_len = 4 * (5+nspans*3);
264 if (d->type == DEV_PX_TYPE_PX)
265 cpu->memory_rw(cpu, cpu->mem, sys_addr,
266 dma_buf, dma_len, MEM_READ,
267 NO_EXCEPTIONS | PHYSICAL);
268 else
269 memmove(dma_buf, &d->sram[sys_addr & 0x1ffff],
270 dma_len); /* TODO: past end of sram? */
271 }
272
273 ofs = 4*5;
274 for (spannr=0; spannr<nspans; spannr++) {
275 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
276 span_len = dma_buf[ofs+0] + (dma_buf[ofs+1] <<
277 8) + (dma_buf[ofs+2] << 16) +
278 (dma_buf[ofs+3] << 24);
279 else
280 span_len = dma_buf[ofs+3] + (dma_buf[ofs+2] <<
281 8) + (dma_buf[ofs+1] << 16) +
282 (dma_buf[ofs+0] << 24);
283 ofs += 4;
284
285 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
286 span_src = dma_buf[ofs+0] + (dma_buf[ofs+1] <<
287 8) + (dma_buf[ofs+2] << 16) +
288 (dma_buf[ofs+3] << 24);
289 else
290 span_src = dma_buf[ofs+3] + (dma_buf[ofs+2] <<
291 8) + (dma_buf[ofs+1] << 16) +
292 (dma_buf[ofs+0] << 24);
293 ofs += 4;
294
295 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
296 span_dst = dma_buf[ofs+0] + (dma_buf[ofs+1] <<
297 8) + (dma_buf[ofs+2] << 16) +
298 (dma_buf[ofs+3] << 24);
299 else
300 span_dst = dma_buf[ofs+3] + (dma_buf[ofs+2] <<
301 8) + (dma_buf[ofs+1] << 16) +
302 (dma_buf[ofs+0] << 24);
303 ofs += 4;
304
305 span_len >>= 3;
306 span_dst >>= 3;
307 span_src >>= 3;
308
309 if (span_len > PX_XSIZE)
310 span_len = PX_XSIZE;
311
312 /* debug(" span %i: len=%i src=%i dst=%i\n",
313 spannr, span_len, span_src, span_dst); */
314
315 memmove(d->vfb_data->framebuffer + span_dst *
316 PX_XSIZE * bytesperpixel, d->vfb_data->framebuffer
317 + span_src * PX_XSIZE * bytesperpixel, span_len *
318 bytesperpixel);
319
320 d->vfb_data->update_x1 = 0; d->vfb_data->update_x2 =
321 PX_XSIZE-1;
322 if ((int32_t)span_dst < d->vfb_data->update_y1)
323 d->vfb_data->update_y1 = span_dst;
324 if ((int32_t)span_dst > d->vfb_data->update_y2)
325 d->vfb_data->update_y2 = span_dst;
326 if ((int32_t)span_src < d->vfb_data->update_y1)
327 d->vfb_data->update_y1 = span_src;
328 if ((int32_t)span_src > d->vfb_data->update_y2)
329 d->vfb_data->update_y2 = span_src;
330 }
331 }
332
333 /* NetBSD and Ultrix erasecols/eraserows */
334 if (cmdword == 0x411) {
335 uint32_t v1, v2, attr;
336 int32_t lw;
337 int x,y,x2,y2;
338 int fb_y;
339 int bg_r, bg_g, bg_b;
340 unsigned char pixels[PX_XSIZE * 3];
341
342 lw = px_readword(cpu, dma_buf, 16);
343 attr = px_readword(cpu, dma_buf, 20);
344 v1 = px_readword(cpu, dma_buf, 24);
345 v2 = px_readword(cpu, dma_buf, 28);
346 #if 0
347 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
348 lw = dma_buf[16] + (dma_buf[17] << 8) +
349 (dma_buf[18] << 16) + (dma_buf[19] << 24);
350 else
351 lw = dma_buf[19] + (dma_buf[18] << 8) +
352 (dma_buf[17] << 16) + (dma_buf[16] << 24);
353
354 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
355 v1 = dma_buf[24] + (dma_buf[25] << 8) +
356 (dma_buf[26] << 16) + (dma_buf[27] << 24);
357 else
358 v1 = dma_buf[27] + (dma_buf[26] << 8) +
359 (dma_buf[25] << 16) + (dma_buf[24] << 24);
360
361 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
362 v2 = dma_buf[28] + (dma_buf[29] << 8) +
363 (dma_buf[30] << 16) + (dma_buf[31] << 24);
364 else
365 v2 = dma_buf[31] + (dma_buf[30] << 8) +
366 (dma_buf[29] << 16) + (dma_buf[28] << 24);
367 #endif
368 bg_r = (attr >> 16) & 255;
369 bg_g = (attr >> 8) & 255;
370 bg_b = attr & 255;
371 if (bg_r == 0)
372 bg_r = bg_g = bg_b = 0;
373 else
374 if (bg_r == 7)
375 bg_r = bg_g = bg_b = 192;
376 else
377 bg_r = bg_g = bg_b = 255;
378
379 v1 -= lw;
380 v2 -= lw;
381
382 x = (v1 >> 19) & 2047;
383 y = (v1 >> 3) & 1023;
384 x2 = (v2 >> 19) & 2047;
385 y2 = (v2 >> 3) & 1023;
386
387 lw = (lw + 1) >> 2;
388
389 if (x2 - x > PX_XSIZE)
390 x2 = PX_XSIZE;
391
392 if (px_debug)
393 debug("[ px: clear/fill: v1 = 0x%08x v2 = 0x%08x "
394 "lw=%i x=%i y=%i x2=%i y2=%i ]\n", (int)v1, (int)v2,
395 lw, x,y, x2,y2);
396
397 if (bytesperpixel == 3) {
398 int xi;
399 for (xi=0; xi<x2-x; xi++) {
400 /* TODO: rgb order? */
401 pixels[xi*3 + 0] = bg_r;
402 pixels[xi*3 + 1] = bg_g;
403 pixels[xi*3 + 2] = bg_b;
404 }
405 } else
406 memset(pixels, attr, (x2 - x) * bytesperpixel);
407
408 if (x < d->vfb_data->update_x1)
409 d->vfb_data->update_x1 = x;
410 if (x2 > d->vfb_data->update_x2)
411 d->vfb_data->update_x2 = x2;
412
413 for (fb_y=y; fb_y < y2 + lw; fb_y ++) {
414 memcpy(d->vfb_data->framebuffer + (fb_y * PX_XSIZE + x)
415 * bytesperpixel, pixels, (x2-x)*bytesperpixel);
416
417 if (fb_y < d->vfb_data->update_y1)
418 d->vfb_data->update_y1 = fb_y;
419 if (fb_y > d->vfb_data->update_y2)
420 d->vfb_data->update_y2 = fb_y;
421 }
422 }
423
424 /* NetBSD and Ultrix putchar */
425 if (cmdword == 0xa21) {
426 /* Ugly test code: */
427 unsigned char pixels[16 * 3];
428 int pixels_len = 16;
429 uint32_t v1, v2, fgcolor, bgcolor;
430 int x, y, x2,y2, i, maxi;
431 int xbit;
432 int suby;
433 int fg_r, fg_g, fg_b;
434 int bg_r, bg_g, bg_b;
435
436 v1 = px_readword(cpu, dma_buf, 52);
437 v2 = px_readword(cpu, dma_buf, 56);
438 fgcolor = px_readword(cpu, dma_buf, 16 * 4);
439 bgcolor = px_readword(cpu, dma_buf, 29 * 4);
440
441 /*
442 * TODO: Which one is r, which one is g, and which one is b?
443 * TODO 2: Use the BT459 palette, these values are hardcoded
444 * for NetBSD and Ultrix grayscale only.
445 */
446 fg_r = (fgcolor >> 16) & 255;
447 fg_g = (fgcolor >> 8) & 255;
448 fg_b = fgcolor & 255;
449 if (fg_r == 0)
450 fg_r = fg_g = fg_b = 0;
451 else
452 if (fg_r == 7)
453 fg_r = fg_g = fg_b = 192;
454 else
455 fg_r = fg_g = fg_b = 255;
456
457 bg_r = (bgcolor >> 16) & 255;
458 bg_g = (bgcolor >> 8) & 255;
459 bg_b = bgcolor & 255;
460 if (bg_r == 0)
461 bg_r = bg_g = bg_b = 0;
462 else
463 if (bg_r == 7)
464 bg_r = bg_g = bg_b = 192;
465 else
466 bg_r = bg_g = bg_b = 255;
467
468 x = (v1 >> 19) & 2047;
469 y = ((v1 - 63) >> 3) & 1023;
470 x2 = (v2 >> 19) & 2047;
471 y2 = ((v2 - 63) >> 3) & 1023;
472
473 if (px_debug)
474 debug("[ px putchar: v1 = 0x%08x v2 = 0x%08x x=%i y=%i ]\n",
475 (int)v1, (int)v2, x,y, x2,y2);
476
477 x %= PX_XSIZE;
478 y %= PX_YSIZE;
479 x2 %= PX_XSIZE;
480 y2 %= PX_YSIZE;
481
482 pixels_len = x2 - x;
483
484 suby = 0;
485 maxi = 12;
486 maxi = 33;
487
488 for (i=4; i<maxi; i++) {
489 int j;
490
491 if (i == 12)
492 i = 30;
493
494 for (j=0; j<2; j++) {
495 for (xbit = 0; xbit < 8; xbit ++) {
496 if (bytesperpixel == 3) {
497 /* 24-bit: */
498 /* TODO: Which one is r,
499 which one is g, and b? */
500 pixels[xbit * 3 + 0] =
501 (dma_buf[i*4 + j*2 + 0] &
502 (1 << xbit))? fg_r : bg_r;
503 pixels[xbit * 3 + 1] =
504 (dma_buf[i*4 + j*2 + 0] &
505 (1 << xbit))? fg_g : bg_g;
506 pixels[xbit * 3 + 2] =
507 (dma_buf[i*4 + j*2 + 0] &
508 (1 << xbit))? fg_b : bg_b;
509 pixels[(xbit + 8) * 3 + 0] =
510 (dma_buf[i*4 + j*2 + 1] &
511 (1 << xbit))? fg_r : bg_r;
512 pixels[(xbit + 8) * 3 + 1] =
513 (dma_buf[i*4 + j*2 + 1] &
514 (1 << xbit))? fg_g : bg_g;
515 pixels[(xbit + 8) * 3 + 2] =
516 (dma_buf[i*4 + j*2 + 1] &
517 (1 << xbit))? fg_b : bg_b;
518 } else {
519 /* 8-bit: */
520 pixels[xbit] = (dma_buf[i*4 +
521 j*2 + 0] & (1 << xbit))?
522 (fgcolor & 255) :
523 (bgcolor & 255);
524 pixels[xbit + 8] = (dma_buf[i*4
525 + j*2 + 1] & (1 << xbit))?
526 (fgcolor & 255) :
527 (bgcolor & 255);
528 }
529 }
530
531 memcpy(d->vfb_data->framebuffer + ((y+suby)
532 * PX_XSIZE + x) * bytesperpixel,
533 pixels, pixels_len * bytesperpixel);
534
535 if (y+suby < d->vfb_data->update_y1)
536 d->vfb_data->update_y1 = y+suby;
537 if (y+suby > d->vfb_data->update_y2)
538 d->vfb_data->update_y2 = y+suby;
539
540 suby ++;
541 }
542
543 if (x < d->vfb_data->update_x1)
544 d->vfb_data->update_x1 = x;
545 if (x2 > d->vfb_data->update_x2)
546 d->vfb_data->update_x2 = x2;
547 }
548 }
549 }
550
551
DEVICE_ACCESS(px)552 DEVICE_ACCESS(px)
553 {
554 uint64_t idata = 0, odata = 0;
555 struct px_data *d = (struct px_data *) extra;
556 size_t i;
557
558 if (writeflag == MEM_WRITE)
559 idata = memory_readmax64(cpu, data, len);
560
561 if (relative_addr < 0x0c0000) {
562 /*
563 * DMA poll: a read from this address should start a DMA
564 * transfer, and return 1 in odata while the DMA is in
565 * progress (STAMP_BUSY), and then 0 (STAMP_OK) once we're
566 * done.
567 *
568 * According to NetBSD's pxreg.h, the following formula gets
569 * us from system address to DMA address: (v is the system
570 * address)
571 *
572 * dma_addr = ( ( ((v & ~0x7fff) << 3) |
573 * (v & 0x7fff) ) & 0x1ffff800) >> 9;
574 *
575 * Hopefully, this is a good enough reversal of that formula:
576 *
577 * sys_addr = ((dma_addr << 9) & 0x7800) +
578 * ((dma_addr << 6) & 0xffff8000);
579 *
580 * If the board type is "PX" then the system address is an
581 * address in host memory. Otherwise, it is relative to
582 * 0x200000 (the i860's memory space on the board).
583 */
584 uint32_t sys_addr; /* system address for DMA transfers */
585 sys_addr = ((relative_addr << 9) & 0x7800) +
586 ((relative_addr << 6) & 0xffff8000);
587
588 /*
589 * If the system address is sane enough, then start a DMA
590 * transfer: (for the "PX" board type, don't allow obviously
591 * too-low physical addresses)
592 */
593 if (sys_addr >= 0x4000 || d->type != DEV_PX_TYPE_PX)
594 dev_px_dma(cpu, sys_addr, d);
595
596 /* Pretend that it was always OK: */
597 odata = STAMP_OK;
598 }
599
600 /* N10 sram: */
601 if (relative_addr >= 0x200000 && relative_addr < 0x280000) {
602 if (d->type == DEV_PX_TYPE_PX)
603 fatal("WARNING: the vdac should be at this "
604 "address. overlap problems?\n");
605
606 if (writeflag == MEM_WRITE) {
607 for (i=0; i<len; i++)
608 d->sram[relative_addr - 0x200000 + i] = data[i];
609 /* NOTE: this return here supresses debug output
610 (which would be printed if we continue) */
611 return 1;
612 } else {
613 /*
614 * Huh? Why have I commented out this? TODO
615 */
616 /* for (i=0; i<len; i++)
617 data[i] = d->sram[relative_addr - 0x200000
618 + i]; */
619 odata = 1;
620 }
621 }
622
623 /* TODO: Most of these aren't implemented yet. */
624
625 switch (relative_addr) {
626
627 case 0x180008: /* hsync */
628 if (writeflag==MEM_READ) {
629 debug("[ px: read from hsync: 0x%08llx ]\n",
630 (long long)odata);
631 } else {
632 debug("[ px: write to hsync: 0x%08llx ]\n",
633 (long long)idata);
634 }
635 break;
636
637 case 0x18000c: /* hsync2 */
638 if (writeflag==MEM_READ) {
639 debug("[ px: read from hsync2: 0x%08llx ]\n",
640 (long long)odata);
641 } else {
642 debug("[ px: write to hsync2: 0x%08llx ]\n",
643 (long long)idata);
644 }
645 break;
646
647 case 0x180010: /* hblank */
648 if (writeflag==MEM_READ) {
649 debug("[ px: read from hblank: 0x%08llx ]\n",
650 (long long)odata);
651 } else {
652 debug("[ px: write to hblank: 0x%08llx ]\n",
653 (long long)idata);
654 }
655 break;
656
657 case 0x180014: /* vsync */
658 if (writeflag==MEM_READ) {
659 debug("[ px: read from vsync: 0x%08llx ]\n",
660 (long long)odata);
661 } else {
662 debug("[ px: write to vsync: 0x%08llx ]\n",
663 (long long)idata);
664 }
665 break;
666
667 case 0x180018: /* vblank */
668 if (writeflag==MEM_READ) {
669 debug("[ px: read from vblank: 0x%08llx ]\n",
670 (long long)odata);
671 } else {
672 debug("[ px: write to vblank: 0x%08llx ]\n",
673 (long long)idata);
674 }
675 break;
676
677 case 0x180020: /* ipdvint */
678 if (writeflag==MEM_READ) {
679 odata = d->intr;
680
681 /* TODO: how do interrupts work on the pixelstamp boards? */
682 odata = random();
683
684 debug("[ px: read from ipdvint: 0x%08llx ]\n",
685 (long long)odata);
686 } else {
687 d->intr = idata;
688 if (idata & STIC_INT_E_WE)
689 d->intr &= ~STIC_INT_E;
690 if (idata & STIC_INT_V_WE)
691 d->intr &= ~STIC_INT_V;
692 if (idata & STIC_INT_P_WE)
693 d->intr &= ~STIC_INT_P;
694 debug("[ px: write to ipdvint: 0x%08llx ]\n",
695 (long long)idata);
696 }
697 break;
698
699 case 0x180028: /* sticsr */
700 if (writeflag==MEM_READ) {
701 debug("[ px: read from sticsr: 0x%08llx ]\n",
702 (long long)odata);
703 } else {
704 debug("[ px: write to sticsr: 0x%08llx ]\n",
705 (long long)idata);
706 }
707 break;
708
709 case 0x180038: /* buscsr */
710 if (writeflag==MEM_READ) {
711 debug("[ px: read from buscsr: 0x%08llx ]\n",
712 (long long)odata);
713 } else {
714 debug("[ px: write to buscsr: 0x%08llx ]\n",
715 (long long)idata);
716 }
717 break;
718
719 case 0x18003c: /* modcl */
720 if (writeflag==MEM_READ) {
721 odata = (d->type << 12) + (d->xconfig << 11) +
722 (d->yconfig << 9);
723 debug("[ px: read from modcl: 0x%llx ]\n",
724 (long long)odata);
725 } else {
726 debug("[ px: write to modcl: 0x%llx ]\n",
727 (long long)idata);
728 }
729 break;
730
731 default:
732 if (writeflag==MEM_READ) {
733 debug("[ px: read from addr 0x%x: 0x%llx ]\n",
734 (int)relative_addr, (long long)odata);
735 } else {
736 debug("[ px: write to addr 0x%x: 0x%llx ]\n",
737 (int)relative_addr, (long long)idata);
738 }
739 }
740
741 if (writeflag == MEM_READ)
742 memory_writemax64(cpu, data, len, odata);
743
744 return 1;
745 }
746
747
dev_px_init(struct machine * machine,struct memory * mem,uint64_t baseaddr,int px_type,const char * irq_path)748 void dev_px_init(struct machine *machine, struct memory *mem,
749 uint64_t baseaddr, int px_type, const char *irq_path)
750 {
751 struct px_data *d;
752
753 CHECK_ALLOCATION(d = (struct px_data *) malloc(sizeof(struct px_data)));
754 memset(d, 0, sizeof(struct px_data));
755
756 d->type = px_type;
757
758 INTERRUPT_CONNECT(irq_path, d->irq);
759
760 d->xconfig = d->yconfig = 0; /* 4x1 */
761
762 d->bitdepth = 24;
763 d->px_name = "(invalid)";
764
765 switch (d->type) {
766 case DEV_PX_TYPE_PX:
767 d->bitdepth = 8;
768 d->px_name = "PX";
769 break;
770 case DEV_PX_TYPE_PXG:
771 d->bitdepth = 8;
772 d->px_name = "PXG";
773 break;
774 case DEV_PX_TYPE_PXGPLUS:
775 d->px_name = "PXG+";
776 break;
777 case DEV_PX_TYPE_PXGPLUSTURBO:
778 d->px_name = "PXG+ TURBO";
779 d->xconfig = d->yconfig = 1; /* 5x2 */
780 break;
781 default:
782 fatal("dev_px_init(): unimplemented px_type\n");
783 }
784
785 d->fb_mem = memory_new(PX_XSIZE * PX_YSIZE * d->bitdepth / 8,
786 machine->arch);
787 if (d->fb_mem == NULL) {
788 fprintf(stderr, "dev_px_init(): out of memory (1)\n");
789 exit(1);
790 }
791
792 d->vfb_data = dev_fb_init(machine, d->fb_mem, 0, VFB_GENERIC,
793 PX_XSIZE, PX_YSIZE, PX_XSIZE, PX_YSIZE, d->bitdepth, d->px_name);
794 if (d->vfb_data == NULL) {
795 fprintf(stderr, "dev_px_init(): out of memory (2)\n");
796 exit(2);
797 }
798
799 switch (d->type) {
800 case DEV_PX_TYPE_PX:
801 dev_bt459_init(machine, mem, baseaddr + 0x200000, 0,
802 d->vfb_data, 8, irq_path, BT459_PX);
803 break;
804 case DEV_PX_TYPE_PXG:
805 case DEV_PX_TYPE_PXGPLUS:
806 case DEV_PX_TYPE_PXGPLUSTURBO:
807 dev_bt459_init(machine, mem, baseaddr + 0x300000, 0,
808 d->vfb_data, d->bitdepth, irq_path, BT459_PX);
809 break;
810 default:
811 fatal("dev_px_init(): unimplemented px_type\n");
812 }
813
814 memory_device_register(mem, "px", baseaddr, DEV_PX_LENGTH,
815 dev_px_access, d, DM_DEFAULT, NULL);
816 machine_add_tickfunction(machine, dev_px_tick, d, 14);
817 }
818
819