Here we will explain how to create an hardware version of a task, writing its SocLib equivalent model.
For instance in the explaination of the process, we'll write a IDCT (inverse discrete cosine transform) coprocessor.
- It handles packets of 64 values, representing a block of 8*8 coefficients
- It has one input and one output fifo
- Input is 32-bit coefficients, output is 8-bit pixels
Coprocessor
First we'll write the coprocessor in Caba SystemC?.
see trunk/dsx/lib/soclib/modules/fifo_idct/caba
Declaration for SocLib code generation
We have to declare this component to soclib build system, see wiki:SoclibDesc:
in trunk/dsx/lib/soclib/modules/fifo_idct/caba/metadata/fifo_idct.sd:
Module('caba:fifo_idct',
classname = 'dsx::caba::FifoIdct',
header_files = [
"../source/include/fifo_idct.h",
"../../include/fifo_idct.h",
],
implementation_files = [
"../source/src/fifo_idct.cpp",
],
ports = [
Port('caba:fifo_output', 'p_to_ctrl'),
Port('caba:fifo_input', 'p_from_ctrl'),
Port('caba:bit_in', 'p_resetn', auto = 'resetn'),
Port('caba:clock_in', 'p_clk', auto = 'clock'),
],
uses = [
Uses('caba:base_module'),
],
instance_parameters = [
parameter.Int('latency'),
],
tmpl_parameters = [
parameter.Type('word_t'),
],
)
Task declaration
Now we define a task, with a software implementation, and a mwmr coprocessor implementation:
in idct.task:
TaskModel(
'hw_idct',
ports = {
'input':MwmrInput(64*4),
'output':MwmrOutput(64),
},
impls = [
SwTask( 'idct',
stack_size = 4096,
sources = [ 'idct.c' ],
defines = [ 'WIDTH', 'HEIGHT' ] ),
MwmrCoproc(
module = 'caba:fifo_idct',
from_coproc = [ 'output:to_ctrl' ],
to_coproc = [ 'input:from_ctrl' ],
config = [],
status = [],
latency = 128,
word_t = 'uint32_t' )
] )
Creating the coprocessor in the netlist
In our netlist, we now have to create the coprocessor and its controller. There is a helper function to do this:
import dsx
import soclib
# ....
# The helper function needs the task implementation: get the task model
idct = dsx.TaskModel.getByName('hw_idct').getImpl(soclib.HwTask)
# The we can call the helper function, it returns the controller
# and the coprocessor components freshly instanciated
# first argument is your current platform (the one from soclib.Architecture()
# second and third arguments are coprocessor and controller names
ctrl, coproc = idct.instanciate(arch, 'idct0', 'idct0_ctrl') # here names are "idct0" and "idct0_ctrl"
# Connections between the controller and the coprocessor has been completed (fifos, config, status)
# Anything else is to be done by the designer.
# For instance, connecting the controller to the interconnect, and assigning a segment to the controller.
ctrl.addSegment('idct0_ctrl', 0x70400000, 0x100, False)
ctrl.vci_initiator // vgmn.to_initiator.new()
ctrl.vci_target // vgmn.to_target.new()
That's all
Now we can map this coprocessor as an hardware task:
import dsx
# ....
tcg = dsx.Tcg(
....
dsx.Task( 'idct0', 'hw_idct', ... ),
....
)
....
mapper.map( "idct0",
coprocessor = "idct0",
controller = "idct0_ctrl")
