1 |
/* |
2 |
* Copyright (C) 2005 Anders Gavare. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
6 |
* |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* 3. The name of the author may not be used to endorse or promote products |
13 |
* derived from this software without specific prior written permission. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* |
28 |
* $Id: pc_bios.c,v 1.5 2005/04/20 02:05:56 debug Exp $ |
29 |
* |
30 |
* Generic PC BIOS emulation. |
31 |
*/ |
32 |
|
33 |
#include <stdio.h> |
34 |
#include <stdlib.h> |
35 |
#include <string.h> |
36 |
|
37 |
#include "console.h" |
38 |
#include "cpu.h" |
39 |
#include "cpu_x86.h" |
40 |
#include "machine.h" |
41 |
#include "memory.h" |
42 |
#include "misc.h" |
43 |
|
44 |
|
45 |
extern int quiet_mode; |
46 |
|
47 |
|
48 |
/* |
49 |
* output_char(): |
50 |
*/ |
51 |
static void output_char(struct cpu *cpu, int x, int y, int ch, int color) |
52 |
{ |
53 |
uint64_t addr = (y * 80 + x) * 2; |
54 |
unsigned char w[2]; |
55 |
|
56 |
w[0] = ch; w[1] = color; |
57 |
cpu->cd.x86.cursegment = 0xb800; |
58 |
cpu->memory_rw(cpu, cpu->mem, addr, &w[0], sizeof(w), MEM_WRITE, |
59 |
CACHE_NONE | PHYSICAL); |
60 |
} |
61 |
|
62 |
|
63 |
/* |
64 |
* set_cursor_pos(): |
65 |
*/ |
66 |
static void set_cursor_pos(struct cpu *cpu, int x, int y) |
67 |
{ |
68 |
int addr = y * 80 + x; |
69 |
unsigned char byte; |
70 |
uint64_t ctrlregs = 0x1000003c0ULL; |
71 |
|
72 |
byte = 0x0e; |
73 |
cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14, |
74 |
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
75 |
byte = (addr >> 8) & 255; |
76 |
cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15, |
77 |
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
78 |
byte = 0x0f; |
79 |
cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x14, |
80 |
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
81 |
byte = addr & 255; |
82 |
cpu->memory_rw(cpu, cpu->mem, ctrlregs + 0x15, |
83 |
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
84 |
} |
85 |
|
86 |
|
87 |
/* |
88 |
* pc_bios_int10(): |
89 |
* |
90 |
* Video functions. |
91 |
*/ |
92 |
static void pc_bios_int10(struct cpu *cpu) |
93 |
{ |
94 |
int x,y; |
95 |
int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff; |
96 |
int al = cpu->cd.x86.r[X86_R_AX] & 0xff; |
97 |
|
98 |
switch (ah) { |
99 |
case 0x00: /* Switch video mode. */ |
100 |
switch (al) { |
101 |
case 0x03: /* 80x25 color textmode */ |
102 |
/* Simply clear the screen and home the cursor |
103 |
for now. TODO: More advanced stuff. */ |
104 |
set_cursor_pos(cpu, 0, 0); |
105 |
for (y=0; y<25; y++) |
106 |
for (x=0; x<80; x++) |
107 |
output_char(cpu, x,y, ' ', 0x07); |
108 |
break; |
109 |
default: |
110 |
fatal("pc_bios_int10(): unimplemented video mode " |
111 |
"0x%02x\n", al); |
112 |
cpu->running = 0; |
113 |
cpu->dead = 1; |
114 |
} |
115 |
break; |
116 |
default: |
117 |
fatal("FATAL: Unimplemented PC BIOS interrupt 0x10 function" |
118 |
" 0x%02x.\n", ah); |
119 |
cpu->running = 0; |
120 |
cpu->dead = 1; |
121 |
} |
122 |
} |
123 |
|
124 |
|
125 |
/* |
126 |
* pc_bios_int13(): |
127 |
* |
128 |
* Disk-related functions. |
129 |
*/ |
130 |
static void pc_bios_int13(struct cpu *cpu) |
131 |
{ |
132 |
int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff; |
133 |
|
134 |
switch (ah) { |
135 |
case 0x00: /* Reset disk, dl = drive */ |
136 |
/* Do nothing. :-) */ |
137 |
break; |
138 |
default: |
139 |
fatal("FATAL: Unimplemented PC BIOS interrupt 0x1a function" |
140 |
" 0x%02x.\n", ah); |
141 |
cpu->running = 0; |
142 |
cpu->dead = 1; |
143 |
} |
144 |
} |
145 |
|
146 |
|
147 |
/* |
148 |
* pc_bios_int1a(): |
149 |
* |
150 |
* Time of Day stuff. |
151 |
*/ |
152 |
static void pc_bios_int1a(struct cpu *cpu) |
153 |
{ |
154 |
int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff; |
155 |
|
156 |
switch (ah) { |
157 |
case 0x00: |
158 |
/* Return tick count? TODO */ |
159 |
cpu->cd.x86.r[X86_R_CX] = 0; |
160 |
cpu->cd.x86.r[X86_R_DX] = 0; |
161 |
break; |
162 |
default: |
163 |
fatal("FATAL: Unimplemented PC BIOS interrupt 0x1a function" |
164 |
" 0x%02x.\n", ah); |
165 |
cpu->running = 0; |
166 |
cpu->dead = 1; |
167 |
} |
168 |
} |
169 |
|
170 |
|
171 |
/* |
172 |
* pc_bios_emul(): |
173 |
*/ |
174 |
int pc_bios_emul(struct cpu *cpu) |
175 |
{ |
176 |
uint32_t addr = (cpu->cd.x86.s[X86_S_CS] << 4) + cpu->pc; |
177 |
int int_nr; |
178 |
|
179 |
int_nr = addr & 0xfff; |
180 |
|
181 |
switch (int_nr) { |
182 |
case 0x10: |
183 |
pc_bios_int10(cpu); |
184 |
break; |
185 |
case 0x13: |
186 |
pc_bios_int13(cpu); |
187 |
break; |
188 |
case 0x1a: |
189 |
pc_bios_int1a(cpu); |
190 |
break; |
191 |
default: |
192 |
fatal("FATAL: Unimplemented PC BIOS interrupt 0x%02x.\n", |
193 |
int_nr); |
194 |
cpu->running = 0; |
195 |
cpu->dead = 1; |
196 |
} |
197 |
|
198 |
/* |
199 |
* Return from the interrupt: Pop ip (pc), cs, and flags. |
200 |
*/ |
201 |
cpu->cd.x86.cursegment = cpu->cd.x86.s[X86_S_SS]; |
202 |
cpu->pc = load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP]); |
203 |
cpu->cd.x86.s[X86_S_CS] = |
204 |
load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP] + 2); |
205 |
cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff) |
206 |
| load_16bit_word(cpu, cpu->cd.x86.r[X86_R_SP] + 4); |
207 |
|
208 |
cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] & ~0xffff) |
209 |
| ((cpu->cd.x86.r[X86_R_SP] + 6) & 0xffff); |
210 |
|
211 |
return 1; |
212 |
} |
213 |
|