// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: ioram.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
int iomem_ui_cmd(void * obj
, int argc
, char * argv
[]){
IOMem
* i
= (IOMem
*)obj
;
i
->handle_ui(argc
, argv
);
static const char * iomem_help
= "SAM IOMem module\n \
sysconf iosram <instance name> start_pa=<addr> size=<size> [file=<name> [addr=<load_addr>]] [rw|ro|wo] [sparse|flat]\n \
The default is zero filled RW memory with Flat impl.\n \
For \'file\' , \'addr\' must be absolute PA. Default \'addr\'=\'start_pa\'\n \
The filename must have a .bin, .img or .elf extension. .img files need not supply \'addr\'\n \
For UI help type <instance name>";
Module::get_help_string(){
Module::create(const char *_modname
, const char *_instance_name
){
return new IOMem(_modname
, _instance_name
);
/***********************************************************/
IOMem::IOMem(const char *_modname
, const char *_instance_name
)
: Module(_modname
, _instance_name
){
ft
= NONE
; // zero filled
at
= RW
; // allow read write
mt
= FLAT
; // FLAT memory model
const char *IOMem::get_help(){
return get_help_string();
// print info about the module
printf("%s: SAM IOMem module\n", getName());
printf("start paddr <0x%llx, end paddr <0x%llx>\n",sAddr
,eAddr
);
printf("loaded with file <%s> at addr <%llx>\n", loadFile
?loadFile
:"none - zero filled", loadAddr
);
printf("s/w access <%s>, implementation <%s model>\n", \
(at
== RW
? "rw":(at
== RO
? "RO":"WO")), mt
== SPARSE
? "sparse":"flat" );
printf("for UI help type %s\n",getName());
// parse the arguments for ram module
IOMem::parse_arg(const char * arg
){
if(argval("start_pa",arg
,&sAddr
)){
debug_more("%s: start_pa = %llx\n",getName(),sAddr
);
}else if(argval("size",arg
,&mem_size
)){
debug_more("%s: size = %llx\n",getName(),mem_size
);
}else if(argval("file",arg
,&loadFile
)){
debug_more("%s: load file = %s\n",getName(), loadFile
);
const char * p
= loadFile
+ strlen(loadFile
) - 4;
else if(!strcmp(p
,".img"))
else if(!strcmp(p
,".elf"))
debug_err("%s: could not identify file type from extension. memory zero filled\n", getName());
}else if(argval("addr",arg
,&loadAddr
)){
debug_more("%s: file load address = %llx\n", loadAddr
);
}else if(!strcmp(arg
,"rw")){
}else if(!strcmp(arg
,"ro")){
}else if(!strcmp(arg
,"wo")){
}else if(!strcmp(arg
,"sparse")){
}else if(!strcmp(arg
,"flat")){
// check if necessary arguments have been supplied in
// configuration file. Initialization fails if returns false.
debug_err("%s: ERROR: must specify start address\n", getName());
debug_err("%s: ERROR: must specify size\n", getName());
// all arguments have been parsed and checked.
// align the size to an 8 byte boundary.
mem_size
= (mem_size
/8)*8 + 8;
eAddr
= sAddr
+ mem_size
- 1;
else if(addrInvalid(loadAddr
)){
debug_err("file load addr invalid, setting to %llx\n",sAddr
);
if(mmi_map_physio(sAddr
,mem_size
, this , iomemLdSt
) != 0){
debug_err("%s: failed to map the addresses to IOMem \n exit...", getName());
memIf
= new SparseMemory(mem_size
);
debug_err("%s: Flat memory not yet implemented. Using sparse model\n",getName());
// memIf = new FlatMemory(mem_size);
memIf
= new SparseMemory(mem_size
);
memIf
->load_bin(loadFile
,loadAddr
- sAddr
);
memIf
->load_img(loadFile
, sAddr
);
memIf
->load_elf(loadFile
,loadAddr
- sAddr
);
mmi_register_instance_cmd(getInstance(),iomem_help
,iomem_ui_cmd
);
// callback function. called whenever there is a ld/st in the address
// range from sAddr to eAddr, hence no range check is needed here
int iomemLdSt(uint32_t cpuid
, void* obj
, uint64_t paddr
, mmi_bool_t wr
, uint32_t size
, \
uint64_t* buf
, uint8_t bytemask
){
return s
->iomemHandler(cpuid
,paddr
,wr
,size
,buf
,bytemask
);
// handle the r/w access from cpu
IOMem::iomemHandler(uint32_t cpuid
,uint64_t paddr
, mmi_bool_t wr
, uint32_t size
, uint64_t* buf
, uint8_t bytemask
){
error
= iomemWrite(paddr
- sAddr
,*buf
,size
);
error
= iomemRead(paddr
- sAddr
,buf
,size
);
// print a debug message if debug_level > 1
debug_more("IOMem %s:%s xactn from cpu %d at address %llx, size %d, buf %llx\n",\
getName(),wr
?"write":"read",cpuid
,paddr
,size
,*buf
);
int IOMem::iomemWrite(uint64_t addr
, uint64_t buf
, int size
){
debug_err("%s - write @ offset %llx : configured as RO memory\n", getName(),addr
);
debug_err("%s write: unsupported size %d, ... ignored\n", getName(), size
);
int IOMem::iomemRead(uint64_t addr
, uint64_t * buf
, int size
){
*buf
= memIf
->ld8u(addr
);
*buf
= memIf
->ld16u(addr
);
*buf
= memIf
->ld32u(addr
);
*buf
= memIf
->ld64(addr
);
debug_err("%s read: unsupported size %d, ... ignored\n", getName(), size
);
void IOMem::ui_cmd_usage(){
printf("ui format: %s <command> <command args> ...\n",getName());
printf("%s supports following ui commands\n",getName());
printf(" write <addr> <value> <size> \n\
write \'size\' bytes to memory at address \'addr\'where, size=[1|2|4|8]\n");
printf(" read <addr> <size>\n\
read \'size\' bytes from memory at address \'addr\'where, size=[1|2|4|8]\n");
printf(" dis <addr> [<n_instr>]\n\
disassemble \'n_instr\' instructions (default 1) starting from address \'addr\'\n");
printf(" dump <addr> <size> [<format>]\n\
dump \'size\' bytes of memory on stdout\n\
where \'format\' is [x|d|c|o], default x\n");
printf(" save <filename> [<addr> [<size>]]\n\
save the memory contents in \'filename\' starting from \'addr\' for \'size\' bytes.\n\
If no \'addr\' and \'size\' arguments provided, save all\n\
If \'addr\' is supplied, but no \'size\', save till the end\n");
printf(" All numerical values are expected either in decimal/octal/hex \n");
printf(" The \'addr\' argument is an absolute physical address\n");
void IOMem::handle_ui(int argc
, char * argv
[]){
if(!strcmp(argv
[1],"write"))
else if(!strcmp(argv
[1],"read"))
else if(!strcmp(argv
[1],"save"))
else if(!strcmp(argv
[1],"dump"))
else if(!strcmp(argv
[1],"dis"))
debug_err("%s: unsupported UI %s\n",getName(),argv
[1]);
bool IOMem::getNum(const char * s
, uint64_t * val
){
bool IOMem::numArgsOK(int argc
, char * args
[]){
for(int i
= 0; i
< argc
; i
++)
bool IOMem::addrInvalid(uint64_t addr
){
void IOMem::ui_write(char * args
[]){
debug_err("%s write: wrong number of command arguments\n", getName());
uint64_t size
, val
, addr
;
if(!getNum(args
[0], &addr
))
if(!getNum(args
[1], &val
))
if(!getNum(args
[2], &size
))
debug_err("%s write: addr out of range\n",getName());
if(size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8){
debug_err("%s write: unsupported write size\n", getName());
iomemWrite(addr
, val
, size
);
debug_err("%s write: error parsing arguments\n",getName());
void IOMem::ui_read(char * args
[]){
debug_err("%s read: wrong number of command arguments\n", getName());
uint64_t size
, addr
, val
= 0;
if(!getNum(args
[0], &addr
))
if(!getNum(args
[1], &size
))
debug_err("%s read: addr out of range\n",getName());
if(size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8){
debug_err("%s read: unsupported read size\n", getName());
iomemRead(addr
, &val
, size
);
debug_err("%s read: error parsing arguments\n",getName());
void IOMem::ui_dump(char * args
[]){
debug_err("%s dump: wrong number of command arguments\n", getName());
if(!getNum(args
[1], &size
))
if(!getNum(args
[0], &addr
))
debug_err("%s dump: addr out of range\n",getName());
if(addr
+ size
-1 > eAddr
){
debug_err("%s dump : cannot dump beyond segment size\n",getName());
size
= size
% 16 ? (size
/16+1) * 16 : size
;
char * format
= strdup(args
[2] ? args
[2]: "x");
if(format
[0] != 'x' && format
[0] != 'o' && format
[0] != 'd' && format
[0] != 'c'){
debug_err("%s dump: unrecognized format argument. Using hex\n", getName());
for( int i
= 0; i
< size
; i
++, j
++){
if( (j
>= 16) && (j
% 16 == 0) )
iomemRead(addr
+ i
, &c
, 1);
for( int i
= 0, j
= 0; i
< size
; i
+=2 , j
+=2 ){
iomemRead(addr
+ i
, &val
, 2);
if( (j
>= 16) && (j
% 16 == 0) )
else if(!strcmp(format
,"o"))
debug_err("%s dump: error parsing arguments\n",getName());
void IOMem::ui_dis(char * args
[]){
debug_err("%s dis: wrong number of command arguments\n", getName());
if(!getNum(args
[0], &addr
))
if(!getNum(args
[1], &n_instr
))
debug_err("%s dis: addr out of range\n",getName());
if((addr
+ n_instr
*4 > eAddr
)){
debug_err("%s dis: addr + n_instr*4 out of range\n",getName());
for(int i
= 0; i
< n_instr
; i
++){
iomemRead(addr
+ i
*4, &val
, 4);
disassemble(val
,sAddr
+ addr
+ i
*4,iline
,LSIZE
);
printf("0x%-20llx: 0x%-10llx : %s \n", addr
+ i
*4, val
, iline
);
debug_err("%s dis: error parsing arguments\n",getName());
void IOMem::ui_save(char * args
[]){
debug_err("%s save: wrong number of command arguments\n", getName());
if(!getNum(args
[0], &addr
))
else if(!getNum
, args
[1],&sz
)
debug_err("%s save: invalid addr value\n",getName());
}else if(addr
+ mem_size
- 1 > eAddr
){
debug_err("%s save: invalid addr/size values\n",getName());
printf("%s save: saving to file %s, start_pa=<%llx>, size=<%llx>\n",getName(),args
[0], addr
, sz
);
memIf
->save(args
[0],addr
- sAddr
,sz
);
bool IOMem::dump(FILE *fp
){
bool IOMem::restore(FILE *fp
){