1 /*
2 * Copyright (C) 2002-2021 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "int10.h"
20
21 #include "mem.h"
22 #include "inout.h"
23
24 static Bit8u cga_masks[4]={0x3f,0xcf,0xf3,0xfc};
25 static Bit8u cga_masks2[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
26
INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color)27 void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) {
28 static bool putpixelwarned = false;
29
30 switch (CurMode->type) {
31 case M_CGA4:
32 {
33 if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)<=5) {
34 // this is a 16k mode
35 Bit16u off=(y>>1)*80+(x>>2);
36 if (y&1) off+=8*1024;
37
38 Bit8u old=real_readb(0xb800,off);
39 if (color & 0x80) {
40 color&=3;
41 old^=color << (2*(3-(x&3)));
42 } else {
43 old=(old&cga_masks[x&3])|((color&3) << (2*(3-(x&3))));
44 }
45 real_writeb(0xb800,off,old);
46 } else {
47 // a 32k mode: PCJr special case (see M_TANDY16)
48 Bit16u seg;
49 if (machine==MCH_PCJR) {
50 Bitu cpupage =
51 (real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE) >> 3) & 0x7;
52 seg = cpupage << 10; // A14-16 to addr bits 14-16
53 } else
54 seg = 0xb800;
55
56 Bit16u off=(y>>2)*160+((x>>2)&(~1));
57 off+=(8*1024) * (y & 3);
58
59 Bit16u old=real_readw(seg,off);
60 if (color & 0x80) {
61 old^=(color&1) << (7-(x&7));
62 old^=((color&2)>>1) << ((7-(x&7))+8);
63 } else {
64 old=(old&(~(0x101<<(7-(x&7))))) | ((color&1) << (7-(x&7))) | (((color&2)>>1) << ((7-(x&7))+8));
65 }
66 real_writew(seg,off,old);
67 }
68 }
69 break;
70 case M_CGA2:
71 {
72 Bit16u off=(y>>1)*80+(x>>3);
73 if (y&1) off+=8*1024;
74 Bit8u old=real_readb(0xb800,off);
75 if (color & 0x80) {
76 color&=1;
77 old^=color << ((7-(x&7)));
78 } else {
79 old=(old&cga_masks2[x&7])|((color&1) << ((7-(x&7))));
80 }
81 real_writeb(0xb800,off,old);
82 }
83 break;
84 case M_TANDY16:
85 {
86 // find out if we are in a 32k mode (0x9 or 0xa)
87 // This requires special handling on the PCJR
88 // because only 16k are mapped at 0xB800
89 bool is_32k = (real_readb(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE) >= 9)?
90 true:false;
91
92 Bit16u segment, offset;
93 if (is_32k) {
94 if (machine==MCH_PCJR) {
95 Bitu cpupage =
96 (real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE) >> 3) & 0x7;
97 segment = cpupage << 10; // A14-16 to addr bits 14-16
98 } else
99 segment = 0xb800;
100 // bits 1 and 0 of y select the bank
101 // two pixels per byte (thus x>>1)
102 offset = (y >> 2) * (CurMode->swidth >> 1) + (x>>1);
103 // select the scanline bank
104 offset += (8*1024) * (y & 3);
105 } else {
106 segment = 0xb800;
107 // bit 0 of y selects the bank
108 offset = (y >> 1) * (CurMode->swidth >> 1) + (x>>1);
109 offset += (8*1024) * (y & 1);
110 }
111
112 // update the pixel
113 Bit8u old=real_readb(segment, offset);
114 Bit8u p[2];
115 p[1] = (old >> 4) & 0xf;
116 p[0] = old & 0xf;
117 Bitu ind = 1-(x & 0x1);
118
119 if (color & 0x80) {
120 // color is to be XORed
121 p[ind]^=(color & 0x7f);
122 } else {
123 p[ind]=color;
124 }
125 old = (p[1] << 4) | p[0];
126 real_writeb(segment,offset, old);
127 }
128 break;
129 case M_LIN4:
130 if ((machine!=MCH_VGA) || (svgaCard!=SVGA_TsengET4K) ||
131 (CurMode->swidth>800)) {
132 // the ET4000 BIOS supports text output in 800x600 SVGA
133 // (Gateway 2)
134 putpixelwarned = true;
135 LOG(LOG_INT10, LOG_ERROR)("PutPixel unhandled mode type %d", CurMode->type);
136 break;
137 }
138 [[fallthrough]];
139 case M_EGA: {
140 /* Set the correct bitmask for the pixel position */
141 IO_Write(0x3ce, 0x8);
142 Bit8u mask = 128 >> (x & 7);
143 IO_Write(0x3cf, mask);
144 /* Set the color to set/reset register */
145 IO_Write(0x3ce, 0x0);
146 IO_Write(0x3cf, color);
147 /* Enable all the set/resets */
148 IO_Write(0x3ce, 0x1);
149 IO_Write(0x3cf, 0xf);
150 /* test for xorring */
151 if (color & 0x80) {
152 IO_Write(0x3ce, 0x3);
153 IO_Write(0x3cf, 0x18);
154 }
155 // Perhaps also set mode 1
156 /* Calculate where the pixel is in video memory */
157 if (CurMode->plength !=
158 (Bitu)real_readw(BIOSMEM_SEG, BIOSMEM_PAGE_SIZE))
159 LOG(LOG_INT10, LOG_ERROR)
160 ("PutPixel_EGA_p: %u != %x", CurMode->plength,
161 real_readw(BIOSMEM_SEG, BIOSMEM_PAGE_SIZE));
162 if (CurMode->swidth !=
163 (Bitu)real_readw(BIOSMEM_SEG, BIOSMEM_NB_COLS) * 8)
164 LOG(LOG_INT10, LOG_ERROR)
165 ("PutPixel_EGA_w: %u!=%x", CurMode->swidth,
166 real_readw(BIOSMEM_SEG, BIOSMEM_NB_COLS) * 8);
167 PhysPt off = 0xa0000 +
168 real_readw(BIOSMEM_SEG, BIOSMEM_PAGE_SIZE) * page +
169 ((y * real_readw(BIOSMEM_SEG, BIOSMEM_NB_COLS) * 8 + x) >>
170 3);
171 /* Bitmask and set/reset should do the rest */
172 mem_readb(off);
173 mem_writeb(off, 0xff);
174 /* Restore bitmask */
175 IO_Write(0x3ce, 0x8);
176 IO_Write(0x3cf, 0xff);
177 IO_Write(0x3ce, 0x1);
178 IO_Write(0x3cf, 0);
179 /* Restore write operating if changed */
180 if (color & 0x80) {
181 IO_Write(0x3ce, 0x3);
182 IO_Write(0x3cf, 0x0);
183 }
184 break;
185 }
186
187 case M_VGA:
188 mem_writeb(PhysMake(0xa000,y*320+x),color);
189 break;
190 case M_LIN8: {
191 if (CurMode->swidth!=(Bitu)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8)
192 LOG(LOG_INT10,LOG_ERROR)("PutPixel_VGA_w: %u!=%x",CurMode->swidth,real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
193 PhysPt off=S3_LFB_BASE+y*real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8+x;
194 mem_writeb(off,color);
195 break;
196 }
197 default:
198 if(GCC_UNLIKELY(!putpixelwarned)) {
199 putpixelwarned = true;
200 LOG(LOG_INT10,LOG_ERROR)("PutPixel unhandled mode type %d",CurMode->type);
201 }
202 break;
203 }
204 }
205
INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color)206 void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color) {
207 switch (CurMode->type) {
208 case M_CGA4:
209 {
210 Bit16u off=(y>>1)*80+(x>>2);
211 if (y&1) off+=8*1024;
212 Bit8u val=real_readb(0xb800,off);
213 *color=(val>>(((3-(x&3)))*2)) & 3 ;
214 }
215 break;
216 case M_CGA2:
217 {
218 Bit16u off=(y>>1)*80+(x>>3);
219 if (y&1) off+=8*1024;
220 Bit8u val=real_readb(0xb800,off);
221 *color=(val>>(((7-(x&7))))) & 1 ;
222 }
223 break;
224 case M_TANDY16:
225 {
226 bool is_32k = (real_readb(BIOSMEM_SEG, BIOSMEM_CURRENT_MODE) >= 9)?true:false;
227 Bit16u segment, offset;
228 if (is_32k) {
229 if (machine==MCH_PCJR) {
230 Bitu cpupage = (real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE) >> 3) & 0x7;
231 segment = cpupage << 10;
232 } else segment = 0xb800;
233 offset = (y >> 2) * (CurMode->swidth >> 1) + (x>>1);
234 offset += (8*1024) * (y & 3);
235 } else {
236 segment = 0xb800;
237 offset = (y >> 1) * (CurMode->swidth >> 1) + (x>>1);
238 offset += (8*1024) * (y & 1);
239 }
240 Bit8u val=real_readb(segment,offset);
241 *color=(val>>((x&1)?0:4)) & 0xf;
242 }
243 break;
244 case M_EGA:
245 {
246 /* Calculate where the pixel is in video memory */
247 if (CurMode->plength!=(Bitu)real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE))
248 LOG(LOG_INT10,LOG_ERROR)("GetPixel_EGA_p: %u!=%x",CurMode->plength,real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE));
249 if (CurMode->swidth!=(Bitu)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8)
250 LOG(LOG_INT10,LOG_ERROR)("GetPixel_EGA_w: %u!=%x",CurMode->swidth,real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
251 PhysPt off=0xa0000+real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)*page+
252 ((y*real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8+x)>>3);
253 Bitu shift=7-(x & 7);
254 /* Set the read map */
255 *color=0;
256 IO_Write(0x3ce,0x4);IO_Write(0x3cf,0);
257 *color|=((mem_readb(off)>>shift) & 1) << 0;
258 IO_Write(0x3ce,0x4);IO_Write(0x3cf,1);
259 *color|=((mem_readb(off)>>shift) & 1) << 1;
260 IO_Write(0x3ce,0x4);IO_Write(0x3cf,2);
261 *color|=((mem_readb(off)>>shift) & 1) << 2;
262 IO_Write(0x3ce,0x4);IO_Write(0x3cf,3);
263 *color|=((mem_readb(off)>>shift) & 1) << 3;
264 break;
265 }
266 case M_VGA:
267 *color=mem_readb(PhysMake(0xa000,320*y+x));
268 break;
269 case M_LIN8: {
270 if (CurMode->swidth!=(Bitu)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8)
271 LOG(LOG_INT10,LOG_ERROR)("GetPixel_VGA_w: %u!=%x",CurMode->swidth,real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8);
272 PhysPt off=S3_LFB_BASE+y*real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8+x;
273 *color = mem_readb(off);
274 break;
275 }
276 default:
277 LOG(LOG_INT10,LOG_ERROR)("GetPixel unhandled mode type %d",CurMode->type);
278 break;
279 }
280 }
281