1 /* pro_vid.c: video board
2 
3    Copyright (c) 1997-2003, Tarik Isani (xhomer@isani.org)
4 
5    This file is part of Xhomer.
6 
7    Xhomer is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License version 2
9    as published by the Free Software Foundation.
10 
11    Xhomer is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Xhomer; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 
22 /* TBD:
23 		-implement appropriate vbi bits
24 */
25 
26 #ifdef PRO
27 #include "pdp11_defs.h"
28 #include "sim_defs.h" /* For sim_gtime() */
29 
30 /* XXX */
31 
32 struct iolink {
33 	int	low;
34 	int	high;
35 	int	(*read)();
36 	int	(*write)(); };
37 
38 extern struct iolink iotable[]; /* from pdp11_cpu */
39 
40 /* 3 planes are allocated even if EBO is not present.  The two additional
41    blank planes are referenced during screen refresh. */
42 
43 unsigned short PRO_VRAM[3][PRO_VID_MEMSIZE/2];
44 
45 unsigned char pro_vid_mvalid[(PRO_VID_MEMSIZE/2) >> PRO_VID_CLS];
46 
47       int	pro_vid_csr;
48       int	pro_vid_p1c;
49       int	pro_vid_scl;
50 
51       int	pro_vid_y_offset;	/* address offset for all vram accesses */
52 
53 LOCAL int	pro_vid_opc;
54 LOCAL int	pro_vid_x;
55 LOCAL int	pro_vid_y;
56 LOCAL int	pro_vid_cnt;
57 LOCAL int	pro_vid_pat;
58 LOCAL int	pro_vid_mbr;
59 
60 LOCAL int	pro_vid_mem_base;
61 
62 LOCAL int	pro_vid_plane_en;	/* This is a composite of the 3 enable bits */
63 
64 LOCAL int	pro_vid_skip;		/* window update cycle skip counter */
65 
66 
67 /* Vertical retrace event scheduler */
68 
pro_vid_sched()69 LOCAL void pro_vid_sched ()
70 {
71 int	interval;
72 
73 	if ((pro_vid_csr & PRO_VID_LM) == 0)
74 	  interval = PRO_EQ_NTSC;
75 	else
76 	  interval = PRO_EQ_PAL;
77 
78 	pro_eq_sched(PRO_EVENT_VID, interval);
79 }
80 
81 
82 /* Vertical retrace event handler */
83 
pro_vid_eq()84 void pro_vid_eq ()
85 {
86 	/* Trigger end of frame interrupt, if enabled */
87 
88 	/* XXX use better int name */
89 
90 	if ((pro_vid_csr & PRO_VID_EFIE) != 0)
91 	  pro_int_set(PRO_INT_2A);
92 
93 
94 	/* Refresh display window, if skip count has been reached */
95 
96 	if (pro_vid_skip == PRO_VID_SKIP)
97 	{
98 	  pro_screen_update();
99 
100 	  pro_vid_skip = 0;
101 	}
102 	else
103 	  pro_vid_skip++;
104 
105 
106 	/* Schedule next event */
107 
108 	pro_vid_sched();
109 }
110 
111 
112 /* Command done event handler */
113 
pro_vid_cmd_eq()114 void pro_vid_cmd_eq ()
115 {
116 	/* Trigger command done interrupt, if enabled */
117 
118 	/* XXX use better int name */
119 
120 	if ((pro_vid_csr & PRO_VID_DIE) != 0)
121 	  pro_int_set(PRO_INT_2B);
122 
123 	/* Set done bit */
124 
125 	pro_vid_csr = pro_vid_csr | PRO_VID_TD;
126 
127 	/* Clear count */
128 
129 	pro_vid_cnt = 0;
130 }
131 
132 
133 /* Video memory */
134 
pro_vram_rd(int * data,int pa,int access)135 int pro_vram_rd (int *data, int pa, int access)
136 {
137 int	vindex;
138 
139 	if ((pa & 017700000) == pro_vid_mem_base)
140 	{
141 	  vindex = vmem((pa-pro_vid_mem_base) >> 1);
142 
143 	  switch (pro_vid_plane_en)
144 	  {
145 	    case 00:
146 	      /* XXX all disabled - return 0? */
147 
148 	      *data = PRO_NOREG;
149 	      break;
150 
151 	    case 01:
152 	    case 03:
153 	    case 05:
154 	    case 07:
155 	      *data = PRO_VRAM[0][vindex];
156 	      break;
157 
158 	    case 02:
159 	    case 06:
160 	      *data = PRO_VRAM[1][vindex];
161 	      break;
162 
163 	    case 04:
164 	      *data = PRO_VRAM[2][vindex];
165 	      break;
166 
167 	    default:
168 	      *data = PRO_NOREG;
169 	      break;
170 	  }
171 
172 	  /* XXX
173 	  printf("Video memory READ!!!!!!!!!!\r\n");
174 	  */
175 	}
176 	else
177 	{
178 	  *data = 0;
179 	  printf("%10f Warning: video memory (R) not at default location!\r\n", sim_gtime());
180 	}
181 
182 	return SCPE_OK;
183 }
184 
185 
pro_vram_wr(int data,int pa,int access)186 int pro_vram_wr (int data, int pa, int access)
187 {
188 int	vindex;
189 
190 	if ((pa & 017700000) == pro_vid_mem_base)
191 	{
192 	  vindex = vmem((pa-pro_vid_mem_base) >> 1);
193 
194 	  /* XXX perform byte enable check */
195 
196 	  /*
197 	  if (access == WRITEB)
198 	    printf("%10f Warning: video memory byte write!\r\n", sim_gtime());
199 	  */
200 
201 	  if ((pro_vid_plane_en & 01) != 0)
202 	  {
203 	      WRITE_WB(PRO_VRAM[0][vindex], 0177777, access);
204 	  }
205 
206 	  if ((pro_vid_plane_en & 02) != 0)
207 	  {
208 	      WRITE_WB(PRO_VRAM[1][vindex], 0177777, access);
209 	  }
210 
211 	  if ((pro_vid_plane_en & 04) != 0)
212 	  {
213 	      WRITE_WB(PRO_VRAM[2][vindex], 0177777, access);
214 	  }
215 
216 	  /* XXX cache is currently cleared even if no memory planes are enabled */
217 
218 	  pro_vid_mvalid[cmem(vindex)] = 0;
219 
220 	  /* XXX
221 	  printf("Video memory WRITE!!!!!!!!!!\r\n");
222 	  */
223 	}
224 	else
225 	{
226 	  printf("%10f Warning: video memory (W) not at default location!\r\n", sim_gtime());
227 	}
228 
229 	return SCPE_OK;
230 }
231 
232 
233 /* Pixel drawing operations */
234 
pro_vid_pixop(int pnum,int x,int y,int data,int pixop)235 LOCAL void pro_vid_pixop(int pnum, int x, int y, int data, int pixop)
236 {
237 int	vindex, vbit, vmask, vdata, bit;
238 
239 	/* Calculate starting memory index and bit offset */
240 
241 	vindex = vmem((y << 6) | ((x >> 4) & 077));
242 
243 	vbit = x & 017;
244 
245 	vmask = ~(01 << vbit) & 0177777;
246 
247 	bit = data << vbit;
248 
249 	vdata = PRO_VRAM[pnum][vindex];
250 
251 	/* Perform operation */
252 
253 	switch (pixop)
254 	{
255 	  case PRO_VID_PIX_XOR:	/* xor pixel */
256 	    vdata = vdata ^ bit;
257 	    break;
258 
259 	  case PRO_VID_PIX_SET:	/* set pixel */
260 	    vdata = vdata | bit;
261 	    break;
262 
263 	  case PRO_VID_PIX_CLR:	/* clear pixel */
264 	    vdata = vdata & (~bit & 0177777);
265 	    break;
266 
267 	  case PRO_VID_PIX_REP:	/* replace pixel */
268 	    vdata = (vdata & vmask) | bit;
269 	    break;
270 
271 	  default:
272 	    break;
273 	}
274 
275 	PRO_VRAM[pnum][vindex] = vdata;
276 
277 	pro_vid_mvalid[cmem(vindex)] = 0;
278 }
279 
280 
pro_clear_mvalid()281 void pro_clear_mvalid ()
282 {
283    memset(&pro_vid_mvalid, 0, sizeof(pro_vid_mvalid));
284 }
285 
286 
287 /* Video registers */
288 
pro_vid_rd(int pa)289 int pro_vid_rd (int pa)
290 {
291 int	data;
292 
293 	switch (pa & 017777776)
294 	{
295 	  case 017774400:
296 	    data = PRO_ID_VID;		/* IDR */
297 	    break;
298 
299 	  case 017774404:
300 	    data = pro_vid_csr;
301 	    break;
302 
303 	  case 017774406:
304 	    data = pro_vid_p1c;
305 	    break;
306 
307 /* EBO */
308 	  case 017774410:
309 	    data = pro_vid_opc;
310 	    break;
311 
312 	  case 017774414:
313 	    data = pro_vid_scl;
314 	    break;
315 
316 	  case 017774416:
317 	    data = pro_vid_x;
318 	    break;
319 
320 	  case 017774420:
321 	    data = pro_vid_y;
322 	    break;
323 
324 /* XXX The following are write-only bits.  The real PRO returns these values */
325 
326 	  case 017774422:
327 	    data = 0177577;
328 	    break;
329 
330 	  case 017774424:
331 	    data = 0177577;
332 	    break;
333 
334 	  case 017774426:
335 	    data = 0177577;
336 	    break;
337 
338 /* EBO */
339 	  case 017774600:
340 	    data = PRO_ID_EBO;
341 	    break;
342 
343 	  default:
344 	    data = PRO_NOREG;
345 	    break;
346 	}
347 
348 	return data;
349 }
350 
pro_vid_wr(int data,int pa,int access)351 void pro_vid_wr (int data, int pa, int access)
352 {
353 int	x, y, pixop, vplane, vindex, vcount, vdata, vpixpat, vwordpat, vsi, old_csr, old_scl;
354 int	pixdata = 0;	/* assign dummy value to silence incorrect gcc warning */
355 
356 int	vop[3];
357 int	voc1, voc0;
358 
359 	switch (pa & 017777776)
360 	{
361 	  case 017774404:
362 	    old_csr = pro_vid_csr;
363 
364 	    WRITE_WB(pro_vid_csr, PRO_VID_CSR_W, access);
365 
366 	    /* XXX this might not be correct, but the ROM seems
367 	           to imply this behavior */
368 
369 	    /* Maybe it should only happen the first time after reset */
370 
371 	    /* Generate TD interrupt if TD enabled and done bit set */
372 
373 	    if (((pro_vid_csr & PRO_VID_DIE) != 0)
374 	       && ((old_csr & PRO_VID_DIE) == 0)
375 	       && ((pro_vid_csr & PRO_VID_TD) != 0))
376 	      pro_int_set(PRO_INT_2B);
377 
378 	    /* Check if mapped mode changed */
379 
380 	    if ((pro_vid_csr & PRO_VID_CME) != (old_csr & PRO_VID_CME))
381 	      pro_mapchange();
382 
383 	    break;
384 
385 	  case 017774406:
386 	    WRITE_W(pro_vid_p1c, PRO_VID_P1C_W);
387 	    pro_vid_plane_en = ((pro_vid_opc & PRO_VID_P3_VME) >> 11)
388 	                       | ((pro_vid_opc & PRO_VID_P2_VME) >> 4)
389 	                       | ((pro_vid_p1c & PRO_VID_P1_VME) >> 5);
390 	    break;
391 
392 /* EBO */
393 	  case 017774410:
394 	    WRITE_W(pro_vid_opc, PRO_VID_OPC_W);
395 	    pro_vid_plane_en = ((pro_vid_opc & PRO_VID_P3_VME) >> 11)
396 	                       | ((pro_vid_opc & PRO_VID_P2_VME) >> 4)
397 	                       | ((pro_vid_p1c & PRO_VID_P1_VME) >> 5);
398 	    break;
399 
400 /* EBO */
401 	  case 017774412:
402 	    /* Write to colormap */
403 
404 	    pro_colormap_write(((data & PRO_VID_INDEX) >> 8), (data & PRO_VID_RGB));
405 
406 	    break;
407 
408 	  case 017774414:
409 	    old_scl = pro_vid_scl;
410 
411 	    WRITE_W(pro_vid_scl, PRO_VID_SCL_W);
412 
413 	    /* Call scroll routine if scl changed */
414 
415 	    if (old_scl != pro_vid_scl)
416 	      pro_scroll();
417 
418 	    /* Update memory offset */
419 
420 	    pro_vid_y_offset = (pro_vid_scl << 6) & 037700;
421 
422 	    break;
423 
424 	  case 017774416:
425 	    WRITE_W(pro_vid_x, PRO_VID_X_W);
426 	    break;
427 
428 	  case 017774420:
429 	    WRITE_W(pro_vid_y, PRO_VID_Y_W);
430 	    break;
431 
432 	  case 017774422:
433 	    WRITE_W(pro_vid_cnt, PRO_VID_CNT_W);
434 
435 	    /* Clear the done bit */
436 
437 	    pro_vid_csr = pro_vid_csr & ~PRO_VID_TD;
438 
439 	    /* XXX kludge - assuming plane, enabled, etc. */
440 
441 	    if (pro_vid_cnt != 0)
442 	    {
443 	      /* Determine operation types for all planes */
444 
445 	      vop[0] = pro_vid_p1c & PRO_VID_P1_OP;
446 	      vop[1] = pro_vid_opc & PRO_VID_P2_OP;
447 	      vop[2] = (pro_vid_opc & PRO_VID_P3_OP) >> 8;
448 
449 	      /* Operation class */
450 
451 	      /* XXX Make these text macros for speed */
452 
453 	      voc1 = pro_vid_csr & PRO_VID_OC1; /* bit mode */
454 
455 	      voc0 = pro_vid_csr & PRO_VID_OC0; /* left to right */
456 
457 	      for(vplane=0; vplane<PRO_VID_NUMPLANES; vplane++)
458 	      {
459 	        x = pro_vid_x;
460 	        y = pro_vid_y;
461 
462 	        /* Calculate memory index (for word mode) */
463 
464 	        vindex = vmem((y << 6) | ((x >> 4) & 077));
465 
466 	        /* Calculate pattern for word mode */
467 
468 /* XXX
469 	        vwordpat = pro_vid_pat;
470 */
471 	        if ((pro_vid_pat & 01) == 0)
472 	          vwordpat = 0;
473 	        else
474 	          vwordpat = 0177777;
475 
476 	        /* Set initial pattern for pixel mode */
477 
478 	        vpixpat = pro_vid_pat;
479 
480 	        /* Set initial shift-in pattern for word screen shift */
481 
482 	        vsi = vwordpat;
483 
484 	        for(vcount = 0; vcount < pro_vid_cnt; vcount++)
485 	        {
486 	          if (voc1 == 0) /* bit mode */
487 	          {
488 	            switch (vop[vplane])
489 	            {
490 	              case PRO_VID_BM_NOP:
491 	                pixop = PRO_VID_PIX_NOP;
492 	                break;
493 
494 	              case PRO_VID_BM_XOR:
495 	                pixop = PRO_VID_PIX_XOR;
496 	                pixdata = vpixpat & 01;
497 	                vpixpat = (vpixpat >> 1) | ((vpixpat << 15) & 0100000);
498 	                break;
499 
500 	              case PRO_VID_BM_MOVE:
501 	                pixop = PRO_VID_PIX_REP;
502 	                pixdata = vpixpat & 01;
503 	                vpixpat = (vpixpat >> 1) | ((vpixpat << 15) & 0100000);
504 	                break;
505 
506 	              case PRO_VID_BM_NMOVE:
507 	                pixop = PRO_VID_PIX_REP;
508 	                pixdata = ~vpixpat & 01;
509 	                vpixpat = (vpixpat >> 1) | ((vpixpat << 15) & 0100000);
510 	                break;
511 
512 	              case PRO_VID_BM_SETPAT:
513 	                pixop = PRO_VID_PIX_SET;
514 	                pixdata = vpixpat & 01;
515 	                vpixpat = (vpixpat >> 1) | ((vpixpat << 15) & 0100000);
516 	                break;
517 
518 	              case PRO_VID_BM_CLRPAT:
519 	                pixop = PRO_VID_PIX_CLR;
520 	                pixdata = vpixpat & 01;
521 	                vpixpat = (vpixpat >> 1) | ((vpixpat << 15) & 0100000);
522 	                break;
523 
524 	              case PRO_VID_BM_CLRBIT:
525 	                pixop = PRO_VID_PIX_CLR;
526 	                pixdata = 01;
527 	                break;
528 
529 	              case PRO_VID_BM_SETBIT:
530 	                pixop = PRO_VID_PIX_SET;
531 	                pixdata = 01;
532 	                break;
533 
534 	              default:
535 	                pixop = PRO_VID_PIX_NOP;
536 	                break;
537 	            }
538 
539 	            /* Perform the pixel operation */
540 
541 	            if (pixop != PRO_VID_PIX_NOP)
542 	              pro_vid_pixop(vplane, x, y, pixdata, pixop);
543 
544 	            /* Update x & y */
545 
546 	            if (voc0 == 0) /* left to right */
547 	            {
548 	              x++;
549 
550 	              if (x == PRO_VID_MEMWIDTH)
551 	              {
552 	                x = 0;
553 	                y++;
554 
555 	                if (y == PRO_VID_MEMHEIGHT)
556 	                  y = 0;
557 	              }
558 	            }
559 	            else /* top to bottom */
560 	            {
561 	              y++;
562 
563 	              if (y == PRO_VID_MEMHEIGHT)
564 	              {
565 	                y = 0;
566 	                x++;
567 
568 	                if (x == PRO_VID_MEMWIDTH)
569 	                  x = 0;
570 	              }
571 	            }
572 
573 	          }
574 	          else /* word mode */
575 	          {
576 	            switch (vop[vplane])
577 	            {
578 	              case PRO_VID_WM_NOP:
579 	                break;
580 
581 	              case PRO_VID_WM_COM:
582 	                PRO_VRAM[vplane][vindex] = (PRO_VRAM[vplane][vindex] ^ 0177777) & 0177777;
583 	                break;
584 
585 	              case PRO_VID_WM_MOVE:
586 	                PRO_VRAM[vplane][vindex] = vwordpat;
587 	                break;
588 
589 	              case PRO_VID_WM_NMOVE:
590 	                PRO_VRAM[vplane][vindex] = (~vwordpat) & 0177777;
591 	                break;
592 
593 	              /* XXX combine these three */
594 
595 	              case PRO_VID_WM_S1:
596 	                vdata = PRO_VRAM[vplane][vindex];
597 	                if (voc0 == 0) /* left to right */
598 	                  PRO_VRAM[vplane][vindex] = ((PRO_VRAM[vplane][vindex] << 1) & 0177777) | ((vsi >> 15) & 01);
599 	                else /* right to left */
600 	                  PRO_VRAM[vplane][vindex] = ((PRO_VRAM[vplane][vindex] >> 1) & 0177777) | ((vsi << 15) & 0100000);
601 	                vsi = vdata;
602 	                break;
603 
604 	              case PRO_VID_WM_S2:
605 	                vdata = PRO_VRAM[vplane][vindex];
606 	                if (voc0 == 0) /* left to right */
607 	                  PRO_VRAM[vplane][vindex] = ((PRO_VRAM[vplane][vindex] << 2) & 0177777) | ((vsi >> 14) & 03);
608 	                else /* right to left */
609 	                  PRO_VRAM[vplane][vindex] = ((PRO_VRAM[vplane][vindex] >> 2) & 0177777) | ((vsi << 14) & 0140000);
610 	                vsi = vdata;
611 	                break;
612 
613 	              case PRO_VID_WM_S4:
614 	                vdata = PRO_VRAM[vplane][vindex];
615 	                if (voc0 == 0) /* left to right */
616 	                  PRO_VRAM[vplane][vindex] = ((PRO_VRAM[vplane][vindex] << 4) & 0177777) | ((vsi >> 12) & 017);
617 	                else /* right to left */
618 	                  PRO_VRAM[vplane][vindex] = ((PRO_VRAM[vplane][vindex] >> 4) & 0177777) | ((vsi << 12) & 0170000);
619 	                vsi = vdata;
620 	                break;
621 
622 	              default:
623 	                break;
624 	            }
625 
626 	            pro_vid_mvalid[cmem(vindex)] = 0;
627 
628 	            /* Update memory index */
629 
630 	            /* XXX is wrap-around handled correctly? */
631 
632 	            if (voc0 == 0) /* left to right */
633 	              vindex = (vindex + 1) & PRO_VID_VADDR_MASK;
634 	            else /* right to left */
635 	              vindex = (vindex - 1) & PRO_VID_VADDR_MASK;
636 
637 	          }
638 
639 	        }
640 	      }
641 
642 	      /* Update pattern register, once all three plane operations
643                  have completed */
644 
645 	      /* XXX Is this the correct behavior? */
646 
647 	      pro_vid_pat = vpixpat;
648 	    }
649 
650 
651 	    /* Schedule completion event */
652 
653 	    pro_eq_sched(PRO_EVENT_VID_CMD, PRO_EQ_CMD);
654 
655 	    break;
656 
657 /* XXX This should only be writeable if the done bit is set */
658 
659 	  case 017774424:
660 	    WRITE_W(pro_vid_pat, PRO_VID_PAT_W);
661 	    break;
662 
663 	  case 017774426:
664 	    WRITE_W(pro_vid_mbr, PRO_VID_MBR_W);
665 	    pro_vid_mem_base = pro_vid_mbr << 15; /* video mem base address */
666 
667 	    /* Update CPU memory decoder */
668 
669 	    iotable[0].low = pro_vid_mem_base;
670 	    iotable[0].high = pro_vid_mem_base + PRO_VID_MEMSIZE - 1;
671 
672 	    break;
673 
674 	  default:
675 	    break;
676 	}
677 }
678 
679 
pro_vid_reset()680 void pro_vid_reset ()
681 {
682 	/* Clear Video memory buffers */
683 
684         memset(&PRO_VRAM, 0, sizeof(PRO_VRAM));
685 
686 	/* XXX some undefined bits have different values in the real PRO */
687 
688 	pro_vid_csr = PRO_VID_CSR | PRO_VID_TD;	/* indicate command completed */
689 	pro_vid_p1c = 0;
690 	pro_vid_opc = 0;
691 	pro_vid_scl = 0177400;
692 	pro_vid_x = 0;
693 	pro_vid_y = 0;
694 	pro_vid_cnt = 0;
695 	pro_vid_pat = 0;
696 	pro_vid_mbr = 0;
697 
698 	pro_vid_mem_base = 0;
699 	pro_vid_plane_en = 0;
700 	pro_vid_y_offset = 0;
701 	pro_vid_skip = 0;
702 
703 
704 	/* Start up vertical retrace event */
705 
706 	pro_vid_sched();
707 
708 	/* Reset display subsystem */
709 
710 	pro_screen_reset();
711 
712 	/* Open display window */
713 
714 	if (pro_screen_init() == PRO_FAIL)
715 	  pro_exit();
716 }
717 
718 
719 /* Exit routine */
720 
pro_vid_exit()721 void pro_vid_exit ()
722 {
723 	pro_screen_close();
724 }
725 #endif
726