dev_8253.cc Source File

Back to the index.

dev_8253.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2009 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  * COMMENT: Intel 8253/8254 Programmable Interval Timer
29  *
30  * TODO/NOTE:
31  * The timers don't really count down. Timer 0 causes clock interrupts
32  * at a specific frequency, but reading the counter register would not
33  * result in anything meaningful.
34  *
35  * (Split counter[] into reset value and current value.)
36  */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "cpu.h"
43 #include "device.h"
44 #include "emul.h"
45 #include "interrupt.h"
46 #include "machine.h"
47 #include "memory.h"
48 #include "misc.h"
49 #include "timer.h"
50 
51 #include "thirdparty/i8253reg.h"
52 
53 
54 /* #define debug fatal */
55 
56 #define DEV_8253_LENGTH 4
57 #define TICK_SHIFT 14
58 
59 
60 struct pit8253_data {
61  int in_use;
62 
64  uint8_t mode_byte;
65 
66  int mode[3];
67  int counter[3];
68 
69  int hz[3];
70 
71  struct timer *timer0;
72  struct interrupt irq;
74 };
75 
76 
77 static void timer0_tick(struct timer *t, void *extra)
78 {
79  struct pit8253_data *d = (struct pit8253_data *) extra;
81 
82  /* printf("%i ", d->pending_interrupts_timer0); fflush(stdout); */
83 }
84 
85 
87 {
88  struct pit8253_data *d = (struct pit8253_data *) extra;
89 
90  if (!d->in_use)
91  return;
92 
93  // Generate interrupts regardless of (d->mode[0] & 0x0e)?
94  // (It seems like Linux/MALTA kernels like this.)
95  if (d->pending_interrupts_timer0 > 0)
97 }
98 
99 
101 {
102  struct pit8253_data *d = (struct pit8253_data *) extra;
103  uint64_t idata = 0, odata = 0;
104 
105  if (writeflag == MEM_WRITE)
106  idata = memory_readmax64(cpu, data, len);
107 
108  d->in_use = 1;
109 
110  switch (relative_addr) {
111 
112  case I8253_TIMER_CNTR0:
113  case I8253_TIMER_CNTR1:
114  case I8253_TIMER_CNTR2:
115  if (writeflag == MEM_WRITE) {
116  switch (d->mode_byte & 0x30) {
117  case I8253_TIMER_LSB:
118  case I8253_TIMER_16BIT:
119  d->counter[relative_addr] &= 0xff00;
120  d->counter[relative_addr] |= (idata & 0xff);
121  break;
122  case I8253_TIMER_MSB:
123  d->counter[relative_addr] &= 0x00ff;
124  d->counter[relative_addr] |= ((idata&0xff)<<8);
125  if (d->counter[relative_addr] != 0)
126  d->hz[relative_addr] = (int) (
127  I8253_TIMER_FREQ / (float)
128  d->counter[relative_addr] + 0.5);
129  else
130  d->hz[relative_addr] = 0;
131  debug("[ 8253: counter %i set to %i (%i Hz) "
132  "]\n", relative_addr, d->counter[
133  relative_addr], d->hz[relative_addr]);
134  switch (relative_addr) {
135  case 0: if (d->timer0 == NULL)
136  d->timer0 = timer_add(
137  d->hz[0], timer0_tick, d);
138  else
140  d->timer0, d->hz[0]);
141  break;
142  case 1: fatal("TODO: DMA refresh?\n");
143  exit(1);
144  case 2: fatal("TODO: 8253 tone generation?\n");
145  break;
146  }
147  break;
148  default:fatal("[ 8253: huh? writing to counter"
149  " %i but neither from msb nor lsb? ]\n",
150  relative_addr);
151  exit(1);
152  }
153  } else {
154  switch (d->mode_byte & 0x30) {
155  case I8253_TIMER_LSB:
156  case I8253_TIMER_16BIT:
157  odata = d->counter[relative_addr] & 0xff;
158  break;
159  case I8253_TIMER_MSB:
160  odata = (d->counter[relative_addr] >> 8) & 0xff;
161  break;
162  default:fatal("[ 8253: huh? reading from counter"
163  " %i but neither from msb nor lsb? ]\n",
164  relative_addr);
165  exit(1);
166  }
167  }
168 
169  /* Switch from LSB to MSB, if accessing as 16-bit word: */
170  if ((d->mode_byte & 0x30) == I8253_TIMER_16BIT)
171  d->mode_byte &= ~I8253_TIMER_LSB;
172 
173  break;
174 
175  case I8253_TIMER_MODE:
176  if (writeflag == MEM_WRITE) {
177  d->mode_byte = idata;
178 
179  d->counter_select = idata >> 6;
180  if (d->counter_select > 2) {
181  debug("[ 8253: attempt to select counter 3,"
182  " which doesn't exist. ]\n");
183  d->counter_select = 0;
184  }
185 
186  d->mode[d->counter_select] = idata & 0x0e;
187 
188  debug("[ 8253: select=%i mode=0x%x ",
189  d->counter_select, d->mode[d->counter_select]);
190  if (idata & 0x30) {
191  switch (idata & 0x30) {
192  case I8253_TIMER_LSB:
193  debug("LSB ");
194  break;
195  case I8253_TIMER_16BIT:
196  debug("LSB+");
197  case I8253_TIMER_MSB:
198  debug("MSB ");
199  }
200  }
201  debug("]\n");
202 
203  if (idata & I8253_TIMER_BCD) {
204  fatal("[ 8253: BCD not yet implemented ]\n");
205  exit(1);
206  }
207  } else {
208  debug("[ 8253: read; can this actually happen? ]\n");
209  odata = d->mode_byte;
210  }
211  break;
212 
213  default:if (writeflag == MEM_WRITE) {
214  fatal("[ 8253: unimplemented write to address 0x%x"
215  " data=0x%02x ]\n", (int)relative_addr, (int)idata);
216  } else {
217  fatal("[ 8253: unimplemented read from address 0x%x "
218  "]\n", (int)relative_addr);
219  }
220  exit(1);
221  }
222 
223  if (writeflag == MEM_READ)
224  memory_writemax64(cpu, data, len, odata);
225 
226  return 1;
227 }
228 
229 
230 DEVINIT(8253)
231 {
232  struct pit8253_data *d;
233 
234  CHECK_ALLOCATION(d = (struct pit8253_data *) malloc(sizeof(struct pit8253_data)));
235  memset(d, 0, sizeof(struct pit8253_data));
236 
237  d->in_use = devinit->in_use;
238 
240 
241  /* Don't cause interrupt, by default. */
242  d->mode[0] = I8253_TIMER_RATEGEN;
243  d->mode[1] = I8253_TIMER_RATEGEN;
244  d->mode[2] = I8253_TIMER_RATEGEN;
245 
248 
250  devinit->addr, DEV_8253_LENGTH, dev_8253_access, (void *)d,
251  DM_DEFAULT, NULL);
252 
253  machine_add_tickfunction(devinit->machine, dev_8253_tick,
254  d, TICK_SHIFT);
255 
256  return 1;
257 }
258 
pit8253_data::mode
int mode[3]
Definition: dev_8253.cc:66
data
u_short data
Definition: siireg.h:79
timer_add
struct timer * timer_add(double freq, void(*timer_tick)(struct timer *timer, void *extra), void *extra)
Definition: timer.cc:75
isa_pic_data::pending_timer_interrupts
int * pending_timer_interrupts
Definition: machine.h:51
TICK_SHIFT
#define TICK_SHIFT
Definition: dev_8253.cc:57
INTERRUPT_CONNECT
#define INTERRUPT_CONNECT(name, istruct)
Definition: interrupt.h:77
INTERRUPT_ASSERT
#define INTERRUPT_ASSERT(istruct)
Definition: interrupt.h:74
timer
Definition: timer.cc:45
pit8253_data::timer0
struct timer * timer0
Definition: dev_8253.cc:71
debug
#define debug
Definition: dev_adb.cc:57
pit8253_data::pending_interrupts_timer0
int pending_interrupts_timer0
Definition: dev_8253.cc:73
DEVICE_TICK
DEVICE_TICK(8253)
Definition: dev_8253.cc:86
I8253_TIMER_LSB
#define I8253_TIMER_LSB
Definition: i8253reg.h:96
devinit::addr
uint64_t addr
Definition: device.h:46
memory_device_register
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
pit8253_data::counter_select
int counter_select
Definition: dev_8253.cc:63
MEM_READ
#define MEM_READ
Definition: memory.h:116
t
vmrs t
Definition: armreg.h:750
DM_DEFAULT
#define DM_DEFAULT
Definition: memory.h:130
interrupt::extra
void * extra
Definition: interrupt.h:59
devinit::machine
struct machine * machine
Definition: device.h:41
pit8253_data::mode_byte
uint8_t mode_byte
Definition: dev_8253.cc:64
device.h
I8253_TIMER_MSB
#define I8253_TIMER_MSB
Definition: i8253reg.h:97
pit8253_data::hz
int hz[3]
Definition: dev_8253.cc:69
MEM_WRITE
#define MEM_WRITE
Definition: memory.h:117
machine_add_tickfunction
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
I8253_TIMER_RATEGEN
#define I8253_TIMER_RATEGEN
Definition: i8253reg.h:91
devinit::interrupt_path
char * interrupt_path
Definition: device.h:50
interrupt.h
fatal
void fatal(const char *fmt,...)
Definition: main.cc:152
machine::isa_pic_data
struct isa_pic_data isa_pic_data
Definition: machine.h:190
DEVICE_ACCESS
DEVICE_ACCESS(8253)
Definition: dev_8253.cc:100
misc.h
pit8253_data::in_use
int in_use
Definition: dev_8253.cc:61
memory_readmax64
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
machine.h
pit8253_data::irq
struct interrupt irq
Definition: dev_8253.cc:72
timer.h
devinit::name
char * name
Definition: device.h:43
emul.h
pit8253_data
Definition: dev_8253.cc:60
I8253_TIMER_FREQ
#define I8253_TIMER_FREQ
Definition: i8253reg.h:75
devinit
Definition: device.h:40
cpu.h
pit8253_data::counter
int counter[3]
Definition: dev_8253.cc:67
machine::memory
struct memory * memory
Definition: machine.h:126
I8253_TIMER_CNTR2
#define I8253_TIMER_CNTR2
Definition: i8253reg.h:84
DEV_8253_LENGTH
#define DEV_8253_LENGTH
Definition: dev_8253.cc:56
i8253reg.h
timer_update_frequency
void timer_update_frequency(struct timer *t, double new_freq)
Definition: timer.cc:132
I8253_TIMER_16BIT
#define I8253_TIMER_16BIT
Definition: i8253reg.h:98
I8253_TIMER_CNTR1
#define I8253_TIMER_CNTR1
Definition: i8253reg.h:83
DEVINIT
DEVINIT(8253)
Definition: dev_8253.cc:230
interrupt
Definition: interrupt.h:36
memory_writemax64
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
cpu
Definition: cpu.h:326
devinit::in_use
int in_use
Definition: device.h:52
I8253_TIMER_CNTR0
#define I8253_TIMER_CNTR0
Definition: i8253reg.h:82
I8253_TIMER_BCD
#define I8253_TIMER_BCD
Definition: i8253reg.h:99
memory.h
CHECK_ALLOCATION
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
I8253_TIMER_MODE
#define I8253_TIMER_MODE
Definition: i8253reg.h:85

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18