Skip to content

Commit b81858b

Browse files
committed
Merge branch 'development' of https://github.com/UCSBarchlab/PyRTL into development
2 parents dd752dd + e15cf0d commit b81858b

File tree

2 files changed

+92
-16
lines changed

2 files changed

+92
-16
lines changed

pyrtl/importexport.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -325,17 +325,21 @@ def twire(w):
325325
output_wire = twire(netio[2])
326326
output_wire <<= twire(netio[0]) | twire(netio[1]) # or gate
327327
elif command['cover_list'].asList() == ['0-', '1', '-0', '1']:
328+
# nand is not really a PyRTL primitive and so should only be added to a netlist
329+
# via a call to nand_synth(). We instead convert it to ~(a & b) rather than
330+
# (~a | ~b) as would be generated if handled by the else case below.
328331
output_wire = twire(netio[2])
329-
output_wire <<= twire(netio[0]).nand(twire(netio[1])) # nand gate
332+
output_wire <<= ~(twire(netio[0]) & twire(netio[1])) # nand gate -> not+and gates
330333
elif command['cover_list'].asList() == ['10', '1', '01', '1']:
331334
output_wire = twire(netio[2])
332335
output_wire <<= twire(netio[0]) ^ twire(netio[1]) # xor gate
333336
else:
334337
# Although the following is fully generic and thus encompasses all of the
335338
# special cases after the simple wire case above, we leave the above in because
336339
# they are commonly found and lead to a slightly cleaner (though equivalent) netlist,
337-
# because we can use nand/xor primitives, or avoid the extra fluff of concat/select
338-
# wires that might be created implicitly as part of rtl_all/rtl_any.
340+
# because we can use the xor primitive/save a gate when converting the nand, or avoid
341+
# the extra fluff of concat/select wires that might be created implicitly as part of
342+
# rtl_all/rtl_any.
339343
def convert_val(ix, val):
340344
wire = twire(netio[ix])
341345
if val == '0':
@@ -758,22 +762,25 @@ def _to_verilog_memories(file, block, varname):
758762
memories = {n.op_param[1] for n in block.logic_subset('m@')}
759763
for m in sorted(memories, key=lambda m: m.id):
760764
print(' // Memory mem_{}: {}'.format(m.id, m.name), file=file)
761-
print(' always @(posedge clk)', file=file)
762-
print(' begin', file=file)
763-
for net in _net_sorted(block.logic_subset('@'), varname):
764-
if net.op_param[1] == m:
765+
writes = [net for net in _net_sorted(block.logic_subset('@'), varname)
766+
if net.op_param[1] == m]
767+
if writes:
768+
print(' always @(posedge clk)', file=file)
769+
print(' begin', file=file)
770+
for net in writes:
765771
t = (varname(net.args[2]), net.op_param[0],
766772
varname(net.args[0]), varname(net.args[1]))
767773
print((' if (%s) begin\n'
768774
' mem_%s[%s] <= %s;\n'
769775
' end') % t, file=file)
770-
print(' end', file=file)
771-
for net in _net_sorted(block.logic_subset('m'), varname):
772-
if net.op_param[1] == m:
773-
dest = varname(net.dests[0])
774-
m_id = net.op_param[0]
775-
index = varname(net.args[0])
776-
print(' assign {:s} = mem_{}[{:s}];'.format(dest, m_id, index), file=file)
776+
print(' end', file=file)
777+
reads = [net for net in _net_sorted(block.logic_subset('m'), varname)
778+
if net.op_param[1] == m]
779+
for net in reads:
780+
dest = varname(net.dests[0])
781+
m_id = net.op_param[0]
782+
index = varname(net.args[0])
783+
print(' assign {:s} = mem_{}[{:s}];'.format(dest, m_id, index), file=file)
777784
print('', file=file)
778785

779786

tests/test_importexport.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,9 @@ def test_blif_or_gate_correct(self):
663663
})
664664
self.assertEqual(sim.tracer.trace['o'], [0, 1, 1, 1])
665665

