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