* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: sparse_mem.h
* 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 ============================================
#ifndef __IOMEM_SPARSE_MEM_H__
#define __IOMEM_SPARSE_MEM_H__
#define switch_endian16(a) (ss_byteswap16(a))
#define switch_endian32(a) (ss_byteswap32(a))
#define switch_endian64(a) (ss_byteswap64(a))
#define switch_endian16(a) (a)
#define switch_endian32(a) (a)
#define switch_endian64(a) (a)
class SparseMemory
:public ioMemIntf
/*{{{*/
void SparseMemory::load_elf64_section(Elf64_Shdr
*shdr
, Elf_Scn
*scn
,
uint64_t base_pa
, uint64_t base_va
);
static const int SAM_NMEM_LOCKS
= 1<<3;
// 8, should be power of 2
// maintain coherence at 8 byte level only
SparseMemory( uint64_t ram_size
=0, uint_t _l1bits
=18, uint_t _l2bits
=10, uint_t _l3bits
=20 );
void setId(const char * n
){ name
= strdup(n
); }
uint64_t get_size() { return size
; }
// get_base() is a private method and should not be used
uint8_t* get_base() { return NULL
; }
int load_img( const char* mem_image_filename
, uint64_t start_pa
);
int load_bin( const char *file
, uint64_t addr
);
int load_elf( const char *filename
, uint64_t base_pa
);
int save( const char* filename
, uint64_t addr
, uint64_t size
);
// Supported Store Operations. st8(), st16(), st32() and st64() are gueranteed to be atomic.
// st128() and st512() are atomic per 64bit quantity.
void st8( uint64_t addr
, uint8_t data
)
*(uint8_t*)(get_st_ptr(addr
)) = data
;
void st16( uint64_t addr
, uint16_t data
)
*(uint16_t*)(get_st_ptr(addr
)) = switch_endian16(data
);
void st32( uint64_t addr
, uint32_t data
)
*(uint32_t*)(get_st_ptr(addr
)) = switch_endian32(data
);
void st64_nl( uint64_t addr
, uint64_t data
)
*(uint64_t*)(get_st_ptr(addr
)) = switch_endian64(data
);
void st64 ( uint64_t addr
, uint64_t data
)
st64_nl(addr
,switch_endian64(data
));
void st128( uint64_t addr
, uint64_t data
[2] )
uint8_t* ptr
= get_st_ptr(addr
& ~uint64_t(0x1f));
*(uint64_t*)(ptr
+ 0) = switch_endian64(data
[0]);
*(uint64_t*)(ptr
+ 8) = switch_endian64(data
[1]);
void st512( uint64_t addr
, uint64_t data
[8] )
uint8_t* ptr
= get_st_ptr(addr
& ~uint64_t(0x3f));
*(uint64_t*)(ptr
+ 0) = switch_endian64(data
[0]);
*(uint64_t*)(ptr
+ 8) = switch_endian64(data
[1]);
*(uint64_t*)(ptr
+ 16) = switch_endian64(data
[2]);
*(uint64_t*)(ptr
+ 24) = switch_endian64(data
[3]);
*(uint64_t*)(ptr
+ 32) = switch_endian64(data
[4]);
*(uint64_t*)(ptr
+ 40) = switch_endian64(data
[5]);
*(uint64_t*)(ptr
+ 48) = switch_endian64(data
[6]);
*(uint64_t*)(ptr
+ 56) = switch_endian64(data
[7]);
uint8_t ld8u ( uint64_t addr
)
return *(uint8_t *)(get_ld_ptr(addr
));
int8_t ld8s( uint64_t addr
)
return *( int8_t *)(get_ld_ptr(addr
));
uint16_t ld16u( uint64_t addr
)
return switch_endian16(*(uint16_t*)(get_ld_ptr(addr
)));
int16_t ld16s( uint64_t addr
)
return switch_endian16(*( int16_t*)(get_ld_ptr(addr
)));
uint32_t ld32u( uint64_t addr
)
return switch_endian32(*(uint32_t*)(get_ld_ptr(addr
)));
int32_t ld32s( uint64_t addr
)
return switch_endian32(*( int32_t*)(get_ld_ptr(addr
)));
uint64_t ld64( uint64_t addr
)
return switch_endian64(*(uint64_t*)(get_ld_ptr(addr
)));
void ld128( uint64_t addr
, uint64_t data
[2] )
uint8_t* ptr
= get_ld_ptr(addr
);
data
[0] = switch_endian64(*(uint64_t*)(ptr
+ 0));
data
[1] = switch_endian64(*(uint64_t*)(ptr
+ 8));
void ld512( uint64_t addr
, uint64_t data
[8] )
uint8_t* ptr
= get_ld_ptr(addr
& ~uint64_t(0x3f));
data
[0] = switch_endian64(*(uint64_t*)(ptr
+ 0));
data
[1] = switch_endian64(*(uint64_t*)(ptr
+ 8));
data
[2] = switch_endian64(*(uint64_t*)(ptr
+ 16));
data
[3] = switch_endian64(*(uint64_t*)(ptr
+ 24));
data
[4] = switch_endian64(*(uint64_t*)(ptr
+ 32));
data
[5] = switch_endian64(*(uint64_t*)(ptr
+ 40));
data
[6] = switch_endian64(*(uint64_t*)(ptr
+ 48));
data
[7] = switch_endian64(*(uint64_t*)(ptr
+ 56));
void ld256( uint64_t addr
, uint64_t data
[4] )
uint8_t* ptr
= get_ld_ptr(addr
& ~uint64_t(0x1f));
data
[0] = switch_endian64(*(uint64_t*)(ptr
+ 0));
data
[1] = switch_endian64(*(uint64_t*)(ptr
+ 8));
data
[2] = switch_endian64(*(uint64_t*)(ptr
+ 16));
data
[3] = switch_endian64(*(uint64_t*)(ptr
+ 24));
int block_read(uint64_t addr
, uint8_t *tgt
, int _size
);
int block_write(uint64_t addr
, const uint8_t *src
, int _size
);
int restore ( FILE * fp
);
// no mem page allocation on load accesses;
// if load goes to uninit location - return unknow value;
uint8_t* get_ld_ptr ( uint64_t addr
)
uint8_t*** o1
= (uint8_t***)((char*)l1
+ ((addr
>> l1shft
) & l1mask
));
return uninit_page
+ ( addr
& 0x7 );
uint8_t** o2
= (uint8_t**)((char*)l2
+ ((addr
>> l2shft
) & l2mask
));
return uninit_page
+ ( addr
& 0x7 );
return l3
+ (addr
& l3mask
);
// allocate mem page if store goes to uninit location;
// acquire a lock to prevent multiple writers on MP run;
uint8_t* get_st_ptr( uint64_t addr
)
uint8_t*** o1
= (uint8_t***)((char*)l1
+ ((addr
>> l1shft
) & l1mask
) );
// check again if level 2 table is already allocated
l2
= *o1
= (uint8_t**)calloc(l2size
,sizeof(uint8_t));
uint8_t** o2
= (uint8_t**)((char*)l2
+ ((addr
>> l2shft
) & l2mask
));
// check again if level 3 page is already allocated
l3
= *o2
= (uint8_t*)calloc(l3size
,sizeof(uint8_t));
mutex_unlock ( &l3_lock
);
return l3
+ (addr
& l3mask
);
uint64_t get_l1size() { return l1size
; }
uint64_t get_l2size() { return l2size
; }
uint64_t get_l3size() { return l3size
; }
void lock ( uint64_t addr
) { mutex_lock ( &locks
[(addr
>> 4) & (SAM_NMEM_LOCKS
-1)] ); }
void unlock ( uint64_t addr
) { mutex_unlock ( &locks
[(addr
>> 4) & (SAM_NMEM_LOCKS
-1)] ); }
uint8_t uninit_page
[512];
mutex_t locks
[SAM_NMEM_LOCKS
];
#endif //__IOMEM_SPARSE_MEM_H__