* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: io.c
* 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 ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)io.c 1.4 07/03/23 SMI"
* Complete the parsing of a generic I/O device.
* Pick out the relevent info and allocated the
* simcpu_t structure in the config_cpu that
* static only to avoid name clashes with other
* modules ... in reality these are exported
* via the cpu_type_t struct pointers
static void io_parse(config_dev_t
*);
static void io_init(config_dev_t
*);
static void io_dump(config_dev_t
*);
static tpaddr_t
io_cacheable(config_addr_t
*, dev_access_t type
,
tpaddr_t off
, uint8_t **cbp
);
static bool_t
io_cpu_access(simcpu_t
*, config_addr_t
*, tpaddr_t off
,
maccess_t op
, uint64_t *regp
);
dev_type_t dev_type_io
= {
generic_device_non_cacheable
,
bool_t is_le
; /* Little Endian Device */
bool_t is_rom
; /* mmap file with MAP_PRIVATE flag */
uint64_t size
; /* size of I/O segment */
* Complete the creation and parsing of the io directives
* Format for parsing internal io data is:
* rom : This is a ROM device i.e no writes allowed
* le : This is a Little Endian device
* access_sizes : Bitmask of valid access sizes for this device
* Bit0 : Byte access ( 8 bit )
* Bit1 : Half word access ( 16 bit )
* Bit2 : Long word access ( 32 bit )
* Bit3 : Xtended word access ( 64 bit )
io_parse(config_dev_t
*config_devp
)
uint64_t io_segment_size
; /* initial value of iodp->size */
* Allocate the io device and all that stuff
iodp
= Xcalloc(1, io_dev_t
);
iodp
->access_sizes
= 1 + 2 + 4 + 8; /* 1 2 4 or 8 byte accesses */
iodp
->size
= config_devp
->addrp
->range
;
DBG( printf("io_parse: parsing device %d\n", config_devp
->device_id
); );
goto finished
; /* nothing more to parse */
lex_fatal("expecting either ; or { when parsing io device");
uint64_t startoffset
= 0LL;
if (tok
== T_R_Brace
) break;
if (streq(lex
.strp
, "rom")) {
} else if (streq(lex
.strp
, "le")) {
} else if (streq(lex
.strp
, "access_sizes")) {
printf("tok=%x %d\n", tok
, tok
);
lex_fatal("Expected a number after access_sizes (e.g 0x1 0x2 0x7 0x8 or 0xf)");
iodp
->access_sizes
= lex
.val
;
if (lex
.val
< config_devp
->addrp
->baseaddr
||
lex
.val
>= config_devp
->addrp
->topaddr
)
lex_fatal("specified load address is outside the "
"range of the io device");
startoffset
= lex
.val
- config_devp
->addrp
->baseaddr
;
lex_fatal("Expected either a start address / offset or filename "
"for io device load directive");
config_devp
->devp
= iodp
;
io_init(config_dev_t
*config_devp
)
iodp
= (io_dev_t
*)config_devp
->devp
;
if (iodp
->size
< pgsize
) {
DBG( fprintf(stderr
, "Using realloc %p size %x\n", iodp
, iodp
->size
); );
iodp
->datap
= Xrealloc(iodp
->datap
, iodp
->size
);
DBG( fprintf(stderr
, "Using mmap %p size %x\n", iodp
, iodp
->size
); );
iodp
->datap
= iodp
->datap
= (void*)mmap(NULL
, sim_roundup(iodp
->size
, pgsize
),
MAP_PRIVATE
| MAP_ANON
| MAP_NORESERVE
, -1, 0);
if (MAP_FAILED
== iodp
->datap
) fatal("Initial mmap of anon memory failed");
io_dump(config_dev_t
*config_devp
)
* Should only get invoked if this is a ROM.
* Indicate the store failed - return false
io_cpu_access(simcpu_t
*sp
, config_addr_t
*cap
, tpaddr_t offset
, maccess_t op
, uint64_t *regp
)
iodp
= cap
->config_devp
->devp
;
if ((offset
< 0) || (offset
>= cap
->range
)) {
if (((1 << (op
& MA_Size_Mask
)) & iodp
->access_sizes
) == 0) {
EXEC_WARNING(("Access size of %d bytes is not valid for this "
"device [PA=0x%llx, SIZE=0x%llx] @ %%PC 0x%llx "
"offset 0x%llx", (1 << (op
& MA_Size_Mask
)),
cap
->baseaddr
, cap
->range
, sp
->pc
, offset
));
/* return success anyways !!! */
switch(op
& MA_Op_Mask
) {
switch(op
& MA_Size_Mask
) {
*regp
= *(uint8_t *)(iodp
->datap
+ offset
);
*regp
= iodp
->is_le
? BSWAP_16(*(uint16_t *)(iodp
->datap
+ offset
)) :
*(uint16_t *)(iodp
->datap
+ offset
);
*regp
= iodp
->is_le
? BSWAP_32(*(uint32_t *)(iodp
->datap
+ offset
)) :
*(uint32_t *)(iodp
->datap
+ offset
);
*regp
= iodp
->is_le
? BSWAP_64(*(uint64_t *)(iodp
->datap
+ offset
)) :
*(uint64_t *)(iodp
->datap
+ offset
);
switch(op
& MA_Size_Mask
) {
*regp
= *(int8_t *)(iodp
->datap
+ offset
);
*regp
= iodp
->is_le
? (sint16_t
)BSWAP_16(*(uint16_t *)(iodp
->datap
+ offset
)) :
*(sint16_t
*)(iodp
->datap
+ offset
);
*regp
= iodp
->is_le
? (sint32_t
)BSWAP_32(*(uint32_t *)(iodp
->datap
+ offset
)) :
*(sint32_t
*)(iodp
->datap
+ offset
);
EXEC_WARNING(("rom_cpu_store: attempted store to ROM @ %%PC 0x%llx "
"of %d bytes at offset 0x%llx",
sp
->pc
, 1 << (op
& MA_Size_Mask
), offset
));
/* Return success anyways !! */
switch(op
& MA_Size_Mask
) {
*((int8_t *)(iodp
->datap
+ offset
)) = *regp
;
*((int16_t *)(iodp
->datap
+ offset
)) = iodp
->is_le
? BSWAP_16(*regp
) : *regp
;
*((int32_t *)(iodp
->datap
+ offset
)) = iodp
->is_le
? BSWAP_32(*regp
) : *regp
;
*((int64_t *)(iodp
->datap
+ offset
)) = iodp
->is_le
? BSWAP_64(*regp
) : *regp
;