Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / devices / mem_bus / libio / io.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: io.c
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23/*
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#pragma ident "@(#)io.c 1.4 07/03/23 SMI"
29
30/*
31 * Complete the parsing of a generic I/O device.
32 *
33 * Pick out the relevent info and allocated the
34 * simcpu_t structure in the config_cpu that
35 * gets handed to us.
36 */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <fcntl.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <sys/mman.h>
45#include <errno.h>
46#include <strings.h>
47
48#include "basics.h"
49#include "allocate.h"
50#include "lexer.h"
51#include "simcore.h"
52#include "config.h"
53#include "dumpinfo.h"
54#include "strutil.h"
55#include "fatal.h"
56#include "sparcv9regs.h"
57#include "device.h"
58#include "bswap.h"
59
60
61/*
62 * static only to avoid name clashes with other
63 * modules ... in reality these are exported
64 * via the cpu_type_t struct pointers
65 */
66static void io_parse(config_dev_t *);
67static void io_init(config_dev_t *);
68static void io_dump(config_dev_t *);
69static tpaddr_t io_cacheable(config_addr_t *, dev_access_t type,
70 tpaddr_t off, uint8_t **cbp);
71static bool_t io_cpu_access(simcpu_t *, config_addr_t *, tpaddr_t off,
72 maccess_t op, uint64_t *regp);
73
74dev_type_t dev_type_io = {
75 "io",
76 io_parse,
77 io_init,
78 io_dump,
79 generic_device_non_cacheable,
80 io_cpu_access,
81 DEV_MAGIC
82};
83
84typedef struct {
85 uint8_t access_sizes;
86 bool_t is_le; /* Little Endian Device */
87 bool_t is_rom; /* mmap file with MAP_PRIVATE flag */
88 uint8_t *datap;
89 uint64_t size; /* size of I/O segment */
90} io_dev_t;
91
92
93/*
94 * Complete the creation and parsing of the io directives
95 *
96 * Format for parsing internal io data is:
97 *
98 * rom : This is a ROM device i.e no writes allowed
99 * le : This is a Little Endian device
100 * access_sizes : Bitmask of valid access sizes for this device
101 * Bit0 : Byte access ( 8 bit )
102 * Bit1 : Half word access ( 16 bit )
103 * Bit2 : Long word access ( 32 bit )
104 * Bit3 : Xtended word access ( 64 bit )
105 */
106
107void
108io_parse(config_dev_t *config_devp)
109{
110 lexer_tok_t tok;
111 io_dev_t *iodp;
112 uint64_t io_segment_size; /* initial value of iodp->size */
113 long pgsize;
114
115 pgsize = getpagesize();
116
117 /*
118 * Allocate the io device and all that stuff
119 */
120 iodp = Xcalloc(1, io_dev_t);
121
122 iodp->access_sizes = 1 + 2 + 4 + 8; /* 1 2 4 or 8 byte accesses */
123 iodp->is_le = false;
124 iodp->datap = (void*)0;
125 iodp->size = config_devp->addrp->range;
126
127/* CSTYLED */
128DBG( printf("io_parse: parsing device %d\n", config_devp->device_id); );
129
130 tok = lex_get_token();
131 switch (tok) {
132 case T_S_Colon:
133 goto finished; /* nothing more to parse */
134 case T_L_Brace:
135 break;
136 default:
137 lex_fatal("expecting either ; or { when parsing io device");
138 }
139
140
141 /*
142 * Start the parsing loop
143 */
144 do {
145 char *fnamep;
146 uint64_t startoffset = 0LL;
147 uint64_t foffset = 0LL;
148 uint64_t flen = 0LL;
149 struct stat sb;
150 int idx;
151
152 tok = lex_get_token();
153
154 if (tok == T_R_Brace) break;
155
156 if (tok != T_Token) {
157 }
158
159 if (streq(lex.strp, "rom")) {
160 iodp->is_rom = true;
161 lex_get(T_S_Colon);
162 continue;
163 } else if (streq(lex.strp, "le")) {
164 iodp->is_le = true;
165 lex_get(T_S_Colon);
166 continue;
167 } else if (streq(lex.strp, "access_sizes")) {
168 tok = lex_get_token();
169 if (tok != T_Number) {
170 printf("tok=%x %d\n", tok, tok);
171 lex_fatal("Expected a number after access_sizes (e.g 0x1 0x2 0x7 0x8 or 0xf)");
172 }
173 iodp->access_sizes = lex.val;
174 lex_get(T_S_Colon);
175 continue;
176 }
177
178 tok = lex_get_token();
179
180 switch (tok) {
181 case T_Plus:
182 lex_get(T_Number);
183 startoffset = lex.val;
184 break;
185 case T_Number:
186 if (lex.val < config_devp->addrp->baseaddr ||
187 lex.val >= config_devp->addrp->topaddr)
188 lex_fatal("specified load address is outside the "
189 "range of the io device");
190
191 startoffset = lex.val - config_devp->addrp->baseaddr;
192 break;
193 default:
194 lex_fatal("Expected either a start address / offset or filename "
195 "for io device load directive");
196 }
197
198 lex_get(T_S_Colon);
199
200 } while (1);
201
202finished:;
203 config_devp->devp = iodp;
204}
205
206void
207io_init(config_dev_t *config_devp)
208{
209 long pgsize;
210 io_dev_t *iodp;
211
212 iodp = (io_dev_t *)config_devp->devp;
213 pgsize = getpagesize();
214
215 if (iodp->size < pgsize) {
216 DBG( fprintf(stderr, "Using realloc %p size %x\n", iodp, iodp->size); );
217
218 iodp->datap = Xrealloc(iodp->datap, iodp->size);
219 return;
220 }
221 DBG( fprintf(stderr, "Using mmap %p size %x\n", iodp, iodp->size); );
222 iodp->datap = iodp->datap = (void*)mmap(NULL, sim_roundup(iodp->size, pgsize),
223 PROT_READ | PROT_WRITE,
224 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
225 if (MAP_FAILED == iodp->datap) fatal("Initial mmap of anon memory failed");
226
227 return;
228}
229
230
231
232
233
234
235/*
236 * I/O configuration dump
237 */
238
239void
240io_dump(config_dev_t *config_devp)
241{
242}
243
244/*
245 * Should only get invoked if this is a ROM.
246 * Indicate the store failed - return false
247 * ROMs are read only.
248 */
249
250bool_t
251io_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset, maccess_t op, uint64_t *regp)
252{
253 io_dev_t *iodp;
254 bool_t ret = true;
255
256 iodp = cap->config_devp->devp;
257
258 if ((offset < 0) || (offset >= cap->range)) {
259 return false;
260 }
261
262 if (((1 << (op & MA_Size_Mask)) & iodp->access_sizes) == 0) {
263 EXEC_WARNING(("Access size of %d bytes is not valid for this "
264 "device [PA=0x%llx, SIZE=0x%llx] @ %%PC 0x%llx "
265 "offset 0x%llx", (1 << (op & MA_Size_Mask)),
266 cap->baseaddr, cap->range, sp->pc, offset));
267 /* return success anyways !!! */
268 return (false);
269 }
270
271 switch(op & MA_Op_Mask) {
272 case MA_Ld:
273 switch(op & MA_Size_Mask) {
274 case MA_Size8:
275 *regp = *(uint8_t *)(iodp->datap + offset);
276 break;
277 case MA_Size16:
278 *regp = iodp->is_le ? BSWAP_16(*(uint16_t *)(iodp->datap + offset)) :
279 *(uint16_t *)(iodp->datap + offset);
280 break;
281 case MA_Size32:
282 *regp = iodp->is_le ? BSWAP_32(*(uint32_t *)(iodp->datap + offset)) :
283 *(uint32_t *)(iodp->datap + offset);
284 break;
285 case MA_Size64:
286 *regp = iodp->is_le ? BSWAP_64(*(uint64_t *)(iodp->datap + offset)) :
287 *(uint64_t *)(iodp->datap + offset);
288 break;
289 default:
290 ret = false;
291 break;
292 }
293 break;
294
295 case MA_LdSigned:
296 switch(op & MA_Size_Mask) {
297 case MA_Size8:
298 *regp = *(int8_t *)(iodp->datap + offset);
299 break;
300 case MA_Size16:
301 *regp = iodp->is_le ? (sint16_t)BSWAP_16(*(uint16_t *)(iodp->datap + offset)) :
302 *(sint16_t *)(iodp->datap + offset);
303 break;
304 case MA_Size32:
305 *regp = iodp->is_le ? (sint32_t)BSWAP_32(*(uint32_t *)(iodp->datap + offset)) :
306 *(sint32_t *)(iodp->datap + offset);
307 break;
308 default:
309 ret = false;
310 break;
311 }
312 break;
313 case MA_St:
314 if (iodp->is_rom) {
315 EXEC_WARNING(("rom_cpu_store: attempted store to ROM @ %%PC 0x%llx "
316 "of %d bytes at offset 0x%llx",
317 sp->pc, 1 << (op & MA_Size_Mask), offset));
318 /* Return success anyways !! */
319 return (true);
320 }
321 switch(op & MA_Size_Mask) {
322 case MA_Size8:
323 *((int8_t *)(iodp->datap + offset)) = *regp;
324 break;
325 case MA_Size16:
326 *((int16_t *)(iodp->datap + offset)) = iodp->is_le ? BSWAP_16(*regp) : *regp;
327 break;
328 case MA_Size32:
329 *((int32_t *)(iodp->datap + offset)) = iodp->is_le ? BSWAP_32(*regp) : *regp;
330 break;
331 case MA_Size64:
332 *((int64_t *)(iodp->datap + offset)) = iodp->is_le ? BSWAP_64(*regp) : *regp;
333 break;
334 default:
335 ret = false;
336 break;
337 }
338 break;
339 default:
340 ret = false;
341 break;
342 }
343
344 return ret;
345}
346