OSDN Git Service

40c82610077bc29ffa3c54ec018eea9e0b9ed6d1
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / towns_vram.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2016.12.28 -
6
7         [ FM-Towns VRAM ]
8         History: 2017.01.16 Initial.
9 */
10
11 #include "common.h"
12 #include "./towns_vram.h"
13
14 #define CLEAR_COLOR RGBA_COLOR(0,0,0,0)
15
16 #if defined(_RGB888)
17 #define _USE_ALPHA_CHANNEL
18 #endif
19
20 namespace FMTOWNS {
21
22 void TOWNS_VRAM::initialize()
23 {
24 #ifdef _USE_ALPHA_CHANNEL
25         for(int i = 0; i < 32768; i++) {
26                 uint8_t g = (i / (32 * 32)) & 0x1f;
27                 uint8_t r = (i / 32) & 0x1f;
28                 uint8_t b = i & 0x1f;
29                 table_32768c[i] = RGBA_COLOR(r << 3, g << 3, b << 3, 0xff);
30         }
31         for(int i = 32768; i < 65536; i++) {
32                 table_32768c[i] = _CLEAR_COLOR;
33         }
34 #endif
35         for(int i = 0; i < TOWNS_CRTC_MAX_LINES; i++) {
36                 line_rendered[0][i] = false;
37                 line_rendered[1][i] = false;
38         }
39
40 }
41 uint32_t TOWNS_VRAM::read_data8(uint32_t addr)
42 {
43         // ToDo:Offset.
44         // ToDo: Wait.
45 #ifdef __LITTLE_ENDIAN__
46         uint8_t*p = (uint8_t*)vram;
47         return (uint32_t)(p[addr & 0x7ffff]);
48 #else
49         pair16_t d;
50         d.w= vram[(addr & 0x7ffff) >> 1];
51         if((addr & 0x01) == 0) { // Hi
52                 return (uint32_t)(d.b.h);
53         } else { // Lo
54                 return (uint32_t)(d.b.l);
55         }
56 #endif  
57 }
58
59
60
61 uint32_t TOWNS_VRAM::read_data16(uint32_t addr)
62 {
63         // ToDo:Offset.
64         // ToDo: Wait.
65         // Host: Little endian
66         // ToDo: Mask Register.
67         uint32_t naddr = (addr & 0x7fffe) >> 1;
68 #ifdef __LITTLE_ENDIAN__
69         uint16_t w = vram[naddr];
70         return (uint32_t)w;
71 #else // __BIG_ENDIAN__ 
72         pair16_t nw;
73         nw.w = vram[naddr];
74         return (uint32_t)(nw.w);
75 #endif
76 }
77
78 uint32_t TOWNS_VRAM::read_data32(uint32_t addr)
79 {
80         // ToDo: Wait.
81         // ToDo: Mask Register.
82 #ifdef __LITTLE_ENDIAN__
83         uint32_t*p = (uint32_t*)vram;
84         uint32_t naddr = (addr & 0x7ffff) >> 2;
85         uint32_t w = p[naddr];
86         return w;
87 #else // __BIG_ENDIAN__ 
88         pair32_t nd;
89         uint32_t naddr = (addr & 0x7ffff) >> 1;
90         nd.w.l = vram[naddr];
91         nd.w.h = vram[naddr + 1];;
92         return nd.d;
93 #endif
94 }
95
96 void TOWNS_VRAM::write_data8(uint32_t addr, uint32_t data)
97 {
98         // ToDo:Offset.
99         // ToDo: Wait.
100         // ToDo: Mask Register.
101         bool dirty;
102         uint32_t naddr = addr & 0x7ffff;
103
104 #ifdef __LITTLE_ENDIAN__
105         uint8_t* p = (uint8_t*)vram;
106         n = p[naddr];
107 #else
108         pair16_t d;
109         // ToDo: Mask register
110         d.w = vram[naddr >> 1];
111         if((addr & 0x01) != 0) { // Hi
112                 n = d.b.h;
113                 d.b.h = data;
114         } else { // Lo
115                 n = d.b.l;
116                 d.b.l = data;
117         }
118 #endif
119         // ToDo: Mask register
120         
121         dirty = ((uint8_t)data != n) ? true : false;
122
123         if(dirty) {
124                 dirty_flag[naddr >> 3] = true;
125         // ToDo: Mask register
126 #ifdef __LITTLE_ENDIAN__
127                 p[naddr] = data;
128 #else
129                 vram[naddr >> 1] = d.w; 
130 #endif
131
132 #if 0           
133                 if((naddr & 1) != 0) {
134                         // Upper address: Change mask for 32768colors. 
135                         uint16_t nd = (n < 0x80) ? 0xffff : 0x0000;
136                         alpha_32768_byte[naddr >> 1] = (uint8_t)nd;
137                         alpha_32768_word[naddr >> 1] = nd;
138                         mask_32768_word[naddr >> 1]  = ~nd;
139                 }
140                 // ToDo: Mask/alpha16.
141                 uint16_t nu = ((n & 0xf0) != 0) ? 0x0000 : 0xffff;
142                 uint16_t nl = ((n & 0x0f) != 0) ? 0x0000 : 0xffff;
143                 naddr = naddr << 1;
144                 alpha_16_byte[naddr + 0] = (uint8_t)nu;
145                 alpha_16_byte[naddr + 1] = (uint8_t)nl;
146                 alpha_16_word[naddr + 0] = nu;
147                 alpha_16_word[naddr + 1] = nl;
148                 mask_16_byte[naddr + 0]  = ~nu;
149                 mask_16_byte[naddr + 1]  = ~nl;
150 #endif
151         }
152 }
153
154 void TOWNS_VRAM::write_data16(uint32_t addr, uint32_t data)
155 {
156         // ToDo:Offset.
157         // ToDo: Wait.
158         bool dirty;
159         uint32_t naddr = (addr & 0x7fffe) >> 1;
160         uint16_t d;
161         // ToDo: Mask register
162         d = vram[naddr];
163     dirty = ((uint16_t)data != d) ? true : false;
164
165         if(dirty) {
166                 dirty_flag[naddr >> 2] = true;
167                 // ToDo: Mask register
168                 vram[naddr] = data; 
169 #if 0           
170                 uint16_t alphaw = (nw.w < 0x8000) ? 0xffff : 0x0000;
171                 alpha_32768_byte[naddr >> 1] = (uint8_t)alphaw;
172                 alpha_32768_word[naddr >> 1] = alphaw;
173                 mask_32768_word[naddr >> 1] = ~alphaw;
174
175                 
176                 uint16_t n0 = ((nw.b.h  & 0xf0) != 0) ? 0x0000 : 0xffff;
177                 uint16_t n1 = ((nw.b.h  & 0x0f) != 0) ? 0x0000 : 0xffff;
178                 uint16_t n2 = ((nw.b.l & 0xf0) != 0)  ? 0x0000 : 0xffff;
179                 uint16_t n3 = ((nw.b.l & 0x0f) != 0)  ? 0x0000 : 0xffff;
180                 naddr = naddr << 1;
181                 alpha_16_byte[naddr + 0] = (uint8_t)n0;
182                 alpha_16_byte[naddr + 1] = (uint8_t)n1;
183                 alpha_16_byte[naddr + 2] = (uint8_t)n2;
184                 alpha_16_byte[naddr + 3] = (uint8_t)n3;
185                 alpha_16_word[naddr + 0] = n0;
186                 alpha_16_word[naddr + 1] = n1;
187                 alpha_16_word[naddr + 2] = n2;
188                 alpha_16_word[naddr + 3] = n3;
189                 
190                 mask_16_byte[naddr + 0]  = ~n0;
191                 mask_16_byte[naddr + 1]  = ~n1;
192                 mask_16_byte[naddr + 2]  = ~n2;
193                 mask_16_byte[naddr + 3]  = ~n3;
194 #endif
195         }
196 }
197
198 void TOWNS_VRAM::write_data32(uint32_t addr, uint32_t data)
199 {
200         // ToDo:Offset.
201         // ToDo: Wait.
202         bool dirty;
203         uint32_t naddr = (addr & 0x7fffc) >> 1;
204         uint32_t *p = (uint32_t*)vram; 
205         pair32_t nw;
206
207         // ToDo: Mask register
208 #ifdef __LITTLE_ENDIAN__
209         nw.d = p[naddr >> 1];
210 #else
211         nw.w.l = vram[naddr + 0];
212         nw.w.h = vram[naddr + 1];
213 #endif
214         // ToDo: Mask register
215     dirty = (data != nw.d) ? true : false;
216
217         if(dirty) {
218                 // ToDo: Mask register
219                 dirty_flag[(naddr >> 2) + 0] = true;
220
221 #ifdef __LITTLE_ENDIAN__
222                 p[naddr >> 1] = data;
223 #else
224                 nw.d = data;
225                 vram[naddr + 0] = nw.w.l;
226                 vram[naddr + 1] = nw.w.h;
227 #endif
228         }       
229 }
230
231
232 uint32_t TOWNS_VRAM::read_plane_data8(uint32_t addr)
233 {
234         // Plane Access
235         pair_t data_p;
236         uint32_t x_addr = 0;
237         uint8_t *p = (uint8_t*)vram;
238         uint32_t mod_pos;
239
240         // ToDo: Writing plane.
241         if(access_page1) x_addr = 0x40000; //?
242         addr = (addr & 0x7fff) << 3;
243         p = &(p[x_addr + addr]); 
244         
245         // 8bit -> 32bit
246         uint32_t *pp = (uint32_t *)p;
247         uint8_t tmp = 0;
248         uint32_t tmp_d = *pp;
249         
250 #ifdef __LITTLE_ENDIAN__
251         uint32_t tmp_m1 = 0x000000f0;
252         uint32_t tmp_m2 = 0x0000000f;
253 #else
254         uint32_t tmp_m1 = 0xf0000000;
255         uint32_t tmp_m2 = 0x0f000000;
256 #endif  
257         uint32_t tmp_r;
258         tmp_d = tmp_d & write_plane_mask;
259         
260         for(int i = 0; i < 4; i++) {
261                 tmp <<= 2;
262                 tmp = tmp | (((tmp_d & tmp_m1) != 0) ? 0x02 : 0x00);
263                 tmp = tmp | (((tmp_d & tmp_m2) != 0) ? 0x01 : 0x00);
264                 
265 #ifdef __LITTLE_ENDIAN__
266                 tmp_d <<= 8;
267 #else
268                 tmp_d >>= 8;
269 #endif          
270         }
271         return tmp;
272 }
273
274 uint32_t TOWNS_VRAM::read_plane_data16(uint32_t addr)
275 {
276         pair16_t d;
277         d.b.l = (uint8_t)(read_plane_data8(addr + 0));
278         d.b.h = (uint8_t)(read_plane_data8(addr + 1));
279         return (uint32_t)(d.w);
280 }
281
282 uint32_t TOWNS_VRAM::read_plane_data32(uint32_t addr)
283 {
284         pair32_t d;
285         d.b.l  = (uint8_t)(read_plane_data8(addr + 0));
286         d.b.h  = (uint8_t)(read_plane_data8(addr + 1));
287         d.b.h2 = (uint8_t)(read_plane_data8(addr + 2));
288         d.b.h3 = (uint8_t)(read_plane_data8(addr + 3));
289         return d.d;
290 }
291
292 void TOWNS_VRAM::write_plane_data8(uint32_t addr, uint32_t data)
293 {
294         // Plane Access
295         pair_t data_p;
296         uint32_t x_addr = 0;
297         uint8_t *p = (uint8_t*)vram;
298         uint32_t mod_pos;
299
300         // ToDo: Writing plane.
301         if(access_page1) x_addr = 0x40000; //?
302         addr = (addr & 0x7fff) << 3;
303         x_addr = x_addr + addr;
304         p = &(p[x_addr]); 
305         
306         // 8bit -> 32bit
307         uint32_t *pp = (uint32_t *)p;
308         uint32_t tmp = 0;
309         uint32_t tmp_d = data & 0xff;
310 #ifdef __LITTLE_ENDIAN__
311         uint32_t tmp_m1 = 0xf0000000 & write_plane_mask;
312         uint32_t tmp_m2 = 0x0f000000 & write_plane_mask;
313 #else
314         uint32_t tmp_m1 = 0x000000f0 & write_plane_mask;
315         uint32_t tmp_m2 = 0x0000000f & write_plane_mask;
316 #endif  
317         uint32_t tmp_r1;
318         uint32_t tmp_r2;
319
320         for(int i = 0; i < 4; i++) {
321 #ifdef __LITTLE_ENDIAN__
322                 tmp = tmp >> 8;
323 #else
324                 tmp = tmp << 8;
325 #endif
326                 tmp = tmp | (((tmp_d & 0x02) != 0) ? tmp_m1 : 0x00);
327                 tmp = tmp | (((tmp_d & 0x01) != 0) ? tmp_m2 : 0x00);
328                 tmp_d >>= 2;
329         }
330         tmp_r1 = *pp;
331         tmp_r2 = tmp_r1;
332         tmp_r1 = tmp_r1 & ~write_plane_mask;
333         tmp_r1 = tmp_d | tmp_r1;
334         if(tmp_r2 != tmp_r1) {
335                 *pp = tmp_r1;
336                 dirty_flag[x_addr >> 3] = true;
337         }
338 }
339
340 void TOWNS_VRAM::write_plane_data16(uint32_t addr, uint32_t data)
341 {
342         pair16_t d;
343         d.w = (uint16_t)data;
344         write_plane_data8(addr + 0, d.b.l);
345         write_plane_data8(addr + 1, d.b.h);
346 }
347
348
349 void TOWNS_VRAM::write_plane_data32(uint32_t addr, uint32_t data)
350 {
351         pair32_t d;
352         d.d = data;
353         write_plane_data8(addr + 0, d.b.l);
354         write_plane_data8(addr + 1, d.b.h);
355         write_plane_data8(addr + 2, d.b.h2);
356         write_plane_data8(addr + 3, d.b.h3);
357 }
358
359
360 // I/Os
361 // Palette.
362 void TOWNS_CRTC::calc_apalette16(int layer, int index)
363 {
364         if(index < 0) return;
365         if(index > 15) return;
366         apalette_16_rgb[layer][index] =
367                 ((uint16_t)(apalette_b & 0x0f)) |
368                 ((uint16_t)(apalette_r & 0x0f) << 4) |
369                 ((uint16_t)(apalette_g & 0x0f) << 8);
370         if(index == 0) {
371                 apalette_16_pixel[layer][index] = _CLEAR_COLOR; // ??
372         } else {
373                 apalette_16_pixel[layer][index] = RGBA_COLOR((apalette_r & 0x0f) << 4, (apalette_g & 0x0f) << 4, (apalette_b & 0x0f) << 4, 0xff);
374         }
375 }
376
377 void TOWNS_CRTC::calc_apalette256(int index)
378 {
379         if(index < 0) return;
380         if(index > 255) return;
381         apalette_256_rgb[layer][index] =
382                 ((uint32_t)apalette_b) |
383                 ((uint32_t)apalette_r << 8) |
384                 ((uint32_t)apalette_g << 16);
385         if(index == 0) {
386                 apalette_256_pixel[index] = _CLEAR_COLOR; // ??
387         } else {
388                 apalette_256_pixel[index] = RGBA_COLOR(apalette_r, apalette_g, apalette_b, 0xff);
389         }
390 }
391
392 void TOWNS_CRTC::set_apalette_r(int layer, uint8_t val)
393 {
394         apalette_r = val;
395         if(apalette_code < 16) {
396                 calc_apalette16(layer, (int)apalette_code);
397         }
398         // if layer == 0 ?
399         calc_apalette256((int)apalette_code % 256);
400 }
401
402 void TOWNS_CRTC::set_apalette_g(int layer, uint8_t val)
403 {
404         apalette_g = val;
405         if(apalette_code < 16) {
406                 calc_apalette16(layer, (int)apalette_code);
407         }
408         // if layer == 0 ?
409         calc_apalette256((int)apalette_code % 256);
410 }
411
412 void TOWNS_CRTC::set_apalette_b(int layer, uint8_t val)
413 {
414         apalette_b = val;
415         if(apalette_code < 16) {
416                 calc_apalette16(layer, (int)apalette_code);
417         }
418         // if layer == 0 ?
419         calc_apalette256((int)apalette_code % 256);
420 }
421
422 void TOWNS_CRTC::set_apalette_num(int layer, uint8_t val)
423 {
424         apalette_code = ((int)val) % 256;
425 }
426
427 // Renderers
428 void TOWNS_CRTC::render_line_16(int layer, bool upper_layer, scrntype_t *framebuffer, uint8_t *vramptr, uint32_t startaddr, uint32_t words)
429 {
430         uint32_t wordptr = 0;
431         int nwords = (int)words / 16;
432         int ip;
433         uint32_t src;
434         uint32_t src1, src2;
435         __DECL_ALIGNED(16) uint8_t  srcdat[16];
436         __DECL_ALIGNED(sizeof(scrntype_t) * 16) scrntype_t tmpdat[16];
437         
438         __DECL_ALIGNED(sizeof(scrntype_t) * 16) scrntype_t alpha_cache_16[16];
439         __DECL_ALIGNED(sizeof(scrntype_t) * 16) scrntype_t data_cache_16[16];
440         
441         scrntype_t *pdst = framebuffer;
442         uint8_t *pp = (uint8_t *)vramptr;
443         if(framebuffer == NULL) return;
444         if(vramptr == NULL) return;
445
446         uintptr_t offset_base = (uintptr_t)startaddr;
447         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
448         uintptr_t offset;
449         // offet_base = (offset_base + [value_of_offset_register]) & mask.
450         offset_base = (offet_base & 0x3ffff) + base;
451         pp = &(pp[offset_base]);
452         
453         for(ip = 0; ip < nwords; ip++) {
454                 if(!dirty_flag[(offset_base >> 3)]) {
455                         pdst += 16;
456                         pp += 8;
457                         offset_base += 8;
458                         continue;
459                 }
460                 dirty_flag[(offset_base >> 3)] = false;
461                 for(int ii = 0; ii < 8; ii++) {
462                         srcdat[ii << 1]       =  pp[ii];
463                         srcdat[(ii << 1) + 1] =  srcdat[ii << 1] & 0x0f;
464                         srcdat[ii << 1]       = (srcdat[ii << 1] & 0x0f) >> 4;
465                 }
466                 
467                 for(int ii = 0; ii < 16; ii++) {
468                         data_cache_16[ii] = apalette_16[layer][srcdat1[ii]];
469                 }
470                 if(upper_layer) {
471                         // ToDo: For hadrdware that does not upport alpha blending(not RGBA32).
472                         for(int ii = 0; ii < 16; i++) {
473                                 alpha_cache_16[ii] = (srcdat[ii] == 0) ? RGBA_COLOR(0, 0, 0, 0) : RGBA_COLOR(255, 255, 255, 255);
474                         }
475                         for(int ii = 0; ii < 16; i++) {
476                                 tmpdat[ii] = alpha_cache_16_byte[ii] * data_cache_16[ii];
477                         }               
478                 } else {
479                         // ToDo: For hadrdware that does not upport alpha blending(not RGBA32).
480                         for(int ii = 0; ii < 16; i++) {
481                                 alpha_cache_16[ii] = (srcdat[ii] == 0) ? RGBA_COLOR(0,0,0,255) : RGBA_COLOR(255, 255, 255, 255);
482                         }
483                         for(int ii = 0; ii < 16; i++) {
484                                 tmpdat[ii] = alpha_cache_16_byte[ii] * data_cache_16[ii];
485                         }               
486                 }
487                 for(int ii = 0; ii < 16; ii++) {
488                         pdst[ii] = tmpdat[ii];
489                 }
490                 pdst += 16;
491                 pp += 8;
492         }
493         int mod_words = words - (nwords * 16);
494         uint8_t sdat1, sdat2;
495         scrntype_t c1, c2;
496         
497         if(mod_words > 0) {
498                 offset_base = (uintptr_t)startaddr;
499                 // offet_base = (offset_base + [value_of_offset_register]) & mask.
500                 offset_base = ((offet_base + nwords) & 0x3ffff) + base;
501                 if(dirty_flag[offset_base >> 3]) {
502                         dirty_flag[offset_base >> 3] = false;
503                         for(int ii = 0; ii < mod_words; i++) {
504                                 if((ii & 1) == 0) {
505                                         sdat1 = *pp;
506                                         sdat2 = sdat1 & 0x0f;
507                                         sdat1 = (sdat1 & 0xf0) >> 4;
508                                         if(upper_layer) {
509                                                 c1 = (sdat1 == 0) ? RGBA_COLOR(0, 0, 0, 0) : RGBA_COLOR(255, 255, 255, 255);
510                                                 c2 = (sdat2 == 0) ? RGBA_COLOR(0, 0, 0, 0) : RGBA_COLOR(255, 255, 255, 255);
511                                         } else {
512                                                 c1 = (sdat1 == 0) ? RGBA_COLOR(0, 0, 0, 255) : RGBA_COLOR(255, 255, 255, 255);
513                                                 c2 = (sdat2 == 0) ? RGBA_COLOR(0, 0, 0, 255) : RGBA_COLOR(255, 255, 255, 255);
514                                         }
515                                 }
516                                 if((ii & 1) == 0) {
517                                         tmpdat[ii] = c1 * apalette_16_pixel[layer][sdat1];
518                                 } else {
519                                         tmpdat[ii] = c2 * apalette_16_pixel[layer][sdat2];
520                                 }
521                                 pp++;
522                         }
523                         for(int ii = 0; ii < mod_words; i++) {
524                                 pdst[ii] = tmpdat[ii];
525                         }
526                 }
527         }
528 }
529
530 void TOWNS_CRTC::render_line_256(int layer, bool upper_layer, scrntype_t *framebuffer, uint8_t *vramptr, uint32_t startaddr, uint32_t words)
531 {
532         uint32_t wordptr = 0;
533         int nwords = (int)words / 8;
534         int ip;
535         __DECL_ALIGNED(8) uint32_t src[2];
536         __DECL_ALIGNED(8) uint8_t  srcdat[8];
537         scrntype_t *pdst  = __builtin_assume_aligned(framebuffer, sizeof(scrntype_t) * 4);
538         uint32_t *pp = (uint32_t *)vramptr;
539         
540         if(framebuffer == NULL) return;
541         if(vramptr == NULL) return;
542
543         uintptr_t offset_base = (uintptr_t)startaddr;
544         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
545         // offet_base = (offset_base + [value_of_offset_register]) & mask.
546         offset_base = (offet_base & 0x3ffff) + base;
547         pp = &(pp[offset_base >> 2]);
548         
549         for(ip = 0; ip < nwords; ip++) {
550                 if(dirty_flag[offset_base >> 3]) {
551                         src[0] = pp[0];
552                         src[1] = pp[1];
553 #if defined(__LITTLE_ENDIAN__)
554                         srcdat[0] = (uint8_t)((src[0] & 0xff000000) >> 24);
555                         srcdat[1] = (uint8_t)((src[0] & 0x00ff0000) >> 16);
556                         srcdat[2] = (uint8_t)((src[0] & 0x0000ff00) >> 8);
557                         srcdat[3] = (uint8_t) (src[0] & 0x000000ff);
558                         
559                         srcdat[4] = (uint8_t)((src[1] & 0xff000000) >> 24);
560                         srcdat[5] = (uint8_t)((src[1] & 0x00ff0000) >> 16);
561                         srcdat[6] = (uint8_t)((src[1] & 0x0000ff00) >> 8);
562                         srcdat[7] = (uint8_t) (src[1] & 0x000000ff);
563 #else
564                         srcdat[0] = (uint8_t)( src[0] & 0x000000ff);
565                         srcdat[1] = (uint8_t)((src[0] & 0x0000ff00) >> 8);
566                         srcdat[2] = (uint8_t)((src[0] & 0x00ff0000) >> 16);
567                         srcdat[3] = (uint8_t)((src[0] & 0xff000000) >> 24);
568                         
569                         srcdat[4] = (uint8_t)( src[1] & 0x000000ff);
570                         srcdat[5] = (uint8_t)((src[1] & 0x0000ff00) >> 8);
571                         srcdat[6] = (uint8_t)((src[1] & 0x00ff0000) >> 16);
572                         srcdat[7] = (uint8_t)((src[1] & 0xff000000) >> 24);
573 #endif
574                         // ToDo: Super Impose.
575                         for(int i = 0; i < 8; i++) {
576                                 pdst[i] = apalette_256_pixel[srcdat[i]];
577                         }
578                 }
579                 pp += 2;
580                 pdst += 8;
581         }
582         int mod_words = words - (nwords * 4);
583         if(mod_words > 0) {
584                 uint8_t src8;
585                 uint8_t *p8 = (uint8_t *)(&pp[ip]);
586                 for(int i = 0; i < mod_words; i++) {
587                         src8 = p8[i];
588                         // ToDo: Super Impose.
589                         pdst[i] = apalette_256_pixel[src8];
590                 }
591         }
592 }
593
594 // To be used table??
595 void TOWNS_CRTC::render_line_32768(int layer, bool do_impose, scrntype_t *pixcache, uint16_t *vramptr, uint32_t words)
596 {
597         uint32_t wordptr = 0;
598         int nwords = (int)words / 8;
599         int ip;
600         uint16_t src16;
601         scrntype_t *pdst = pixcache;
602         uint16_t *pp = (uint16_t *)vramptr;
603         uint16_t *cachep = (uint16_t *)srcdat;
604         __DECL_ALIGNED(16) pair16_t rgb[8];
605         __DECL_ALIGNED(8) uint8_t a[8];
606         __DECL_ALIGNED(8) uint8_t r[8];
607         __DECL_ALIGNED(8) uint8_t g[8];
608         __DECL_ALIGNED(8) uint8_t b[8];
609         __DECL_ALIGNED(sizeof(scrntype_t) * 8) scrntype_t dcache[8];
610
611         int i = 0;
612         
613         if(framebuffer == NULL) return;
614         if(vramptr == NULL) return;
615
616         uintptr_t offset_base = (uintptr_t)startaddr;
617         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
618         // offet_base = (offset_base + [value_of_offset_register]) & mask.
619         offset_base = (offet_base & 0x3ffff) + base;
620         pp = &(pp[offset_base >> 1]);
621         for(ip = 0; ip < nwords; ip++) {
622                 if(dirty_flag[offset_base >> 3]) {
623                         dirty_flags[offset_base >> 3] = false;
624                         for(int i = 0; i < 8; i++) {
625                                 rgb[i].w = pp[i];
626                         }
627                         for(int i = 0; i < 8; i++) {
628                                 dcache[i] = _CLEAR_COLOR;
629                         }
630                         
631                         for(int ii = 0; ii < 8; ii++) {
632                                 //g5r5b5
633                                 g[ii] = rgb[ii].b.h & 0x7c;
634                                 b[ii] = rgb[ii].b.l & 0x1f;
635                         }
636                         for(int ii = 0; ii < 8; ii++) {
637                                 //g5r5b5
638                                 b[ii] = b[ii] << 3;
639                         }
640                         for(int ii = 0; ii < 8; ii++) {
641                                 r[ii] = ((rgb[ii].b.h & 0x03) << 6) | ((rgb[ii].b.l & 0xe0) >> 2);
642                         }
643                         if(do_impose) {
644                                 for(int ii = 0; ii < 8; ii++) {
645                                         a[ii] =  (rgb[ii].h < 0x80) ? 0xff : 0x00;
646                                 }
647                         } else {
648                                 for(int ii = 0; ii < 8; ii++) {
649                                         a[ii] = 0xff;
650                                 }
651                         }
652                         for(int ii = 0; ii < 8; ii++) {
653                                 dcache[ii] = RGBA_COLOR(r[ii], g[ii], b[ii], a[ii]);
654                         }
655                         for(int ii = 0; ii < 8; ii++) {
656                                 pdst[ii] = dcache[ii];
657                         }
658                 }
659                 offset_base += 8;
660                 pdst += 8;
661                 pp += 16;
662         }
663         for(int i = 0; i < 8; i++) {
664                 dcache[i] = _CLEAR_COLOR;
665         }
666         int mod_words = words - nwords * 8;
667         for(ip = 0; ip < mod_words; ip++) {
668                 rgb[ip].w = pp[ip];
669                 //g5r5b5
670                 g[ip] = rgb[ip].b.h & 0x7c;
671                 r[ip] = ((rgb[ip].b.h & 0x03)  << 6) | ((rgb[ip].b.l & 0xe0) >> 2);
672                 b[ip] = (rgb[ip].b.l & 0x1f)   << 3;
673                 if(do_impose) {
674                         a[ip] = (rgb[ip].b.h < 0x80) ? 0xff : 0x00;
675                 } else {
676                         a[i] = 0xff;
677                 }
678                 dcache[ip] = RGBA_COLOR(r[ip], g[ip], b[ip], a[ip]);
679         }
680         for(ip = 0; ip < mod_words; ip++) {
681                 pdst[ip] = dcache[ip];
682         }
683 }
684
685 void TOWNS_CRTC::vzoom_pixel(scrntype_t*src, int width, int srclines, scrntype_t* dst, int stride, int dstlines, float vzoom)
686 {
687         if(src == dst) return;
688         if(vzoom <= 0.0f) return;
689         if((src == NULL) || (dst == NULL)) return;
690         if(width <= 0) return;
691         if(srclines <= 0) return;
692         if(dstlines <= 0) return;
693
694         scrntype_t *psrc = src;
695         scrntype_t *pdst = dst;
696
697         float vzoom_int = floor(vzoom);
698         float vzoom_mod = vzoom - vzoom_int;
699         float nmod = 0.0f;
700         int nint = (int)vzoom_int;
701         int srcline = 0;
702         int linecount = 0;
703         for(srcline = 0; srcline < srclines; srcline++) {
704                 int ifactor = nint;
705                 if(nmod >= 1.0f) {
706                         nmod = nmod - 1.0f;
707                         ifactor++;
708                 }
709                 for(int ii = 0; ii < ifactor; ii++) {
710                         // ToDo: Mask, blend.
711                         memcpy(pdst, psrc, width * sizeof(scrntype_t));
712                         linecount++;
713                         if(linecount >= dstlines) goto _exit0;;
714                         pdst += stride;
715                 }
716                 psrc += stride;
717                 nmod = nmod + vzoom_mod;
718         }
719 _exit0: 
720         return;
721 }
722                 
723 void TOWNS_CRTC::hzoom_pixel(scrntype_t* src, int width, scrntype_t* dst, int dst_width, float hzoom)
724 {
725         if(src == dst) return;
726         if(hzoom <= 0.0f) return;
727         if((src == NULL) || (dst == NULL)) return;
728         if(width <= 0) return;
729         if(dst_width <= 0) return;
730
731         scrntype_t* pdst = dst;
732         float hzoom_int = floor(hzoom);
733         float hzoom_mod = hzoom - hzoom_int;
734         float nmod = 0.0f;
735         int nint = (int)hzoom_int;
736         if((nint == 1) && (hzoom_mod <= 0.0f)) {
737                 // x1.0
738                 scrntype_t *sp = src;
739                 scrntype_t pcache[4];
740                 int nw = width / 4;
741                 int dx = 0;
742                 int ycount = 0;
743                 for(int ii = 0; ii < nw; ii++) {
744                         if((dx + 3) >= dst_width) break;
745                         for(int j = 0; j < 4; j++) {
746                                 pcache[j] = sp[j];
747                         }
748                         // ToDo: Mask/Alpha
749                         for(int j = 0; j < 4; j++) {
750                                 pdst[j] = pcache[j];
751                         }
752                         dx += 4;
753                         pdst += 4;
754                         sp += 4;
755                 }
756                 nw = width - dx;
757                 if(dx >= dst_width) return;
758                 for(int ii = 0; ii < nw; ii++) {
759                         if(dx >= dst_width) goto __exit_0;
760                         // ToDo: Mask/Alpha
761                         pcache[ii] = sp[ii];
762                         pdst[ii] = pcache[ii];
763                         dx++;
764                 }
765         } else {
766                 scrntype_t *sp = src;
767                 int dx = 0;
768                 int xcount = 0;
769                 for(int i = 0; i < width; i++) {
770                         // ToDo : Storage via SIMD.
771                         if(dx >= dst_width) goto __exit_0;
772                         
773                         int ifactor = nint;
774                         if(nmod >= 1.0f) {
775                                 ifactor++;
776                                 nmod = nmod - 1.0f;
777                         }
778                         scrntype_t pix = *sp++;
779                         scrntype_t pcache[4];
780                         // ToDo: MASK/ALPHA
781                 
782                         int jfactor = ifactor / 4;
783                         xcount = 0;
784                         for(int k = 0; k < 4; k++) {
785                                 pcache[k] = pix;
786                         }
787                         for(int j = 0; j < jfactor; j++) {
788                                 if((dx + 3) >= dst_width) break; 
789                                 for(int k = 0; k < 4; k++) {
790                                         pdst[k] = pcache[k];
791                                 }
792                                 xcount += 4;
793                                 pdst += 4;
794                                 dx += 4;
795                         }
796                         ifactor = ifactor - xcount;
797                         if(ifactor < 0) ifactor = 0;
798                         for(int k = 0; k < ifactor; k++) {
799                                 if(dx >= dst_width) goto __exit_0;
800                                 pdst[k] = pcache[k];
801                                 dx++;
802                         }
803                         nmod = nmod + hzoom_mod;
804                         
805                         pdst += ifactor;
806                 }               
807         }
808 __exit_0:
809         return;
810 }
811
812 }
813 #undef _CLEAR_COLOR
814