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