Skip to content

Commit

Permalink
Merge pull request #64 from yuqisun/ConstMemRTL
Browse files Browse the repository at this point in the history
Add ConstQueueDynamicRTL.

Description please refer to #64 (comment)
  • Loading branch information
yuqisun authored Jan 19, 2025
2 parents c8fc46a + 9c4567f commit 7222dae
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 1 deletion.
4 changes: 3 additions & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ jobs:
pip install -U git+https://github.com/tancheng/pymtl3.1@yo-struct-list-fix
pip install hypothesis
pip install pytest
pip install py-markdown-table
pip list
- name: Test and translate with pytest
Expand All @@ -77,4 +78,5 @@ jobs:
pytest ../scale_out/test/RingMultiCgraRTL_test.py -xvs --test-verilog --dump-vtb --dump-vcd
# Multi-cgra with mesh topology.
pytest ../scale_out/test/MeshMultiCgraRTL_test.py -xvs --test-verilog --dump-vtb --dump-vcd
# Const Queue
pytest ../mem/const/test/ConstQueueDynamicRTL_test.py -xvs
113 changes: 113 additions & 0 deletions mem/const/ConstQueueDynamicRTL.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
==========================================================================
ConstQueueDynamicRTL.py
==========================================================================
Constant Queue with regs used for simulation.
If queue is full, will stop receiving new data.
Author : Yuqi Sun
Date : Jan 11, 2025
"""
from py_markdown_table.markdown_table import markdown_table
from pymtl3.stdlib.primitive import RegisterFile

from ...lib.basic.val_rdy.ifcs import ValRdyRecvIfcRTL as RecvIfcRTL
from ...lib.basic.val_rdy.ifcs import ValRdySendIfcRTL as SendIfcRTL
from ...lib.opt_type import *


class ConstQueueDynamicRTL(Component):
def construct(s, DataType, const_mem_size):
# Constant
# addr type: number of bits to represent the address
# 2^addr_size = const_mem_size
# i.e. const_mem_size = 8
# ConstMemAddrType is 3 bits
# ConstMemAddrTyp(1) = 001
# ConstMemAddrType(2) = 010
AddrType = mk_bits(max(1, clog2(const_mem_size)))

# Makes write cursor type 1 bit more than mem addr type as need compare with const_mem_size,
# otherwise, number will be back to 000 when 111 + 1 (given const_mem_size = 8)
WrCurType = mk_bits(clog2(const_mem_size + 1))

# write cursor and read cursor
s.wr_cur = Wire(WrCurType)
s.rd_cur = Wire(AddrType)

# Interface
s.send_const = SendIfcRTL(DataType)
s.recv_const = RecvIfcRTL(DataType)

# Component
# 1 rd_port: number of read port is 0.
# 1 wr_port: number of write port is 0.
# Type, nregs, rd_ports, wr_ports
s.reg_file = RegisterFile(DataType, const_mem_size, 1, 1)

# Connections
s.send_const.msg //= s.reg_file.rdata[0]
s.reg_file.raddr[0] //= s.rd_cur


@update
def load_const():
not_full = s.wr_cur < const_mem_size
s.recv_const.rdy @= not_full
if s.recv_const.val & not_full:
s.reg_file.waddr[0] @= trunc(s.wr_cur, AddrType)
s.reg_file.wdata[0] @= s.recv_const.msg
s.reg_file.wen[0] @= 1


@update_ff
def update_wr_cur():
not_full = (s.wr_cur < const_mem_size)
# Checks if there's a valid const (from producer) to be written.
if s.recv_const.val & not_full:
s.wr_cur <<= s.wr_cur + 1


@update
def update_send_val():
# Checks if read cursor is in front of write cursor.
if (zext(s.rd_cur, WrCurType) < s.wr_cur):
s.send_const.val @= 1
else:
s.send_const.val @= 0


@update_ff
def update_rd_cur():
# Checks whether the "reader" successfully read the data at rd_cur,
# and proceed rd_cur accordingly.
if s.send_const.rdy:
if zext((s.rd_cur), WrCurType) < s.wr_cur:
s.rd_cur <<= s.rd_cur + 1
else:
s.rd_cur <<= 0


def line_trace(s, verbosity = 0):
if verbosity == 0:
const_mem_str = "|".join([str(data) for data in s.reg_file.regs])
return f'const_mem_str: {const_mem_str}'
else:
return s.verbose_trace(verbosity = verbosity)


def verbose_trace(self, verbosity = 1):
reg_list = []
for addr, data in enumerate(self.reg_file.regs):
reg_dict = {
'addr': addr,
'payload': data.payload,
'predicate': data.predicate,
'wr_cur': '<-' if addr == self.wr_cur else '',
'rd_cur': '<-' if addr == self.rd_cur else ''
}
reg_list.append(reg_dict)
res_md = markdown_table(reg_list).set_params(quote = False).get_markdown()
return (f"wr_cur: {self.wr_cur}, rd_cur: {self.rd_cur}, send.val: {self.send_const.val}, send_const.rdy: {self.send_const.rdy}"
f"{res_md}")

79 changes: 79 additions & 0 deletions mem/const/test/ConstQueueDynamicRTL_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
==========================================================================
ConstQueueDynamicRTL_test.py
==========================================================================
Test cases for constant queue with regs.
Author : Yuqi Sun
Date : Jan 11, 2025
"""
from ..ConstQueueDynamicRTL import ConstQueueDynamicRTL
from ....lib.basic.val_rdy.SinkRTL import SinkRTL
from ....lib.basic.val_rdy.SourceRTL import SourceRTL
from ....lib.messages import *


