blob: d51eb64692e6380cf3d114934b5145068dbbea82 [file] [log] [blame]
wdenk452cfd62002-11-19 11:04:11 +00001/*
2 * Mostly done after the Scitech Bios emulation
3 * Written by Hans-Jörg Frieden
4 * Hyperion Entertainment
5 */
6#include "x86emu.h"
7#include "glue.h"
8
9#undef DEBUG
10#ifdef DEBUG
11#define PRINTF(fmt, args...) printf(fmt, ## args)
12#else
13#define PRINTF(fmt, args...)
14#endif
15
16#define BIOS_SEG 0xFFF0
17#define PCIBIOS_SUCCESSFUL 0
18#define PCIBIOS_DEVICE_NOT_FOUND 0x86
19
20typedef unsigned char UBYTE;
21typedef unsigned short UWORD;
22typedef unsigned long ULONG;
23
24typedef char BYTE;
25typedef short WORT;
26typedef long LONG;
27
28static inline UBYTE read_byte(volatile UBYTE* from)
29{
30 int x;
31 asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
32 return (UBYTE)x;
33}
34
35static inline void write_byte(volatile UBYTE *to, int x)
36{
37 asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
38}
39
40static inline UWORD read_word_little(volatile UWORD *from)
41{
42 int x;
43 asm volatile ("lhbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m" (*from));
44 return (UWORD)x;
45}
46
47static inline UWORD read_word_big(volatile UWORD *from)
48{
49 int x;
50 asm volatile ("lhz %0,%1\n eieio" : "=r" (x) : "m" (*from));
51 return (UWORD)x;
52}
53
54static inline void write_word_little(volatile UWORD *to, int x)
55{
56 asm volatile ("sthbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
57}
58
59static inline void write_word_big(volatile UWORD *to, int x)
60{
61 asm volatile ("sth %1,%0\n eieio" : "=m" (*to) : "r" (x));
62}
63
64static inline ULONG read_long_little(volatile ULONG *from)
65{
66 unsigned long x;
67 asm volatile ("lwbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m"(*from));
68 return (ULONG)x;
69}
70
71static inline ULONG read_long_big(volatile ULONG *from)
72{
73 unsigned long x;
74 asm volatile ("lwz %0,%1\n eieio" : "=r" (x) : "m" (*from));
75 return (ULONG)x;
76}
77
78static inline void write_long_little(volatile ULONG *to, ULONG x)
79{
80 asm volatile ("stwbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
81}
82
83static inline void write_long_big(volatile ULONG *to, ULONG x)
84{
85 asm volatile ("stw %1,%0\n eieio" : "=m" (*to) : "r" (x));
86}
87
88#define port_to_mem(from) (0xFE000000|(from))
89#define in_byte(from) read_byte( (UBYTE *)port_to_mem(from))
90#define in_word(from) read_word_little((UWORD *)port_to_mem(from))
91#define in_long(from) read_long_little((ULONG *)port_to_mem(from))
92#define out_byte(to, val) write_byte((UBYTE *)port_to_mem(to), val)
93#define out_word(to, val) write_word_little((UWORD *)port_to_mem(to), val)
94#define out_long(to, val) write_long_little((ULONG *)port_to_mem(to), val)
95
96static void X86API undefined_intr(int intno)
97{
98 extern u16 A1_rdw(u32 addr);
99 if (A1_rdw(intno * 4 + 2) == BIOS_SEG)
100 {
101 PRINTF("Undefined interrupt %xh called AX = %xh, BX = %xh, CX = %xh, DX = %xh\n",
102 intno, M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
103 X86EMU_halt_sys();
104 }
105 else
106 {
107 PRINTF("Calling interrupt %xh, AL=%xh, AH=%xh\n", intno, M.x86.R_AL, M.x86.R_AH);
108 X86EMU_prepareForInt(intno);
109 }
110}
111
112static void X86API int42(int intno);
113static void X86API int15(int intno);
114
115static void X86API int10(int intno)
116{
117 if (A1_rdw(intno*4+2) == BIOS_SEG)
118 int42(intno);
119 else
120 {
121 PRINTF("int10: branching to %04X:%04X, AL=%xh, AH=%xh\n", A1_rdw(intno*4+2), A1_rdw(intno*4),
122 M.x86.R_AL, M.x86.R_AH);
123 X86EMU_prepareForInt(intno);
124 }
125}
126
127static void X86API int1A(int intno)
128{
129 int device;
130
131 switch(M.x86.R_AX)
132 {
wdenk57b2d802003-06-27 21:31:46 +0000133 case 0xB101: /* PCI Bios Present? */
wdenk452cfd62002-11-19 11:04:11 +0000134 M.x86.R_AL = 0x00;
135 M.x86.R_EDX = 0x20494350;
136 M.x86.R_BX = 0x0210;
137 M.x86.R_CL = 3;
138 CLEAR_FLAG(F_CF);
139 break;
wdenk57b2d802003-06-27 21:31:46 +0000140 case 0xB102: /* Find device */
wdenk452cfd62002-11-19 11:04:11 +0000141 device = mypci_find_device(M.x86.R_DX, M.x86.R_CX, M.x86.R_SI);
142 if (device != -1)
143 {
144 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
145 M.x86.R_BH = mypci_bus(device);
146 M.x86.R_BL = mypci_devfn(device);
147 }
148 else
149 {
150 M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
151 }
152 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
153 break;
wdenk57b2d802003-06-27 21:31:46 +0000154 case 0xB103: /* Find PCI class code */
wdenk452cfd62002-11-19 11:04:11 +0000155 M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND;
wdenk57b2d802003-06-27 21:31:46 +0000156 /*printf("Find by class not yet implmented"); */
wdenk452cfd62002-11-19 11:04:11 +0000157 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
158 break;
wdenk57b2d802003-06-27 21:31:46 +0000159 case 0xB108: /* read config byte */
wdenk452cfd62002-11-19 11:04:11 +0000160 M.x86.R_CL = mypci_read_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
161 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
162 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
wdenk57b2d802003-06-27 21:31:46 +0000163 /*printf("read_config_byte %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
164 /* M.x86.R_CL); */
wdenk452cfd62002-11-19 11:04:11 +0000165 break;
wdenk57b2d802003-06-27 21:31:46 +0000166 case 0xB109: /* read config word */
wdenk452cfd62002-11-19 11:04:11 +0000167 M.x86.R_CX = mypci_read_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
168 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
169 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
wdenk57b2d802003-06-27 21:31:46 +0000170 /*printf("read_config_word %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
171 /* M.x86.R_CX); */
wdenk452cfd62002-11-19 11:04:11 +0000172 break;
wdenk57b2d802003-06-27 21:31:46 +0000173 case 0xB10A: /* read config dword */
wdenk452cfd62002-11-19 11:04:11 +0000174 M.x86.R_ECX = mypci_read_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI);
175 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
176 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
wdenk57b2d802003-06-27 21:31:46 +0000177 /*printf("read_config_long %x,%x,%x -> %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
178 /* M.x86.R_ECX); */
wdenk452cfd62002-11-19 11:04:11 +0000179 break;
wdenk57b2d802003-06-27 21:31:46 +0000180 case 0xB10B: /* write config byte */
wdenk452cfd62002-11-19 11:04:11 +0000181 mypci_write_cfg_byte(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CL);
182 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
183 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
wdenk57b2d802003-06-27 21:31:46 +0000184 /*printf("write_config_byte %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
185 /* M.x86.R_CL); */
wdenk452cfd62002-11-19 11:04:11 +0000186 break;
wdenk57b2d802003-06-27 21:31:46 +0000187 case 0xB10C: /* write config word */
wdenk452cfd62002-11-19 11:04:11 +0000188 mypci_write_cfg_word(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_CX);
189 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
190 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
wdenk57b2d802003-06-27 21:31:46 +0000191 /*printf("write_config_word %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
192 /* M.x86.R_CX); */
wdenk452cfd62002-11-19 11:04:11 +0000193 break;
wdenk57b2d802003-06-27 21:31:46 +0000194 case 0xB10D: /* write config dword */
wdenk452cfd62002-11-19 11:04:11 +0000195 mypci_write_cfg_long(M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, M.x86.R_ECX);
196 M.x86.R_AH = PCIBIOS_SUCCESSFUL;
197 CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL), F_CF);
wdenk57b2d802003-06-27 21:31:46 +0000198 /*printf("write_config_long %x,%x,%x <- %x\n", M.x86.R_BH, M.x86.R_BL, M.x86.R_DI, */
199 /* M.x86.R_ECX); */
wdenk452cfd62002-11-19 11:04:11 +0000200 break;
201 default:
202 PRINTF("BIOS int %xh: Unknown function AX=%04xh\n", intno, M.x86.R_AX);
203
204 }
205}
206
207void bios_init(void)
208{
209 int i;
210 X86EMU_intrFuncs bios_intr_tab[256];
wdenk57b2d802003-06-27 21:31:46 +0000211
wdenk452cfd62002-11-19 11:04:11 +0000212 for (i=0; i<256; i++)
213 {
214 write_long_little(M.mem_base+i*4, BIOS_SEG<<16);
215 bios_intr_tab[i] = undefined_intr;
216 }
217
218 bios_intr_tab[0x10] = int10;
219 bios_intr_tab[0x1A] = int1A;
220 bios_intr_tab[0x42] = int42;
221 bios_intr_tab[0x15] = int15;
222
223 bios_intr_tab[0x6D] = int42;
wdenk57b2d802003-06-27 21:31:46 +0000224
wdenk452cfd62002-11-19 11:04:11 +0000225 X86EMU_setupIntrFuncs(bios_intr_tab);
226 video_init();
227}
228
229unsigned char setup_40x25[] =
230{
231 0x38, 0x28, 0x2d, 0x0a, 0x1f, 6, 0x19,
232 0x1c, 2, 7, 6, 7, 0, 0, 0, 0
233};
234
235unsigned char setup_80x25[] =
236{
237 0x71, 0x50, 0x5a, 0x0a, 0x1f, 6, 0x19,
238 0x1c, 2, 7, 6, 7, 0, 0, 0, 0
239};
240
241unsigned char setup_graphics[] =
242{
243 0x38, 0x28, 0x20, 0x0a, 0x7f, 6, 0x64,
244 0x70, 2, 1, 6, 7, 0, 0, 0, 0
245};
246
247unsigned char setup_bw[] =
248{
249 0x61, 0x50, 0x52, 0x0f, 0x19, 6, 0x19,
250 0x19, 2, 0x0d, 0x0b, 0x0c, 0, 0, 0, 0
251};
252
253unsigned char * setup_modes[] =
254{
wdenk57b2d802003-06-27 21:31:46 +0000255 setup_40x25, /* mode 0: 40x25 bw text */
256 setup_40x25, /* mode 1: 40x25 col text */
257 setup_80x25, /* mode 2: 80x25 bw text */
258 setup_80x25, /* mode 3: 80x25 col text */
259 setup_graphics, /* mode 4: 320x200 col graphics */
260 setup_graphics, /* mode 5: 320x200 bw graphics */
261 setup_graphics, /* mode 6: 640x200 bw graphics */
262 setup_bw /* mode 7: 80x25 mono text */
wdenk452cfd62002-11-19 11:04:11 +0000263};
264
265unsigned int setup_cols[] =
266{
267 40, 40, 80, 80, 40, 40, 80, 80
268};
269
270unsigned char setup_modesets[] =
271{
272 0x2C, 0x28, 0x2D, 0x29, 0x2A, 0x2E, 0x1E, 0x29
273};
274
275unsigned int setup_bufsize[] =
276{
277 2048, 2048, 4096, 2096, 16384, 16384, 16384, 4096
278};
279
280void bios_set_mode(int mode)
281{
282 int i;
wdenk57b2d802003-06-27 21:31:46 +0000283 unsigned char mode_set = setup_modesets[mode]; /* Control register value */
284 unsigned char *setup_regs = setup_modes[mode]; /* Register 3D4 Array */
wdenk452cfd62002-11-19 11:04:11 +0000285
wdenk57b2d802003-06-27 21:31:46 +0000286 /* Switch video off */
wdenk452cfd62002-11-19 11:04:11 +0000287 out_byte(0x3D8, mode_set & 0x37);
288
wdenk57b2d802003-06-27 21:31:46 +0000289 /* Set up parameters at 3D4h */
wdenk452cfd62002-11-19 11:04:11 +0000290 for (i=0; i<16; i++)
291 {
292 out_byte(0x3D4, (unsigned char)i);
293 out_byte(0x3D5, *setup_regs);
294 setup_regs++;
295 }
296
wdenk57b2d802003-06-27 21:31:46 +0000297 /* Enable video */
wdenk452cfd62002-11-19 11:04:11 +0000298 out_byte(0x3D8, mode_set);
299
wdenk57b2d802003-06-27 21:31:46 +0000300 /* Set overscan */
wdenk452cfd62002-11-19 11:04:11 +0000301 if (mode == 6) out_byte(0x3D9, 0x3F);
302 else out_byte(0x3D9, 0x30);
303}
304
305static void bios_print_string(void)
306{
307 extern void video_bios_print_string(char *string, int x, int y, int attr, int count);
308 char *s = (char *)(M.x86.R_ES<<4) + M.x86.R_BP;
309 int attr;
310 if (M.x86.R_AL & 0x02) attr = - 1;
311 else attr = M.x86.R_BL;
312 video_bios_print_string(s, M.x86.R_DH, M.x86.R_DL, attr, M.x86.R_CX);
313}
314
315static void X86API int42(int intno)
316{
317 switch (M.x86.R_AH)
318 {
319 case 0x00:
320 bios_set_mode(M.x86.R_AL);
321 break;
322 case 0x13:
323 bios_print_string();
324 break;
325 default:
326 PRINTF("Warning: VIDEO BIOS interrupt %xh unimplemented function %xh, AL = %xh\n",
327 intno, M.x86.R_AH, M.x86.R_AL);
328 }
329}
330
331static void X86API int15(int intno)
332{
333 PRINTF("Called interrupt 15h: AX = %xh, BX = %xh, CX = %xh, DX = %xh\n",
334 M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
335}