Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ycai
simbricks
Commits
edc84de6
"include/ck/utility/multi_index.hpp" did not exist on "fcbb978828b308d8c367a3eeaebee485a61b548c"
Commit
edc84de6
authored
May 04, 2023
by
Jonas Kaufmann
Committed by
Antoine Kaufmann
May 09, 2023
Browse files
sims/external/simics: add SimBricks PCIe adapter
parent
01bdcb45
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1163 additions
and
0 deletions
+1163
-0
sims/external/simics/modules/simbricks-pcie/Makefile
sims/external/simics/modules/simbricks-pcie/Makefile
+28
-0
sims/external/simics/modules/simbricks-pcie/module_load.py
sims/external/simics/modules/simbricks-pcie/module_load.py
+41
-0
sims/external/simics/modules/simbricks-pcie/simbricks_pcie.c
sims/external/simics/modules/simbricks-pcie/simbricks_pcie.c
+1003
-0
sims/external/simics/modules/simbricks-pcie/simbricks_pcie_comp.py
...rnal/simics/modules/simbricks-pcie/simbricks_pcie_comp.py
+91
-0
No files found.
sims/external/simics/modules/simbricks-pcie/Makefile
0 → 100644
View file @
edc84de6
# -*- Makefile ; coding: utf-8 -*-
# © 2010 Intel Corporation
# Simics module makefile
MODULE_CLASSES
=
simbricks_pcie
MODULE_COMPONENTS
=
simbricks_pcie_comp
SRC_FILES
=
simbricks_pcie.c
PYTHON_FILES
=
simbricks_pcie_comp.py module_load.py
# SIMBRICKS_LIB needs to be set by caller
MODULE_CFLAGS
:=
-I
"
$(SIMBRICKS_LIB)
"
-Wno-address-of-packed-member
MODULE_LDFLAGS
:=
-L
"
$(SIMBRICKS_LIB)
"
-lsimbricks
D
:=
1
SIMICS_API
:=
6
THREAD_SAFE
:=
yes
COMPILE_PYC
=
0
ifeq
($(MODULE_MAKEFILE),)
$(error
Make
sure
you
compile
your
module
from
the
project
directory)
else
include
$(MODULE_MAKEFILE)
endif
sims/external/simics/modules/simbricks-pcie/module_load.py
0 → 100644
View file @
edc84de6
# SimBricks PCIe Adapter
#
# Copyright (c) 2020-2023 Max Planck Institute for Software Systems
# Copyright (c) 2020-2023 National University of Singapore
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import
cli
class_name
=
'simbricks_pcie'
# info command prints static information
def
get_info
(
obj
):
return
[]
# status command prints dynamic information
def
get_status
(
obj
):
return
[(
'Registers'
,
[(
'Value'
,
obj
.
value
)])]
cli
.
new_info_command
(
class_name
,
get_info
)
cli
.
new_status_command
(
class_name
,
get_status
)
from
.
import
simbricks_pcie_comp
simbricks_pcie_comp
.
simbricks_pcie_comp
.
register
()
sims/external/simics/modules/simbricks-pcie/simbricks_pcie.c
0 → 100644
View file @
edc84de6
/*
* SimBricks PCIe Adapter.
*
* Copyright (c) 2020-2023 Max Planck Institute for Software Systems
* Copyright (c) 2020-2023 National University of Singapore
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#define VERBOSE_DEBUG_PRINTS 0
#define INTERRUPT_DISABLE_BIT 1 << 10
#define INTERRUPT_STATUS_BIT 1 << 3
#include <math.h>
#include <simics/device-api.h>
#include <simics/model-iface/transaction.h>
#include "simics/base/map-target.h"
#include "simics/devs/io-memory.h"
#include "simics/devs/pci.h"
#include "simics/host-info.h"
#include "simics/model-iface/cycle.h"
#include "simics/model-iface/register-view.h"
#include "simics/util/alloc.h"
// use simics-internal static assert for checks in proto header
#define SIMBRICKS_PROTO_MSG_SZCHECK(s) \
STATIC_ASSERT(sizeof(s) == 64 && "SimBrick message size check failed")
#include <simbricks/pcie/if.h>
#include "simics/base-types.h"
#include "simics/base/attr-value.h"
#include "simics/base/conf-object.h"
#include "simics/base/event.h"
#include "simics/base/log.h"
#include "simics/base/memory.h"
#include "simics/base/time.h"
#include "simics/base/transaction.h"
#include "simics/base/types.h"
#include "simics/model-iface/components.h"
#include "simics/simulator-api.h"
#include "simics/simulator/processor.h"
#include "simics/util/help-macros.h"
#include "simics/util/vect.h"
typedef
struct
{
/* Simics object */
conf_object_t
obj
;
conf_object_t
*
pci_bus
;
const
pci_bus_interface_t
*
pci_bus_iface
;
map_target_t
*
memory_target
;
struct
__attribute__
((
__packed__
))
{
/* this */
uint16
vendor_id
;
uint16
device_id
;
uint16
command
;
uint16
status
;
uint8
revision_id
;
uint8
prog_if
;
uint8
subclass
;
uint8
class_code
;
uint8
cache_line_size
;
uint8
primary_latency_timer
;
uint8
header_type
;
uint8
bist
;
uint32
bars
[
6
];
uint32
cardbus_cis_ptr
;
uint16
subsystem_vendor_id
;
uint16
subsystem_id
;
uint32
expansion_rom_base_address
;
uint8
capabilities_ptr
;
uint8
reserved
[
7
];
uint8
interrupt_line
;
uint8
interrupt_pin
;
uint8
min_grant
;
uint8
max_latency
;
uint8
unused
[
192
];
}
pci_config
;
/* config parameters */
const
char
*
socket_path
;
/* path to ux socket to connect to */
uint64
pci_latency
;
uint64
sync_period
;
bool
debug_prints
;
bool
verbose
;
struct
SimbricksPcieIf
pcie_if
;
struct
SimbricksProtoPcieDevIntro
dev_intro
;
bool
sync
;
cycles_t
ts_base
;
conf_object_t
*
pico_second_clock
;
}
simbricks_pcie_t
;
static
event_class_t
*
sync_event
;
static
event_class_t
*
poll_event
;
static
inline
uint64
ts_to_proto
(
simbricks_pcie_t
*
simbricks
,
cycles_t
simics_ts
)
{
return
simics_ts
-
simbricks
->
ts_base
;
}
static
inline
cycles_t
ts_from_proto
(
simbricks_pcie_t
*
simbricks
,
uint64
proto_ts
)
{
return
(
cycles_t
)(
proto_ts
+
simbricks
->
ts_base
);
}
static
inline
cycles_t
rel_to_current
(
simbricks_pcie_t
*
simbricks
,
cycles_t
simics_ts
)
{
cycles_t
curr_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
return
simics_ts
-
curr_ts
;
}
static
inline
cycles_t
rel_to_current_proto
(
simbricks_pcie_t
*
simbricks
,
uint64
proto_ts
)
{
cycles_t
curr_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
uint64
curr_proto_ts
=
ts_to_proto
(
simbricks
,
curr_ts
);
return
(
cycles_t
)(
proto_ts
-
curr_proto_ts
);
}
static
inline
uint64_t
ceil_power_of_2
(
uint64_t
len
)
{
long
double
log_len
=
ceill
(
log2l
(
len
));
ASSERT
(
log_len
>=
4
);
/* makes masking easier */
return
(
uint64_t
)
powl
(
2
,
log_len
);
}
/* mask values in BAR registers to indicate size and set lower bit to indicate
* correct type */
static
void
mask_bars
(
simbricks_pcie_t
*
simbricks
)
{
ASSERT
(
sizeof
(
simbricks
->
dev_intro
.
bars
)
/
sizeof
(
simbricks
->
dev_intro
.
bars
[
0
])
==
sizeof
(
simbricks
->
pci_config
.
bars
)
/
sizeof
(
simbricks
->
pci_config
.
bars
[
0
]));
simbricks
->
pci_bus_iface
->
remove_map
(
simbricks
->
pci_bus
,
&
simbricks
->
obj
,
Sim_Addr_Space_IO
,
0
);
simbricks
->
pci_bus_iface
->
remove_map
(
simbricks
->
pci_bus
,
&
simbricks
->
obj
,
Sim_Addr_Space_Memory
,
0
);
for
(
int
i
=
0
;
i
<
sizeof
(
simbricks
->
dev_intro
.
bars
)
/
sizeof
(
simbricks
->
dev_intro
.
bars
[
0
]);
++
i
)
{
uint64_t
len
=
simbricks
->
dev_intro
.
bars
[
i
].
len
;
/* len == 0 means BAR is unused */
if
(
len
==
0
)
{
continue
;
}
len
=
ceil_power_of_2
(
len
);
uint64
mask
=
~
(
len
-
1
);
ASSERT
(
!
(
simbricks
->
dev_intro
.
bars
[
0
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_DUMMY
)
&&
"TODO"
);
uint64
base_addr
;
if
(
simbricks
->
dev_intro
.
bars
[
i
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_64
)
{
/* 64 bit memory space BAR */
uint64
*
bar_64
=
(
uint64
*
)
&
simbricks
->
pci_config
.
bars
[
i
];
*
bar_64
&=
mask
;
/* BAR type bit */
*
bar_64
&=
~
0
b0001LL
;
/* indicate 64 bit */
*
bar_64
|=
0
b0100LL
;
/* indicate prefetchable */
if
(
simbricks
->
dev_intro
.
bars
[
i
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_PF
)
{
*
bar_64
|=
0
b1000LL
;
}
base_addr
=
*
bar_64
&
mask
;
}
else
{
simbricks
->
pci_config
.
bars
[
i
]
&=
mask
;
if
(
simbricks
->
dev_intro
.
bars
[
i
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_IO
)
{
/* IO space BAR */
simbricks
->
pci_config
.
bars
[
i
]
|=
0
b01
;
}
else
if
(
simbricks
->
dev_intro
.
bars
[
i
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_PF
)
{
/* 32 bit memory BAR */
simbricks
->
pci_config
.
bars
[
i
]
|=
0
b1000
;
}
base_addr
=
simbricks
->
pci_config
.
bars
[
i
]
&
mask
;
}
/* map BARs */
if
(
base_addr
>
0LL
&&
base_addr
<
(
~
0LL
&
mask
))
{
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"mask_bars: mapping BAR bar=%u base_addr=0x%llx size=0x%lx"
,
i
,
base_addr
,
len
);
map_info_t
info
=
{
base_addr
,
base_addr
,
len
,
0
,
0
,
0
,
Sim_Swap_None
};
if
(
!
simbricks
->
pci_bus_iface
->
add_map
(
simbricks
->
pci_bus
,
&
simbricks
->
obj
,
simbricks
->
dev_intro
.
bars
[
i
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_IO
?
Sim_Addr_Space_IO
:
Sim_Addr_Space_Memory
,
NULL
,
info
))
{
SIM_LOG_ERROR
(
&
simbricks
->
obj
,
1
,
"mask_bars: Could not add mapping for base_addr=0x%llx"
,
base_addr
);
}
}
if
(
simbricks
->
dev_intro
.
bars
[
i
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_64
)
{
++
i
;
}
}
}
/******************************************************************************/
/* Initialization */
static
int
simbricks_connect
(
simbricks_pcie_t
*
simbricks
)
{
struct
SimbricksProtoPcieDevIntro
*
d_i
=
&
simbricks
->
dev_intro
;
struct
SimbricksProtoPcieHostIntro
host_intro
;
struct
SimbricksBaseIfParams
params
;
size_t
len
;
uint64
first_sync_ts
=
0
,
first_msg_ts
=
0
;
volatile
union
SimbricksProtoPcieD2H
*
msg
;
struct
SimbricksBaseIf
*
base_if
=
&
simbricks
->
pcie_if
.
base
;
if
(
!
simbricks
->
socket_path
)
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"socket path not set but required"
);
return
0
;
}
SimbricksPcieIfDefaultParams
(
&
params
);
params
.
link_latency
=
simbricks
->
pci_latency
*
1000
;
params
.
sync_interval
=
simbricks
->
sync_period
*
1000
;
params
.
blocking_conn
=
true
;
params
.
sock_path
=
simbricks
->
socket_path
;
params
.
sync_mode
=
(
simbricks
->
sync
?
kSimbricksBaseIfSyncRequired
:
kSimbricksBaseIfSyncDisabled
);
if
(
SimbricksBaseIfInit
(
base_if
,
&
params
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"SimbricksBaseIfInit failed"
);
return
0
;
}
if
(
SimbricksBaseIfConnect
(
base_if
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"SimbricksBaseIfConnect failed"
);
return
0
;
}
if
(
SimbricksBaseIfConnected
(
base_if
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"SimbricksBaseIfConnected indicates unconnected"
);
return
0
;
}
/* prepare & send host intro */
memset
(
&
host_intro
,
0
,
sizeof
(
host_intro
));
if
(
SimbricksBaseIfIntroSend
(
base_if
,
&
host_intro
,
sizeof
(
host_intro
)))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"SimbricksBaseIfIntroSend failed"
);
return
0
;
}
/* receive device intro */
len
=
sizeof
(
*
d_i
);
if
(
SimbricksBaseIfIntroRecv
(
base_if
,
d_i
,
&
len
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"SimbricksBaseIfIntroRecv failed"
);
return
0
;
}
if
(
len
!=
sizeof
(
*
d_i
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"rx dev intro: length is not as expected"
);
return
0
;
}
/* copy pci config */
simbricks
->
pci_config
.
vendor_id
=
d_i
->
pci_vendor_id
;
simbricks
->
pci_config
.
device_id
=
d_i
->
pci_device_id
;
simbricks
->
pci_config
.
revision_id
=
d_i
->
pci_revision
;
simbricks
->
pci_config
.
prog_if
=
d_i
->
pci_progif
;
simbricks
->
pci_config
.
subclass
=
d_i
->
pci_subclass
;
simbricks
->
pci_config
.
class_code
=
d_i
->
pci_class
;
mask_bars
(
simbricks
);
/* enable legacy interrupts */
simbricks
->
pci_config
.
interrupt_pin
=
1
;
if
(
simbricks
->
sync
)
{
/* send a first sync */
if
(
SimbricksPcieIfH2DOutSync
(
&
simbricks
->
pcie_if
,
0
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"sending initial sync failed"
);
return
0
;
}
first_sync_ts
=
SimbricksPcieIfH2DOutNextSync
(
&
simbricks
->
pcie_if
);
SIM_LOG_INFO
(
4
,
&
simbricks
->
obj
,
1
,
"first_sync_ts: %llu"
,
first_sync_ts
);
/* wait for first message so we know its timestamp */
do
{
msg
=
SimbricksPcieIfD2HInPeek
(
&
simbricks
->
pcie_if
,
0
);
first_msg_ts
=
SimbricksPcieIfD2HInTimestamp
(
&
simbricks
->
pcie_if
);
}
while
(
!
msg
&&
!
first_msg_ts
);
}
/* schedule sync and poll events */
if
(
simbricks
->
sync
)
{
simbricks
->
ts_base
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
SIM_LOG_INFO
(
4
,
&
simbricks
->
obj
,
1
,
"simbricks_connect: ts_base %lld"
,
simbricks
->
ts_base
);
SIM_event_post_cycle
(
simbricks
->
pico_second_clock
,
sync_event
,
&
simbricks
->
obj
,
rel_to_current_proto
(
simbricks
,
first_sync_ts
),
NULL
);
SIM_event_post_cycle
(
simbricks
->
pico_second_clock
,
poll_event
,
&
simbricks
->
obj
,
rel_to_current_proto
(
simbricks
,
first_sync_ts
),
NULL
);
}
else
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"Running unsynchronized not implemented"
);
}
return
1
;
}
/******************************************************************************/
/* Message processing */
/* allocate host-to-device queue entry */
static
inline
volatile
union
SimbricksProtoPcieH2D
*
simbricks_comm_h2d_alloc
(
simbricks_pcie_t
*
simbricks
,
cycles_t
cur_ts
)
{
volatile
union
SimbricksProtoPcieH2D
*
msg
;
while
(
!
(
msg
=
SimbricksPcieIfH2DOutAlloc
(
&
simbricks
->
pcie_if
,
ts_to_proto
(
simbricks
,
cur_ts
))))
{
}
// performance optimization: reschedule sync timer since we are going to send
// a message and an additional sync message is therefore not necessary for one
// whole sync interal
SIM_event_cancel_time
(
simbricks
->
pico_second_clock
,
sync_event
,
&
simbricks
->
obj
,
NULL
,
NULL
);
uint64
next_sync
=
SimbricksPcieIfH2DOutNextSync
(
&
simbricks
->
pcie_if
);
cycles_t
rel_next_sync
=
rel_to_current_proto
(
simbricks
,
next_sync
);
SIM_event_post_cycle
(
simbricks
->
pico_second_clock
,
sync_event
,
&
simbricks
->
obj
,
rel_next_sync
,
NULL
);
return
msg
;
}
/* process read completion from memory to host */
static
void
simbricks_comm_d2h_rcomp
(
simbricks_pcie_t
*
simbricks
,
uint64
cur_ts
,
// NOLINT
uint64
req_id
,
const
void
*
data
)
{
transaction_t
*
transaction
=
(
transaction_t
*
)
req_id
;
// NOLINT
unsigned
size
=
SIM_transaction_size
(
transaction
);
bytes_t
bytes
=
{
data
,
size
};
SIM_set_transaction_bytes
(
transaction
,
bytes
);
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_rcomp: completed transaction size=%u val=0x%llx"
,
size
,
size
<=
8
?
SIM_get_transaction_value_le
(
transaction
)
:
-
1
);
SIM_complete_transaction
(
transaction
,
Sim_PE_No_Exception
);
}
#define ATOM_TYPE_req_id uint64_t
SIM_CUSTOM_ATOM
(
req_id
);
/* NOLINT */
exception_type_t
rw_transaction_comp_callback
(
conf_object_t
*
obj
,
transaction_t
*
comp_transaction
,
exception_type_t
exc
);
static
void
simbricks_comm_d2h_rw
(
simbricks_pcie_t
*
simbricks
,
volatile
union
SimbricksProtoPcieD2H
*
msg
,
bool
is_read
)
{
volatile
struct
SimbricksProtoPcieD2HRead
*
read
=
&
msg
->
read
;
volatile
struct
SimbricksProtoPcieD2HWrite
*
write
=
&
msg
->
write
;
uint64_t
offset
=
is_read
?
read
->
offset
:
write
->
offset
;
unsigned
size
=
is_read
?
read
->
len
:
write
->
len
;
cycles_t
cur_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
transaction_t
*
transaction
=
MM_ZALLOC
(
1
,
transaction_t
);
atom_t
*
atoms
=
MM_ZALLOC
(
8
,
atom_t
);
transaction
->
atoms
=
atoms
;
atoms
[
0
]
=
ATOM_size
(
size
);
uint8
*
data
=
MM_ZALLOC
(
size
,
uint8
);
atoms
[
1
]
=
ATOM_data
(
data
);
if
(
is_read
)
{
atoms
[
2
]
=
ATOM_flags
(
0
);
atoms
[
3
]
=
ATOM_req_id
(
read
->
req_id
);
}
else
{
atoms
[
2
]
=
ATOM_flags
(
Sim_Transaction_Write
);
memcpy
(
data
,
(
uint8
*
)
write
->
data
,
write
->
len
);
atoms
[
3
]
=
ATOM_req_id
(
write
->
req_id
);
}
atoms
[
4
]
=
ATOM_initiator
(
&
simbricks
->
obj
);
atoms
[
5
]
=
ATOM_completion
(
rw_transaction_comp_callback
);
atoms
[
6
]
=
ATOM_owner
(
&
simbricks
->
obj
);
atoms
[
7
]
=
ATOM_LIST_END
;
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_rw: issuing transaction to pci_bus "
"cur_ts=%lli is_read=%u offset=0x%lx size=%u"
,
cur_ts
,
is_read
,
offset
,
size
);
exception_type_t
exc
=
SIM_issue_transaction
(
simbricks
->
memory_target
,
transaction
,
offset
);
SIM_monitor_transaction
(
transaction
,
exc
);
}
/* send a read completion message to device */
exception_type_t
rw_transaction_comp_callback
(
conf_object_t
*
obj
,
transaction_t
*
comp_transaction
,
exception_type_t
exc
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
cycles_t
cur_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
bool
is_read
=
SIM_transaction_is_read
(
comp_transaction
);
unsigned
size
=
SIM_transaction_size
(
comp_transaction
);
if
(
exc
!=
Sim_PE_No_Exception
)
{
SIM_LOG_CRITICAL
(
obj
,
1
,
"rw_transaction_comp_callback: transaction not successful "
"exc=%u is_read=%u"
,
exc
,
is_read
);
}
volatile
union
SimbricksProtoPcieH2D
*
msg
=
simbricks_comm_h2d_alloc
(
simbricks
,
cur_ts
);
volatile
struct
SimbricksProtoPcieH2DReadcomp
*
readcomp
=
&
msg
->
readcomp
;
volatile
struct
SimbricksProtoPcieH2DWritecomp
*
writecomp
=
&
msg
->
writecomp
;
if
(
is_read
)
{
readcomp
->
req_id
=
ATOM_get_transaction_req_id
(
comp_transaction
);
buffer_t
bytes
=
{(
uint8
*
)
readcomp
->
data
,
size
};
SIM_get_transaction_bytes
(
comp_transaction
,
bytes
);
}
else
{
writecomp
->
req_id
=
ATOM_get_transaction_req_id
(
comp_transaction
);
}
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_h2d_rwcomp: sending message to device "
"cur_ts=%lli is_read=%u size=%u val=0x%llx"
,
cur_ts
,
is_read
,
size
,
size
<=
8
?
SIM_get_transaction_value_le
(
comp_transaction
)
:
-
1
);
SimbricksPcieIfH2DOutSend
(
&
simbricks
->
pcie_if
,
msg
,
is_read
?
SIMBRICKS_PROTO_PCIE_H2D_MSG_READCOMP
:
SIMBRICKS_PROTO_PCIE_H2D_MSG_WRITECOMP
);
MM_FREE
(
comp_transaction
->
atoms
);
MM_FREE
(
comp_transaction
);
return
exc
;
}
/* process incoming SimBricks protocol messages from memory simulator */
static
void
simbricks_comm_d2h_process
(
simbricks_pcie_t
*
simbricks
,
int64
cur_ts
,
volatile
union
SimbricksProtoPcieD2H
*
msg
)
{
uint8_t
type
=
SimbricksPcieIfD2HInType
(
&
simbricks
->
pcie_if
,
msg
);
#if VERBOSE_DEBUG_PRINTS
SIM_LOG_INFO
(
4
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_m2h_process: ts=%lld type=%u"
,
cur_ts
,
type
);
#endif
switch
(
type
)
{
case
SIMBRICKS_PROTO_MSG_TYPE_SYNC
:
{
/* nop */
break
;
}
case
SIMBRICKS_PROTO_PCIE_D2H_MSG_READCOMP
:
{
simbricks_comm_d2h_rcomp
(
simbricks
,
cur_ts
,
msg
->
readcomp
.
req_id
,
(
void
*
)
msg
->
readcomp
.
data
);
break
;
}
case
SIMBRICKS_PROTO_PCIE_D2H_MSG_WRITECOMP
:
{
SIM_LOG_ERROR
(
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_process: We are using posted writes, "
"so there shouldn't be a completion message here."
);
break
;
}
case
SIMBRICKS_PROTO_PCIE_D2H_MSG_READ
:
case
SIMBRICKS_PROTO_PCIE_D2H_MSG_WRITE
:
{
simbricks_comm_d2h_rw
(
simbricks
,
msg
,
type
==
SIMBRICKS_PROTO_PCIE_D2H_MSG_READ
);
break
;
}
case
SIMBRICKS_PROTO_PCIE_D2H_MSG_INTERRUPT
:
{
switch
(
msg
->
interrupt
.
inttype
)
{
case
SIMBRICKS_PROTO_PCIE_INT_LEGACY_HI
:
if
(
simbricks
->
pci_config
.
status
&
INTERRUPT_STATUS_BIT
)
{
SIM_LOG_INFO
(
1
,
&
simbricks
->
obj
,
1
,
"(WARNING) simbricks_comm_d2h_process: interrupt is already "
"raised. Not raising again. cur_ts=%lli line=%u"
,
cur_ts
,
simbricks
->
pci_config
.
interrupt_line
);
break
;
}
simbricks
->
pci_config
.
status
|=
INTERRUPT_STATUS_BIT
;
if
(
simbricks
->
pci_config
.
command
&
INTERRUPT_DISABLE_BIT
)
{
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_process: delaying interrupt due to "
"Interrupt Disable bit being set. cur_ts=%lli line=%u"
,
cur_ts
,
simbricks
->
pci_config
.
interrupt_line
);
break
;
}
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_process: raising interrupt "
"cur_ts=%lli line=%u"
,
cur_ts
,
simbricks
->
pci_config
.
interrupt_line
);
simbricks
->
pci_bus_iface
->
raise_interrupt
(
simbricks
->
pci_bus
,
&
simbricks
->
obj
,
0
);
break
;
case
SIMBRICKS_PROTO_PCIE_INT_LEGACY_LO
:
if
(
!
(
simbricks
->
pci_config
.
status
&
INTERRUPT_STATUS_BIT
))
{
SIM_LOG_INFO
(
1
,
&
simbricks
->
obj
,
1
,
"(WARNING) simbricks_comm_d2h_process: interrupt is already "
"lowered. Not lowering again. cur_ts=%lli line=%u"
,
cur_ts
,
simbricks
->
pci_config
.
interrupt_line
);
break
;
}
simbricks
->
pci_config
.
status
&=
~
(
INTERRUPT_STATUS_BIT
);
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_process: lowering interrupt "
"cur_ts=%lli line=%u"
,
cur_ts
,
simbricks
->
pci_config
.
interrupt_line
);
simbricks
->
pci_bus_iface
->
lower_interrupt
(
simbricks
->
pci_bus
,
&
simbricks
->
obj
,
0
);
break
;
default:
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"simbricks_comm_m2h_process: inttype %u not implemented"
,
msg
->
interrupt
.
inttype
);
break
;
}
break
;
}
default:
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"simbricks_comm_m2h_process: unhandled message type %u"
,
type
);
}
}
SimbricksPcieIfD2HInDone
(
&
simbricks
->
pcie_if
,
msg
);
}
/* sync event callback for sending synchronization messages to memory */
static
void
sync_event_callback
(
conf_object_t
*
obj
,
lang_void
*
data
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
cycles_t
cur_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
uint64
proto_ts
=
ts_to_proto
(
simbricks
,
cur_ts
);
uint64
sync_ts
=
SimbricksPcieIfH2DOutNextSync
(
&
simbricks
->
pcie_if
);
if
(
proto_ts
>
sync_ts
+
1
)
{
SIM_LOG_INFO
(
1
,
obj
,
1
,
"(WARNING) simbricks_timer_sync: expected_ts=%llu cur_ts=%llu"
,
sync_ts
,
proto_ts
);
}
#if VERBOSE_DEBUG_PRINTS
SIM_LOG_INFO
(
4
,
obj
,
1
,
"simbricks_timer_sync: ts=%lld pts=%llu npts=%llu"
,
cur_ts
,
proto_ts
,
sync_ts
);
#endif
while
(
SimbricksPcieIfH2DOutSync
(
&
simbricks
->
pcie_if
,
proto_ts
))
{
}
uint64
next_sync_pts
=
SimbricksPcieIfH2DOutNextSync
(
&
simbricks
->
pcie_if
);
cycles_t
next_sync_ts
=
ts_from_proto
(
simbricks
,
next_sync_pts
);
#if VERBOSE_DEBUG_PRINTS
SIM_LOG_INFO
(
4
,
obj
,
1
,
"simbricks_timer_sync: next pts=%llu pts=%lld"
,
next_sync_pts
,
next_sync_ts
);
#endif
SIM_event_post_cycle
(
simbricks
->
pico_second_clock
,
sync_event
,
&
simbricks
->
obj
,
rel_to_current
(
simbricks
,
next_sync_ts
),
NULL
);
}
/* poll event callback for processing incoming messages from memory to host */
static
void
poll_event_callback
(
conf_object_t
*
obj
,
lang_void
*
data
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
int64
cur_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
uint64
proto_ts
=
ts_to_proto
(
simbricks
,
cur_ts
);
uint64
next_ts
;
volatile
union
SimbricksProtoPcieD2H
*
msg
;
volatile
union
SimbricksProtoPcieD2H
*
next_msg
;
uint64
poll_ts
=
SimbricksPcieIfD2HInTimestamp
(
&
simbricks
->
pcie_if
);
if
(
proto_ts
>
poll_ts
+
1
||
proto_ts
<
poll_ts
)
{
SIM_LOG_INFO
(
1
,
obj
,
1
,
"(WARNING) simbricks_timer_poll: expected_pts=%llu cur_pts=%llu"
,
poll_ts
,
proto_ts
);
}
#if VERBOSE_DEBUG_PRINTS
SIM_LOG_INFO
(
4
,
obj
,
1
,
"simbricks_timer_poll: ts=%lld sync_ts=%lld"
,
cur_ts
,
SIM_event_find_next_cycle
(
simbricks
->
pico_second_clock
,
sync_event
,
obj
,
NULL
,
NULL
));
#endif
/* poll until we have a message (should not usually spin) */
do
{
msg
=
SimbricksPcieIfD2HInPoll
(
&
simbricks
->
pcie_if
,
proto_ts
);
}
while
(
msg
==
NULL
);
simbricks_comm_d2h_process
(
simbricks
,
cur_ts
,
msg
);
/* process additional available messages */
for
(;;)
{
msg
=
SimbricksPcieIfD2HInPoll
(
&
simbricks
->
pcie_if
,
proto_ts
);
if
(
msg
==
NULL
)
{
break
;
}
simbricks_comm_d2h_process
(
simbricks
,
cur_ts
,
msg
);
}
/* Wait for next message so we know its timestamp and when to schedule the
* timer. */
do
{
next_msg
=
SimbricksPcieIfD2HInPeek
(
&
simbricks
->
pcie_if
,
proto_ts
);
next_ts
=
SimbricksPcieIfD2HInTimestamp
(
&
simbricks
->
pcie_if
);
}
while
(
!
next_msg
&&
next_ts
<=
proto_ts
);
/* set timer for next message */
SIM_event_post_cycle
(
simbricks
->
pico_second_clock
,
poll_event
,
&
simbricks
->
obj
,
rel_to_current_proto
(
simbricks
,
next_ts
),
NULL
);
}
static
exception_type_t
handle_config_transaction
(
conf_object_t
*
obj
,
transaction_t
*
transaction
,
uint64
addr
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
unsigned
int
size
=
SIM_transaction_size
(
transaction
);
bool
is_read
=
SIM_transaction_is_read
(
transaction
);
cycles_t
cur_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
bool
interrupt_disable_before
=
simbricks
->
pci_config
.
command
&
INTERRUPT_DISABLE_BIT
;
if
(
addr
+
size
>
sizeof
(
simbricks
->
pci_config
))
{
SIM_LOG_CRITICAL
(
obj
,
1
,
"handle_config_transaction: access past pci_config bounds "
"cur_ts=%lli addr=%llu size=%u"
,
cur_ts
,
addr
,
size
);
return
Sim_PE_IO_Error
;
}
if
(
is_read
)
{
bytes_t
bytes
=
{((
uint8
*
)
&
simbricks
->
pci_config
)
+
addr
,
size
};
SIM_set_transaction_bytes
(
transaction
,
bytes
);
}
else
if
(
SIM_transaction_is_write
(
transaction
))
{
buffer_t
buffer
=
{((
uint8
*
)
&
simbricks
->
pci_config
)
+
addr
,
size
};
SIM_get_transaction_bytes
(
transaction
,
buffer
);
if
(
0x10
<=
addr
&&
addr
<
0x28
)
{
mask_bars
(
simbricks
);
}
}
else
{
SIM_LOG_CRITICAL
(
obj
,
1
,
"mem_handle_transaction: unsupported access to pci_config cur_ts=%lli"
,
cur_ts
);
return
Sim_PE_IO_Error
;
}
SIM_LOG_INFO
(
3
,
obj
,
1
,
"handle_config_transaction: cur_ts=%lli addr=0x%llx size=%u "
"is_read=%u val=0x%llx"
,
cur_ts
,
addr
,
size
,
is_read
,
size
<=
8
?
SIM_get_transaction_value_le
(
transaction
)
:
-
1
);
if
(
interrupt_disable_before
&&
(
simbricks
->
pci_config
.
command
&
INTERRUPT_DISABLE_BIT
)
==
0
&&
(
simbricks
->
pci_config
.
command
&
INTERRUPT_STATUS_BIT
))
{
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"simbricks_comm_d2h_process: Interrupt Disable bit changed to 0, "
"raising delayed interrupt. cur_ts=%lli "
,
cur_ts
);
simbricks
->
pci_bus_iface
->
raise_interrupt
(
simbricks
->
pci_bus
,
&
simbricks
->
obj
,
0
);
}
return
Sim_PE_No_Exception
;
}
static
exception_type_t
handle_bar_transaction
(
conf_object_t
*
obj
,
transaction_t
*
transaction
,
uint64
addr
)
{
volatile
union
SimbricksProtoPcieH2D
*
msg
;
volatile
struct
SimbricksProtoPcieH2DRead
*
read
;
volatile
struct
SimbricksProtoPcieH2DWrite
*
write
;
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
unsigned
size
=
SIM_transaction_size
(
transaction
);
cycles_t
cur_ts
=
SIM_cycle_count
(
simbricks
->
pico_second_clock
);
bool
is_write
=
SIM_transaction_is_write
(
transaction
);
/* determine BAR number being accessed */
for
(
unsigned
bar
=
0
;
bar
<
sizeof
(
simbricks
->
dev_intro
.
bars
)
/
sizeof
(
simbricks
->
dev_intro
.
bars
[
0
]);
(
simbricks
->
dev_intro
.
bars
[
bar
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_64
)
?
bar
+=
2
:
++
bar
)
{
/* determine base address */
uint64_t
len
=
ceil_power_of_2
(
simbricks
->
dev_intro
.
bars
[
0
].
len
);
uint64
mask
=
~
(
len
-
1
);
uint64
base_addr
=
simbricks
->
pci_config
.
bars
[
bar
];
if
(
simbricks
->
dev_intro
.
bars
[
bar
].
flags
&
SIMBRICKS_PROTO_PCIE_BAR_64
)
{
uint64
*
base_addr_ptr
=
(
uint64
*
)
&
simbricks
->
pci_config
.
bars
[
bar
];
base_addr
=
*
base_addr_ptr
;
}
base_addr
&=
mask
;
/* check whether access belongs to current BAR */
if
(
!
(
base_addr
<=
addr
&&
addr
<
base_addr
+
len
))
{
continue
;
}
/* handle write transaction */
if
(
is_write
)
{
msg
=
simbricks_comm_h2d_alloc
(
simbricks
,
cur_ts
);
write
=
&
msg
->
write
;
write
->
bar
=
bar
;
write
->
offset
=
addr
-
base_addr
;
write
->
len
=
size
;
unsigned
int
max_size
=
SimbricksPcieIfH2DOutMsgLen
(
&
simbricks
->
pcie_if
)
-
sizeof
(
*
write
);
if
(
size
>
max_size
)
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"Message size in out queue of %u bytes does not "
"suffice. Requiring %u bytes."
,
max_size
,
size
);
return
Sim_PE_IO_Error
;
}
buffer_t
data
=
{(
uint8
*
)
write
->
data
,
size
};
SIM_get_transaction_bytes
(
transaction
,
data
);
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"handle_bar_transaction: Sending posted write to device. ts=%llu "
"bar=%u offset=0x%lx len=%u val=0x%llx"
,
cur_ts
,
write
->
bar
,
write
->
offset
,
write
->
len
,
size
<=
8
?
SIM_get_transaction_value_le
(
transaction
)
:
-
1
);
SimbricksPcieIfH2DOutSend
(
&
simbricks
->
pcie_if
,
msg
,
SIMBRICKS_PROTO_PCIE_H2D_MSG_WRITE_POSTED
);
/* we don't wait for the completion of writes so we are done here */
return
Sim_PE_No_Exception
;
}
if
(
!
SIM_transaction_is_read
(
transaction
))
{
SIM_LOG_CRITICAL
(
obj
,
1
,
"handle_bar_transaction: access is neither write nor read. ts=%llu "
"addr=0x%llx size=%u"
,
cur_ts
,
addr
,
size
);
return
Sim_PE_IO_Error
;
}
/* handle read transaction */
msg
=
simbricks_comm_h2d_alloc
(
simbricks
,
cur_ts
);
read
=
&
msg
->
read
;
read
->
bar
=
bar
;
read
->
offset
=
addr
-
base_addr
;
read
->
len
=
size
;
read
->
req_id
=
(
uint64_t
)
SIM_defer_transaction
(
obj
,
transaction
);
if
(
!
read
->
req_id
)
{
SIM_LOG_ERROR
(
obj
,
1
,
"handle_bar_transaction: Cannot defer transaction. ts=%llu "
"bar=%u offset=0x%lx len=%u"
,
cur_ts
,
read
->
bar
,
read
->
offset
,
read
->
len
);
return
Sim_PE_Async_Required
;
}
SIM_LOG_INFO
(
3
,
&
simbricks
->
obj
,
1
,
"handle_bar_transaction: Sending read to device. ts=%llu "
"bar=%u offset=0x%lx len=%u"
,
cur_ts
,
read
->
bar
,
read
->
offset
,
read
->
len
);
SimbricksPcieIfH2DOutSend
(
&
simbricks
->
pcie_if
,
msg
,
SIMBRICKS_PROTO_PCIE_H2D_MSG_READ
);
return
Sim_PE_Deferred
;
}
/* no BAR matched */
SIM_LOG_ERROR
(
obj
,
1
,
"handle_bar_transaction: no BAR matched access ts=%lli addr=0x%llx "
"size=0x%x is_write=%u"
,
cur_ts
,
addr
,
size
,
SIM_transaction_is_write
(
transaction
));
return
Sim_PE_IO_Error
;
}
static
exception_type_t
handle_transaction
(
conf_object_t
*
obj
,
transaction_t
*
transaction
,
uint64
addr
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
if
(
addr
<
sizeof
(
simbricks
->
pci_config
))
{
return
handle_config_transaction
(
obj
,
transaction
,
addr
);
}
return
handle_bar_transaction
(
obj
,
transaction
,
addr
);
}
static
void
pci_bus_reset
(
conf_object_t
*
obj
)
{
SIM_LOG_INFO
(
3
,
obj
,
1
,
"pci_bus_reset: unimplemented. obj=%s"
,
SIM_object_name
(
obj
));
}
static
void
pci_system_error
(
conf_object_t
*
obj
)
{
SIM_LOG_INFO
(
3
,
obj
,
1
,
"pci_system_error: unimplemented. obj=%s"
,
SIM_object_name
(
obj
));
}
static
void
pci_interrupt_raised
(
conf_object_t
*
obj
,
int
pin
)
{
SIM_LOG_ERROR
(
obj
,
1
,
"pci_interrupt_raised: unimplemented. pin=0x%i"
,
pin
);
}
static
void
pci_interrupt_lowered
(
conf_object_t
*
obj
,
int
pin
)
{
SIM_LOG_ERROR
(
obj
,
1
,
"interrupt_lowered: unimplemented. pin=0x%i"
,
pin
);
}
/******************************************************************************/
/* Device Attribute Getters and Setters */
static
attr_value_t
get_pci_bus_attr
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
return
SIM_make_attr_object
(
simbricks
->
pci_bus
);
}
static
set_error_t
set_pci_bus_attr
(
conf_object_t
*
obj
,
attr_value_t
*
attr_val
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
if
(
!
SIM_attr_is_object
(
*
attr_val
))
{
return
Sim_Set_Illegal_Value
;
}
simbricks
->
pci_bus
=
SIM_attr_object
(
*
attr_val
);
return
Sim_Set_Ok
;
}
static
attr_value_t
get_socket_attr
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
return
SIM_make_attr_string
(
simbricks
->
socket_path
);
}
static
set_error_t
set_socket_attr
(
conf_object_t
*
obj
,
attr_value_t
*
attr_val
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
if
(
!
SIM_attr_is_string
(
*
attr_val
))
{
return
Sim_Set_Illegal_Value
;
}
simbricks
->
socket_path
=
SIM_attr_string
(
*
attr_val
);
return
Sim_Set_Ok
;
}
static
attr_value_t
get_pci_latency_attr
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
return
SIM_make_attr_uint64
(
simbricks
->
pci_latency
);
}
static
set_error_t
set_pci_latency_attr
(
conf_object_t
*
obj
,
attr_value_t
*
attr_val
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
if
(
!
SIM_attr_is_uint64
(
*
attr_val
))
{
return
Sim_Set_Illegal_Value
;
}
simbricks
->
pci_latency
=
SIM_attr_integer
(
*
attr_val
);
return
Sim_Set_Ok
;
}
static
attr_value_t
get_sync_period_attr
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
return
SIM_make_attr_uint64
(
simbricks
->
sync_period
);
}
static
set_error_t
set_sync_period_attr
(
conf_object_t
*
obj
,
attr_value_t
*
attr_val
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
if
(
!
SIM_attr_is_uint64
(
*
attr_val
))
{
return
Sim_Set_Illegal_Value
;
}
simbricks
->
sync_period
=
SIM_attr_integer
(
*
attr_val
);
return
Sim_Set_Ok
;
}
/******************************************************************************/
/* Simics Initialization */
/* Allocate memory for the object. */
static
conf_object_t
*
alloc_object
(
conf_class_t
*
cls
)
{
simbricks_pcie_t
*
empty
=
MM_ZALLOC
(
1
,
simbricks_pcie_t
);
return
&
empty
->
obj
;
}
/* Initialize the object before any attributes are set. */
static
void
*
init_object
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
simbricks
->
sync
=
true
;
return
obj
;
}
/* Initialization once all objects have been finalized, if needed. */
static
void
objects_finalized
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
simbricks
=
(
simbricks_pcie_t
*
)
obj
;
/* obtain picosecond clock */
conf_object_t
*
clock
=
SIM_object_clock
(
obj
);
if
(
!
clock
)
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"objects_finalized: cannot obtain object clock"
);
return
;
}
simbricks
->
pico_second_clock
=
SIM_picosecond_clock
(
clock
);
if
(
!
simbricks
->
pico_second_clock
)
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"objects_finalized: cannot obtain picosecond clock"
);
}
ASSERT
(
simbricks
->
pci_bus
!=
NULL
);
simbricks
->
pci_bus_iface
=
SIM_get_interface
(
simbricks
->
pci_bus
,
"pci_bus"
);
ASSERT
(
simbricks
->
pci_bus_iface
!=
NULL
);
simbricks
->
memory_target
=
SIM_new_map_target
(
simbricks
->
pci_bus_iface
->
memory_space
(
simbricks
->
pci_bus
),
NULL
,
NULL
);
if
(
!
simbricks_connect
(
simbricks
))
{
SIM_LOG_CRITICAL
(
&
simbricks
->
obj
,
1
,
"simbricks_connect failed"
);
}
}
/* Free memory allocated for the object. */
static
void
dealloc_object
(
conf_object_t
*
obj
)
{
simbricks_pcie_t
*
empty
=
(
simbricks_pcie_t
*
)
obj
;
SIM_free_map_target
(
empty
->
memory_target
);
MM_FREE
(
empty
);
}
/* Called once when the device module is loaded into Simics. */
void
init_local
(
void
)
{
/* Define and register the device class. */
const
class_info_t
class_info
=
{.
alloc
=
alloc_object
,
.
init
=
init_object
,
.
objects_finalized
=
objects_finalized
,
.
dealloc
=
dealloc_object
,
.
description
=
"SimBricks PCIe Adapter"
,
.
short_desc
=
"SimBricks PCIe Adapter"
,
.
kind
=
Sim_Class_Kind_Vanilla
};
conf_class_t
*
pcie_cls
=
SIM_create_class
(
"simbricks_pcie"
,
&
class_info
);
/* register interfaces */
static
const
transaction_interface_t
kTransactionIface
=
{
.
issue
=
handle_transaction
};
SIM_REGISTER_INTERFACE
(
pcie_cls
,
transaction
,
&
kTransactionIface
);
static
const
pci_device_interface_t
kPciDevIface
=
{
pci_bus_reset
,
NULL
,
NULL
,
pci_system_error
,
pci_interrupt_raised
,
pci_interrupt_lowered
};
SIM_REGISTER_INTERFACE
(
pcie_cls
,
pci_device
,
&
kPciDevIface
);
/* register events we later want to insert into event queues */
sync_event
=
SIM_register_event
(
"simbricks-sync"
,
pcie_cls
,
0
,
sync_event_callback
,
NULL
,
NULL
,
NULL
,
NULL
);
poll_event
=
SIM_register_event
(
"simbricks-poll"
,
pcie_cls
,
0
,
poll_event_callback
,
NULL
,
NULL
,
NULL
,
NULL
);
// add device attributes
SIM_register_attribute
(
pcie_cls
,
"pci_bus"
,
get_pci_bus_attr
,
set_pci_bus_attr
,
Sim_Attr_Required
,
"o"
,
"PCI bus device is connected to."
);
SIM_register_attribute
(
pcie_cls
,
"socket"
,
get_socket_attr
,
set_socket_attr
,
Sim_Attr_Required
,
"s"
,
"Socket Path for SimBricks messages"
);
SIM_register_attribute
(
pcie_cls
,
"pci_latency"
,
get_pci_latency_attr
,
set_pci_latency_attr
,
Sim_Attr_Required
,
"i"
,
"PCI Latency in ns from host to device"
);
SIM_register_attribute
(
pcie_cls
,
"sync_period"
,
get_sync_period_attr
,
set_sync_period_attr
,
Sim_Attr_Optional
,
"i"
,
"Period for sending SimBricks synchronization messages in nanoseconds."
);
}
sims/external/simics/modules/simbricks-pcie/simbricks_pcie_comp.py
0 → 100644
View file @
edc84de6
# SimBricks PCIe Adapter Component
#
# Copyright (c) 2020-2023 Max Planck Institute for Software Systems
# Copyright (c) 2020-2023 National University of Singapore
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import
simics
from
comp
import
StandardComponent
,
SimpleConfigAttribute
,
Interface
class
simbricks_pcie_comp
(
StandardComponent
):
"""SimBricks PCIe adapter device."""
_class_desc
=
'SimBricks PCIe adapter device'
_help_categories
=
(
'PCI'
,)
def
setup
(
self
):
super
().
setup
()
if
not
self
.
instantiated
.
val
:
self
.
add_objects
()
self
.
add_connectors
()
def
add_objects
(
self
):
simbricks_pcie_dev
=
self
.
add_pre_obj
(
'simbricks_pcie_dev'
,
'simbricks_pcie'
)
simbricks_pcie_dev
.
socket
=
self
.
socket
.
val
simbricks_pcie_dev
.
pci_latency
=
self
.
pci_latency
.
val
simbricks_pcie_dev
.
sync_period
=
self
.
sync_period
.
val
def
add_connectors
(
self
):
self
.
add_connector
(
slot
=
'pci_bus'
,
type
=
'pci-bus'
,
hotpluggable
=
True
,
required
=
True
,
multi
=
False
,
direction
=
simics
.
Sim_Connector_Direction_Up
)
class
basename
(
StandardComponent
.
basename
):
"""The default name for the created component."""
val
=
'simbricks_pcie'
class
socket
(
SimpleConfigAttribute
(
None
,
's'
,
simics
.
Sim_Attr_Required
)):
"""Socket Path for SimBricks messages."""
class
pci_latency
(
SimpleConfigAttribute
(
None
,
'i'
,
simics
.
Sim_Attr_Required
)
):
"""PCI Latency in nanoseconds from host to device."""
class
sync_period
(
SimpleConfigAttribute
(
None
,
'i'
,
simics
.
Sim_Attr_Required
)
):
"""Period for sending SimBricks synchronization messages in
nanoseconds."""
class
component_connector
(
Interface
):
"""Uses connector for handling connections between components."""
def
get_check_data
(
self
,
cnt
):
return
[]
def
get_connect_data
(
self
,
cnt
):
return
[[[
0
,
self
.
_up
.
get_slot
(
'simbricks_pcie_dev'
)]]]
def
check
(
self
,
cnt
,
attr
):
return
True
def
connect
(
self
,
cnt
,
attr
):
self
.
_up
.
get_slot
(
'simbricks_pcie_dev'
).
pci_bus
=
attr
[
1
]
def
disconnect
(
self
,
cnt
):
self
.
_up
.
get_slot
(
'simbricks_pcie_dev'
).
pci_bus
=
None
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment