Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / ioram / ioram.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: ioram.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21#include "ioram.h"
22
23
24int iomem_ui_cmd(void * obj, int argc, char * argv[]){
25 IOMem * i = (IOMem *)obj;
26 i->handle_ui(argc, argv);
27 return 0;
28}
29
30static const char * iomem_help = "SAM IOMem module\n \
31Sysconf format is :\n \
32sysconf iosram <instance name> start_pa=<addr> size=<size> [file=<name> [addr=<load_addr>]] [rw|ro|wo] [sparse|flat]\n \
33The default is zero filled RW memory with Flat impl.\n \
34For \'file\' , \'addr\' must be absolute PA. Default \'addr\'=\'start_pa\'\n \
35The filename must have a .bin, .img or .elf extension. .img files need not supply \'addr\'\n \
36For UI help type <instance name>";
37
38const char *
39Module::get_help_string(){
40 return iomem_help;
41}
42
43Module *
44Module::create(const char *_modname, const char *_instance_name){
45 return new IOMem(_modname, _instance_name);
46}
47
48/***********************************************************/
49
50IOMem::IOMem(const char *_modname, const char *_instance_name)
51 : Module(_modname, _instance_name){
52
53 sAddr = eAddr = -1;
54 mem_size = 0;
55 ft = NONE; // zero filled
56 at = RW; // allow read write
57 mt = FLAT; // FLAT memory model
58 loadFile = 0;
59 loadAddr = 0;
60 memIf = 0;
61}
62
63// one line help
64const char *IOMem::get_help(){
65 return get_help_string();
66}
67
68
69// print info about the module
70void IOMem::modinfo(){
71 printf("%s: SAM IOMem module\n", getName());
72 printf("start paddr <0x%llx, end paddr <0x%llx>\n",sAddr,eAddr);
73 printf("loaded with file <%s> at addr <%llx>\n", loadFile?loadFile:"none - zero filled", loadAddr);
74 printf("s/w access <%s>, implementation <%s model>\n", \
75 (at == RW ? "rw":(at == RO ? "RO":"WO")), mt == SPARSE ? "sparse":"flat" );
76 printf("for UI help type %s\n",getName());
77 return;
78}
79
80
81
82// parse the arguments for ram module
83bool
84IOMem::parse_arg(const char * arg){
85 if(argval("start_pa",arg,&sAddr)){
86 debug_more("%s: start_pa = %llx\n",getName(),sAddr);
87 return true;
88 }else if(argval("size",arg,&mem_size)){
89 debug_more("%s: size = %llx\n",getName(),mem_size);
90 return true;
91 }else if(argval("file",arg,&loadFile)){
92 debug_more("%s: load file = %s\n",getName(), loadFile);
93 const char * p = loadFile + strlen(loadFile) - 4;
94 if(!strcmp(p,".bin"))
95 ft = BIN;
96 else if(!strcmp(p,".img"))
97 ft = IMG;
98 else if(!strcmp(p,".elf"))
99 ft = ELF;
100 else
101 debug_err("%s: could not identify file type from extension. memory zero filled\n", getName());
102 return true;
103 }else if(argval("addr",arg,&loadAddr)){
104 debug_more("%s: file load address = %llx\n", loadAddr);
105 }else if(!strcmp(arg,"rw")){
106 at = RW;
107 return true;
108 }else if(!strcmp(arg,"ro")){
109 at = RO;
110 return true;
111 }else if(!strcmp(arg,"wo")){
112 at = WO;
113 return true;
114 }else if(!strcmp(arg,"sparse")){
115 mt = SPARSE;
116 return true;
117 }else if(!strcmp(arg,"flat")){
118 mt = FLAT;
119 return true;
120 }
121 return false;
122}
123
124
125// check if necessary arguments have been supplied in
126// configuration file. Initialization fails if returns false.
127bool
128IOMem::check_args(){
129 if(sAddr == -1){
130 debug_err("%s: ERROR: must specify start address\n", getName());
131 return false;
132 }else if(mem_size == 0){
133 debug_err("%s: ERROR: must specify size\n", getName());
134 return false;
135 }else
136 return true;
137}
138
139// all arguments have been parsed and checked.
140void
141IOMem::init_done(){
142// 1.
143
144
145 // align the size to an 8 byte boundary.
146 if(mem_size % 8 != 0)
147 mem_size = (mem_size/8)*8 + 8;
148
149 eAddr = sAddr + mem_size - 1;
150
151 if(loadAddr == 0)
152 loadAddr = sAddr;
153 else if(addrInvalid(loadAddr)){
154 debug_err("file load addr invalid, setting to %llx\n",sAddr);
155 loadAddr = sAddr;
156 }
157
158 if(mmi_map_physio(sAddr,mem_size, this , iomemLdSt) != 0){
159 debug_err("%s: failed to map the addresses to IOMem \n exit...", getName());
160 exit(1); // fatal error
161 }
162
163 if( mt == SPARSE )
164 memIf = new SparseMemory(mem_size);
165 else if( mt == FLAT ){
166 debug_err("%s: Flat memory not yet implemented. Using sparse model\n",getName());
167 // memIf = new FlatMemory(mem_size);
168 memIf = new SparseMemory(mem_size);
169 }
170
171 memIf->setId(getName());
172
173 if(ft == BIN)
174 memIf->load_bin(loadFile,loadAddr - sAddr);
175 else if(ft == IMG)
176 memIf->load_img(loadFile, sAddr);
177 else if(ft == ELF)
178 memIf->load_elf(loadFile,loadAddr - sAddr);
179
180 mmi_register_instance_cmd(getInstance(),iomem_help,iomem_ui_cmd);
181 return;
182}
183
184// callback function. called whenever there is a ld/st in the address
185// range from sAddr to eAddr, hence no range check is needed here
186int iomemLdSt(uint32_t cpuid, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, \
187uint64_t* buf, uint8_t bytemask){
188
189 IOMem* s = (IOMem*)obj;
190
191 return s->iomemHandler(cpuid,paddr,wr,size,buf,bytemask);
192}
193
194// handle the r/w access from cpu
195int
196IOMem::iomemHandler(uint32_t cpuid,uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask){
197
198 int error;
199
200 if(wr)
201 error = iomemWrite(paddr - sAddr,*buf,size);
202 else
203 error = iomemRead(paddr - sAddr,buf,size);
204
205 // print a debug message if debug_level > 1
206 debug_more("IOMem %s:%s xactn from cpu %d at address %llx, size %d, buf %llx\n",\
207 getName(),wr?"write":"read",cpuid,paddr,size,*buf);
208
209 return error;
210}
211
212int IOMem::iomemWrite(uint64_t addr, uint64_t buf, int size){
213
214 if(at == RO){
215 debug_err("%s - write @ offset %llx : configured as RO memory\n", getName(),addr);
216 return -1;
217 }
218
219 switch(size){
220 case 1:
221 memIf->st8(addr,buf);
222 return 0;
223 case 2:
224 memIf->st16(addr,buf);
225 return 0;
226 case 4:
227 memIf->st32(addr,buf);
228 return 0;
229 case 8:
230 memIf->st64(addr,buf);
231 return 0;
232 default:
233 debug_err("%s write: unsupported size %d, ... ignored\n", getName(), size);
234 return 0;
235 }
236}
237
238int IOMem::iomemRead(uint64_t addr, uint64_t * buf, int size){
239 switch(size){
240 case 1:
241 *buf = memIf->ld8u(addr);
242 return 0;
243 case 2:
244 *buf = memIf->ld16u(addr);
245 return 0;
246 case 4:
247 *buf = memIf->ld32u(addr);
248 return 0;
249 case 8:
250 *buf = memIf->ld64(addr);
251 return 0;
252 default:
253 debug_err("%s read: unsupported size %d, ... ignored\n", getName(), size);
254 return 0;
255 }
256}
257
258
259void IOMem::ui_cmd_usage(){
260 printf("ui format: %s <command> <command args> ...\n",getName());
261 printf("%s supports following ui commands\n",getName());
262 printf(" write <addr> <value> <size> \n\
263 write \'size\' bytes to memory at address \'addr\'where, size=[1|2|4|8]\n");
264 printf(" read <addr> <size>\n\
265 read \'size\' bytes from memory at address \'addr\'where, size=[1|2|4|8]\n");
266 printf(" dis <addr> [<n_instr>]\n\
267 disassemble \'n_instr\' instructions (default 1) starting from address \'addr\'\n");
268 printf(" dump <addr> <size> [<format>]\n\
269 dump \'size\' bytes of memory on stdout\n\
270 where \'format\' is [x|d|c|o], default x\n");
271 printf(" save <filename> [<addr> [<size>]]\n\
272 save the memory contents in \'filename\' starting from \'addr\' for \'size\' bytes.\n\
273 If no \'addr\' and \'size\' arguments provided, save all\n\
274 If \'addr\' is supplied, but no \'size\', save till the end\n");
275 printf(" All numerical values are expected either in decimal/octal/hex \n");
276 printf(" The \'addr\' argument is an absolute physical address\n");
277}
278
279void IOMem::handle_ui(int argc, char * argv[]){
280
281 if(argc == 1){
282 ui_cmd_usage();
283 return;
284 }else{
285 if(!strcmp(argv[1],"write"))
286 ui_write(&argv[2]);
287 else if(!strcmp(argv[1],"read"))
288 ui_read(&argv[2]);
289 else if(!strcmp(argv[1],"save"))
290 ui_save(&argv[2]);
291 else if(!strcmp(argv[1],"dump"))
292 ui_dump(&argv[2]);
293 else if(!strcmp(argv[1],"dis"))
294 ui_dis(&argv[2]);
295 else
296 debug_err("%s: unsupported UI %s\n",getName(),argv[1]);
297 }
298 return;
299}
300
301extern int errno;
302
303bool IOMem::getNum(const char * s, uint64_t * val){
304 errno = 0;
305 if(!s)
306 return false;
307 *val = strtoll(s,0,0);
308 if(errno)
309 return false;
310 return true;
311}
312bool IOMem::numArgsOK(int argc, char * args[]){
313 for(int i = 0; i < argc; i++)
314 if(!args[i])
315 return false;
316 return true;
317}
318
319bool IOMem::addrInvalid(uint64_t addr){
320 if(addr > eAddr)
321 return true;
322 if(addr < sAddr)
323 return true;
324 return false;
325}
326
327void IOMem::ui_write(char * args[]){
328 if(!numArgsOK(3,args)){
329 debug_err("%s write: wrong number of command arguments\n", getName());
330 return;
331 }
332
333 uint64_t size, val, addr;
334
335 if(!getNum(args[0], &addr))
336 goto ui_write_err;
337 if(!getNum(args[1], &val))
338 goto ui_write_err;
339 if(!getNum(args[2], &size))
340 goto ui_write_err;
341
342 if(addrInvalid(addr)){
343 debug_err("%s write: addr out of range\n",getName());
344 return;
345 }
346
347 if(size != 1 && size != 2 && size != 4 && size != 8){
348 debug_err("%s write: unsupported write size\n", getName());
349 return;
350 }
351
352 addr -= sAddr;
353 iomemWrite(addr, val, size);
354
355 return;
356ui_write_err:
357 debug_err("%s write: error parsing arguments\n",getName());
358}
359
360void IOMem::ui_read(char * args[]){
361 if(!numArgsOK(2,args)){
362 debug_err("%s read: wrong number of command arguments\n", getName());
363 return;
364 }
365
366 uint64_t size, addr, val = 0;
367
368 if(!getNum(args[0], &addr))
369 goto ui_read_err;
370 if(!getNum(args[1], &size))
371 goto ui_read_err;
372
373 if(addrInvalid(addr)){
374 debug_err("%s read: addr out of range\n",getName());
375 return;
376 }
377
378 if(size != 1 && size != 2 && size != 4 && size != 8){
379 debug_err("%s read: unsupported read size\n", getName());
380 return;
381 }
382
383 addr -= sAddr;
384
385 iomemRead(addr, &val , size);
386 printf("0x%llx\n",val);
387 fflush(stdout);
388 return;
389
390ui_read_err:
391 debug_err("%s read: error parsing arguments\n",getName());
392}
393
394
395void IOMem::ui_dump(char * args[]){
396 if(!numArgsOK(2,args)){
397 debug_err("%s dump: wrong number of command arguments\n", getName());
398 return;
399 }
400
401 uint64_t size, addr;
402
403 if(!getNum(args[1], &size))
404 goto ui_dump_err;
405 if(!getNum(args[0], &addr))
406 goto ui_dump_err;
407
408 if(addrInvalid(addr)){
409 debug_err("%s dump: addr out of range\n",getName());
410 return;
411 }
412
413 if(addr + size -1 > eAddr){
414 debug_err("%s dump : cannot dump beyond segment size\n",getName());
415 return;
416 }
417
418 addr -= sAddr;
419 size = size % 16 ? (size/16+1) * 16 : size;
420
421 char * format = strdup(args[2] ? args[2]: "x");
422 if(format[0] != 'x' && format[0] != 'o' && format[0] != 'd' && format[0] != 'c'){
423 debug_err("%s dump: unrecognized format argument. Using hex\n", getName());
424 free(format);
425 format = strdup("x");
426 }
427
428 if(!strcmp(format,"c")){
429 uint64_t c;
430 int j = 0;
431 for( int i = 0; i < size; i++, j++){
432 if( (j >= 16) && (j % 16 == 0) )
433 printf("\n");
434 iomemRead(addr + i, &c, 1);
435 if(j % 16 == 0)
436 printf("%010o ",i);
437 if(isprint(c))
438 printf("%3c ",c);
439 else
440 printf("%03lld ",c);
441 }
442 printf("\n");
443 fflush(stdout);
444 return;
445 }
446
447 for( int i = 0, j = 0; i < size; i+=2 , j+=2 ){
448 uint64_t val;
449
450 iomemRead(addr + i, &val, 2);
451 if( (j >= 16) && (j % 16 == 0) )
452 printf("\n");
453 if(j % 16 == 0)
454 printf("%010o ",i);
455 if(!strcmp(format,"x"))
456 printf("%04llx ",val);
457 else if(!strcmp(format,"o"))
458 printf("%06llo ",val);
459 else
460 printf("%05lld ",val);
461 }
462
463 printf("\n");
464 fflush(stdout);
465
466 return;
467
468ui_dump_err:
469 debug_err("%s dump: error parsing arguments\n",getName());
470}
471
472void IOMem::ui_dis(char * args[]){
473 if(!numArgsOK(1,args)){
474 debug_err("%s dis: wrong number of command arguments\n", getName());
475 return;
476 }
477
478 uint64_t n_instr, addr;
479
480 if(!getNum(args[0], &addr))
481 goto ui_dis_error;
482
483 if(args[1]){
484 if(!getNum(args[1], &n_instr))
485 goto ui_dis_error;
486 }else
487 n_instr = 1;
488
489 if(addrInvalid(addr)){
490 debug_err("%s dis: addr out of range\n",getName());
491 return;
492 }
493
494 if((addr + n_instr*4 > eAddr)){
495 debug_err("%s dis: addr + n_instr*4 out of range\n",getName());
496 return;
497 }
498
499 addr -= sAddr;
500
501 for(int i = 0; i < n_instr; i++){
502 uint64_t val;
503 const int LSIZE = 128;
504 char iline[LSIZE];
505 iomemRead(addr + i*4, &val, 4);
506 disassemble(val,sAddr + addr + i*4,iline,LSIZE);
507 printf("0x%-20llx: 0x%-10llx : %s \n", addr + i*4, val, iline);
508 }
509
510 fflush(stdout);
511
512 return;
513ui_dis_error:
514 debug_err("%s dis: error parsing arguments\n",getName());
515}
516
517void IOMem::ui_save(char * args[]){
518 uint64_t addr, sz;
519 if(!numArgsOK(1,args)){
520 debug_err("%s save: wrong number of command arguments\n", getName());
521 return;
522 }
523
524 if(!getNum(args[0], &addr))
525 addr = sAddr;
526 else if(!getNum, args[1],&sz)
527 sz = mem_size;
528
529 if(addrInvalid(addr)){
530 debug_err("%s save: invalid addr value\n",getName());
531 return;
532 }else if(addr + mem_size - 1 > eAddr){
533 debug_err("%s save: invalid addr/size values\n",getName());
534 return;
535 }
536
537 printf("%s save: saving to file %s, start_pa=<%llx>, size=<%llx>\n",getName(),args[0], addr, sz);
538 memIf->save(args[0],addr - sAddr,sz);
539 return;
540}
541
542bool IOMem::dump(FILE *fp){
543 assert(fp);
544 memIf->dump(fp);
545 return true;
546}
547bool IOMem::restore(FILE *fp){
548 assert(fp);
549 memIf->restore(fp);
550 return true;
551}
552
553