1 /*
2  * crtc-mem.c - A line-based CRTC emulation (under construction).
3  *
4  * Written by
5  *  Ettore Perazzoli <ettore@comm2000.it>
6  *  Andre Fachat <fachat@physik.tu-chemnitz.de>
7  *
8  * 16/24bpp support added by
9  *  Steven Tieu <stieu@physics.ubc.ca>
10  *  Teemu Rantanen <tvr@cs.hut.fi>
11  *
12  * This file is part of VICE, the Versatile Commodore Emulator.
13  * See README for copyright notice.
14  *
15  *  This program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  This program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with this program; if not, write to the Free Software
27  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28  *  02111-1307  USA.
29  *
30  */
31 
32 #include "vice.h"
33 
34 #include "alarm.h"
35 #include "crtc-mem.h"
36 #include "crtc.h"
37 #include "crtctypes.h"
38 #include "maincpu.h"
39 #include "types.h"
40 
41 
42 /* CRTC interface functions.
43    - bit 0 of the addr is wired to register-select of the chip
44    FIXME: Several registers are not implemented.  */
45 
crtc_store(uint16_t addr,uint8_t value)46 void crtc_store(uint16_t addr, uint8_t value)
47 {
48     int current_cycle;
49 
50     current_cycle = maincpu_clk - crtc.rl_start;
51 
52     addr &= 1;
53 
54     if (!addr) {
55         /* low on register-select permits writes to the address register */
56         crtc.regno = value & 0x1f;
57         return;
58     }
59 
60 #if 0
61     /* debug display, just not the cursor (for CBM-II) */
62     if (crtc.regno < 14 && crtc.regno != 10) {
63         printf("store_crtc(reg=%d, %d) - cline=%d, ycount=%d, char=%d\n",
64                crtc.regno, value, crtc.current_charline, crtc.raster.ycounter,
65                current_cycle);
66     }
67 #endif
68 
69     crtc.regs[crtc.regno] = value;
70 
71     switch (crtc.regno) {
72         case CRTC_REG_HTOTAL:       /* R00  Horizontal total (characters + 1) */
73             if (current_cycle > value) {
74                 value = 255;
75             }
76             crtc.rl_len = value;
77             if (crtc.initialized) {
78                 alarm_set(crtc.raster_draw_alarm, crtc.rl_start + value);
79             }
80             break;
81 
82         case CRTC_REG_HDISP:        /* R01  Horizontal characters displayed */
83             if (!(current_cycle < crtc.rl_visible)) {
84                 break;
85             }
86 
87             /* the compare is not yet done */
88             if ((crtc.regs[1]) > current_cycle) {
89                 /* only if we write a higher value than the counter,
90                  we can update disp_cycles here */
91                 crtc.rl_visible = crtc.regs[1];
92                 crtc.henable = 1;
93             } else {
94                 /* we write a value lower than the counter -> never reached,
95                  open border */
96                 crtc.rl_visible = crtc.rl_len + 1;
97                 crtc.henable = 0;
98             }
99             break;
100 
101         case CRTC_REG_HSYNC:        /* R02  Horizontal Sync Position */
102             if (current_cycle < crtc.rl_sync) {
103                 /* FIXME: middle of pulse, adjust from reg. 3 */
104                 crtc.rl_sync = value;
105             }
106             break;
107 
108         case CRTC_REG_SYNCWIDTH:    /* R03  Horizontal/Vertical Sync widths */
109             break;
110 
111         case CRTC_REG_VTOTAL:       /* R04  Vertical total (character) rows */
112             crtc.regs[CRTC_REG_VTOTAL] &= 0x7f;
113             break;
114 
115         case CRTC_REG_VTOTALADJ:    /* R05  Vertical total line adjust */
116             crtc.regs[CRTC_REG_VTOTALADJ] &= 0x1f;
117             break;
118 
119         case CRTC_REG_VDISP:        /* R06  Number of display lines on screen */
120             crtc.regs[CRTC_REG_VDISP] &= 0x7f;
121             break;
122 
123         case CRTC_REG_VSYNC:        /* R07  Vertical sync position */
124             crtc.regs[CRTC_REG_VSYNC] &= 0x7f;
125             break;
126 
127         case CRTC_REG_MODECTRL:     /* R08  unused: Interlace and Skew */
128             break;
129 
130         case CRTC_REG_SCANLINE:     /* R09  number of lines per character line, including spacing */
131             crtc.regs[CRTC_REG_SCANLINE] &= 0x1f;
132             break;
133 
134         case CRTC_REG_CURSORSTART:  /* R10  Cursor start (not implemented on the PET) */
135             crtc.regs[CRTC_REG_CURSORSTART] &= 0x7f;
136             /* FIXME: set start line */
137             value = ((value >> 5) & 0x03) ^ 0x01; /* cursor mode */
138             if (!(crtc.hw_cursor && (crtc.crsrmode != value))) {
139                 break;
140             }
141 
142             crtc.crsrmode = value;
143             crtc.crsrstate = 1;
144             crtc.crsrcnt = 16;
145             break;
146 
147         case CRTC_REG_CURSOREND:    /* R11  Cursor end (not implemented on the PET) */
148             crtc.regs[CRTC_REG_CURSOREND] &= 0x7f;
149             /* FIXME: set end line */
150             break;
151 
152         case CRTC_REG_DISPSTARTH:   /* R12  Control register */
153             /* This is actually the upper 6 video RAM address bits.
154              * But CBM decided that the two uppermost bits should be used
155              * for control.
156              * The usage here is from the 8032 schematics on funet.
157              *
158              * Bit 0: 1=add 256 to screen start address ( 512 for 80-columns)
159              * Bit 1: 1=add 512 to screen start address (1024 for 80-columns)
160              * Bit 2: no connection
161              * Bit 3: no connection
162              * Bit 4: use top half of 4K character generator
163              * Bit 5: invert video signal
164              * Bit 6: (no pin on the CRTC, video address is 14 bit only)
165              * Bit 7: (no pin on the CRTC, video address is 14 bit only)
166              */
167             /* FIXME: check if the above also applies to CBM2 and all the other PET models */
168             /* The CRTC loads its internal counter when it starts a new
169              * frame. At this point the address/mode changes are evaluated now.
170              */
171             crtc.regs[CRTC_REG_DISPSTARTH] &= 0x3f;
172             break;
173 
174         case CRTC_REG_DISPSTARTL:   /* R13  Address of first character */
175             break;
176 
177         case CRTC_REG_CURSORPOSH:   /* R14  Cursor location  HI -- unused */
178             crtc.regs[CRTC_REG_CURSORPOSH] &= 0x3f;
179 #if 0
180             crsr_set_dirty();
181             crsrpos = ((crsrpos & 0x00ff) | ((value << 8) & 0x3f00)) & addr_mask;
182             crsrrel = crsrpos - scrpos;
183             crsr_set_dirty();
184 #endif
185             break;
186 
187         case CRTC_REG_CURSORPOSL:   /* R15  Cursor location  LO -- unused */
188 #if 0
189             crsr_set_dirty();
190             crsrpos = ((crsrpos & 0x3f00) | (value & 0xff)) & addr_mask;
191             crsrrel = crsrpos - scrpos;
192             crsr_set_dirty();
193 #endif
194             break;
195 
196         case CRTC_REG_LPENH:        /* R16 Light Pen HI -- read only */
197         case CRTC_REG_LPENL:        /* R17 Light Pen LO -- read only */
198             break;
199 
200         case 18:
201         case 19:                    /* R18-9 Update address HI/LO (only 6545)  */
202             break;
203 
204         default:
205             break;
206     }
207 }
208 
crtc_read(uint16_t addr)209 uint8_t crtc_read(uint16_t addr)
210 {
211     /* Status register:
212      *  bit 7: 0 = register 31 (update reg.) has been read/written by CPU
213      *         1 = update strobe received
214      *      6: 0 = register 16 or 17 has been read by CPU
215      *         1 = light pen strobe has been received
216      *      5: 0 = scan is not in vertical retrace
217      *         1 = scan is in vertical retrace (ends 5 char clock times
218      *             before end of retrace, for possibly critical RAM refresh
219      *             timings...)
220      */
221     if (!(addr & 1)) {
222         /* low on register-select permits reads from the status register */
223         /* FIXME: implement bit 7 and bit 6 */
224         return crtc_offscreen() ? 32 : 0;
225     }
226 
227     /* internal registers */
228     switch (crtc.regno) {
229         case CRTC_REG_CURSORPOSH:
230         case CRTC_REG_CURSORPOSL:
231             return crtc.regs[crtc.regno];
232 
233         case CRTC_REG_LPENH:
234         case CRTC_REG_LPENL:
235             /* FIXME: Light Pen X,Y */
236             return 0xff;
237 
238         default:
239             return 0;       /* All the rest are write-only registers */
240     }
241 
242     return 0;
243 }
244 
crtc_peek(uint16_t addr)245 uint8_t crtc_peek(uint16_t addr)
246 {
247     return crtc_read(addr);
248 }
249 
250 /* FIXME: to be moved to `crtc.c'.  */
251 
252 #if 0
253 void crtc_set_char(int crom)
254 {
255     chargen_rel = (chargen_rel & ~0x800) | (crom ? 0x800 : 0);
256     /* chargen_rel is computed for 8bytes/char, but charom is 16bytes/char */
257     chargen_ptr = chargen_rom + (chargen_rel << 1);
258 }
259 
260 static void crtc_update_memory_ptrs(void)
261 {
262     scraddr = crtc[13] + ((crtc[12] & 0x3f) << 8);
263 
264     /* depends on machine */
265     do_update_memory_ptrs();
266 
267     /* chargen_rel is computed for 8bytes/char, but charom is 16bytes/char */
268     chargen_ptr = chargen_rom + (chargen_rel << 1);
269 
270     scraddr &= addr_mask;
271 }
272 
273 #endif
274