Skip to content
This repository has been archived by the owner on Jan 7, 2023. It is now read-only.

Python API

Andrey Ayupov edited this page Mar 23, 2017 · 5 revisions

Python Interface Spec API

See Code Generation section for usage guidelines.

Basic Features

Sample of a basic interface spec in Python:

from cog_acctempl import *

dut = DUT("cycle_detection")

inps = [TypedRead("Node","inp",buf_size_in_cl = 2, max_burst_count = 1)]
outs = [TypedWrite("CycleExistInfo","out")]

dut.add_rds(inps)
dut.add_wrs(outs)

dut.add_ut( UserType("Node",[UnsignedLongLongField("next_offset"), UnsignedLongLongField("val")]) )
dut.add_ut( UserType("CycleExistInfo",[UnsignedIntField("info")]) )

Design Name and Config

DUT and design name

DUT is a class used to define a design. Below are its methods:

DUT(nm) constructor that takes a name of the design. Generated files will have this name as prefix.

  • nm - String - given name of the design

add_rd(v) adds a memory read port to the design

  • v - [TypedRead|SingleRead] - read port

add_wr(v) adds a memory write port to the design

  • v - TypedWrite - write port

add_rds(l) adds a list of memory read ports to the design

  • l - List of [TypedRead|SingleRead] - list of read ports

add_wrs(l) adds a list of memory write ports to the design

  • l - List of TypedWrite - list of write ports

add_ut(v) adds a user type to the design

  • v - UserType - user type

get_ut(ty) returns a user type given a type name

  • ty - String - type name

add_extra_config_field(v) adds extra fields to the config struct in addition to automatically created used for memory ports

  • v - [ArrayField|BitReducedField|UserTypeField|{Unsigned,Signed}{LongLong,Int,Short,Char}Field] - field

add_extra_config_fields(l) adds a list of extra fields to the config struct in addition to automatically created fields used for memory ports

  • l - List of [ArrayField|BitReducedField|UserTypeField|{Unsigned,Signed}{LongLong,Int,Short,Char}Field]

Memory Interface Types

TypedRead

TypedRead defines a burst read port bundle and a corresponding AccIn load-unit(C++ reference guide). It can be used for both streaming and random accesses. The responses will arrive in the same order as requests were sent.

TypedRead (ty, nm, buf_size_in_cl = "128", max_burst_count = "1<<24", buf_size_in_burst_reqs = None)

  • ty - String - payload type (one of User Interface Type)
  • nm - String - prefix of the bundle (actual port names will get special suffixes)
  • buf_size_in_cl - String - number of parallel outstanding cacheline-worth requests in flight supported (user type objects will be packed into cachelines for streaming requests and each user type request will initiate a cacheline-worth request for random requests)
  • max_burst_count - String - maximum number of requested per one request in user type (e.g. may be 1 for random accesses or very large value for streaming accesses)
  • buf_size_in_burst_reqs - String - maximum number of parallel user requests in flight (should be not assigned for random acceses, but can be 1 for streaming applications when you request a large chunk of data but only once)

SingleRead

SingleRead represents a random access read port and a corresponding AccIn load-unit (C++ reference guide). It should be used for random read requests only. The responses may come out of order. The unit may have better performance than the TypedRead port for this memory access pattern.

SingleRead(ty, tag_ty, nm, buf_size = "128")

  • ty - String - payload type (one of User Interface Type)
  • tag_ty - String - tag type that is the type of a tag that will be send along with each request and will arrive with a corresponding response. It is used to match a response to a request.
  • nm - String - prefix of the bundle (actual port names will get special suffixes)
  • buf_size - String - number of outstanding request in user types (usually large 64-128)

TypedWrite

TypedWrite represents a streaming write port and a corresponding store-unit (C++ reference guide)

TypedWrite(ty, nm)

  • ty - String - payload type (one of User Interface Type)
  • nm - String - prefix of the bundle (actual port names will get special suffixes)

User Interface Types

usertypes is an associative map and it captures information about user C-structs that are used as payloads for the memory interfaces. The key to the map is the alias name of a struct (often real struct name). The value is the UserType object.

UserType(ty, fields)

  • ty - String - struct name
  • fields - List of [ArrayField|BitReducedField|UserTypeField|{Unsigned,Signed}{LongLong,Int,Short,Char}Field] - fields of the struct

ArrayField(ty, count) Used to have a C array of elements in the struct

  • ty - [UserTypeField|{Unsigned,Signed}{LongLong,Int,Short,Char}Field] - array element type
  • count - Int - size of the array

