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