1 /*
2 * crtc-draw.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 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 #include "vice.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "crtc-draw.h"
34 #include "crtc.h"
35 #include "crtctypes.h"
36 #include "raster-modes.h"
37 #include "types.h"
38
39
40 /*
41 * Bit expansion table: expands 4 bits to 4 bytes,
42 * placing each bit in the lsb of the bytes.
43 * The msb of the input is mapped to the lowest-address byte.
44 *
45 * The table maps nybbles at a time, since mapping a whole byte
46 * would take 2 tables, each 16 times as big, and that would
47 * not be so nice on the cpu cache.
48 */
49 uint32_t dwg_table[16];
50
init_drawing_tables(void)51 static void init_drawing_tables(void)
52 {
53 int byte, p;
54 uint8_t msk;
55
56 for (byte = 0; byte < 0x10; byte++) {
57 for (msk = 0x08, p = 0; p < 4; msk >>= 1, p++) {
58 *((uint8_t *)(dwg_table + byte) + p)
59 = (byte & msk ? 1 : 0);
60 }
61 }
62 }
63
64
65 /***************************************************************************/
66
draw_standard_background(unsigned int start_pixel,unsigned int end_pixel)67 static void draw_standard_background(unsigned int start_pixel,
68 unsigned int end_pixel)
69 {
70 memset(crtc.raster.draw_buffer_ptr + start_pixel,
71 0,
72 end_pixel - start_pixel + 1);
73 }
74
75 /***************************************************************************/
76
77 /* inline function... */
DRAW(int reverse_flag,int offset,int scr_rel,int xs,int xc,int xe)78 static inline void DRAW(int reverse_flag, int offset, int scr_rel,
79 int xs, int xc, int xe)
80 {
81 /* FIXME: `p' has to be aligned on a 4 byte boundary!
82 Is there a better way than masking `offset'? */
83 uint8_t *p = crtc.raster.draw_buffer_ptr + (offset & ~3);
84 uint32_t *pw = (uint32_t *)p;
85 uint8_t *chargen_ptr, *screen_ptr;
86 int screen_rel;
87 int i, d;
88 /* pointer to current chargen line */
89 chargen_ptr = crtc.chargen_base
90 + crtc.chargen_rel
91 + (crtc.raster.ycounter & 0x0f);
92 /* pointer to current screen line */
93 screen_ptr = crtc.screen_base;
94 screen_rel = ((scr_rel) + (xs));
95
96 if (crtc.crsrmode && crtc.cursor_lines && crtc.crsrstate) {
97 int crsrrel = ((crtc.regs[14] << 8) | crtc.regs[15]) & crtc.vaddr_mask;
98
99 for (i = (xs); i < (xc); i++) {
100 d = *(chargen_ptr
101 + (screen_ptr[screen_rel & crtc.vaddr_mask] << 4));
102
103 /* FIXME: mask with 0x3fff (screen_rel must be expanded) */
104 if (screen_rel == crsrrel) {
105 d ^= 0xff;
106 }
107
108 screen_rel++;
109
110 if ((reverse_flag)) {
111 d ^= 0xff;
112 }
113
114 *pw++ = dwg_table[d >> 4];
115 *pw++ = dwg_table[d & 0x0f];
116 }
117 } else {
118 for (i = (xs); i < (xc); i++) {
119 /* we use 16 bytes/char character generator */
120 d = *(chargen_ptr
121 + (screen_ptr[screen_rel & crtc.vaddr_mask] << 4));
122 screen_rel++;
123
124 if ((reverse_flag)) {
125 d ^= 0xff;
126 }
127
128 *pw++ = dwg_table[d >> 4];
129 *pw++ = dwg_table[d & 0x0f];
130 }
131 }
132
133 /* blank the rest */
134 for (; i < (xe); i++) {
135 *pw++ = 0;
136 *pw++ = 0;
137 }
138
139 if (crtc.hires_draw_callback) {
140 (crtc.hires_draw_callback)(p, xs, xc, scr_rel + xs, crtc.raster.ycounter);
141 }
142 }
143
draw_standard_line(void)144 static void draw_standard_line(void)
145 {
146 int rl_pos = crtc.xoffset + crtc.hjitter;
147 /*
148 if (crtc.current_line == 1)
149 printf("rl_pos=%d, scr_rel=%d, hw_cols=%d, rl_vis=%d, rl_len=%d\n",
150 rl_pos, crtc.screen_rel, crtc.hw_cols, crtc.rl_visible,
151 crtc.rl_len);
152 */
153 /* FIXME: check the ends against the maximum line length */
154 /* the first part is left of rl_pos. Data is taken from prev. rl */
155 if (rl_pos > 8) {
156 DRAW(0,
157 rl_pos % 8,
158 crtc.prev_screen_rel,
159 (crtc.prev_rl_len + 1) * crtc.hw_cols - (rl_pos / 8),
160 crtc.prev_rl_visible * crtc.hw_cols,
161 (crtc.prev_rl_len + 1) * crtc.hw_cols);
162 }
163
164 /* this is the "normal" part of the rasterline */
165 DRAW(0,
166 rl_pos,
167 crtc.screen_rel,
168 0,
169 crtc.rl_visible * crtc.hw_cols,
170 (crtc.rl_len + 1) * crtc.hw_cols);
171 }
172
draw_reverse_line(void)173 static void draw_reverse_line(void)
174 {
175 int rl_pos = crtc.xoffset + crtc.hjitter;
176
177 /* the first part is left of rl_pos. Data is taken from prev. rl */
178 if (rl_pos > 8) {
179 DRAW(1,
180 rl_pos % 8,
181 crtc.prev_screen_rel,
182 (crtc.prev_rl_len + 1) * crtc.hw_cols - (rl_pos / 8),
183 crtc.prev_rl_visible * crtc.hw_cols,
184 (crtc.prev_rl_len + 1) * crtc.hw_cols);
185 }
186
187 /* this is the "normal" part of the rasterline */
188 DRAW(1,
189 rl_pos,
190 crtc.screen_rel,
191 0,
192 crtc.rl_visible * crtc.hw_cols,
193 (crtc.rl_len + 1) * crtc.hw_cols);
194 }
195
get_std_text(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)196 static int get_std_text(raster_cache_t *cache, unsigned int *xs,
197 unsigned int *xe, int rr)
198 {
199 *xs = 0;
200 *xe = (crtc.rl_len + 1) * crtc.hw_cols;
201
202 return 1;
203 }
204
draw_std_text_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)205 static void draw_std_text_cached(raster_cache_t *cache, unsigned int xs,
206 unsigned int xe)
207 {
208 draw_standard_line();
209 }
210
get_rev_text(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)211 static int get_rev_text(raster_cache_t *cache, unsigned int *xs,
212 unsigned int *xe, int rr)
213 {
214 *xs = 0;
215 *xe = (crtc.rl_len + 1) * crtc.hw_cols;
216
217 return 1;
218 }
219
draw_rev_text_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)220 static void draw_rev_text_cached(raster_cache_t *cache, unsigned int xs,
221 unsigned int xe)
222 {
223 draw_reverse_line();
224 }
225
226 /***************************************************************************/
227
setup_modes(void)228 static void setup_modes(void)
229 {
230 raster_modes_set(crtc.raster.modes, CRTC_STANDARD_MODE,
231 get_std_text,
232 draw_std_text_cached,
233 draw_standard_line,
234 draw_standard_background,
235 NULL /* draw_std_text_foreground */ );
236
237 raster_modes_set(crtc.raster.modes, CRTC_REVERSE_MODE,
238 get_rev_text,
239 draw_rev_text_cached,
240 draw_reverse_line,
241 draw_standard_background,
242 NULL /* draw_rev_text_foreground*/);
243 }
244
245
crtc_draw_init(void)246 void crtc_draw_init(void)
247 {
248 init_drawing_tables();
249
250 setup_modes();
251 }
252