666-
def test_blif_nand_gate_correct(self):
666+
def test_blif_nand_gate_to_primitives_correct(self):
667+
# This tests that there should be no NAND gates generated during BLIF import;
668+
# they should be converted to AND+NOT.
667669
blif = """\
668670
.model Top
669671
.inputs a b
@@ -675,7 +677,9 @@ def test_blif_nand_gate_correct(self):
675677
"""
676678
pyrtl.input_from_blif(blif)
677679
block = pyrtl.working_block()
678-
self.assertEqual(len(block.logic_subset('n')), 1)
680+
self.assertEqual(len(block.logic_subset('n')), 0)
681+
self.assertEqual(len(block.logic_subset('&')), 1)
682+
self.assertEqual(len(block.logic_subset('~')), 1)
679683
sim = pyrtl.Simulation()
680684
sim.step_multiple({
681685
'a': '0011',
@@ -1384,6 +1388,56 @@ def test_blif_nor_gate_correct(self):
13841388
"""
13851389

13861390

1391+
verilog_output_mems_with_no_writes = """\
1392+
// Generated automatically via PyRTL
1393+
// As one initial test of synthesis, map to FPGA with:
1394+
// yosys -p "synth_xilinx -top toplevel" thisfile.v
1395+
1396+
module toplevel(clk, rst, in1, out1);
1397+
input clk;
1398+
input rst;
1399+
input[2:0] in1;
1400+
output[7:0] out1;
1401+
1402+
reg[7:0] mem_0[7:0]; //tmp0
1403+
reg[7:0] mem_1[255:0]; //tmp1
1404+
1405+
wire const_0_1;
1406+
wire[7:0] const_1_42;
1407+
wire[7:0] tmp2;
1408+
1409+
initial begin
1410+
mem_0[0]=8'ha;
1411+
mem_0[1]=8'h14;
1412+
mem_0[2]=8'h1e;
1413+
mem_0[3]=8'h28;
1414+
mem_0[4]=8'h32;
1415+
mem_0[5]=8'h3c;
1416+
mem_0[6]=8'h0;
1417+
mem_0[7]=8'h0;
1418+
end
1419+
1420+
// Combinational
1421+
assign const_0_1 = 1;
1422+
assign const_1_42 = 42;
1423+
assign out1 = tmp2;
1424+
1425+
// Memory mem_0: tmp0
1426+
assign tmp2 = mem_0[in1];
1427+
1428+
// Memory mem_1: tmp1
1429+
always @(posedge clk)
1430+
begin
1431+
if (const_0_1) begin
1432+
mem_1[tmp2] <= const_1_42;
1433+
end
1434+
end
1435+
1436+
endmodule
1437+
1438+
"""
1439+
1440+
13871441
verilog_output_counter_no_reset = """\
13881442
// Generated automatically via PyRTL
13891443
// As one initial test of synthesis, map to FPGA with:
@@ -1568,6 +1622,21 @@ def test_textual_consistency_large(self):
15681622

15691623
self.assertEqual(buffer.getvalue(), verilog_output_large)
15701624

1625+
def test_mems_with_no_writes(self):
1626+
rdata = {0: 10, 1: 20, 2: 30, 3: 40, 4: 50, 5: 60}
1627+
rom = pyrtl.RomBlock(8, 3, rdata, pad_with_zeros=True)
1628+
mem = pyrtl.MemBlock(8, 8)
1629+
in1 = pyrtl.Input(3, 'in1')
1630+
out1 = pyrtl.Output(8, 'out1')
1631+
w = rom[in1]
1632+
out1 <<= w
1633+
mem[w] <<= 42
1634+
1635+
buffer = io.StringIO()
1636+
pyrtl.output_to_verilog(buffer)
1637+
1638+
self.assertEqual(buffer.getvalue(), verilog_output_mems_with_no_writes)
1639+
15711640
def check_counter_text(self, add_reset, expected):
15721641
r = pyrtl.Register(4, reset_value=2)
15731642
r.next <<= r + 1

0 commit comments

Comments
 (0)