dev_lca.cc Source File

Back to the index.

dev_lca.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2011 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: LCA PCI bus, for Alpha machines
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "bus_isa.h"
36 #include "bus_pci.h"
37 #include "cpu.h"
38 #include "device.h"
39 #include "emul.h"
40 #include "interrupt.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "misc.h"
44 
46 
47 #define LCA_ISA_BASE (LCA_PCI_SIO + 0x10000000)
48 #define LCA_ISA_MEMBASE (LCA_PCI_SIO + 0x18000000)
49 
50 
51 struct lca_data {
52  struct pci_data *pci_data;
53 
54  uint64_t ioc_conf;
55  uint64_t tlb_enable;
56  uint64_t window_base_0;
57  uint64_t window_mask_0;
58  uint64_t window_t_base_0;
59  uint64_t window_base_1;
60  uint64_t window_mask_1;
61  uint64_t window_t_base_1;
62 };
63 
64 
65 /*
66  * lca_interrupt_assert():
67  *
68  * Line 0 = ISA interrupt.
69  */
71 {
72  fatal("lca_interrupt_assert: TODO\n");
73  exit(1);
74 }
75 
76 
77 /*
78  * lca_interrupt_deassert():
79  *
80  * Line 0 = ISA interrupt.
81  */
83 {
84  fatal("lca_interrupt_deassert: TODO\n");
85  exit(1);
86 }
87 
88 
89 DEVICE_ACCESS(lca_pci_conf)
90 {
91  uint64_t idata = 0, odata = 0;
92  int tag, bus, dev, func, reg;
93  struct lca_data *d = (struct lca_data *) extra;
94 
95  if (writeflag == MEM_WRITE)
96  idata = memory_readmax64(cpu, data, len);
97 
98  /*
99  * 1. Decompose the address into a tag.
100  *
101  * According to NetBSD's lca_pci.c, the address is composed like this:
102  *
103  * addr = tag << 5 | (regoffset & ~0x03) << 5 | 0x3 << 3
104  */
105  reg = (relative_addr >> 5) & 0xfc;
106  tag = (relative_addr >> 5) & ~0xff;
107 
108  /*
109  * 2. Decompose the tag into bus, dev, and func.
110  *
111  * The tag can be constructed in one of two ways. On the primary
112  * bus (nr 0):
113  *
114  * tag = (1 << (device + 11)) | (function << 8);
115  *
116  * and on other busses, the tag is a normal:
117  *
118  * tag = (bus << 16) | (device << 11) | (function << 8)
119  */
120  /* printf("tag = 0x%x\n", (int)tag); */
121  bus = d->ioc_conf & 1;
122 
123  if (bus == 0) {
124  for (dev=0; dev<21; dev++)
125  if (tag & (0x800 << dev))
126  break;
127  if (dev >= 21) {
128  /* fatal("[ LCA: No bus 0 device? TODO ]\n");
129  exit(1); */
130  dev = 0;
131  }
132  } else {
133  fatal("TODO. Non-zero bus.\n");
134  exit(1);
135  }
136 
137  func = (tag >> 8) & 7;
138  /* printf("bus=%i dev=%i func=%i reg=%i\n", bus,dev,func,reg); */
139 
140  /* Pass PCI accesses onto bus_pci: */
141  bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg);
142  bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
143  &odata : &idata, len, writeflag);
144 
145  if (writeflag == MEM_READ)
146  memory_writemax64(cpu, data, len, odata);
147 
148  return 1;
149 }
150 
151 
153 {
154  unsigned int ofs, i;
155  uint8_t byte;
156 
157  relative_addr >>= 5;
158 
159  ofs = relative_addr & 3;
160  if (ofs > len) {
161  fatal("[ ofs=%i len=%i in lca_isa access function. "
162  "aborting ]\n", ofs, len);
163  exit(1);
164  }
165 
166  if (writeflag == MEM_WRITE) {
167  byte = data[ofs % len];
168  return cpu->memory_rw(cpu, cpu->mem, LCA_ISA_BASE +
169  relative_addr, &byte, 1, writeflag, CACHE_NONE);
170  }
171 
172  cpu->memory_rw(cpu, cpu->mem, LCA_ISA_BASE + relative_addr,
173  &byte, 1, MEM_READ, CACHE_NONE);
174 
175  for (i=0; i<len; i++)
176  data[i] = i == ofs? byte : 0x00;
177 
178  return 1;
179 }
180 
181 
183 {
184  uint64_t idata = 0, odata = 0;
185  struct lca_data *d = (struct lca_data *) extra;
186 
187  if (writeflag == MEM_WRITE)
188  idata = memory_readmax64(cpu, data, len);
189 
190  switch (relative_addr + LCA_IOC_BASE) {
191 
192  case LCA_IOC_BASE:
193  /* Ignore? Linux reads from the base at startup. */
194  break;
195 
196  case LCA_IOC_CONF:
197  if (writeflag == MEM_READ) {
198  odata = d->ioc_conf;
199  } else {
200  d->ioc_conf = idata;
201  /* Only bit 0 is implemented so far, the PCI bus 0 vs
202  bus non-0 selection bit. */
203  if (idata & ~1) {
204  fatal("TODO: Write to unimplemented bit of"
205  " IOC_CONF: 0x%x\n", (int)idata);
206  exit(1);
207  }
208  }
209  break;
210 
211  case LCA_IOC_TBIA:
212  /* TLB Invalidate All. */
213  /* TODO: For now, let's just ignore it. */
214  break;
215 
216  case LCA_IOC_TB_ENA:
217  if (writeflag == MEM_READ) {
218  odata = d->tlb_enable;
219  } else {
220  d->tlb_enable = idata;
221  /* TODO: Actually implement this. */
222  if (idata & ~IOC_TB_ENA_TEN) {
223  fatal("TODO: LCA_IOC_TB_ENA value "
224  " (0x%" PRIx64") has unimplemented "
225  "bits.\n", (uint64_t)idata);
226  exit(1);
227  }
228  }
229  break;
230 
231  case LCA_IOC_W_BASE0:
232  if (writeflag == MEM_READ) {
233  odata = d->window_base_0;
234  } else {
235  d->window_base_0 = idata;
236  /* TODO: Actually implement this. */
237  if (idata != 0ULL && idata != 0x300800000ULL) {
238  fatal("TODO: LCA_IOC_W_BASE0 value differs"
239  " (0x%" PRIx64") from the only implemented"
240  " values\n", (uint64_t)idata);
241  exit(1);
242  }
243  }
244  break;
245 
246  case LCA_IOC_W_MASK0:
247  if (writeflag == MEM_READ) {
248  odata = d->window_mask_0;
249  } else {
250  d->window_mask_0 = idata;
251  /* TODO: Actually implement this. */
252  if (idata != 0x700000ULL) {
253  fatal("TODO: LCA_IOC_W_MASK0 value differs"
254  " (0x%" PRIx64") from the only implemented"
255  " value\n", (uint64_t)idata);
256  exit(1);
257  }
258  }
259  break;
260 
261  case LCA_IOC_W_T_BASE0:
262  if (writeflag == MEM_READ) {
263  odata = d->window_t_base_0;
264  } else {
265  d->window_t_base_0 = idata;
266  /* TODO: Actually implement this. */
267  }
268  break;
269 
270  case LCA_IOC_W_BASE1:
271  if (writeflag == MEM_READ) {
272  odata = d->window_base_1;
273  } else {
274  d->window_base_1 = idata;
275  /* TODO: Actually implement this. */
276  if (idata != 0x240000000ULL) {
277  fatal("TODO: LCA_IOC_W_BASE1 value differs"
278  " (0x%" PRIx64") from the only implemented"
279  " value\n", (uint64_t)idata);
280  exit(1);
281  }
282  }
283  break;
284 
285  case LCA_IOC_W_MASK1:
286  if (writeflag == MEM_READ) {
287  odata = d->window_mask_1;
288  } else {
289  d->window_mask_1 = idata;
290  /* TODO: Actually implement this. */
291  if (idata != 0x3ff00000ULL) {
292  fatal("TODO: LCA_IOC_W_MASK1 value differs"
293  " (0x%" PRIx64") from the only implemented"
294  " value\n", (uint64_t)idata);
295  exit(1);
296  }
297  }
298  break;
299 
300  case LCA_IOC_W_T_BASE1:
301  if (writeflag == MEM_READ) {
302  odata = d->window_t_base_1;
303  } else {
304  d->window_t_base_1 = idata;
305  /* TODO: Actually implement this. */
306  }
307  break;
308 
309  default:fatal("[ lca_ioc: unimplemented %s to offset 0x%x",
310  writeflag == MEM_WRITE? "write" : "read", (int)
311  relative_addr);
312  if (writeflag == MEM_WRITE)
313  fatal(": 0x%x", (int)idata);
314  fatal(" ]\n");
315  exit(1);
316  }
317 
318  if (writeflag == MEM_READ)
319  memory_writemax64(cpu, data, len, odata);
320 
321  return 1;
322 }
323 
324 
326 {
327  char *interrupt_path;
328  struct interrupt interrupt_template;
329  struct lca_data *d;
330 
331  CHECK_ALLOCATION(d = (struct lca_data *) malloc(sizeof(struct lca_data)));
332  memset(d, 0, sizeof(struct lca_data));
333 
334  /* Register a PCI bus: */
335  d->pci_data = bus_pci_init(
336  devinit->machine,
337  "TODO: irq" /* pciirq: TODO */,
338  LCA_PCI_SIO, /* pci device io offset */
339  0x00000000, /* pci device mem offset: TODO */
340  0x00000000, /* PCI portbase: TODO */
341  0x00000000, /* PCI membase: TODO */
342  "TODO: pci irq base", /* PCI irqbase: TODO */
343  LCA_ISA_BASE, /* ISA portbase */
344  LCA_ISA_MEMBASE, /* ISA membase */
345  "TODO: irqbase isa"); /* ISA irqbase: TODO */
346 
347  /* Add the "sio0" controller (as seen by NetBSD): */
349  0, 7, 0, "i82378zb");
350 
351  memory_device_register(devinit->machine->memory, "lca_pci_conf",
352  LCA_PCI_CONF, 0x20000000, dev_lca_pci_conf_access, (void *)d,
353  DM_DEFAULT, NULL);
354 
356  LCA_PCI_SIO, 0x10000 << 5, dev_lca_isa_access, (void *)d,
357  DM_DEFAULT, NULL);
358 
360  LCA_IOC_BASE, 0x20000000, dev_lca_ioc_access, (void *)d,
361  DM_DEFAULT, NULL);
362 
363  CHECK_ALLOCATION(interrupt_path = (char *)
364  malloc(strlen(devinit->machine->path) + 10));
365  snprintf(interrupt_path, strlen(devinit->machine->path) + 10,
366  "%s.lca", devinit->machine->path);
367 
368  memset(&interrupt_template, 0, sizeof(interrupt_template));
369  interrupt_template.line = 0;
370  interrupt_template.name = interrupt_path;
371  interrupt_template.extra = d;
372  interrupt_template.interrupt_assert = lca_interrupt_assert;
373  interrupt_template.interrupt_deassert = lca_interrupt_deassert;
374  interrupt_handler_register(&interrupt_template);
375 
376  bus_isa_init(devinit->machine, interrupt_path,
378 
379  return 1;
380 }
381 
#define IOC_TB_ENA_TEN
Definition: alpha_lcareg.h:71
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
void fatal(const char *fmt,...)
Definition: main.cc:152
uint64_t window_t_base_0
Definition: dev_lca.cc:58
void(* interrupt_assert)(struct interrupt *)
Definition: interrupt.h:38
#define DM_DEFAULT
Definition: memory.h:130
#define LCA_IOC_TBIA
Definition: alpha_lcareg.h:69
struct memory * mem
Definition: cpu.h:362
#define LCA_PCI_SIO
Definition: alpha_lcareg.h:45
#define LCA_ISA_BASE
Definition: dev_lca.cc:47
void interrupt_handler_register(struct interrupt *templ)
Definition: interrupt.cc:81
DEVINIT(lca)
Definition: dev_lca.cc:325
#define MEM_READ
Definition: memory.h:116
void(* interrupt_deassert)(struct interrupt *)
Definition: interrupt.h:39
uint64_t ioc_conf
Definition: dev_lca.cc:54
struct memory * memory
Definition: machine.h:126
void bus_pci_add(struct machine *machine, struct pci_data *pci_data, struct memory *mem, int bus, int device, int function, const char *name)
Definition: bus_pci.cc:217
uint64_t tlb_enable
Definition: dev_lca.cc:55
uint64_t window_mask_1
Definition: dev_lca.cc:60
#define reg(x)
#define LCA_IOC_W_T_BASE0
Definition: alpha_lcareg.h:75
uint64_t window_base_0
Definition: dev_lca.cc:56
DEVICE_ACCESS(lca_pci_conf)
Definition: dev_lca.cc:89
#define LCA_ISA_MEMBASE
Definition: dev_lca.cc:48
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
char * path
Definition: machine.h:108
void bus_pci_setaddr(struct cpu *cpu, struct pci_data *pci_data, int bus, int device, int function, int reg)
Definition: bus_pci.cc:197
int(* memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
Definition: cpu.h:365
#define LCA_IOC_W_MASK0
Definition: alpha_lcareg.h:74
u_short data
Definition: siireg.h:79
#define MEM_WRITE
Definition: memory.h:117
#define LCA_IOC_TB_ENA
Definition: alpha_lcareg.h:70
#define BUS_ISA_IDE1
Definition: bus_isa.h:59
Definition: device.h:40
uint64_t window_mask_0
Definition: dev_lca.cc:57
#define LCA_IOC_W_T_BASE1
Definition: alpha_lcareg.h:79
#define LCA_IOC_CONF
Definition: alpha_lcareg.h:54
uint64_t window_base_1
Definition: dev_lca.cc:59
uint32_t line
Definition: interrupt.h:51
Definition: cpu.h:326
struct machine * machine
Definition: device.h:41
char * name
Definition: interrupt.h:66
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
struct bus_isa_data * bus_isa_init(struct machine *machine, char *interrupt_base_path, uint32_t bus_isa_flags, uint64_t isa_portbase, uint64_t isa_membase)
Definition: bus_isa.cc:174
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
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
struct pci_data * pci_data
Definition: dev_lca.cc:52
#define LCA_PCI_CONF
Definition: alpha_lcareg.h:46
#define LCA_IOC_W_BASE0
Definition: alpha_lcareg.h:73
#define LCA_IOC_W_MASK1
Definition: alpha_lcareg.h:78
struct pci_data * bus_pci_init(struct machine *machine, const char *irq_path, uint64_t pci_actual_io_offset, uint64_t pci_actual_mem_offset, uint64_t pci_portbase, uint64_t pci_membase, const char *pci_irqbase, uint64_t isa_portbase, uint64_t isa_membase, const char *isa_irqbase)
Definition: bus_pci.cc:356
#define BUS_ISA_IDE0
Definition: bus_isa.h:58
void * extra
Definition: interrupt.h:59
void bus_pci_data_access(struct cpu *cpu, struct pci_data *pci_data, uint64_t *data, int len, int writeflag)
Definition: bus_pci.cc:96
#define LCA_IOC_BASE
Definition: alpha_lcareg.h:44
#define CACHE_NONE
Definition: memory.h:123
void lca_interrupt_deassert(struct interrupt *interrupt)
Definition: dev_lca.cc:82
uint64_t window_t_base_1
Definition: dev_lca.cc:61
#define LCA_IOC_W_BASE1
Definition: alpha_lcareg.h:77
void lca_interrupt_assert(struct interrupt *interrupt)
Definition: dev_lca.cc:70

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13