Revision 80cabfad
b/Makefile.target | ||
---|---|---|
1 | 1 |
include config.mak |
2 | 2 |
|
3 | 3 |
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) |
4 |
VPATH=$(SRC_PATH):$(TARGET_PATH) |
|
4 |
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
|
|
5 | 5 |
CFLAGS=-Wall -O2 -g |
6 | 6 |
LDFLAGS=-g |
7 | 7 |
LIBS= |
... | ... | |
204 | 204 |
endif |
205 | 205 |
|
206 | 206 |
# must use static linking to avoid leaving stuff in virtual address space |
207 |
VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o |
|
207 |
VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ |
|
208 |
fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o |
|
208 | 209 |
ifeq ($(TARGET_ARCH), ppc) |
209 | 210 |
VL_OBJS+= hw.o |
210 | 211 |
endif |
b/hw/i8254.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU 8253/8254 interval timer emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
#include <stdlib.h> |
|
25 |
#include <stdio.h> |
|
26 |
#include <stdarg.h> |
|
27 |
#include <string.h> |
|
28 |
#include <getopt.h> |
|
29 |
#include <inttypes.h> |
|
30 |
#include <unistd.h> |
|
31 |
#include <sys/mman.h> |
|
32 |
#include <fcntl.h> |
|
33 |
#include <signal.h> |
|
34 |
#include <time.h> |
|
35 |
#include <sys/time.h> |
|
36 |
#include <malloc.h> |
|
37 |
#include <termios.h> |
|
38 |
#include <sys/poll.h> |
|
39 |
#include <errno.h> |
|
40 |
#include <sys/wait.h> |
|
41 |
#include <netinet/in.h> |
|
42 |
|
|
43 |
#include "cpu.h" |
|
44 |
#include "vl.h" |
|
45 |
|
|
46 |
#define RW_STATE_LSB 0 |
|
47 |
#define RW_STATE_MSB 1 |
|
48 |
#define RW_STATE_WORD0 2 |
|
49 |
#define RW_STATE_WORD1 3 |
|
50 |
#define RW_STATE_LATCHED_WORD0 4 |
|
51 |
#define RW_STATE_LATCHED_WORD1 5 |
|
52 |
|
|
53 |
PITChannelState pit_channels[3]; |
|
54 |
|
|
55 |
static int pit_get_count(PITChannelState *s) |
|
56 |
{ |
|
57 |
uint64_t d; |
|
58 |
int counter; |
|
59 |
|
|
60 |
d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); |
|
61 |
switch(s->mode) { |
|
62 |
case 0: |
|
63 |
case 1: |
|
64 |
case 4: |
|
65 |
case 5: |
|
66 |
counter = (s->count - d) & 0xffff; |
|
67 |
break; |
|
68 |
case 3: |
|
69 |
/* XXX: may be incorrect for odd counts */ |
|
70 |
counter = s->count - ((2 * d) % s->count); |
|
71 |
break; |
|
72 |
default: |
|
73 |
counter = s->count - (d % s->count); |
|
74 |
break; |
|
75 |
} |
|
76 |
return counter; |
|
77 |
} |
|
78 |
|
|
79 |
/* get pit output bit */ |
|
80 |
int pit_get_out(PITChannelState *s) |
|
81 |
{ |
|
82 |
uint64_t d; |
|
83 |
int out; |
|
84 |
|
|
85 |
d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); |
|
86 |
switch(s->mode) { |
|
87 |
default: |
|
88 |
case 0: |
|
89 |
out = (d >= s->count); |
|
90 |
break; |
|
91 |
case 1: |
|
92 |
out = (d < s->count); |
|
93 |
break; |
|
94 |
case 2: |
|
95 |
if ((d % s->count) == 0 && d != 0) |
|
96 |
out = 1; |
|
97 |
else |
|
98 |
out = 0; |
|
99 |
break; |
|
100 |
case 3: |
|
101 |
out = (d % s->count) < ((s->count + 1) >> 1); |
|
102 |
break; |
|
103 |
case 4: |
|
104 |
case 5: |
|
105 |
out = (d == s->count); |
|
106 |
break; |
|
107 |
} |
|
108 |
return out; |
|
109 |
} |
|
110 |
|
|
111 |
/* get the number of 0 to 1 transitions we had since we call this |
|
112 |
function */ |
|
113 |
/* XXX: maybe better to use ticks precision to avoid getting edges |
|
114 |
twice if checks are done at very small intervals */ |
|
115 |
int pit_get_out_edges(PITChannelState *s) |
|
116 |
{ |
|
117 |
uint64_t d1, d2; |
|
118 |
int64_t ticks; |
|
119 |
int ret, v; |
|
120 |
|
|
121 |
ticks = cpu_get_ticks(); |
|
122 |
d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, |
|
123 |
PIT_FREQ, ticks_per_sec); |
|
124 |
d2 = muldiv64(ticks - s->count_load_time, |
|
125 |
PIT_FREQ, ticks_per_sec); |
|
126 |
s->count_last_edge_check_time = ticks; |
|
127 |
switch(s->mode) { |
|
128 |
default: |
|
129 |
case 0: |
|
130 |
if (d1 < s->count && d2 >= s->count) |
|
131 |
ret = 1; |
|
132 |
else |
|
133 |
ret = 0; |
|
134 |
break; |
|
135 |
case 1: |
|
136 |
ret = 0; |
|
137 |
break; |
|
138 |
case 2: |
|
139 |
d1 /= s->count; |
|
140 |
d2 /= s->count; |
|
141 |
ret = d2 - d1; |
|
142 |
break; |
|
143 |
case 3: |
|
144 |
v = s->count - ((s->count + 1) >> 1); |
|
145 |
d1 = (d1 + v) / s->count; |
|
146 |
d2 = (d2 + v) / s->count; |
|
147 |
ret = d2 - d1; |
|
148 |
break; |
|
149 |
case 4: |
|
150 |
case 5: |
|
151 |
if (d1 < s->count && d2 >= s->count) |
|
152 |
ret = 1; |
|
153 |
else |
|
154 |
ret = 0; |
|
155 |
break; |
|
156 |
} |
|
157 |
return ret; |
|
158 |
} |
|
159 |
|
|
160 |
/* val must be 0 or 1 */ |
|
161 |
void pit_set_gate(PITChannelState *s, int val) |
|
162 |
{ |
|
163 |
switch(s->mode) { |
|
164 |
default: |
|
165 |
case 0: |
|
166 |
case 4: |
|
167 |
/* XXX: just disable/enable counting */ |
|
168 |
break; |
|
169 |
case 1: |
|
170 |
case 5: |
|
171 |
if (s->gate < val) { |
|
172 |
/* restart counting on rising edge */ |
|
173 |
s->count_load_time = cpu_get_ticks(); |
|
174 |
s->count_last_edge_check_time = s->count_load_time; |
|
175 |
} |
|
176 |
break; |
|
177 |
case 2: |
|
178 |
case 3: |
|
179 |
if (s->gate < val) { |
|
180 |
/* restart counting on rising edge */ |
|
181 |
s->count_load_time = cpu_get_ticks(); |
|
182 |
s->count_last_edge_check_time = s->count_load_time; |
|
183 |
} |
|
184 |
/* XXX: disable/enable counting */ |
|
185 |
break; |
|
186 |
} |
|
187 |
s->gate = val; |
|
188 |
} |
|
189 |
|
|
190 |
static inline void pit_load_count(PITChannelState *s, int val) |
|
191 |
{ |
|
192 |
if (val == 0) |
|
193 |
val = 0x10000; |
|
194 |
s->count_load_time = cpu_get_ticks(); |
|
195 |
s->count_last_edge_check_time = s->count_load_time; |
|
196 |
s->count = val; |
|
197 |
if (s == &pit_channels[0] && val <= pit_min_timer_count) { |
|
198 |
fprintf(stderr, |
|
199 |
"\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", |
|
200 |
PIT_FREQ / pit_min_timer_count); |
|
201 |
} |
|
202 |
} |
|
203 |
|
|
204 |
void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) |
|
205 |
{ |
|
206 |
int channel, access; |
|
207 |
PITChannelState *s; |
|
208 |
|
|
209 |
addr &= 3; |
|
210 |
if (addr == 3) { |
|
211 |
channel = val >> 6; |
|
212 |
if (channel == 3) |
|
213 |
return; |
|
214 |
s = &pit_channels[channel]; |
|
215 |
access = (val >> 4) & 3; |
|
216 |
switch(access) { |
|
217 |
case 0: |
|
218 |
s->latched_count = pit_get_count(s); |
|
219 |
s->rw_state = RW_STATE_LATCHED_WORD0; |
|
220 |
break; |
|
221 |
default: |
|
222 |
s->mode = (val >> 1) & 7; |
|
223 |
s->bcd = val & 1; |
|
224 |
s->rw_state = access - 1 + RW_STATE_LSB; |
|
225 |
break; |
|
226 |
} |
|
227 |
} else { |
|
228 |
s = &pit_channels[addr]; |
|
229 |
switch(s->rw_state) { |
|
230 |
case RW_STATE_LSB: |
|
231 |
pit_load_count(s, val); |
|
232 |
break; |
|
233 |
case RW_STATE_MSB: |
|
234 |
pit_load_count(s, val << 8); |
|
235 |
break; |
|
236 |
case RW_STATE_WORD0: |
|
237 |
case RW_STATE_WORD1: |
|
238 |
if (s->rw_state & 1) { |
|
239 |
pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); |
|
240 |
} else { |
|
241 |
s->latched_count = val; |
|
242 |
} |
|
243 |
s->rw_state ^= 1; |
|
244 |
break; |
|
245 |
} |
|
246 |
} |
|
247 |
} |
|
248 |
|
|
249 |
uint32_t pit_ioport_read(CPUState *env, uint32_t addr) |
|
250 |
{ |
|
251 |
int ret, count; |
|
252 |
PITChannelState *s; |
|
253 |
|
|
254 |
addr &= 3; |
|
255 |
s = &pit_channels[addr]; |
|
256 |
switch(s->rw_state) { |
|
257 |
case RW_STATE_LSB: |
|
258 |
case RW_STATE_MSB: |
|
259 |
case RW_STATE_WORD0: |
|
260 |
case RW_STATE_WORD1: |
|
261 |
count = pit_get_count(s); |
|
262 |
if (s->rw_state & 1) |
|
263 |
ret = (count >> 8) & 0xff; |
|
264 |
else |
|
265 |
ret = count & 0xff; |
|
266 |
if (s->rw_state & 2) |
|
267 |
s->rw_state ^= 1; |
|
268 |
break; |
|
269 |
default: |
|
270 |
case RW_STATE_LATCHED_WORD0: |
|
271 |
case RW_STATE_LATCHED_WORD1: |
|
272 |
if (s->rw_state & 1) |
|
273 |
ret = s->latched_count >> 8; |
|
274 |
else |
|
275 |
ret = s->latched_count & 0xff; |
|
276 |
s->rw_state ^= 1; |
|
277 |
break; |
|
278 |
} |
|
279 |
return ret; |
|
280 |
} |
|
281 |
|
|
282 |
void pit_init(void) |
|
283 |
{ |
|
284 |
PITChannelState *s; |
|
285 |
int i; |
|
286 |
|
|
287 |
for(i = 0;i < 3; i++) { |
|
288 |
s = &pit_channels[i]; |
|
289 |
s->mode = 3; |
|
290 |
s->gate = (i != 2); |
|
291 |
pit_load_count(s, 0); |
|
292 |
} |
|
293 |
|
|
294 |
register_ioport_write(0x40, 4, pit_ioport_write, 1); |
|
295 |
register_ioport_read(0x40, 3, pit_ioport_read, 1); |
|
296 |
} |
|
297 |
|
b/hw/i8259.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU 8259 interrupt controller emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
#include <stdlib.h> |
|
25 |
#include <stdio.h> |
|
26 |
#include <stdarg.h> |
|
27 |
#include <string.h> |
|
28 |
#include <getopt.h> |
|
29 |
#include <inttypes.h> |
|
30 |
#include <unistd.h> |
|
31 |
#include <sys/mman.h> |
|
32 |
#include <fcntl.h> |
|
33 |
#include <signal.h> |
|
34 |
#include <time.h> |
|
35 |
#include <sys/time.h> |
|
36 |
#include <malloc.h> |
|
37 |
#include <termios.h> |
|
38 |
#include <sys/poll.h> |
|
39 |
#include <errno.h> |
|
40 |
#include <sys/wait.h> |
|
41 |
#include <netinet/in.h> |
|
42 |
|
|
43 |
#include "cpu.h" |
|
44 |
#include "vl.h" |
|
45 |
|
|
46 |
/* debug PIC */ |
|
47 |
//#define DEBUG_PIC |
|
48 |
|
|
49 |
typedef struct PicState { |
|
50 |
uint8_t last_irr; /* edge detection */ |
|
51 |
uint8_t irr; /* interrupt request register */ |
|
52 |
uint8_t imr; /* interrupt mask register */ |
|
53 |
uint8_t isr; /* interrupt service register */ |
|
54 |
uint8_t priority_add; /* highest irq priority */ |
|
55 |
uint8_t irq_base; |
|
56 |
uint8_t read_reg_select; |
|
57 |
uint8_t poll; |
|
58 |
uint8_t special_mask; |
|
59 |
uint8_t init_state; |
|
60 |
uint8_t auto_eoi; |
|
61 |
uint8_t rotate_on_auto_eoi; |
|
62 |
uint8_t special_fully_nested_mode; |
|
63 |
uint8_t init4; /* true if 4 byte init */ |
|
64 |
} PicState; |
|
65 |
|
|
66 |
/* 0 is master pic, 1 is slave pic */ |
|
67 |
PicState pics[2]; |
|
68 |
int pic_irq_requested; |
|
69 |
|
|
70 |
/* set irq level. If an edge is detected, then the IRR is set to 1 */ |
|
71 |
static inline void pic_set_irq1(PicState *s, int irq, int level) |
|
72 |
{ |
|
73 |
int mask; |
|
74 |
mask = 1 << irq; |
|
75 |
if (level) { |
|
76 |
if ((s->last_irr & mask) == 0) |
|
77 |
s->irr |= mask; |
|
78 |
s->last_irr |= mask; |
|
79 |
} else { |
|
80 |
s->last_irr &= ~mask; |
|
81 |
} |
|
82 |
} |
|
83 |
|
|
84 |
/* return the highest priority found in mask (highest = smallest |
|
85 |
number). Return 8 if no irq */ |
|
86 |
static inline int get_priority(PicState *s, int mask) |
|
87 |
{ |
|
88 |
int priority; |
|
89 |
if (mask == 0) |
|
90 |
return 8; |
|
91 |
priority = 0; |
|
92 |
while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) |
|
93 |
priority++; |
|
94 |
return priority; |
|
95 |
} |
|
96 |
|
|
97 |
/* return the pic wanted interrupt. return -1 if none */ |
|
98 |
static int pic_get_irq(PicState *s) |
|
99 |
{ |
|
100 |
int mask, cur_priority, priority; |
|
101 |
|
|
102 |
mask = s->irr & ~s->imr; |
|
103 |
priority = get_priority(s, mask); |
|
104 |
if (priority == 8) |
|
105 |
return -1; |
|
106 |
/* compute current priority. If special fully nested mode on the |
|
107 |
master, the IRQ coming from the slave is not taken into account |
|
108 |
for the priority computation. */ |
|
109 |
mask = s->isr; |
|
110 |
if (s->special_fully_nested_mode && s == &pics[0]) |
|
111 |
mask &= ~(1 << 2); |
|
112 |
cur_priority = get_priority(s, mask); |
|
113 |
if (priority < cur_priority) { |
|
114 |
/* higher priority found: an irq should be generated */ |
|
115 |
return (priority + s->priority_add) & 7; |
|
116 |
} else { |
|
117 |
return -1; |
|
118 |
} |
|
119 |
} |
|
120 |
|
|
121 |
/* raise irq to CPU if necessary. must be called every time the active |
|
122 |
irq may change */ |
|
123 |
void pic_update_irq(void) |
|
124 |
{ |
|
125 |
int irq2, irq; |
|
126 |
|
|
127 |
/* first look at slave pic */ |
|
128 |
irq2 = pic_get_irq(&pics[1]); |
|
129 |
if (irq2 >= 0) { |
|
130 |
/* if irq request by slave pic, signal master PIC */ |
|
131 |
pic_set_irq1(&pics[0], 2, 1); |
|
132 |
pic_set_irq1(&pics[0], 2, 0); |
|
133 |
} |
|
134 |
/* look at requested irq */ |
|
135 |
irq = pic_get_irq(&pics[0]); |
|
136 |
if (irq >= 0) { |
|
137 |
if (irq == 2) { |
|
138 |
/* from slave pic */ |
|
139 |
pic_irq_requested = 8 + irq2; |
|
140 |
} else { |
|
141 |
/* from master pic */ |
|
142 |
pic_irq_requested = irq; |
|
143 |
} |
|
144 |
#if defined(DEBUG_PIC) |
|
145 |
{ |
|
146 |
int i; |
|
147 |
for(i = 0; i < 2; i++) { |
|
148 |
printf("pic%d: imr=%x irr=%x padd=%d\n", |
|
149 |
i, pics[i].imr, pics[i].irr, pics[i].priority_add); |
|
150 |
|
|
151 |
} |
|
152 |
} |
|
153 |
printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); |
|
154 |
#endif |
|
155 |
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); |
|
156 |
} |
|
157 |
} |
|
158 |
|
|
159 |
#ifdef DEBUG_IRQ_LATENCY |
|
160 |
int64_t irq_time[16]; |
|
161 |
int64_t cpu_get_ticks(void); |
|
162 |
#endif |
|
163 |
#if defined(DEBUG_PIC) |
|
164 |
int irq_level[16]; |
|
165 |
#endif |
|
166 |
|
|
167 |
void pic_set_irq(int irq, int level) |
|
168 |
{ |
|
169 |
#if defined(DEBUG_PIC) |
|
170 |
if (level != irq_level[irq]) { |
|
171 |
printf("pic_set_irq: irq=%d level=%d\n", irq, level); |
|
172 |
irq_level[irq] = level; |
|
173 |
} |
|
174 |
#endif |
|
175 |
#ifdef DEBUG_IRQ_LATENCY |
|
176 |
if (level) { |
|
177 |
irq_time[irq] = cpu_get_ticks(); |
|
178 |
} |
|
179 |
#endif |
|
180 |
pic_set_irq1(&pics[irq >> 3], irq & 7, level); |
|
181 |
pic_update_irq(); |
|
182 |
} |
|
183 |
|
|
184 |
/* acknowledge interrupt 'irq' */ |
|
185 |
static inline void pic_intack(PicState *s, int irq) |
|
186 |
{ |
|
187 |
if (s->auto_eoi) { |
|
188 |
if (s->rotate_on_auto_eoi) |
|
189 |
s->priority_add = (irq + 1) & 7; |
|
190 |
} else { |
|
191 |
s->isr |= (1 << irq); |
|
192 |
} |
|
193 |
s->irr &= ~(1 << irq); |
|
194 |
} |
|
195 |
|
|
196 |
int cpu_x86_get_pic_interrupt(CPUState *env) |
|
197 |
{ |
|
198 |
int irq, irq2, intno; |
|
199 |
|
|
200 |
/* signal the pic that the irq was acked by the CPU */ |
|
201 |
irq = pic_irq_requested; |
|
202 |
#ifdef DEBUG_IRQ_LATENCY |
|
203 |
printf("IRQ%d latency=%0.3fus\n", |
|
204 |
irq, |
|
205 |
(double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); |
|
206 |
#endif |
|
207 |
#if defined(DEBUG_PIC) |
|
208 |
printf("pic_interrupt: irq=%d\n", irq); |
|
209 |
#endif |
|
210 |
|
|
211 |
if (irq >= 8) { |
|
212 |
irq2 = irq & 7; |
|
213 |
pic_intack(&pics[1], irq2); |
|
214 |
irq = 2; |
|
215 |
intno = pics[1].irq_base + irq2; |
|
216 |
} else { |
|
217 |
intno = pics[0].irq_base + irq; |
|
218 |
} |
|
219 |
pic_intack(&pics[0], irq); |
|
220 |
return intno; |
|
221 |
} |
|
222 |
|
|
223 |
void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) |
|
224 |
{ |
|
225 |
PicState *s; |
|
226 |
int priority, cmd, irq; |
|
227 |
|
|
228 |
#ifdef DEBUG_PIC |
|
229 |
printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); |
|
230 |
#endif |
|
231 |
s = &pics[addr >> 7]; |
|
232 |
addr &= 1; |
|
233 |
if (addr == 0) { |
|
234 |
if (val & 0x10) { |
|
235 |
/* init */ |
|
236 |
memset(s, 0, sizeof(PicState)); |
|
237 |
s->init_state = 1; |
|
238 |
s->init4 = val & 1; |
|
239 |
if (val & 0x02) |
|
240 |
hw_error("single mode not supported"); |
|
241 |
if (val & 0x08) |
|
242 |
hw_error("level sensitive irq not supported"); |
|
243 |
} else if (val & 0x08) { |
|
244 |
if (val & 0x04) |
|
245 |
s->poll = 1; |
|
246 |
if (val & 0x02) |
|
247 |
s->read_reg_select = val & 1; |
|
248 |
if (val & 0x40) |
|
249 |
s->special_mask = (val >> 5) & 1; |
|
250 |
} else { |
|
251 |
cmd = val >> 5; |
|
252 |
switch(cmd) { |
|
253 |
case 0: |
|
254 |
case 4: |
|
255 |
s->rotate_on_auto_eoi = cmd >> 2; |
|
256 |
break; |
|
257 |
case 1: /* end of interrupt */ |
|
258 |
case 5: |
|
259 |
priority = get_priority(s, s->isr); |
|
260 |
if (priority != 8) { |
|
261 |
irq = (priority + s->priority_add) & 7; |
|
262 |
s->isr &= ~(1 << irq); |
|
263 |
if (cmd == 5) |
|
264 |
s->priority_add = (irq + 1) & 7; |
|
265 |
pic_update_irq(); |
|
266 |
} |
|
267 |
break; |
|
268 |
case 3: |
|
269 |
irq = val & 7; |
|
270 |
s->isr &= ~(1 << irq); |
|
271 |
pic_update_irq(); |
|
272 |
break; |
|
273 |
case 6: |
|
274 |
s->priority_add = (val + 1) & 7; |
|
275 |
pic_update_irq(); |
|
276 |
break; |
|
277 |
case 7: |
|
278 |
irq = val & 7; |
|
279 |
s->isr &= ~(1 << irq); |
|
280 |
s->priority_add = (irq + 1) & 7; |
|
281 |
pic_update_irq(); |
|
282 |
break; |
|
283 |
default: |
|
284 |
/* no operation */ |
|
285 |
break; |
|
286 |
} |
|
287 |
} |
|
288 |
} else { |
|
289 |
switch(s->init_state) { |
|
290 |
case 0: |
|
291 |
/* normal mode */ |
|
292 |
s->imr = val; |
|
293 |
pic_update_irq(); |
|
294 |
break; |
|
295 |
case 1: |
|
296 |
s->irq_base = val & 0xf8; |
|
297 |
s->init_state = 2; |
|
298 |
break; |
|
299 |
case 2: |
|
300 |
if (s->init4) { |
|
301 |
s->init_state = 3; |
|
302 |
} else { |
|
303 |
s->init_state = 0; |
|
304 |
} |
|
305 |
break; |
|
306 |
case 3: |
|
307 |
s->special_fully_nested_mode = (val >> 4) & 1; |
|
308 |
s->auto_eoi = (val >> 1) & 1; |
|
309 |
s->init_state = 0; |
|
310 |
break; |
|
311 |
} |
|
312 |
} |
|
313 |
} |
|
314 |
|
|
315 |
static uint32_t pic_poll_read (PicState *s, uint32_t addr1) |
|
316 |
{ |
|
317 |
int ret; |
|
318 |
|
|
319 |
ret = pic_get_irq(s); |
|
320 |
if (ret >= 0) { |
|
321 |
if (addr1 >> 7) { |
|
322 |
pics[0].isr &= ~(1 << 2); |
|
323 |
pics[0].irr &= ~(1 << 2); |
|
324 |
} |
|
325 |
s->irr &= ~(1 << ret); |
|
326 |
s->isr &= ~(1 << ret); |
|
327 |
if (addr1 >> 7 || ret != 2) |
|
328 |
pic_update_irq(); |
|
329 |
} else { |
|
330 |
ret = 0x07; |
|
331 |
pic_update_irq(); |
|
332 |
} |
|
333 |
|
|
334 |
return ret; |
|
335 |
} |
|
336 |
|
|
337 |
uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) |
|
338 |
{ |
|
339 |
PicState *s; |
|
340 |
unsigned int addr; |
|
341 |
int ret; |
|
342 |
|
|
343 |
addr = addr1; |
|
344 |
s = &pics[addr >> 7]; |
|
345 |
addr &= 1; |
|
346 |
if (s->poll) { |
|
347 |
ret = pic_poll_read(s, addr1); |
|
348 |
s->poll = 0; |
|
349 |
} else { |
|
350 |
if (addr == 0) { |
|
351 |
if (s->read_reg_select) |
|
352 |
ret = s->isr; |
|
353 |
else |
|
354 |
ret = s->irr; |
|
355 |
} else { |
|
356 |
ret = s->imr; |
|
357 |
} |
|
358 |
} |
|
359 |
#ifdef DEBUG_PIC |
|
360 |
printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); |
|
361 |
#endif |
|
362 |
return ret; |
|
363 |
} |
|
364 |
|
|
365 |
/* memory mapped interrupt status */ |
|
366 |
uint32_t pic_intack_read(CPUState *env) |
|
367 |
{ |
|
368 |
int ret; |
|
369 |
|
|
370 |
ret = pic_poll_read(&pics[0], 0x00); |
|
371 |
if (ret == 2) |
|
372 |
ret = pic_poll_read(&pics[1], 0x80) + 8; |
|
373 |
/* Prepare for ISR read */ |
|
374 |
pics[0].read_reg_select = 1; |
|
375 |
|
|
376 |
return ret; |
|
377 |
} |
|
378 |
|
|
379 |
void pic_init(void) |
|
380 |
{ |
|
381 |
#if defined (TARGET_I386) || defined (TARGET_PPC) |
|
382 |
register_ioport_write(0x20, 2, pic_ioport_write, 1); |
|
383 |
register_ioport_read(0x20, 2, pic_ioport_read, 1); |
|
384 |
register_ioport_write(0xa0, 2, pic_ioport_write, 1); |
|
385 |
register_ioport_read(0xa0, 2, pic_ioport_read, 1); |
|
386 |
#endif |
|
387 |
} |
|
388 |
|
b/hw/mc146818rtc.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU MC146818 RTC emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
#include <stdlib.h> |
|
25 |
#include <stdio.h> |
|
26 |
#include <stdarg.h> |
|
27 |
#include <string.h> |
|
28 |
#include <getopt.h> |
|
29 |
#include <inttypes.h> |
|
30 |
#include <unistd.h> |
|
31 |
#include <sys/mman.h> |
|
32 |
#include <fcntl.h> |
|
33 |
#include <signal.h> |
|
34 |
#include <time.h> |
|
35 |
#include <sys/time.h> |
|
36 |
#include <malloc.h> |
|
37 |
#include <termios.h> |
|
38 |
#include <sys/poll.h> |
|
39 |
#include <errno.h> |
|
40 |
#include <sys/wait.h> |
|
41 |
#include <netinet/in.h> |
|
42 |
|
|
43 |
#include "cpu.h" |
|
44 |
#include "vl.h" |
|
45 |
|
|
46 |
//#define DEBUG_CMOS |
|
47 |
|
|
48 |
#define RTC_SECONDS 0 |
|
49 |
#define RTC_SECONDS_ALARM 1 |
|
50 |
#define RTC_MINUTES 2 |
|
51 |
#define RTC_MINUTES_ALARM 3 |
|
52 |
#define RTC_HOURS 4 |
|
53 |
#define RTC_HOURS_ALARM 5 |
|
54 |
#define RTC_ALARM_DONT_CARE 0xC0 |
|
55 |
|
|
56 |
#define RTC_DAY_OF_WEEK 6 |
|
57 |
#define RTC_DAY_OF_MONTH 7 |
|
58 |
#define RTC_MONTH 8 |
|
59 |
#define RTC_YEAR 9 |
|
60 |
|
|
61 |
#define RTC_REG_A 10 |
|
62 |
#define RTC_REG_B 11 |
|
63 |
#define RTC_REG_C 12 |
|
64 |
#define RTC_REG_D 13 |
|
65 |
|
|
66 |
/* PC cmos mappings */ |
|
67 |
#define REG_IBM_CENTURY_BYTE 0x32 |
|
68 |
#define REG_IBM_PS2_CENTURY_BYTE 0x37 |
|
69 |
|
|
70 |
RTCState rtc_state; |
|
71 |
|
|
72 |
static void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) |
|
73 |
{ |
|
74 |
RTCState *s = &rtc_state; |
|
75 |
|
|
76 |
if ((addr & 1) == 0) { |
|
77 |
s->cmos_index = data & 0x7f; |
|
78 |
} else { |
|
79 |
#ifdef DEBUG_CMOS |
|
80 |
printf("cmos: write index=0x%02x val=0x%02x\n", |
|
81 |
s->cmos_index, data); |
|
82 |
#endif |
|
83 |
switch(addr) { |
|
84 |
case RTC_SECONDS_ALARM: |
|
85 |
case RTC_MINUTES_ALARM: |
|
86 |
case RTC_HOURS_ALARM: |
|
87 |
/* XXX: not supported */ |
|
88 |
s->cmos_data[s->cmos_index] = data; |
|
89 |
break; |
|
90 |
case RTC_SECONDS: |
|
91 |
case RTC_MINUTES: |
|
92 |
case RTC_HOURS: |
|
93 |
case RTC_DAY_OF_WEEK: |
|
94 |
case RTC_DAY_OF_MONTH: |
|
95 |
case RTC_MONTH: |
|
96 |
case RTC_YEAR: |
|
97 |
s->cmos_data[s->cmos_index] = data; |
|
98 |
break; |
|
99 |
case RTC_REG_A: |
|
100 |
case RTC_REG_B: |
|
101 |
s->cmos_data[s->cmos_index] = data; |
|
102 |
break; |
|
103 |
case RTC_REG_C: |
|
104 |
case RTC_REG_D: |
|
105 |
/* cannot write to them */ |
|
106 |
break; |
|
107 |
default: |
|
108 |
s->cmos_data[s->cmos_index] = data; |
|
109 |
break; |
|
110 |
} |
|
111 |
} |
|
112 |
} |
|
113 |
|
|
114 |
static inline int to_bcd(int a) |
|
115 |
{ |
|
116 |
return ((a / 10) << 4) | (a % 10); |
|
117 |
} |
|
118 |
|
|
119 |
static void cmos_update_time(RTCState *s) |
|
120 |
{ |
|
121 |
struct tm *tm; |
|
122 |
time_t ti; |
|
123 |
|
|
124 |
ti = time(NULL); |
|
125 |
tm = gmtime(&ti); |
|
126 |
s->cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); |
|
127 |
s->cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); |
|
128 |
s->cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); |
|
129 |
s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); |
|
130 |
s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); |
|
131 |
s->cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); |
|
132 |
s->cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); |
|
133 |
s->cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); |
|
134 |
s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE]; |
|
135 |
} |
|
136 |
|
|
137 |
static uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) |
|
138 |
{ |
|
139 |
RTCState *s = &rtc_state; |
|
140 |
int ret; |
|
141 |
if ((addr & 1) == 0) { |
|
142 |
return 0xff; |
|
143 |
} else { |
|
144 |
switch(s->cmos_index) { |
|
145 |
case RTC_SECONDS: |
|
146 |
case RTC_MINUTES: |
|
147 |
case RTC_HOURS: |
|
148 |
case RTC_DAY_OF_WEEK: |
|
149 |
case RTC_DAY_OF_MONTH: |
|
150 |
case RTC_MONTH: |
|
151 |
case RTC_YEAR: |
|
152 |
case REG_IBM_CENTURY_BYTE: |
|
153 |
case REG_IBM_PS2_CENTURY_BYTE: |
|
154 |
cmos_update_time(s); |
|
155 |
ret = s->cmos_data[s->cmos_index]; |
|
156 |
break; |
|
157 |
case RTC_REG_A: |
|
158 |
ret = s->cmos_data[s->cmos_index]; |
|
159 |
/* toggle update-in-progress bit for Linux (same hack as |
|
160 |
plex86) */ |
|
161 |
s->cmos_data[RTC_REG_A] ^= 0x80; |
|
162 |
break; |
|
163 |
case RTC_REG_C: |
|
164 |
ret = s->cmos_data[s->cmos_index]; |
|
165 |
pic_set_irq(s->irq, 0); |
|
166 |
s->cmos_data[RTC_REG_C] = 0x00; |
|
167 |
break; |
|
168 |
default: |
|
169 |
ret = s->cmos_data[s->cmos_index]; |
|
170 |
break; |
|
171 |
} |
|
172 |
#ifdef DEBUG_CMOS |
|
173 |
printf("cmos: read index=0x%02x val=0x%02x\n", |
|
174 |
s->cmos_index, ret); |
|
175 |
#endif |
|
176 |
return ret; |
|
177 |
} |
|
178 |
} |
|
179 |
|
|
180 |
void rtc_timer(void) |
|
181 |
{ |
|
182 |
RTCState *s = &rtc_state; |
|
183 |
if (s->cmos_data[RTC_REG_B] & 0x50) { |
|
184 |
pic_set_irq(s->irq, 1); |
|
185 |
} |
|
186 |
} |
|
187 |
|
|
188 |
void rtc_init(int base, int irq) |
|
189 |
{ |
|
190 |
RTCState *s = &rtc_state; |
|
191 |
|
|
192 |
cmos_update_time(s); |
|
193 |
|
|
194 |
s->irq = irq; |
|
195 |
s->cmos_data[RTC_REG_A] = 0x26; |
|
196 |
s->cmos_data[RTC_REG_B] = 0x02; |
|
197 |
s->cmos_data[RTC_REG_C] = 0x00; |
|
198 |
s->cmos_data[RTC_REG_D] = 0x80; |
|
199 |
|
|
200 |
register_ioport_write(base, 2, cmos_ioport_write, 1); |
|
201 |
register_ioport_read(base, 2, cmos_ioport_read, 1); |
|
202 |
} |
|
203 |
|
b/hw/ne2000.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU NE2000 emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
#include <stdlib.h> |
|
25 |
#include <stdio.h> |
|
26 |
#include <stdarg.h> |
|
27 |
#include <string.h> |
|
28 |
#include <getopt.h> |
|
29 |
#include <inttypes.h> |
|
30 |
#include <unistd.h> |
|
31 |
#include <sys/mman.h> |
|
32 |
#include <fcntl.h> |
|
33 |
#include <signal.h> |
|
34 |
#include <time.h> |
|
35 |
#include <sys/time.h> |
|
36 |
#include <malloc.h> |
|
37 |
#include <termios.h> |
|
38 |
#include <sys/poll.h> |
|
39 |
#include <errno.h> |
|
40 |
#include <sys/wait.h> |
|
41 |
#include <netinet/in.h> |
|
42 |
|
|
43 |
#include "cpu.h" |
|
44 |
#include "vl.h" |
|
45 |
|
|
46 |
/* debug NE2000 card */ |
|
47 |
//#define DEBUG_NE2000 |
|
48 |
|
|
49 |
/***********************************************************/ |
|
50 |
/* ne2000 emulation */ |
|
51 |
|
|
52 |
#define E8390_CMD 0x00 /* The command register (for all pages) */ |
|
53 |
/* Page 0 register offsets. */ |
|
54 |
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ |
|
55 |
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ |
|
56 |
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ |
|
57 |
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ |
|
58 |
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ |
|
59 |
#define EN0_TSR 0x04 /* Transmit status reg RD */ |
|
60 |
#define EN0_TPSR 0x04 /* Transmit starting page WR */ |
|
61 |
#define EN0_NCR 0x05 /* Number of collision reg RD */ |
|
62 |
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ |
|
63 |
#define EN0_FIFO 0x06 /* FIFO RD */ |
|
64 |
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ |
|
65 |
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ |
|
66 |
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ |
|
67 |
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ |
|
68 |
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ |
|
69 |
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ |
|
70 |
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ |
|
71 |
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ |
|
72 |
#define EN0_RSR 0x0c /* rx status reg RD */ |
|
73 |
#define EN0_RXCR 0x0c /* RX configuration reg WR */ |
|
74 |
#define EN0_TXCR 0x0d /* TX configuration reg WR */ |
|
75 |
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ |
|
76 |
#define EN0_DCFG 0x0e /* Data configuration reg WR */ |
|
77 |
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ |
|
78 |
#define EN0_IMR 0x0f /* Interrupt mask reg WR */ |
|
79 |
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ |
|
80 |
|
|
81 |
#define EN1_PHYS 0x11 |
|
82 |
#define EN1_CURPAG 0x17 |
|
83 |
#define EN1_MULT 0x18 |
|
84 |
|
|
85 |
/* Register accessed at EN_CMD, the 8390 base addr. */ |
|
86 |
#define E8390_STOP 0x01 /* Stop and reset the chip */ |
|
87 |
#define E8390_START 0x02 /* Start the chip, clear reset */ |
|
88 |
#define E8390_TRANS 0x04 /* Transmit a frame */ |
|
89 |
#define E8390_RREAD 0x08 /* Remote read */ |
|
90 |
#define E8390_RWRITE 0x10 /* Remote write */ |
|
91 |
#define E8390_NODMA 0x20 /* Remote DMA */ |
|
92 |
#define E8390_PAGE0 0x00 /* Select page chip registers */ |
|
93 |
#define E8390_PAGE1 0x40 /* using the two high-order bits */ |
|
94 |
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ |
|
95 |
|
|
96 |
/* Bits in EN0_ISR - Interrupt status register */ |
|
97 |
#define ENISR_RX 0x01 /* Receiver, no error */ |
|
98 |
#define ENISR_TX 0x02 /* Transmitter, no error */ |
|
99 |
#define ENISR_RX_ERR 0x04 /* Receiver, with error */ |
|
100 |
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ |
|
101 |
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ |
|
102 |
#define ENISR_COUNTERS 0x20 /* Counters need emptying */ |
|
103 |
#define ENISR_RDC 0x40 /* remote dma complete */ |
|
104 |
#define ENISR_RESET 0x80 /* Reset completed */ |
|
105 |
#define ENISR_ALL 0x3f /* Interrupts we will enable */ |
|
106 |
|
|
107 |
/* Bits in received packet status byte and EN0_RSR*/ |
|
108 |
#define ENRSR_RXOK 0x01 /* Received a good packet */ |
|
109 |
#define ENRSR_CRC 0x02 /* CRC error */ |
|
110 |
#define ENRSR_FAE 0x04 /* frame alignment error */ |
|
111 |
#define ENRSR_FO 0x08 /* FIFO overrun */ |
|
112 |
#define ENRSR_MPA 0x10 /* missed pkt */ |
|
113 |
#define ENRSR_PHY 0x20 /* physical/multicast address */ |
|
114 |
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ |
|
115 |
#define ENRSR_DEF 0x80 /* deferring */ |
|
116 |
|
|
117 |
/* Transmitted packet status, EN0_TSR. */ |
|
118 |
#define ENTSR_PTX 0x01 /* Packet transmitted without error */ |
|
119 |
#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ |
|
120 |
#define ENTSR_COL 0x04 /* The transmit collided at least once. */ |
|
121 |
#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ |
|
122 |
#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ |
|
123 |
#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ |
|
124 |
#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ |
|
125 |
#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ |
|
126 |
|
|
127 |
#define NE2000_MEM_SIZE 32768 |
|
128 |
|
|
129 |
typedef struct NE2000State { |
|
130 |
uint8_t cmd; |
|
131 |
uint32_t start; |
|
132 |
uint32_t stop; |
|
133 |
uint8_t boundary; |
|
134 |
uint8_t tsr; |
|
135 |
uint8_t tpsr; |
|
136 |
uint16_t tcnt; |
|
137 |
uint16_t rcnt; |
|
138 |
uint32_t rsar; |
|
139 |
uint8_t isr; |
|
140 |
uint8_t dcfg; |
|
141 |
uint8_t imr; |
|
142 |
uint8_t phys[6]; /* mac address */ |
|
143 |
uint8_t curpag; |
|
144 |
uint8_t mult[8]; /* multicast mask array */ |
|
145 |
int irq; |
|
146 |
uint8_t mem[NE2000_MEM_SIZE]; |
|
147 |
} NE2000State; |
|
148 |
|
|
149 |
static NE2000State ne2000_state; |
|
150 |
int net_fd = -1; |
|
151 |
|
|
152 |
static void ne2000_reset(NE2000State *s) |
|
153 |
{ |
|
154 |
int i; |
|
155 |
|
|
156 |
s->isr = ENISR_RESET; |
|
157 |
s->mem[0] = 0x52; |
|
158 |
s->mem[1] = 0x54; |
|
159 |
s->mem[2] = 0x00; |
|
160 |
s->mem[3] = 0x12; |
|
161 |
s->mem[4] = 0x34; |
|
162 |
s->mem[5] = 0x56; |
|
163 |
s->mem[14] = 0x57; |
|
164 |
s->mem[15] = 0x57; |
|
165 |
|
|
166 |
/* duplicate prom data */ |
|
167 |
for(i = 15;i >= 0; i--) { |
|
168 |
s->mem[2 * i] = s->mem[i]; |
|
169 |
s->mem[2 * i + 1] = s->mem[i]; |
|
170 |
} |
|
171 |
} |
|
172 |
|
|
173 |
static void ne2000_update_irq(NE2000State *s) |
|
174 |
{ |
|
175 |
int isr; |
|
176 |
isr = s->isr & s->imr; |
|
177 |
if (isr) |
|
178 |
pic_set_irq(s->irq, 1); |
|
179 |
else |
|
180 |
pic_set_irq(s->irq, 0); |
|
181 |
} |
|
182 |
|
|
183 |
/* return true if the NE2000 can receive more data */ |
|
184 |
int ne2000_can_receive(void) |
|
185 |
{ |
|
186 |
NE2000State *s = &ne2000_state; |
|
187 |
int avail, index, boundary; |
|
188 |
|
|
189 |
if (s->cmd & E8390_STOP) |
|
190 |
return 0; |
|
191 |
index = s->curpag << 8; |
|
192 |
boundary = s->boundary << 8; |
|
193 |
if (index < boundary) |
|
194 |
avail = boundary - index; |
|
195 |
else |
|
196 |
avail = (s->stop - s->start) - (index - boundary); |
|
197 |
if (avail < (MAX_ETH_FRAME_SIZE + 4)) |
|
198 |
return 0; |
|
199 |
return 1; |
|
200 |
} |
|
201 |
|
|
202 |
void ne2000_receive(uint8_t *buf, int size) |
|
203 |
{ |
|
204 |
NE2000State *s = &ne2000_state; |
|
205 |
uint8_t *p; |
|
206 |
int total_len, next, avail, len, index; |
|
207 |
|
|
208 |
#if defined(DEBUG_NE2000) |
|
209 |
printf("NE2000: received len=%d\n", size); |
|
210 |
#endif |
|
211 |
|
|
212 |
index = s->curpag << 8; |
|
213 |
/* 4 bytes for header */ |
|
214 |
total_len = size + 4; |
|
215 |
/* address for next packet (4 bytes for CRC) */ |
|
216 |
next = index + ((total_len + 4 + 255) & ~0xff); |
|
217 |
if (next >= s->stop) |
|
218 |
next -= (s->stop - s->start); |
|
219 |
/* prepare packet header */ |
|
220 |
p = s->mem + index; |
|
221 |
p[0] = ENRSR_RXOK; /* receive status */ |
|
222 |
p[1] = next >> 8; |
|
223 |
p[2] = total_len; |
|
224 |
p[3] = total_len >> 8; |
|
225 |
index += 4; |
|
226 |
|
|
227 |
/* write packet data */ |
|
228 |
while (size > 0) { |
|
229 |
avail = s->stop - index; |
|
230 |
len = size; |
|
231 |
if (len > avail) |
|
232 |
len = avail; |
|
233 |
memcpy(s->mem + index, buf, len); |
|
234 |
buf += len; |
|
235 |
index += len; |
|
236 |
if (index == s->stop) |
|
237 |
index = s->start; |
|
238 |
size -= len; |
|
239 |
} |
|
240 |
s->curpag = next >> 8; |
|
241 |
|
|
242 |
/* now we can signal we have receive something */ |
|
243 |
s->isr |= ENISR_RX; |
|
244 |
ne2000_update_irq(s); |
|
245 |
} |
|
246 |
|
|
247 |
static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) |
|
248 |
{ |
|
249 |
NE2000State *s = &ne2000_state; |
|
250 |
int offset, page; |
|
251 |
|
|
252 |
addr &= 0xf; |
|
253 |
#ifdef DEBUG_NE2000 |
|
254 |
printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); |
|
255 |
#endif |
|
256 |
if (addr == E8390_CMD) { |
|
257 |
/* control register */ |
|
258 |
s->cmd = val; |
|
259 |
if (val & E8390_START) { |
|
260 |
/* test specific case: zero length transfert */ |
|
261 |
if ((val & (E8390_RREAD | E8390_RWRITE)) && |
|
262 |
s->rcnt == 0) { |
|
263 |
s->isr |= ENISR_RDC; |
|
264 |
ne2000_update_irq(s); |
|
265 |
} |
|
266 |
if (val & E8390_TRANS) { |
|
267 |
net_send_packet(net_fd, s->mem + (s->tpsr << 8), s->tcnt); |
|
268 |
/* signal end of transfert */ |
|
269 |
s->tsr = ENTSR_PTX; |
|
270 |
s->isr |= ENISR_TX; |
|
271 |
ne2000_update_irq(s); |
|
272 |
} |
|
273 |
} |
|
274 |
} else { |
|
275 |
page = s->cmd >> 6; |
|
276 |
offset = addr | (page << 4); |
|
277 |
switch(offset) { |
|
278 |
case EN0_STARTPG: |
|
279 |
s->start = val << 8; |
|
280 |
break; |
|
281 |
case EN0_STOPPG: |
|
282 |
s->stop = val << 8; |
|
283 |
break; |
|
284 |
case EN0_BOUNDARY: |
|
285 |
s->boundary = val; |
|
286 |
break; |
|
287 |
case EN0_IMR: |
|
288 |
s->imr = val; |
|
289 |
ne2000_update_irq(s); |
|
290 |
break; |
|
291 |
case EN0_TPSR: |
|
292 |
s->tpsr = val; |
|
293 |
break; |
|
294 |
case EN0_TCNTLO: |
|
295 |
s->tcnt = (s->tcnt & 0xff00) | val; |
|
296 |
break; |
|
297 |
case EN0_TCNTHI: |
|
298 |
s->tcnt = (s->tcnt & 0x00ff) | (val << 8); |
|
299 |
break; |
|
300 |
case EN0_RSARLO: |
|
301 |
s->rsar = (s->rsar & 0xff00) | val; |
|
302 |
break; |
|
303 |
case EN0_RSARHI: |
|
304 |
s->rsar = (s->rsar & 0x00ff) | (val << 8); |
|
305 |
break; |
|
306 |
case EN0_RCNTLO: |
|
307 |
s->rcnt = (s->rcnt & 0xff00) | val; |
|
308 |
break; |
|
309 |
case EN0_RCNTHI: |
|
310 |
s->rcnt = (s->rcnt & 0x00ff) | (val << 8); |
|
311 |
break; |
|
312 |
case EN0_DCFG: |
|
313 |
s->dcfg = val; |
|
314 |
break; |
|
315 |
case EN0_ISR: |
|
316 |
s->isr &= ~val; |
|
317 |
ne2000_update_irq(s); |
|
318 |
break; |
|
319 |
case EN1_PHYS ... EN1_PHYS + 5: |
|
320 |
s->phys[offset - EN1_PHYS] = val; |
|
321 |
break; |
|
322 |
case EN1_CURPAG: |
|
323 |
s->curpag = val; |
|
324 |
break; |
|
325 |
case EN1_MULT ... EN1_MULT + 7: |
|
326 |
s->mult[offset - EN1_MULT] = val; |
|
327 |
break; |
|
328 |
} |
|
329 |
} |
|
330 |
} |
|
331 |
|
|
332 |
static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) |
|
333 |
{ |
|
334 |
NE2000State *s = &ne2000_state; |
|
335 |
int offset, page, ret; |
|
336 |
|
|
337 |
addr &= 0xf; |
|
338 |
if (addr == E8390_CMD) { |
|
339 |
ret = s->cmd; |
|
340 |
} else { |
|
341 |
page = s->cmd >> 6; |
|
342 |
offset = addr | (page << 4); |
|
343 |
switch(offset) { |
|
344 |
case EN0_TSR: |
|
345 |
ret = s->tsr; |
|
346 |
break; |
|
347 |
case EN0_BOUNDARY: |
|
348 |
ret = s->boundary; |
|
349 |
break; |
|
350 |
case EN0_ISR: |
|
351 |
ret = s->isr; |
|
352 |
break; |
|
353 |
case EN1_PHYS ... EN1_PHYS + 5: |
|
354 |
ret = s->phys[offset - EN1_PHYS]; |
|
355 |
break; |
|
356 |
case EN1_CURPAG: |
|
357 |
ret = s->curpag; |
|
358 |
break; |
|
359 |
case EN1_MULT ... EN1_MULT + 7: |
|
360 |
ret = s->mult[offset - EN1_MULT]; |
|
361 |
break; |
|
362 |
default: |
|
363 |
ret = 0x00; |
|
364 |
break; |
|
365 |
} |
|
366 |
} |
|
367 |
#ifdef DEBUG_NE2000 |
|
368 |
printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); |
|
369 |
#endif |
|
370 |
return ret; |
|
371 |
} |
|
372 |
|
|
373 |
static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) |
|
374 |
{ |
|
375 |
NE2000State *s = &ne2000_state; |
|
376 |
uint8_t *p; |
|
377 |
|
|
378 |
#ifdef DEBUG_NE2000 |
|
379 |
printf("NE2000: asic write val=0x%04x\n", val); |
|
380 |
#endif |
|
381 |
p = s->mem + s->rsar; |
|
382 |
if (s->dcfg & 0x01) { |
|
383 |
/* 16 bit access */ |
|
384 |
p[0] = val; |
|
385 |
p[1] = val >> 8; |
|
386 |
s->rsar += 2; |
|
387 |
s->rcnt -= 2; |
|
388 |
} else { |
|
389 |
/* 8 bit access */ |
|
390 |
p[0] = val; |
|
391 |
s->rsar++; |
|
392 |
s->rcnt--; |
|
393 |
} |
|
394 |
/* wrap */ |
|
395 |
if (s->rsar == s->stop) |
|
396 |
s->rsar = s->start; |
|
397 |
if (s->rcnt == 0) { |
|
398 |
/* signal end of transfert */ |
|
399 |
s->isr |= ENISR_RDC; |
|
400 |
ne2000_update_irq(s); |
|
401 |
} |
|
402 |
} |
|
403 |
|
|
404 |
static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) |
|
405 |
{ |
|
406 |
NE2000State *s = &ne2000_state; |
|
407 |
uint8_t *p; |
|
408 |
int ret; |
|
409 |
|
|
410 |
p = s->mem + s->rsar; |
|
411 |
if (s->dcfg & 0x01) { |
|
412 |
/* 16 bit access */ |
|
413 |
ret = p[0] | (p[1] << 8); |
|
414 |
s->rsar += 2; |
|
415 |
s->rcnt -= 2; |
|
416 |
} else { |
|
417 |
/* 8 bit access */ |
|
418 |
ret = p[0]; |
|
419 |
s->rsar++; |
|
420 |
s->rcnt--; |
|
421 |
} |
|
422 |
/* wrap */ |
|
423 |
if (s->rsar == s->stop) |
|
424 |
s->rsar = s->start; |
|
425 |
if (s->rcnt == 0) { |
|
426 |
/* signal end of transfert */ |
|
427 |
s->isr |= ENISR_RDC; |
|
428 |
ne2000_update_irq(s); |
|
429 |
} |
|
430 |
#ifdef DEBUG_NE2000 |
|
431 |
printf("NE2000: asic read val=0x%04x\n", ret); |
|
432 |
#endif |
|
433 |
return ret; |
|
434 |
} |
|
435 |
|
|
436 |
static void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) |
|
437 |
{ |
|
438 |
/* nothing to do (end of reset pulse) */ |
|
439 |
} |
|
440 |
|
|
441 |
static uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) |
|
442 |
{ |
|
443 |
NE2000State *s = &ne2000_state; |
|
444 |
ne2000_reset(s); |
|
445 |
return 0; |
|
446 |
} |
|
447 |
|
|
448 |
void ne2000_init(int base, int irq) |
|
449 |
{ |
|
450 |
NE2000State *s = &ne2000_state; |
|
451 |
|
|
452 |
register_ioport_write(base, 16, ne2000_ioport_write, 1); |
|
453 |
register_ioport_read(base, 16, ne2000_ioport_read, 1); |
|
454 |
|
|
455 |
register_ioport_write(base + 0x10, 1, ne2000_asic_ioport_write, 1); |
|
456 |
register_ioport_read(base + 0x10, 1, ne2000_asic_ioport_read, 1); |
|
457 |
register_ioport_write(base + 0x10, 2, ne2000_asic_ioport_write, 2); |
|
458 |
register_ioport_read(base + 0x10, 2, ne2000_asic_ioport_read, 2); |
|
459 |
|
|
460 |
register_ioport_write(base + 0x1f, 1, ne2000_reset_ioport_write, 1); |
|
461 |
register_ioport_read(base + 0x1f, 1, ne2000_reset_ioport_read, 1); |
|
462 |
s->irq = irq; |
|
463 |
|
|
464 |
ne2000_reset(s); |
|
465 |
} |
b/hw/pc.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU PC System Emulator |
|
3 |
* |
|
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
#include <stdlib.h> |
|
25 |
#include <stdio.h> |
|
26 |
#include <stdarg.h> |
|
27 |
#include <string.h> |
|
28 |
#include <getopt.h> |
|
29 |
#include <inttypes.h> |
|
30 |
#include <unistd.h> |
|
31 |
#include <sys/mman.h> |
|
32 |
#include <fcntl.h> |
|
33 |
#include <signal.h> |
|
34 |
#include <time.h> |
|
35 |
#include <sys/time.h> |
|
36 |
#include <malloc.h> |
|
37 |
#include <termios.h> |
|
38 |
#include <sys/poll.h> |
|
39 |
#include <errno.h> |
|
40 |
#include <sys/wait.h> |
|
41 |
#include <netinet/in.h> |
|
42 |
|
|
43 |
#include "cpu.h" |
|
44 |
#include "vl.h" |
|
45 |
|
|
46 |
#define BIOS_FILENAME "bios.bin" |
|
47 |
#define VGABIOS_FILENAME "vgabios.bin" |
|
48 |
#define LINUX_BOOT_FILENAME "linux_boot.bin" |
|
49 |
|
|
50 |
#define KERNEL_LOAD_ADDR 0x00100000 |
|
51 |
#define INITRD_LOAD_ADDR 0x00400000 |
|
52 |
#define KERNEL_PARAMS_ADDR 0x00090000 |
|
53 |
#define KERNEL_CMDLINE_ADDR 0x00099000 |
|
54 |
|
|
55 |
int speaker_data_on; |
|
56 |
int dummy_refresh_clock; |
|
57 |
|
|
58 |
static void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) |
|
59 |
{ |
|
60 |
} |
|
61 |
|
|
62 |
#define REG_EQUIPMENT_BYTE 0x14 |
|
63 |
|
|
64 |
static void cmos_init(int ram_size, int boot_device) |
|
65 |
{ |
|
66 |
RTCState *s = &rtc_state; |
|
67 |
int val; |
|
68 |
|
|
69 |
/* various important CMOS locations needed by PC/Bochs bios */ |
|
70 |
|
|
71 |
s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ |
|
72 |
s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ |
|
73 |
|
|
74 |
/* memory size */ |
|
75 |
val = (ram_size / 1024) - 1024; |
|
76 |
if (val > 65535) |
|
77 |
val = 65535; |
|
78 |
s->cmos_data[0x17] = val; |
|
79 |
s->cmos_data[0x18] = val >> 8; |
|
80 |
s->cmos_data[0x30] = val; |
|
81 |
s->cmos_data[0x31] = val >> 8; |
|
82 |
|
|
83 |
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); |
|
84 |
if (val > 65535) |
|
85 |
val = 65535; |
|
86 |
s->cmos_data[0x34] = val; |
Also available in: Unified diff