#-------------------------------------------------------------------------
# Test harness
#-------------------------------------------------------------------------

class TestHarness(Component):

def construct(s, MemUnit, DataType, const_mem_size, src_const, read_data):
s.src_const_pkt = SourceRTL(DataType, src_const)
s.read_data = SinkRTL(DataType, read_data)

s.const_queue = MemUnit(DataType, const_mem_size)
s.src_const_pkt.send //= s.const_queue.recv_const
s.read_data.recv //= s.const_queue.send_const

def done(self):
return self.src_const_pkt.done()

def line_trace(s):
return s.const_queue.line_trace(verbosity = 1)

def run_sim(test_harness, max_cycles = 20):
test_harness.elaborate()
test_harness.apply(DefaultPassGroup())
test_harness.sim_reset()

ncycles = 0
while not test_harness.done() and ncycles < max_cycles:
test_harness.sim_tick()
ncycles += 1
print("\n{}: {}".format(ncycles, test_harness.line_trace()))

for i in range(3):
test_harness.sim_tick()
print("\nextra clk {}: {}".format(i, test_harness.line_trace()))
print("\nmem: {}".format(test_harness.line_trace()))


def test_const_num_lt_mem():
MemUnit = ConstQueueDynamicRTL
DataType = mk_data(4, 1)
const_mem_size = 8

# The number of source const is less than the memory size.
src_const = [DataType(9, 1), DataType(8, 1), DataType(7, 1)]
read_data = [DataType(9, 1), DataType(8, 1), DataType(7, 1), DataType(0, 0)]
th = TestHarness(MemUnit, DataType, const_mem_size, src_const, read_data)
run_sim(th)

def test_const_num_gt_mem():
MemUnit = ConstQueueDynamicRTL
DataType = mk_data(4, 1)
const_mem_size = 8

# The number of source const is more than the memory size.
src_const = [DataType(9, 1), DataType(8, 1), DataType(7, 1), DataType(6, 1),
DataType(5, 1), DataType(4, 1), DataType(3, 1), DataType(2, 1),
DataType(1, 1)]
read_data = [DataType(9, 1), DataType(8, 1), DataType(7, 1), DataType(6, 1),
DataType(5, 1), DataType(4, 1), DataType(3, 1), DataType(2, 1),
DataType(9, 1)]
th = TestHarness(MemUnit, DataType, const_mem_size, src_const, read_data)
run_sim(th)


0 comments on commit 7222dae

Please sign in to comment.