BitReducedField(ty, bitwidth) Used to represent bit fields of C-structs (e.g. int data : 5)

  • ty - [{Unsigned,Signed}{LongLong,Int,Short,Char}Field] - type
  • bitwidth - Int - bitwidth (must be less or equal than the parent type can hold)

UnsignedLongLongField(nm) Represents 'unsigned long long' C type

  • nm - String - name of the field of C type unsigned long long

SignedLongLongField(nm) Represents 'long long' C type

  • nm - String - name of the field of C type long long

UnsignedIntField(nm) Represents 'unsigned int' C type

  • nm - String - name of the field of C type unsigned int

SignedIntField(nm) Represents 'int' C type

  • nm - String - name of the field of C type int

UnsignedShortField(nm) Represents 'unsigned short' C type

  • nm - String - name of the field of C type unsigned short

SignedShortField(nm) Represents 'short' C type

  • nm - String - name of the field of C type short

UnsignedCharField(nm) Represents 'unsigned char' C type

  • nm - String - name of the field of C type unsigned char

SignedCharField(nm) Represents 'char' C type

  • nm - String - name of the field of C type char

UserTypeField(nm, ty) Represents a user type. Can be used to create an array of structs or to include a struct in another struct

  • nm - String - name of the field
  • ty - String - name of the struct

Advanced Features

Sample of more advanced interface specs in Python:

...

dut.module.add_cthreads( [CThread("inp_fetcher",writes_to_done=True),
                          CThread("inp_addr_gen"),
                          CThread("out_addr_gen")])

dut.get_cthread( "inp_fetcher").add_ports( [RdRespPort("inp"),
                                            WrDataPort("out")])

dut.get_cthread( "inp_addr_gen").add_ports( [RdReqPort("inp")])
dut.get_cthread( "out_addr_gen").add_ports( [WrReqPort("out")])

if __name__ == "__main__":
    dut.dump_dot( dut.nm + ".dot")

Here are more member variable and methods on the DUT class:

add_cthread(v), add_cthreads(vs), get_cthreads(nm) add a get cthreads

add_storage_fifo(v), add_storage_fifos(vs) add a storage (internal) fifo to the module

dump_dot(fn) writes a dot formatted file describing the interconnect structure of the modules and threads.

  • fn - String - filename

This class defines an internal FIFO

StorageFIFO(ty, capacity, nm)

  • capacity - Int - number of storage locations

  • nm - String - name of the storage fifo

Here are several classes for expressing ports. Only the constructor is needed.

Port( channel) is the superclass of the following six. For all, channel is a String refering to the name of the channel

RdReqPort( channel) the request port of a read (input) channel

RdRespPort( channel) the response port of a read (input) channel

WrReqPort( channel) the request port of a write (output) channel

WrDataPort( channel) the data port of a write (output) channel

EnqueuePort( channel) the enqueue (put) side of a storage fifo

DequeuePort( channel) the dequeue (get) side of a storage fifo

The channel interconnection structure is specified using this classs.

CThread( nm, ports=None, writes_to_done=False)

  • nm - String - naming the thread

  • ports is a list of Port objects used in this thread

  • writes_to_done - Bool - specifies whether this thread is (uniquely) responsible for signaling completion

Instead of assigning the ports in the constructor, you can alternatively use the methods add_port( p) and add_ports( ps) to attach ports to threads where p is a single Port object and ps is a list of Port objects.

Internal Hierarchy

We can also group the threads into internal modules (currently one-level) to allow easier experimentation with backend-flows.

To the DUT class we have

add_module(v), add_modules(vs), get_module(nm) add and get modules

The class Module contains these member methods:

add_cthread(v), add_cthreads(vs), get_cthreads(nm) add and get cthreads

add_storage_fifo(v), add_storage_fifos(vs) add a storage (internal) fifo to the module

The follow specification produces the hierarchy shown in the diagram.

...
dut.add_modules( [Module("frontend")])

dut.get_module("frontend").add_cthreads( [CThread("inp_fetcher",writes_to_done=True),
                                          CThread("inp_addr_gen")])

dut.module.add_cthreads( [CThread("out_addr_gen")])

dut.get_cthread( "inp_fetcher").add_ports( [RdRespPort("inp"),
                                            WrDataPort("out")])

dut.get_cthread( "inp_addr_gen").add_ports( [RdReqPort("inp")])
dut.get_cthread( "out_addr_gen").add_ports( [WrReqPort("out")])
...

drawing

The two threads inp_addr_gen and inp_fetcher were encapsulated in the internal module named frontend. All necessary SystemC boilerplate is generated automatically.