diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index c393708..33e4921 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -66,4 +66,6 @@ jobs: pytest ../cgra/translate/CGRAMemRightAndBottomRTL_matmul_2x2_test.py -xvs --tb=short pytest ../cgra/translate/CGRAMemRightAndBottomRTL_matmul_2x2_test.py -xvs --tb=short --test-verilog --dump-vtb --dump-vcd pytest ../noc/PyOCN/pymtl3_net/ringnet/test/RingNetworkRTL_test.py --tb=short -sv + pytest --tb=short -sv ../cgra/translate/CGRAWithControllerRTL_test.py --test-verilog --dump-vtb --dump-vcd + pytest --tb=short -sv ../scale_out/translate/RingMultiCGRARTL_test.py --test-verilog --dump-vtb --dump-vcd diff --git a/cgra/CGRAWithControllerRTL.py b/cgra/CGRAWithControllerRTL.py new file mode 100644 index 0000000..1695993 --- /dev/null +++ b/cgra/CGRAWithControllerRTL.py @@ -0,0 +1,130 @@ +""" +========================================================================= +CGRAWithControllerRTL.py +========================================================================= + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + +from pymtl3 import * +from ..fu.flexible.FlexibleFuRTL import FlexibleFuRTL +from ..fu.single.MemUnitRTL import MemUnitRTL +from ..fu.single.AdderRTL import AdderRTL +from ..lib.util.common import * +from ..lib.basic.en_rdy.ifcs import SendIfcRTL, RecvIfcRTL +from ..lib.basic.val_rdy.ifcs import ValRdySendIfcRTL +from ..lib.basic.val_rdy.ifcs import ValRdyRecvIfcRTL +from ..lib.opt_type import * +from ..mem.data.DataMemScalableRTL import DataMemScalableRTL +from ..noc.ChannelNormalRTL import ChannelNormalRTL +from ..noc.CrossbarSeparateRTL import CrossbarSeparateRTL +from ..tile.TileSeparateCrossbarRTL import TileSeparateCrossbarRTL +from ..controller.ControllerRTL import ControllerRTL + + +class CGRAWithControllerRTL(Component): + + def construct(s, DataType, PredicateType, CtrlType, NocPktType, + width, height, ctrl_mem_size, data_mem_size, num_ctrl, + total_steps, FunctionUnit, FuList, preload_data = None, + preload_const = None): + + s.num_tiles = width * height + s.num_mesh_ports = 4 + AddrType = mk_bits(clog2(ctrl_mem_size)) + + # Interfaces + s.recv_waddr = [RecvIfcRTL(AddrType) for _ in range(s.num_tiles)] + s.recv_wopt = [RecvIfcRTL(CtrlType) for _ in range(s.num_tiles)] + + # Explicitly provides the ValRdyRecvIfcRTL in the library, as the + # translation pass sometimes not able to distinguish the + # EnRdyRecvIfcRTL from it. + s.recv_from_other = ValRdyRecvIfcRTL(NocPktType) + s.send_to_other = ValRdySendIfcRTL(NocPktType) + + # s.recv_towards_controller = RecvIfcRTL(DataType) + # s.send_from_controller = SendIfcRTL(DataType) + + + # Components + if preload_const == None: + preload_const = [[DataType(0, 0)] for _ in range(width*height)] + s.tile = [TileSeparateCrossbarRTL(DataType, PredicateType, CtrlType, + ctrl_mem_size, data_mem_size, num_ctrl, + total_steps, 4, 2, s.num_mesh_ports, + s.num_mesh_ports, const_list = preload_const[i]) + for i in range( s.num_tiles)] + s.data_mem = DataMemScalableRTL(DataType, data_mem_size, height, height, preload_data) + s.controller = ControllerRTL(NocPktType, DataType, AddrType) + + # Connections + + # Connects data memory with controller. + s.data_mem.recv_from_noc //= s.controller.send_to_master + s.data_mem.send_to_noc //= s.controller.recv_from_master + + s.recv_from_other //= s.controller.recv_from_other + s.send_to_other //= s.controller.send_to_other + + # s.recv_towards_controller //= s.controller.recv_from_master + # s.send_from_controller //= s.controller.send_to_master + + for i in range(s.num_tiles): + s.recv_waddr[i] //= s.tile[i].recv_waddr + s.recv_wopt[i] //= s.tile[i].recv_wopt + + if i // width > 0: + s.tile[i].send_data[PORT_SOUTH] //= s.tile[i-width].recv_data[PORT_NORTH] + + if i // width < height - 1: + s.tile[i].send_data[PORT_NORTH] //= s.tile[i+width].recv_data[PORT_SOUTH] + + if i % width > 0: + s.tile[i].send_data[PORT_WEST] //= s.tile[i-1].recv_data[PORT_EAST] + + if i % width < width - 1: + s.tile[i].send_data[PORT_EAST] //= s.tile[i+1].recv_data[PORT_WEST] + + if i // width == 0: + s.tile[i].send_data[PORT_SOUTH].rdy //= 0 + s.tile[i].recv_data[PORT_SOUTH].en //= 0 + s.tile[i].recv_data[PORT_SOUTH].msg //= DataType(0, 0) + + if i // width == height - 1: + s.tile[i].send_data[PORT_NORTH].rdy //= 0 + s.tile[i].recv_data[PORT_NORTH].en //= 0 + s.tile[i].recv_data[PORT_NORTH].msg //= DataType(0, 0) + + if i % width == 0: + s.tile[i].send_data[PORT_WEST].rdy //= 0 + s.tile[i].recv_data[PORT_WEST].en //= 0 + s.tile[i].recv_data[PORT_WEST].msg //= DataType(0, 0) + + if i % width == width - 1: + s.tile[i].send_data[PORT_EAST].rdy //= 0 + s.tile[i].recv_data[PORT_EAST].en //= 0 + s.tile[i].recv_data[PORT_EAST].msg //= DataType(0, 0) + + if i % width == 0: + s.tile[i].to_mem_raddr //= s.data_mem.recv_raddr[i//width] + s.tile[i].from_mem_rdata //= s.data_mem.send_rdata[i//width] + s.tile[i].to_mem_waddr //= s.data_mem.recv_waddr[i//width] + s.tile[i].to_mem_wdata //= s.data_mem.recv_wdata[i//width] + else: + s.tile[i].to_mem_raddr.rdy //= 0 + s.tile[i].from_mem_rdata.en //= 0 + s.tile[i].from_mem_rdata.msg //= DataType(0, 0) + s.tile[i].to_mem_waddr.rdy //= 0 + s.tile[i].to_mem_wdata.rdy //= 0 + + + # Line trace + def line_trace( s ): + # str = "||".join([ x.element.line_trace() for x in s.tile ]) + # str += " :: [" + s.data_mem.line_trace() + "]" + res = "||\n".join([ (("[tile"+str(i)+"]: ") + x.line_trace() + x.ctrl_mem.line_trace()) + for (i,x) in enumerate(s.tile) ]) + res += "\n :: [" + s.data_mem.line_trace() + "] \n" + return res diff --git a/cgra/test/CGRAWithControllerRTL_test.py b/cgra/test/CGRAWithControllerRTL_test.py new file mode 100644 index 0000000..4d50a18 --- /dev/null +++ b/cgra/test/CGRAWithControllerRTL_test.py @@ -0,0 +1,156 @@ +""" +========================================================================== +CGRAWithControllerRTL_test.py +========================================================================== +Test cases for CGRA with controller. + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.test_utils import (run_sim, + config_model_with_cmdline_opts) +from pymtl3.passes.backends.verilog import (VerilogTranslationPass, + VerilogVerilatorImportPass) +from ..CGRAWithControllerRTL import CGRAWithControllerRTL +from ...fu.flexible.FlexibleFuRTL import FlexibleFuRTL +from ...fu.single.AdderRTL import AdderRTL +from ...fu.single.MemUnitRTL import MemUnitRTL +from ...fu.single.ShifterRTL import ShifterRTL +from ...lib.messages import * +from ...lib.opt_type import * +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL + + +#------------------------------------------------------------------------- +# Test harness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, width, height, ctrl_mem_size, + data_mem_size, src_opt, ctrl_waddr): + + s.num_tiles = width * height + AddrType = mk_bits(clog2(ctrl_mem_size)) + + s.src_opt = [TestSrcRTL(CtrlType, src_opt[i]) + for i in range(s.num_tiles)] + s.ctrl_waddr = [TestSrcRTL(AddrType, ctrl_waddr[i]) + for i in range(s.num_tiles)] + + s.dut = DUT(DataType, PredicateType, CtrlType, NocPktType, + width, height, ctrl_mem_size, data_mem_size, + len(src_opt[0]), len(src_opt[0]), FunctionUnit, FuList) + + # Connections + s.dut.send_to_other.rdy //= 0 + s.dut.recv_from_other.val //= 0 + s.dut.recv_from_other.msg //= NocPktType(0, 0, 0, 0, 0, 0) + + for i in range(s.num_tiles): + connect(s.src_opt[i].send, s.dut.recv_wopt[i]) + connect(s.ctrl_waddr[i].send, s.dut.recv_waddr[i]) + + def done(s): + done = True + for i in range(s.num_tiles): + if not s.src_opt[i].done(): + done = False + break + return done + + def line_trace(s): + return s.dut.line_trace() + +def test_homo_2x2(cmdline_opts): + num_tile_inports = 4 + num_tile_outports = 4 + num_fu_inports = 4 + num_fu_outports = 2 + num_routing_outports = num_tile_outports + num_fu_inports + ctrl_mem_size = 6 + data_mem_size = 8 + width = 2 + height = 2 + TileInType = mk_bits(clog2(num_tile_inports + 1)) + FuInType = mk_bits(clog2(num_fu_inports + 1)) + FuOutType = mk_bits(clog2(num_fu_outports + 1)) + AddrType = mk_bits(clog2(ctrl_mem_size)) + num_tiles = width * height + DUT = CGRAWithControllerRTL + FunctionUnit = FlexibleFuRTL + FuList = [MemUnitRTL, AdderRTL] + DataType = mk_data(32, 1) + PredicateType = mk_predicate(1, 1) + CtrlType = mk_separate_ctrl(num_fu_inports, num_fu_outports, + num_tile_inports, num_tile_outports) + NocPktType = mk_ring_multi_cgra_pkt(nrouters = 4, + payload_nbits = 32, + predicate_nbits = 1) + pickRegister = [FuInType(x + 1) for x in range(num_fu_inports)] + src_opt = [[ + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + # TODO: make below as TileInType(5) to double check. + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_STR, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]) + + ] for _ in range(num_tiles)] + ctrl_waddr = [[AddrType(0), AddrType(1), AddrType(2), AddrType(3), + AddrType(4), AddrType(5)] for _ in range(num_tiles)] + th = TestHarness(DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, width, height, ctrl_mem_size, + data_mem_size, src_opt, ctrl_waddr) + th.elaborate() + th.dut.set_metadata(VerilogVerilatorImportPass.vl_Wno_list, + ['UNSIGNED', 'UNOPTFLAT', 'WIDTH', 'WIDTHCONCAT', + 'ALWCOMBORDER']) + th = config_model_with_cmdline_opts(th, cmdline_opts, duts=['dut']) + run_sim(th) + diff --git a/cgra/translate/CGRAWithControllerRTL_test.py b/cgra/translate/CGRAWithControllerRTL_test.py new file mode 100644 index 0000000..4d50a18 --- /dev/null +++ b/cgra/translate/CGRAWithControllerRTL_test.py @@ -0,0 +1,156 @@ +""" +========================================================================== +CGRAWithControllerRTL_test.py +========================================================================== +Test cases for CGRA with controller. + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.test_utils import (run_sim, + config_model_with_cmdline_opts) +from pymtl3.passes.backends.verilog import (VerilogTranslationPass, + VerilogVerilatorImportPass) +from ..CGRAWithControllerRTL import CGRAWithControllerRTL +from ...fu.flexible.FlexibleFuRTL import FlexibleFuRTL +from ...fu.single.AdderRTL import AdderRTL +from ...fu.single.MemUnitRTL import MemUnitRTL +from ...fu.single.ShifterRTL import ShifterRTL +from ...lib.messages import * +from ...lib.opt_type import * +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL + + +#------------------------------------------------------------------------- +# Test harness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, width, height, ctrl_mem_size, + data_mem_size, src_opt, ctrl_waddr): + + s.num_tiles = width * height + AddrType = mk_bits(clog2(ctrl_mem_size)) + + s.src_opt = [TestSrcRTL(CtrlType, src_opt[i]) + for i in range(s.num_tiles)] + s.ctrl_waddr = [TestSrcRTL(AddrType, ctrl_waddr[i]) + for i in range(s.num_tiles)] + + s.dut = DUT(DataType, PredicateType, CtrlType, NocPktType, + width, height, ctrl_mem_size, data_mem_size, + len(src_opt[0]), len(src_opt[0]), FunctionUnit, FuList) + + # Connections + s.dut.send_to_other.rdy //= 0 + s.dut.recv_from_other.val //= 0 + s.dut.recv_from_other.msg //= NocPktType(0, 0, 0, 0, 0, 0) + + for i in range(s.num_tiles): + connect(s.src_opt[i].send, s.dut.recv_wopt[i]) + connect(s.ctrl_waddr[i].send, s.dut.recv_waddr[i]) + + def done(s): + done = True + for i in range(s.num_tiles): + if not s.src_opt[i].done(): + done = False + break + return done + + def line_trace(s): + return s.dut.line_trace() + +def test_homo_2x2(cmdline_opts): + num_tile_inports = 4 + num_tile_outports = 4 + num_fu_inports = 4 + num_fu_outports = 2 + num_routing_outports = num_tile_outports + num_fu_inports + ctrl_mem_size = 6 + data_mem_size = 8 + width = 2 + height = 2 + TileInType = mk_bits(clog2(num_tile_inports + 1)) + FuInType = mk_bits(clog2(num_fu_inports + 1)) + FuOutType = mk_bits(clog2(num_fu_outports + 1)) + AddrType = mk_bits(clog2(ctrl_mem_size)) + num_tiles = width * height + DUT = CGRAWithControllerRTL + FunctionUnit = FlexibleFuRTL + FuList = [MemUnitRTL, AdderRTL] + DataType = mk_data(32, 1) + PredicateType = mk_predicate(1, 1) + CtrlType = mk_separate_ctrl(num_fu_inports, num_fu_outports, + num_tile_inports, num_tile_outports) + NocPktType = mk_ring_multi_cgra_pkt(nrouters = 4, + payload_nbits = 32, + predicate_nbits = 1) + pickRegister = [FuInType(x + 1) for x in range(num_fu_inports)] + src_opt = [[ + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + # TODO: make below as TileInType(5) to double check. + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_STR, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]) + + ] for _ in range(num_tiles)] + ctrl_waddr = [[AddrType(0), AddrType(1), AddrType(2), AddrType(3), + AddrType(4), AddrType(5)] for _ in range(num_tiles)] + th = TestHarness(DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, width, height, ctrl_mem_size, + data_mem_size, src_opt, ctrl_waddr) + th.elaborate() + th.dut.set_metadata(VerilogVerilatorImportPass.vl_Wno_list, + ['UNSIGNED', 'UNOPTFLAT', 'WIDTH', 'WIDTHCONCAT', + 'ALWCOMBORDER']) + th = config_model_with_cmdline_opts(th, cmdline_opts, duts=['dut']) + run_sim(th) + diff --git a/controller/ControllerRTL.py b/controller/ControllerRTL.py new file mode 100644 index 0000000..8fc4664 --- /dev/null +++ b/controller/ControllerRTL.py @@ -0,0 +1,106 @@ +""" +========================================================================== +ControllerRTL.py +========================================================================== +Simple controller for CGRA. + +Author : Cheng Tan + Date : Dec 2, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.primitive import RegisterFile +from ..lib.basic.en_rdy.ifcs import SendIfcRTL, RecvIfcRTL +from ..lib.basic.val_rdy.ifcs import SendIfcRTL as ValRdySendIfcRTL +from ..lib.basic.val_rdy.ifcs import RecvIfcRTL as ValRdyRecvIfcRTL +from ..noc.ChannelNormalRTL import ChannelNormalRTL +from ..lib.opt_type import * + + +class ControllerRTL(Component): + + def construct(s, RingPktType, CGRADataType, CGRAAddrType): + + # # Constant + + # AddrType = mk_bits( clog2( data_mem_size ) ) + + # Interface + + # # Read/write Data from local CGRA data memory. + # s.recv_raddr_from_local = RecvIfcRTL(AddrType) + # s.send_rdata_from_local = SendIfcRTL(DataType) + # s.recv_waddr_from_local = RecvIfcRTL(AddrType) + # s.recv_wdata_from_local = RecvIfcRTL(DataType) + + # # Read/write Data to local CGRA data memory. + # s.recv_raddr_to_local = RecvIfcRTL(CGRAAddrType) + # s.send_rdata_to_local = SendIfcRTL(CGRADataType) + # s.recv_waddr_to_local = RecvIfcRTL(CGRAAddrType) + # s.recv_wdata_to_local = RecvIfcRTL(CGRADataType) + + # Request from other CGRA. + s.recv_from_other = ValRdyRecvIfcRTL(RingPktType) + s.send_to_other = ValRdySendIfcRTL(RingPktType) + + # Request from master. + s.recv_from_master = RecvIfcRTL(CGRADataType) + s.send_to_master = SendIfcRTL(CGRADataType) + + # Data formatting to simplify assignment. + s.pkt2data = Wire(CGRADataType) + s.data2pkt = Wire(RingPktType) + + + # Component + s.queue = ChannelNormalRTL(CGRADataType, latency = 1, num_entries = 2) + + # # TODO: below ifcs should be connected through another NoC within + # # one CGRA, instead of per-tile and performing like a bus. + # # Configuration signals to be written into and read from per-tile + # # control memory. + # s.recv_waddr = [RecvIfcRTL(AddrType) for _ in range(s.num_tiles)] + # s.recv_wopt = [RecvIfcRTL(CtrlType) for _ in range(s.num_tiles)] + + # s.send_waddr = [SendIfcRTL(AddrType) for _ in range(s.num_tiles)] + # s.send_wopt = [SendIfcRTL(CtrlType) for _ in range(s.num_tiles)] + + # # Cmd to invoke/terminate tiles execution. + # s.recv_cmd = [RecvIfcRTL(b2) for _ in range(s.num_tiles)] + # s.send_cmd = [SendIfcRTL(b2) for _ in range(s.num_tiles)] + + # Connections + s.queue.recv //= s.recv_from_master + + + @update + def update_data(): + s.pkt2data.payload @= s.recv_from_other.msg.payload + # s.data2pkt.payload @= s.recv_from_master.msg.payload + s.data2pkt.payload @= s.queue.send.msg.payload + s.data2pkt.src @= 1 + s.data2pkt.dst @= 2 + + + # Can also be @update instead of @update_ff + @update + def update_controller(): + s.recv_from_other.rdy @= s.send_to_master.rdy + s.send_to_master.en @= s.recv_from_other.val & s.send_to_master.rdy + s.send_to_master.msg @= s.pkt2data + + # s.recv_from_master.rdy @= s.send_to_other.rdy + # s.send_to_other.val @= s.recv_from_master.en + s.send_to_other.val @= s.queue.count > 0 + s.send_to_other.msg @= s.data2pkt + s.queue.send.rdy @= s.send_to_other.rdy + + + def line_trace(s): + recv_from_master_str = "recv_from_master: " + str(s.recv_from_master.msg) + send_to_master_str = "send_to_master: " + str(s.send_to_master.msg) + recv_from_other_str = "recv_from_other: " + str(s.recv_from_other.msg) + send_to_other_str = "send_to_other: " + str(s.send_to_other.msg) + return f'{recv_from_master_str} || {send_to_master_str} || {recv_from_other_str} || {send_to_other_str}' + diff --git a/multi_cgra/__init__.py b/controller/__init__.py similarity index 100% rename from multi_cgra/__init__.py rename to controller/__init__.py diff --git a/controller/test/ControllerRTL_test.py b/controller/test/ControllerRTL_test.py new file mode 100644 index 0000000..4fabc55 --- /dev/null +++ b/controller/test/ControllerRTL_test.py @@ -0,0 +1,127 @@ +''' +========================================================================= +ControllerRTL_test.py +========================================================================= +Simple test for ControllerRTL. + +Author : Cheng Tan + Date : Dec 2, 2024 +''' + + +from pymtl3 import * +from pymtl3.stdlib.test_utils import TestVectorSimulator +from ..ControllerRTL import ControllerRTL +from ...lib.basic.en_rdy.test_sinks import TestSinkRTL +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL +from ...lib.basic.val_rdy.SourceRTL import SourceRTL as TestValRdySrcRTL +from ...lib.basic.val_rdy.ifcs import SendIfcRTL as ValRdySendIfcRTL +from ...lib.basic.val_rdy.ifcs import RecvIfcRTL as ValRdyRecvIfcRTL +from ...lib.messages import * +from ...noc.PyOCN.pymtl3_net.ocnlib.test.stream_sinks import NetSinkRTL as TestNetSinkRTL +import pytest + + +#------------------------------------------------------------------------- +# TestHarness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, MsgType, PktType, AddrType, src_msgs, sink_msgs, src_pkts, sink_pkts): + + cmp_fn = lambda a, b : a.payload == b.payload + s.src_en_rdy = TestSrcRTL(MsgType, src_msgs) + s.sink_en_rdy = TestSinkRTL(MsgType, sink_msgs) + s.src_val_rdy = TestValRdySrcRTL(PktType, src_pkts) + s.sink_val_rdy = TestNetSinkRTL(PktType, sink_pkts, cmp_fn = cmp_fn) + + s.dut = ControllerRTL(PktType, MsgType, AddrType) + + # Connections + s.src_en_rdy.send //= s.dut.recv_from_master + s.dut.send_to_master //= s.sink_en_rdy.recv + s.src_val_rdy.send //= s.dut.recv_from_other + s.dut.send_to_other //= s.sink_val_rdy.recv + + def done(s): + return s.src_en_rdy.done() and s.sink_en_rdy.done() and \ + s.src_val_rdy.done() and s.sink_val_rdy.done() + + def line_trace( s ): + return s.dut.line_trace() + # return s.src.line_trace() + "-> | " + s.dut.line_trace() + # return s.src.line_trace() + "-> | " + s.dut.line_trace() + \ + # " | -> " + s.sink.line_trace() + +#------------------------------------------------------------------------- +# run_rtl_sim +#------------------------------------------------------------------------- + +def run_sim(test_harness, max_cycles=20): + + # Create a simulator + test_harness.elaborate() + test_harness.apply( DefaultPassGroup() ) + test_harness.sim_reset() + + # Run simulation + ncycles = 0 + print() + print( "{}:{}".format( ncycles, test_harness.line_trace() )) + while not test_harness.done() and ncycles < max_cycles: + test_harness.sim_tick() + ncycles += 1 + print( "{}:{}".format( ncycles, test_harness.line_trace() )) + + # Check timeout + assert ncycles < max_cycles + + test_harness.sim_tick() + test_harness.sim_tick() + test_harness.sim_tick() + +#------------------------------------------------------------------------- +# Test cases +#------------------------------------------------------------------------- + +def mk_src_pkts( nterminals, lst ): + src_pkts = [ [] for _ in range( nterminals ) ] + src = 0 + for pkt in lst: + if hasattr(pkt, 'fl_type'): + if pkt.fl_type == 0: + src = pkt.src + else: + src = pkt.src + src_pkts[ src ].append( pkt ) + return src_pkts + +DataType = mk_data(32, 1) +test_msgs = [DataType(1, 1, 1), DataType(2, 1), DataType(3, 1)] +sink_msgs = [DataType(4, 0), DataType(5, 0), DataType(6, 0)] + +nterminals = 4 +Pkt = mk_ring_multi_cgra_pkt(nterminals, payload_nbits = 32, + predicate_nbits = 1) +src_pkts = [ + # src dst opq vc payload predicate + Pkt(1, 2, 0, 0, 4, 0), + Pkt(1, 2, 0, 0, 5, 0), + Pkt(1, 2, 0, 0, 6, 0), +] + +sink_pkts = [ + # src dst opq vc payload predicate + Pkt(1, 2, 0, 0, 1, 0), + Pkt(1, 2, 0, 0, 2, 0), + Pkt(1, 2, 0, 0, 3, 0), +] + +ctrl_mem_size = 4 +AddrType = mk_bits(clog2(ctrl_mem_size)) + +def test_simple(): + th = TestHarness(DataType, Pkt, AddrType, test_msgs, sink_msgs, src_pkts, sink_pkts) + run_sim(th) + diff --git a/multi_cgra/test/__init__.py b/controller/test/__init__.py similarity index 100% rename from multi_cgra/test/__init__.py rename to controller/test/__init__.py diff --git a/lib/basic/val_rdy/ifcs.py b/lib/basic/val_rdy/ifcs.py index 0912b51..644b98f 100644 --- a/lib/basic/val_rdy/ifcs.py +++ b/lib/basic/val_rdy/ifcs.py @@ -29,6 +29,19 @@ def construct( s, Type ): def __str__( s ): return valrdy_to_str( s.msg, s.val, s.rdy, s.trace_len ) +class ValRdyRecvIfcRTL( Interface ): + + def construct( s, Type ): + + s.msg = InPort( Type ) + s.val = InPort() + s.rdy = OutPort() + + s.trace_len = len(str(Type())) + + def __str__( s ): + return valrdy_to_str( s.msg, s.val, s.rdy, s.trace_len ) + class SendIfcRTL( Interface ): def construct( s, Type ): @@ -42,6 +55,19 @@ def construct( s, Type ): def __str__( s ): return valrdy_to_str( s.msg, s.val, s.rdy, s.trace_len ) +class ValRdySendIfcRTL( Interface ): + + def construct( s, Type ): + + s.msg = OutPort( Type ) + s.val = OutPort() + s.rdy = InPort() + + s.trace_len = len(str(Type())) + + def __str__( s ): + return valrdy_to_str( s.msg, s.val, s.rdy, s.trace_len ) + class MasterIfcRTL( Interface ): def construct( s, ReqType, RespType ): s.ReqType = ReqType diff --git a/mem/data/DataMemScalableRTL.py b/mem/data/DataMemScalableRTL.py new file mode 100644 index 0000000..b23a739 --- /dev/null +++ b/mem/data/DataMemScalableRTL.py @@ -0,0 +1,122 @@ +""" +========================================================================== +DataMemScalableRTL.py +========================================================================== +Data memory for CGRA. It has addtional port to connect to controller, +which can be used for multi-CGRA fabric. + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.primitive import RegisterFile +from ...lib.basic.en_rdy.ifcs import SendIfcRTL, RecvIfcRTL +from ...lib.opt_type import * + + +class DataMemScalableRTL(Component): + + def construct(s, DataType, data_mem_size, rd_ports = 1, wr_ports = 1, + preload_data = None): + + # Constant + + AddrType = mk_bits(clog2(data_mem_size)) + + # Interface + + s.recv_raddr = [RecvIfcRTL(AddrType) for _ in range(rd_ports)] + s.send_rdata = [SendIfcRTL(DataType) for _ in range(rd_ports)] + s.recv_waddr = [RecvIfcRTL(AddrType) for _ in range(wr_ports)] + s.recv_wdata = [RecvIfcRTL(DataType) for _ in range(wr_ports)] + + s.recv_from_noc = RecvIfcRTL(DataType) + s.send_to_noc = SendIfcRTL(DataType) + + # Component + + s.reg_file = RegisterFile( DataType, data_mem_size, rd_ports, wr_ports + rd_ports ) + s.initWrites = [ Wire( b1 ) for _ in range( data_mem_size ) ] + + # FIXME: Following signals need to be set via some logic, i.e., + # handling miss accesses. + s.send_to_noc.en //= 0 + s.send_to_noc.msg //= DataType(0, 0) + s.recv_from_noc.rdy //= 0 + + if preload_data == None: + @update + def update_read_without_init(): + for i in range( rd_ports ): + # s.reg_file.wen[wr_ports + i] @= b1(0) + s.reg_file.raddr[i] @= s.recv_raddr[i].msg + s.send_rdata[i].msg @= s.reg_file.rdata[i] + + for i in range( wr_ports ): + s.reg_file.wen[i] @= b1(0) + s.reg_file.waddr[i] @= s.recv_waddr[i].msg + s.reg_file.wdata[i] @= s.recv_wdata[i].msg + if s.recv_waddr[i].en == b1(1): + s.reg_file.wen[i] @= s.recv_wdata[i].en & s.recv_waddr[i].en + + else: + s.preloadData = [ Wire( DataType ) for _ in range( data_mem_size ) ] + for i in range( len( preload_data ) ): + s.preloadData[ i ] //= preload_data[i] + + @update + def update_read_with_init(): + + for i in range( rd_ports ): + s.reg_file.wen[wr_ports + i] @= b1(0) + if s.initWrites[s.recv_raddr[i].msg] == b1(0): + s.send_rdata[i].msg @= s.preloadData[s.recv_raddr[i].msg] + s.reg_file.waddr[wr_ports + i] @= s.recv_raddr[i].msg + s.reg_file.wdata[wr_ports + i] @= s.preloadData[s.recv_raddr[i].msg] + s.reg_file.wen[wr_ports + i] @= b1(1) + else: + s.reg_file.raddr[i] @= s.recv_raddr[i].msg + s.send_rdata[i].msg @= s.reg_file.rdata[i] + + for i in range( wr_ports ): + if s.recv_waddr[i].en == b1(1): + s.reg_file.waddr[i] @= s.recv_waddr[i].msg + s.reg_file.wdata[i] @= s.recv_wdata[i].msg + s.reg_file.wen[i] @= s.recv_wdata[i].en & s.recv_waddr[i].en + + # Connections + + @update_ff + def update_init(): + for i in range( rd_ports ): + if s.recv_raddr[i].en == b1(1): + s.initWrites[s.recv_raddr[i].msg] <<= s.initWrites[s.recv_raddr[i].msg] | b1(1) + for i in range( wr_ports ): + if s.recv_waddr[i].en == b1(1): + s.initWrites[s.recv_waddr[i].msg] <<= s.initWrites[s.recv_waddr[i].msg] | b1(1) + + @update + def update_signal(): + for i in range( rd_ports ): + s.recv_raddr[i].rdy @= s.send_rdata[i].rdy + # b1( 1 ) # s.send_rdata[i].rdy + s.send_rdata[i].en @= s.recv_raddr[i].en + # s.send_rdata[i].rdy # s.recv_raddr[i].en + for i in range( wr_ports ): + s.recv_waddr[i].rdy @= Bits1( 1 ) + s.recv_wdata[i].rdy @= Bits1( 1 ) + + def line_trace(s): + recv_raddr_str = "recv_read_addr: " + "|".join([str(data.msg) for data in s.recv_raddr]) + recv_waddr_str = "recv_write_addr: " + "|".join([str(data.msg) for data in s.recv_waddr]) + recv_wdata_str = "recv_write_data: " + "|".join([str(data.msg) for data in s.recv_wdata]) + content_str = "content: " + "|".join([str(data) for data in s.reg_file.regs]) + send_rdata_str = "send_read_data: " + "|".join([str(data.msg) for data in s.send_rdata]) + return f'{recv_raddr_str} || {recv_waddr_str} || {recv_wdata_str} || [{content_str}] || {send_rdata_str}' + # return f'DataMem: {recv_str} : [{out_str}] : {send_str} initWrites: {s.initWrites}' + # return s.reg_file.line_trace() + # return f'<{s.reg_file.wen[0]}>{s.reg_file.waddr[0]}:{s.reg_file.wdata[0]}|{s.reg_file.raddr[0]}:{s.reg_file.rdata[0]}' + # rf_trace = f'<{s.reg_file.wen[0]}>{s.reg_file.waddr[0]}:{s.reg_file.wdata[0]}|{s.reg_file.raddr[0]}:{s.reg_file.rdata[0]}' + # return f'[{s.recv_wdata[0].en & s.recv_waddr[0].en}]{s.recv_waddr[0]}<{s.recv_wdata[0]}({rf_trace}){s.recv_raddr[0]}>{s.send_rdata[0]}' diff --git a/scale_out/RingMultiCGRARTL.py b/scale_out/RingMultiCGRARTL.py new file mode 100644 index 0000000..b55f17e --- /dev/null +++ b/scale_out/RingMultiCGRARTL.py @@ -0,0 +1,77 @@ +""" +========================================================================== +RingMultiCGRARTL.py +========================================================================== +Ring connecting multiple CGRAs, each CGRA contains one controller. + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.primitive import RegisterFile +from ..lib.basic.en_rdy.ifcs import SendIfcRTL, RecvIfcRTL +from ..lib.opt_type import * +from ..noc.PyOCN.pymtl3_net.ringnet.RingNetworkRTL import RingNetworkRTL +from ..cgra.CGRAWithControllerRTL import CGRAWithControllerRTL +from ..noc.PyOCN.pymtl3_net.ocnlib.ifcs.positions import mk_ring_pos + + +class RingMultiCGRARTL(Component): + + def construct(s, CGRADataType, CGRAAddrType, PredicateType, + CtrlType, NocPktType, num_terminals, width, height, + ctrl_mem_size, data_mem_size, num_ctrl, total_steps, + FunctionUnit, FuList, preload_data = None, + preload_const = None): + + # Constant + RingPos = mk_ring_pos(num_terminals) + s.num_terminals = num_terminals + s.num_tiles = width * height + AddrType = mk_bits(clog2(ctrl_mem_size)) + + # Interface + + # # Request from/to CPU. + # s.recv_from_cpu = RecvIfcRTL(CGRADataType) + # s.send_to_cpu = SendIfcRTL(CGRADataType) + s.recv_waddr = [[RecvIfcRTL(AddrType) for _ in range(s.num_tiles)] + for _ in range(s.num_terminals)] + s.recv_wopt = [[RecvIfcRTL(CtrlType) for _ in range(s.num_tiles)] + for _ in range(s.num_terminals)] + + + # Components + # s.controller = [ControllerRTL(RingPktType, CGRADataType, CGRAAddrType) + # for i in range(s.num_terminals)] + s.cgra = [CGRAWithControllerRTL( + CGRADataType, PredicateType, CtrlType, NocPktType, + width, height, ctrl_mem_size, data_mem_size, num_ctrl, + total_steps, FunctionUnit, FuList, preload_data = None, + preload_const = None) for i in range(s.num_terminals)] + s.ring = RingNetworkRTL(NocPktType, RingPos, num_terminals, 0) + + + # Connections + for i in range(s.num_terminals): + # s.recv_from_master[i] //= s.cgra[i].recv_from_master + # s.send_to_master[i] //= s.cgra[i].send_to_master + + # s.controller[i].recv_from_other //= s.ring.send[i] + # s.controller[i].send_to_other //= s.ring.recv[i] + s.ring.send[i] //= s.cgra[i].recv_from_other + s.ring.recv[i] //= s.cgra[i].send_to_other + + for j in range(s.num_tiles): + s.recv_waddr[i][j] //= s.cgra[i].recv_waddr[j] + s.recv_wopt[i][j] //= s.cgra[i].recv_wopt[j] + + + def line_trace(s): + res = "||\n".join([(("[cgra["+str(i)+"]: ") + x.line_trace()) + for (i,x) in enumerate(s.cgra)]) + res += " ## ring: " + s.ring.line_trace() + return res + diff --git a/scale_out/RingWithControllerRTL.py b/scale_out/RingWithControllerRTL.py new file mode 100644 index 0000000..091e912 --- /dev/null +++ b/scale_out/RingWithControllerRTL.py @@ -0,0 +1,58 @@ +""" +========================================================================== +RingWithControllerRTL.py +========================================================================== +Ring connecting multiple controllers. + +Author : Cheng Tan + Date : Dec 3, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.primitive import RegisterFile +from ..lib.basic.en_rdy.ifcs import SendIfcRTL, RecvIfcRTL +from ..lib.basic.val_rdy.ifcs import SendIfcRTL as ValRdySendIfcRTL +from ..lib.basic.val_rdy.ifcs import RecvIfcRTL as ValRdyRecvIfcRTL +from ..lib.opt_type import * +from ..noc.PyOCN.pymtl3_net.ringnet.RingNetworkRTL import RingNetworkRTL +from ..controller.ControllerRTL import ControllerRTL +from ..noc.PyOCN.pymtl3_net.ocnlib.ifcs.positions import mk_ring_pos + + +class RingWithControllerRTL(Component): + + def construct(s, RingPktType, CGRADataType, CGRAAddrType, num_terminals): + + # Constant + RingPos = mk_ring_pos(num_terminals) + s.num_terminals = num_terminals + + # Interface + + # Request from/to master. + s.recv_from_master = [RecvIfcRTL(CGRADataType) for _ in range(s.num_terminals)] + s.send_to_master = [SendIfcRTL(CGRADataType) for _ in range(s.num_terminals)] + + # Components + s.controller = [ControllerRTL(RingPktType, CGRADataType, CGRAAddrType) + for i in range(s.num_terminals)] + s.ring = RingNetworkRTL(RingPktType, RingPos, num_terminals, 0) + + # Connections + for i in range(s.num_terminals): + s.recv_from_master[i] //= s.controller[i].recv_from_master + s.send_to_master[i] //= s.controller[i].send_to_master + + # s.controller[i].recv_from_other //= s.ring.send[i] + # s.controller[i].send_to_other //= s.ring.recv[i] + s.ring.send[i] //= s.controller[i].recv_from_other + s.ring.recv[i] //= s.controller[i].send_to_other + + + def line_trace(s): + res = "||\n".join([(("[controller["+str(i)+"]: ") + x.line_trace()) + for (i,x) in enumerate(s.controller)]) + res += " ## ring: " + s.ring.line_trace() + return res + diff --git a/scale_out/__init__.py b/scale_out/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scale_out/test/RingMultiCGRARTL_test.py b/scale_out/test/RingMultiCGRARTL_test.py new file mode 100644 index 0000000..017beec --- /dev/null +++ b/scale_out/test/RingMultiCGRARTL_test.py @@ -0,0 +1,166 @@ +""" +========================================================================== +CGRAWithControllerRTL_test.py +========================================================================== +Test cases for CGRA with controller. + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.test_utils import (run_sim, + config_model_with_cmdline_opts) +from pymtl3.passes.backends.verilog import (VerilogTranslationPass, + VerilogVerilatorImportPass) +from ..RingMultiCGRARTL import RingMultiCGRARTL +from ...fu.flexible.FlexibleFuRTL import FlexibleFuRTL +from ...fu.single.AdderRTL import AdderRTL +from ...fu.single.MemUnitRTL import MemUnitRTL +from ...fu.single.ShifterRTL import ShifterRTL +from ...lib.messages import * +from ...lib.opt_type import * +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL + + +#------------------------------------------------------------------------- +# Test harness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, num_terminals, width, height, + ctrl_mem_size, data_mem_size, src_opt, ctrl_waddr): + + s.num_terminals = num_terminals + s.num_tiles = width * height + AddrType = mk_bits(clog2(ctrl_mem_size)) + + s.src_opt = [[TestSrcRTL(CtrlType, src_opt[j]) + for j in range(s.num_tiles)] + for i in range(s.num_terminals)] + s.ctrl_waddr = [[TestSrcRTL(AddrType, ctrl_waddr[j]) + for j in range(s.num_tiles)] + for i in range(s.num_terminals)] + + s.dut = DUT(DataType, AddrType, PredicateType, CtrlType, NocPktType, + num_terminals, width, height, ctrl_mem_size, data_mem_size, + len(src_opt[0]), len(src_opt[0]), FunctionUnit, FuList) + + # Connections + # s.dut.data_mem.recv_from_noc.rdy //= 0 + # s.dut.data_mem.send_to_noc.msg //= DataType(0, 0) + # s.dut.data_mem.send_to_noc.en //= 0 + # s.src_val_rdy.send //= s.dut.recv_from_other + # s.dut.send_to_other //= s.sink_val_rdy.recv + + # s.dut.recv_towards_controller.en //= 0 + # s.dut.recv_towards_controller.msg //= DataType(0, 0) + # s.dut.send_from_controller.rdy //= 0 + + for i in range(num_terminals): + for j in range(s.num_tiles): + connect(s.src_opt[i][j].send, s.dut.recv_wopt[i][j]) + connect(s.ctrl_waddr[i][j].send, s.dut.recv_waddr[i][j]) + + def done(s): + for i in range(s.num_terminals): + for j in range(s.num_tiles): + if not s.src_opt[i][j].done(): + return False + return True + + def line_trace(s): + return s.dut.line_trace() + +def test_homo_2x2(cmdline_opts): + num_tile_inports = 4 + num_tile_outports = 4 + num_fu_inports = 4 + num_fu_outports = 2 + num_routing_outports = num_tile_outports + num_fu_inports + ctrl_mem_size = 6 + data_mem_size = 8 + num_terminals = 4 + width = 2 + height = 2 + TileInType = mk_bits(clog2(num_tile_inports + 1)) + FuInType = mk_bits(clog2(num_fu_inports + 1)) + FuOutType = mk_bits(clog2(num_fu_outports + 1)) + AddrType = mk_bits(clog2(ctrl_mem_size)) + num_tiles = width * height + DUT = RingMultiCGRARTL + FunctionUnit = FlexibleFuRTL + FuList = [MemUnitRTL, AdderRTL] + DataType = mk_data(32, 1) + PredicateType = mk_predicate(1, 1) + CtrlType = mk_separate_ctrl(num_fu_inports, num_fu_outports, + num_tile_inports, num_tile_outports) + NocPktType = mk_ring_multi_cgra_pkt(nrouters = num_terminals, + payload_nbits = 32, + predicate_nbits = 1) + pickRegister = [FuInType(x + 1) for x in range(num_fu_inports)] + src_opt = [[ + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + # TODO: make below as TileInType(5) to double check. + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_STR, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]) + + ] for _ in range(num_tiles)] + ctrl_waddr = [[AddrType(0), AddrType(1), AddrType(2), AddrType(3), + AddrType(4), AddrType(5)] for _ in range(num_tiles)] + th = TestHarness(DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, num_terminals, width, height, + ctrl_mem_size, data_mem_size, src_opt, ctrl_waddr) + th.elaborate() + th.dut.set_metadata(VerilogVerilatorImportPass.vl_Wno_list, + ['UNSIGNED', 'UNOPTFLAT', 'WIDTH', 'WIDTHCONCAT', + 'ALWCOMBORDER']) + th = config_model_with_cmdline_opts(th, cmdline_opts, duts=['dut']) + run_sim(th) + diff --git a/multi_cgra/test/RingNetworkRTL_test.py b/scale_out/test/RingNetworkRTL_test.py similarity index 96% rename from multi_cgra/test/RingNetworkRTL_test.py rename to scale_out/test/RingNetworkRTL_test.py index 25f8a85..d4b9bb0 100644 --- a/multi_cgra/test/RingNetworkRTL_test.py +++ b/scale_out/test/RingNetworkRTL_test.py @@ -95,7 +95,8 @@ def _test_cgra_data(s, translation = ''): ]) dst_pkts = ringnet_fl(src_pkts) th = TestHarness(Pkt, nterminals, src_pkts, dst_pkts) - cmdline_opts={'dump_vcd': False, 'test_verilog': translation, + # cmdline_opts={'dump_vcd': False, 'test_verilog': translation, + cmdline_opts={'dump_vcd': False, 'test_verilog': False, 'dump_vtb': False} run_sim(th, cmdline_opts) diff --git a/scale_out/test/RingWithControllerRTL_test.py b/scale_out/test/RingWithControllerRTL_test.py new file mode 100644 index 0000000..6581ad8 --- /dev/null +++ b/scale_out/test/RingWithControllerRTL_test.py @@ -0,0 +1,151 @@ +""" +========================================================================= +RingWithControllerRTL_test.py +========================================================================= +Test for RingControllerRTL with CGRA message. + +Author : Cheng Tan + Date : Dec 3, 2024 +""" + + +from pymtl3 import * +from ...lib.messages import * +from ...lib.opt_type import * +from ...lib.basic.en_rdy.test_sinks import TestSinkRTL +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL +from ...noc.PyOCN.pymtl3_net.ocnlib.utils import run_sim +from ..RingWithControllerRTL import RingWithControllerRTL + + +#------------------------------------------------------------------------- +# TestHarness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, RingPktType, CGRADataType, CGRAAddrType, num_terminals, + src_msgs, sink_msgs): + + s.num_terminals = num_terminals + s.srcs = [TestSrcRTL(CGRADataType, src_msgs[i]) + for i in range(num_terminals)] + s.dut = RingWithControllerRTL(RingPktType, CGRADataType, + CGRAAddrType, num_terminals) + s.sinks = [TestSinkRTL(CGRADataType, sink_msgs[i]) + for i in range(num_terminals)] + + # Connections + for i in range (s.dut.num_terminals): + s.srcs[i].send //= s.dut.recv_from_master[i] + s.dut.send_to_master[i] //= s.sinks[i].recv + + def done(s): + for i in range(s.num_terminals): + if not s.srcs[i].done() or not s.sinks[i].done(): + return False + return True + + def line_trace(s): + return s.dut.line_trace() + +#------------------------------------------------------------------------- +# run_rtl_sim +#------------------------------------------------------------------------- + +def run_sim(test_harness, max_cycles=20): + + # Create a simulator + test_harness.elaborate() + test_harness.apply( DefaultPassGroup() ) + test_harness.sim_reset() + + # Run simulation + ncycles = 0 + print() + print( "{}:{}".format( ncycles, test_harness.line_trace() )) + while not test_harness.done() and ncycles < max_cycles: + test_harness.sim_tick() + ncycles += 1 + print( "{}:{}".format( ncycles, test_harness.line_trace() )) + + # Check timeout + assert ncycles < max_cycles + + test_harness.sim_tick() + test_harness.sim_tick() + test_harness.sim_tick() + + +#========================================================================= +# Test cases +#========================================================================= + +# class RingWithController_Tests: +# +# @classmethod +# def setup_class(cls): +# cls.DutType = RingWithControllerRTL +# +# def _test_ring_data(s, translation = ''): +# DataType = mk_data(32, 1) +# num_terminals = 4 +# RingPktType = mk_ring_multi_cgra_pkt(num_terminals, +# payload_nbits = 32, +# predicate_nbits = 1) +# src_data = [ +# [], +# [], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)] +# ] +# +# sink_data = [ +# [], +# [], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)] +# ] +# +# ctrl_mem_size = 4 +# AddrType = mk_bits(clog2(ctrl_mem_size)) +# +# th = TestHarness(RingPktType, DataType, AddrType, num_terminals, +# src_data, sink_data) +# cmdline_opts={'dump_vcd': False, 'test_verilog': translation, +# 'dump_vtb': False} +# run_sim(th, cmdline_opts) +# +# def test_ring_data(self): +# self._test_ring_data('zeros') + + +DataType = mk_data(32, 1) +num_terminals = 4 +RingPktType = mk_ring_multi_cgra_pkt(num_terminals, + payload_nbits = 32, + predicate_nbits = 1) +src_data = [ + [], + [DataType(7, 1, 1), DataType(8, 1), DataType(9, 1)], + [DataType(1, 1, 1), DataType(2, 1), DataType(3, 1)], + [] + ] + +sink_data = [ + [], + [], + # The expected data is received in an interleaved way. + [DataType(1, 0, 0), DataType(7, 0, 0), DataType(2, 0, 0), DataType(8, 0, 0), DataType(3, 0, 0), DataType(9, 0, 0)], + [] + ] + +ctrl_mem_size = 4 +AddrType = mk_bits(clog2(ctrl_mem_size)) + +def test_simple(): + th = TestHarness(RingPktType, DataType, AddrType, num_terminals, + src_data, sink_data) + run_sim(th) + + diff --git a/scale_out/test/__init__.py b/scale_out/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scale_out/translate/RingMultiCGRARTL_test.py b/scale_out/translate/RingMultiCGRARTL_test.py new file mode 100644 index 0000000..017beec --- /dev/null +++ b/scale_out/translate/RingMultiCGRARTL_test.py @@ -0,0 +1,166 @@ +""" +========================================================================== +CGRAWithControllerRTL_test.py +========================================================================== +Test cases for CGRA with controller. + +Author : Cheng Tan + Date : Dec 4, 2024 +""" + + +from pymtl3 import * +from pymtl3.stdlib.test_utils import (run_sim, + config_model_with_cmdline_opts) +from pymtl3.passes.backends.verilog import (VerilogTranslationPass, + VerilogVerilatorImportPass) +from ..RingMultiCGRARTL import RingMultiCGRARTL +from ...fu.flexible.FlexibleFuRTL import FlexibleFuRTL +from ...fu.single.AdderRTL import AdderRTL +from ...fu.single.MemUnitRTL import MemUnitRTL +from ...fu.single.ShifterRTL import ShifterRTL +from ...lib.messages import * +from ...lib.opt_type import * +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL + + +#------------------------------------------------------------------------- +# Test harness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, num_terminals, width, height, + ctrl_mem_size, data_mem_size, src_opt, ctrl_waddr): + + s.num_terminals = num_terminals + s.num_tiles = width * height + AddrType = mk_bits(clog2(ctrl_mem_size)) + + s.src_opt = [[TestSrcRTL(CtrlType, src_opt[j]) + for j in range(s.num_tiles)] + for i in range(s.num_terminals)] + s.ctrl_waddr = [[TestSrcRTL(AddrType, ctrl_waddr[j]) + for j in range(s.num_tiles)] + for i in range(s.num_terminals)] + + s.dut = DUT(DataType, AddrType, PredicateType, CtrlType, NocPktType, + num_terminals, width, height, ctrl_mem_size, data_mem_size, + len(src_opt[0]), len(src_opt[0]), FunctionUnit, FuList) + + # Connections + # s.dut.data_mem.recv_from_noc.rdy //= 0 + # s.dut.data_mem.send_to_noc.msg //= DataType(0, 0) + # s.dut.data_mem.send_to_noc.en //= 0 + # s.src_val_rdy.send //= s.dut.recv_from_other + # s.dut.send_to_other //= s.sink_val_rdy.recv + + # s.dut.recv_towards_controller.en //= 0 + # s.dut.recv_towards_controller.msg //= DataType(0, 0) + # s.dut.send_from_controller.rdy //= 0 + + for i in range(num_terminals): + for j in range(s.num_tiles): + connect(s.src_opt[i][j].send, s.dut.recv_wopt[i][j]) + connect(s.ctrl_waddr[i][j].send, s.dut.recv_waddr[i][j]) + + def done(s): + for i in range(s.num_terminals): + for j in range(s.num_tiles): + if not s.src_opt[i][j].done(): + return False + return True + + def line_trace(s): + return s.dut.line_trace() + +def test_homo_2x2(cmdline_opts): + num_tile_inports = 4 + num_tile_outports = 4 + num_fu_inports = 4 + num_fu_outports = 2 + num_routing_outports = num_tile_outports + num_fu_inports + ctrl_mem_size = 6 + data_mem_size = 8 + num_terminals = 4 + width = 2 + height = 2 + TileInType = mk_bits(clog2(num_tile_inports + 1)) + FuInType = mk_bits(clog2(num_fu_inports + 1)) + FuOutType = mk_bits(clog2(num_fu_outports + 1)) + AddrType = mk_bits(clog2(ctrl_mem_size)) + num_tiles = width * height + DUT = RingMultiCGRARTL + FunctionUnit = FlexibleFuRTL + FuList = [MemUnitRTL, AdderRTL] + DataType = mk_data(32, 1) + PredicateType = mk_predicate(1, 1) + CtrlType = mk_separate_ctrl(num_fu_inports, num_fu_outports, + num_tile_inports, num_tile_outports) + NocPktType = mk_ring_multi_cgra_pkt(nrouters = num_terminals, + payload_nbits = 32, + predicate_nbits = 1) + pickRegister = [FuInType(x + 1) for x in range(num_fu_inports)] + src_opt = [[ + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + # TODO: make below as TileInType(5) to double check. + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + CtrlType(OPT_INC, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_STR, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]), + + CtrlType(OPT_ADD, b1(0), + pickRegister, + [TileInType(4), TileInType(3), TileInType(2), TileInType(1), + TileInType(0), TileInType(0), TileInType(0), TileInType(0)], + + [FuOutType(0), FuOutType(0), FuOutType(0), FuOutType(0), + FuOutType(1), FuOutType(1), FuOutType(1), FuOutType(1)]) + + ] for _ in range(num_tiles)] + ctrl_waddr = [[AddrType(0), AddrType(1), AddrType(2), AddrType(3), + AddrType(4), AddrType(5)] for _ in range(num_tiles)] + th = TestHarness(DUT, FunctionUnit, FuList, DataType, PredicateType, + CtrlType, NocPktType, num_terminals, width, height, + ctrl_mem_size, data_mem_size, src_opt, ctrl_waddr) + th.elaborate() + th.dut.set_metadata(VerilogVerilatorImportPass.vl_Wno_list, + ['UNSIGNED', 'UNOPTFLAT', 'WIDTH', 'WIDTHCONCAT', + 'ALWCOMBORDER']) + th = config_model_with_cmdline_opts(th, cmdline_opts, duts=['dut']) + run_sim(th) + diff --git a/scale_out/translate/RingWithControllerRTL_test.py b/scale_out/translate/RingWithControllerRTL_test.py new file mode 100644 index 0000000..d3cf9f5 --- /dev/null +++ b/scale_out/translate/RingWithControllerRTL_test.py @@ -0,0 +1,158 @@ +""" +========================================================================= +RingWithControllerRTL_test.py +========================================================================= +Test for RingControllerRTL with CGRA message. + +Author : Cheng Tan + Date : Dec 3, 2024 +""" + + +from pymtl3 import * +from ...lib.messages import * +from ...lib.opt_type import * +from ...lib.basic.en_rdy.test_sinks import TestSinkRTL +from ...lib.basic.en_rdy.test_srcs import TestSrcRTL +from ..RingWithControllerRTL import RingWithControllerRTL +from pymtl3.stdlib.test_utils import config_model_with_cmdline_opts +from pymtl3.passes.backends.verilog import (VerilogTranslationPass, + VerilogVerilatorImportPass) + + +#------------------------------------------------------------------------- +# TestHarness +#------------------------------------------------------------------------- + +class TestHarness(Component): + + def construct(s, RingPktType, CGRADataType, CGRAAddrType, num_terminals, + src_msgs, sink_msgs): + + s.num_terminals = num_terminals + s.srcs = [TestSrcRTL(CGRADataType, src_msgs[i]) + for i in range(num_terminals)] + s.dut = RingWithControllerRTL(RingPktType, CGRADataType, + CGRAAddrType, num_terminals) + s.sinks = [TestSinkRTL(CGRADataType, sink_msgs[i]) + for i in range(num_terminals)] + + # Connections + for i in range (s.dut.num_terminals): + s.srcs[i].send //= s.dut.recv_from_master[i] + s.dut.send_to_master[i] //= s.sinks[i].recv + + def done(s): + for i in range(s.num_terminals): + if not s.srcs[i].done() or not s.sinks[i].done(): + return False + return True + + def line_trace(s): + return s.dut.line_trace() + +#------------------------------------------------------------------------- +# run_rtl_sim +#------------------------------------------------------------------------- + +def run_sim(test_harness, max_cycles=20): + + # Create a simulator + test_harness.elaborate() + test_harness.apply( DefaultPassGroup() ) + test_harness.sim_reset() + + # Run simulation + ncycles = 0 + print() + print( "{}:{}".format( ncycles, test_harness.line_trace() )) + while not test_harness.done() and ncycles < max_cycles: + test_harness.sim_tick() + ncycles += 1 + print( "{}:{}".format( ncycles, test_harness.line_trace() )) + + # Check timeout + assert ncycles < max_cycles + + test_harness.sim_tick() + test_harness.sim_tick() + test_harness.sim_tick() + + +#========================================================================= +# Test cases +#========================================================================= + +# class RingWithController_Tests: +# +# @classmethod +# def setup_class(cls): +# cls.DutType = RingWithControllerRTL +# +# def _test_ring_data(s, translation = ''): +# DataType = mk_data(32, 1) +# num_terminals = 4 +# RingPktType = mk_ring_multi_cgra_pkt(num_terminals, +# payload_nbits = 32, +# predicate_nbits = 1) +# src_data = [ +# [], +# [], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)] +# ] +# +# sink_data = [ +# [], +# [], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)], +# [DataType(7, 1, 1), DataType(2, 1), DataType(3, 1)] +# ] +# +# ctrl_mem_size = 4 +# AddrType = mk_bits(clog2(ctrl_mem_size)) +# +# th = TestHarness(RingPktType, DataType, AddrType, num_terminals, +# src_data, sink_data) +# cmdline_opts={'dump_vcd': False, 'test_verilog': translation, +# 'dump_vtb': False} +# run_sim(th, cmdline_opts) +# +# def test_ring_data(self): +# self._test_ring_data('zeros') + + +DataType = mk_data(32, 1) +num_terminals = 4 +RingPktType = mk_ring_multi_cgra_pkt(num_terminals, + payload_nbits = 32, + predicate_nbits = 1) +src_data = [ + [], + [DataType(7, 1, 1), DataType(8, 1), DataType(9, 1)], + [DataType(1, 1, 1), DataType(2, 1), DataType(3, 1)], + [] + ] + +sink_data = [ + [], + [], + # The expected data is received in an interleaved way. + [DataType(1, 0, 0), DataType(7, 0, 0), DataType(2, 0, 0), DataType(8, 0, 0), DataType(3, 0, 0), DataType(9, 0, 0)], + [] + ] + +ctrl_mem_size = 4 +AddrType = mk_bits(clog2(ctrl_mem_size)) + +def test_simple(cmdline_opts): + th = TestHarness(RingPktType, DataType, AddrType, num_terminals, + src_data, sink_data) + th.elaborate() + th.dut.set_metadata(VerilogVerilatorImportPass.vl_Wno_list, + ['UNSIGNED', 'UNOPTFLAT', 'WIDTH', 'WIDTHCONCAT', + 'ALWCOMBORDER']) + th = config_model_with_cmdline_opts(th, cmdline_opts, duts=['dut']) + run_sim(th) + + diff --git a/scale_out/translate/__init__.py b/scale_out/translate/__init__.py new file mode 100644 index 0000000..e69de29