2018-11-01 23:32:23 UTC
As I'm sure most of you are aware, I added an implementation of the systemc
API/kernel in gem5. While it's now possible to instantiate systemc objects
in a gem5 config and hand around pointers to them using config parameters,
there isn't a way to hook those objects to gem5's memory system like native
objects which have gem5 ports.
TLM is a pretty big ball of stuff, and given the existing implementation
and my interest in not breaking that or creating something slightly
incompatible and/or confusing, I want to dump my thoughts so far and get
some feedback and even ideally assistance from some folks who know these
areas better than I do.
Connecting ports in gem5's configs:
At the topmost level, the port binding mechanism calls a python function
ccConnect on PortRef objects, the things which represent gem5 ports in
gem5's python configuration files. That function does some sanity checks,
and ultimately calls connectPorts which is a function exposed from C++.
The C++ implementation of connectPorts is in
src/python/pybind11/pyobject.cc, where it takes two sets of parameters, a
SimObject, name, and index for each side of the connection being made. This
file used to have a bunch of conditional compilation in it, but you may
remember some changes I made recently which got rid of that.
Looking at the body of this function, the first thing it does is to use
dynamic_cast to try to cast these SimObject pointers in to ethernet related
objects. If that's successful, then the assumption is that these objects
are really connecting together an Ethernet network, rather than the memory
interconnect network within a system. If so, then the lookupEthPort
function is called which extracts the appropriate interfaces, and those are
If that doesn't work, then the function moves on to check to see if the
SimObjects are MessageBuffers from Ruby. If so, then nothing happens since
apparently that's handled somewhere else(?).
Then finally if even that doesn't work, gem5 checks if the SimObjects are
MemObjects. If so, then they have their ports extracted with the
getMasterPort and getSlavePort functions which return port objects, and
then those are glued together.
It seems slightly dubious to me that these are all hanging off the same
port interface, but lets set that aside for now. What we have are really
three different mechanisms which are all serially in the same function, and
that function checks them one at a time to figure out which one applies.
This has at least two deficiencies. First, this function has a lot of
unrelated stuff in it depending on what flavor of binding it's doing. On
average, two thirds of the function is dead weight for any particular
Second, if we wanted to add a new type of binding, for instance between a
systemc object and a gem5 object or vice versa, then we'd have to modify
this common and fairly core file to build that in from the ground up.
I did a little research, and my understanding is that pybind11 will let you
polymorphically bind C++ functions to a single python function name. At
call time, it will check each one one at a time until it finds one that
works, and then will call that. By making connectPorts three different
functions which take pointers of the desired types and then binding all of
them to the connectPorts name in python, we make pybind11 the arbiter and
central collection point, rather than the hard coded body of this C++
Connecting systemc and gem5 objects:
I'm thinking there are two different ways to do this. The first would be to
make a systemc interface type which is the same as or inherits from the
gem5 port interface. The systemc module/model would need to speak the gem5
protocol directly, and this wouldn't be very easy to use when passing
through packets (or whatever TLM calls them) which were generated by a
module which didn't buy into using gem5's memory system protocol natively.
Looking at the code in util/tlm, I don't 100% understand what's going on
there (although the examples are great, thank you for those), but it looks
like you've already done something at least sort of like this. Is any of
that applicable here?
The second way would be to slightly repackage the bridge in util/tlm so
that it was more of a single entity in the gem5 config with two sides, a
gem5 side and a TLM side. This is a little different from how it looks like
it works in the examples since it's (by necessity) split into two halves
which live on either side of the gem5/systemc dividing line.
I understand this less, although I'll keep looking at it to try to grok all
the moving pieces. I haven't really learned much about TLM so that may be a
limiting factor in learning how this works. This seems like a more robust
solution and would leverage the work that's already been done, but I'm not
sure how much work it would be or if there would be significant gotchas
Thoughts/feedback would be greatly appreciated! Thanks!