From: Tobias Platen Date: Sat, 25 Jan 2020 14:03:20 +0000 (+0100) Subject: convert numbers to python format X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=HEAD;p=sv2nmigen.git convert numbers to python format --- diff --git a/absyn.py b/absyn.py index 2931be8..386e5d3 100644 --- a/absyn.py +++ b/absyn.py @@ -57,6 +57,8 @@ class CondStatement: def makeBlock(x): if(type(x) == Assignment): return [x] + elif(type(x) == CondStatement): + return [x] else: return x.statements @@ -69,6 +71,7 @@ class Absyn: self.ports = [] self.wires = [] self.comb = [] + self.sync = [] def open(self): if(self.outputfile is None): @@ -133,7 +136,9 @@ class Absyn: def do_assign(self, a, stmts, indent): stmts.children.append(self.indent(indent)) - stmts.children.append(Leaf(token.STRING, "m.d.comb += ")) + stmts.children.append(Leaf(token.STRING, "m.d.")) + stmts.children.append(Leaf(token.STRING, self.blocktype)) + stmts.children.append(Leaf(token.STRING, " += ")) if(self.isPort(a.left)): stmts.children.append(Leaf(token.STRING, "self.")) stmts.children.append(Leaf(token.STRING, a.left)) @@ -196,12 +201,18 @@ class Absyn: stmts.children.append(Leaf(token.STRING, ")")) stmts.children.append(self.nl()) - # refactor: assignments non cond + self.blocktype = "comb" for a in self.assign: - self.do_assign(a, stmts) + self.do_assign(a, stmts, 2) for c in self.comb: - print("comb", c) + if(type(c) == Assignment): + self.do_assign(c, stmts, 2) + else: + self.do_ifblock(c, stmts, 2) + + self.blocktype = "sync" + for c in self.sync: if(type(c) == Assignment): self.do_assign(c, stmts, 2) else: @@ -258,6 +269,9 @@ class Absyn: # cond assigmments and other nested blocks def always_comb(self, p3, p1): - print("always_comb") slist = p3[6] self.comb += slist.statements + + def always_ff(self, p3, p1): + slist = p3[1] + self.sync += slist.statements diff --git a/examples/always_ff.sv b/examples/always_ff.sv new file mode 100644 index 0000000..1b7ca86 --- /dev/null +++ b/examples/always_ff.sv @@ -0,0 +1,11 @@ +module always_comb_test( + input clk, + input a, + output b +); + +always_ff @(posedge clk) begin + a <= b; +end + +endmodule diff --git a/examples/test_assignment.py b/examples/test_assignment.py deleted file mode 100644 index 3972ac4..0000000 --- a/examples/test_assignment.py +++ /dev/null @@ -1,22 +0,0 @@ -from nmigen.compat.sim import run_simulation - -import assignment - -def tbench(dut): - yield dut.i.eq(1) - yield - yield - yield - yield dut.i.eq(0) - yield - yield - yield - - -def test_ass(): - dut = assignment.assignment(); - run_simulation(dut, tbench(dut), vcd_name="test.vcd") - - -if __name__ == "__main__": - test_ass() diff --git a/examples/tlb.py b/examples/tlb.py deleted file mode 100644 index 5e08a9f..0000000 --- a/examples/tlb.py +++ /dev/null @@ -1,272 +0,0 @@ -# this file has been generated by sv2nmigen - -from nmigen import Signal, Module, Const, Cat, Elaboratable - - - -class tlb(Elaboratable): - - def __init__(self): - self.clk_i = Signal() # input - self.rst_ni = Signal() # input - self.flush_i = Signal() # input - self.lu_access_i = Signal() # input - self.lu_asid_i = Signal(ASID_WIDTH) # input - self.lu_vaddr_i = Signal(64) # input - self.lu_is_2M_o = Signal() # output - self.lu_is_1G_o = Signal() # output - self.lu_hit_o = Signal() # output - def elaborate(self, platform=None): - m = Module() - return m - -#// Copyright 2018 ETH Zurich and University of Bologna. -#// Copyright and related rights are licensed under the Solderpad Hardware -#// License, Version 0.51 (the "License"); you may not use this file except in -#// compliance with the License. You may obtain a copy of the License at -#// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -#// or agreed to in writing, software, hardware and materials distributed under -#// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -#// CONDITIONS OF ANY KIND, either express or implied. See the License for the -#// specific language governing permissions and limitations under the License. -#// -#// Author: David Schaffenrath, TU Graz -#// Author: Florian Zaruba, ETH Zurich -#// Date: 21.4.2017 -#// Description: Translation Lookaside Buffer, SV39 -#// fully set-associative -# -#//import ariane_pkg::*; -# -#module tlb #( -# parameter int TLB_ENTRIES = 4, -# parameter int ASID_WIDTH = 1 -# )( -# input logic clk_i, // Clock -# input logic rst_ni, // Asynchronous reset active low -# input logic flush_i, // Flush signal -# // Update TLB -# //input tlb_update_t update_i, -# // Lookup signals -# input logic lu_access_i, -# input logic [ASID_WIDTH-1:0] lu_asid_i, -# input logic [63:0] lu_vaddr_i, -# //output riscv::pte_t lu_content_o, -# output logic lu_is_2M_o, -# output logic lu_is_1G_o, -# output logic lu_hit_o -#); -# -""" #docstring_begin - // SV39 defines three levels of page tables - struct packed { - logic [ASID_WIDTH-1:0] asid; - logic [8:0] vpn2; - logic [8:0] vpn1; - logic [8:0] vpn0; - logic is_2M; - logic is_1G; - logic valid; - } [TLB_ENTRIES-1:0] tags_q, tags_n; - - riscv::pte_t [TLB_ENTRIES-1:0] content_q, content_n; - logic [8:0] vpn0, vpn1, vpn2; - logic [TLB_ENTRIES-1:0] lu_hit; // to replacement logic - logic [TLB_ENTRIES-1:0] replace_en; // replace the following entry, set by replacement strategy - //------------- - // Translation - //------------- - always_comb begin : translation - vpn0 = lu_vaddr_i[20:12]; - vpn1 = lu_vaddr_i[29:21]; - vpn2 = lu_vaddr_i[38:30]; - - // default assignment - lu_hit = '{default: 0}; - lu_hit_o = 1'b0; - lu_content_o = '{default: 0}; - lu_is_1G_o = 1'b0; - lu_is_2M_o = 1'b0; - - for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin - // first level match, this may be a giga page, check the ASID flags as well - if (tags_q[i].valid && lu_asid_i == tags_q[i].asid && vpn2 == tags_q[i].vpn2) begin - // second level - if (tags_q[i].is_1G) begin - lu_is_1G_o = 1'b1; - lu_content_o = content_q[i]; - lu_hit_o = 1'b1; - lu_hit[i] = 1'b1; - // not a giga page hit so check further - end else if (vpn1 == tags_q[i].vpn1) begin - // this could be a 2 mega page hit or a 4 kB hit - // output accordingly - if (tags_q[i].is_2M || vpn0 == tags_q[i].vpn0) begin - lu_is_2M_o = tags_q[i].is_2M; - lu_content_o = content_q[i]; - lu_hit_o = 1'b1; - lu_hit[i] = 1'b1; - end - end - end - end - end - - // ------------------ - // Update and Flush - // ------------------ - always_comb begin : update_flush - tags_n = tags_q; - content_n = content_q; - - for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin - if (flush_i) begin - // invalidate logic - if (lu_asid_i == 1'b0) // flush everything if ASID is 0 - tags_n[i].valid = 1'b0; - else if (lu_asid_i == tags_q[i].asid) // just flush entries from this ASID - tags_n[i].valid = 1'b0; - - // normal replacement - end else if (update_i.valid & replace_en[i]) begin - // update tag array - tags_n[i] = '{ - asid: update_i.asid, - vpn2: update_i.vpn [26:18], - vpn1: update_i.vpn [17:9], - vpn0: update_i.vpn [8:0], - is_1G: update_i.is_1G, - is_2M: update_i.is_2M, - valid: 1'b1 - }; - // and content as well - content_n[i] = update_i.content; - end - end - end - - // ----------------------------------------------- - // PLRU - Pseudo Least Recently Used Replacement - // ----------------------------------------------- - logic[2*(TLB_ENTRIES-1)-1:0] plru_tree_q, plru_tree_n; - always_comb begin : plru_replacement - plru_tree_n = plru_tree_q; - // The PLRU-tree indexing: - // lvl0 0 - // / \ - // / \ - // lvl1 1 2 - // / \ / \ - // lvl2 3 4 5 6 - // / \ /\/\ /\ - // ... ... ... ... - // Just predefine which nodes will be set/cleared - // E.g. for a TLB with 8 entries, the for-loop is semantically - // equivalent to the following pseudo-code: - // unique case (1'b1) - // lu_hit[7]: plru_tree_n[0, 2, 6] = {1, 1, 1}; - // lu_hit[6]: plru_tree_n[0, 2, 6] = {1, 1, 0}; - // lu_hit[5]: plru_tree_n[0, 2, 5] = {1, 0, 1}; - // lu_hit[4]: plru_tree_n[0, 2, 5] = {1, 0, 0}; - // lu_hit[3]: plru_tree_n[0, 1, 4] = {0, 1, 1}; - // lu_hit[2]: plru_tree_n[0, 1, 4] = {0, 1, 0}; - // lu_hit[1]: plru_tree_n[0, 1, 3] = {0, 0, 1}; - // lu_hit[0]: plru_tree_n[0, 1, 3] = {0, 0, 0}; - // default: begin /* No hit */ end - // endcase - for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin - automatic int unsigned idx_base, shift, new_index; - // we got a hit so update the pointer as it was least recently used - if (lu_hit[i] & lu_access_i) begin - // Set the nodes to the values we would expect - for (int unsigned lvl = 0; lvl < $clog2(TLB_ENTRIES); lvl++) begin - idx_base = $unsigned((2**lvl)-1); - // lvl0 <=> MSB, lvl1 <=> MSB-1, ... - shift = $clog2(TLB_ENTRIES) - lvl; - // to circumvent the 32 bit integer arithmetic assignment - new_index = ~((i >> (shift-1)) & 32'b1); - plru_tree_n[idx_base + (i >> shift)] = new_index[0]; - end - end - end - // Decode tree to write enable signals - // Next for-loop basically creates the following logic for e.g. an 8 entry - // TLB (note: pseudo-code obviously): - // replace_en[7] = &plru_tree_q[ 6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,1} - // replace_en[6] = &plru_tree_q[~6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,0} - // replace_en[5] = &plru_tree_q[ 5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,1} - // replace_en[4] = &plru_tree_q[~5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,0} - // replace_en[3] = &plru_tree_q[ 4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,1} - // replace_en[2] = &plru_tree_q[~4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,0} - // replace_en[1] = &plru_tree_q[ 3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,1} - // replace_en[0] = &plru_tree_q[~3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,0} - // For each entry traverse the tree. If every tree-node matches, - // the corresponding bit of the entry's index, this is - // the next entry to replace. - for (int unsigned i = 0; i < TLB_ENTRIES; i += 1) begin - automatic logic en; - automatic int unsigned idx_base, shift, new_index; - en = 1'b1; - for (int unsigned lvl = 0; lvl < $clog2(TLB_ENTRIES); lvl++) begin - idx_base = $unsigned((2**lvl)-1); - // lvl0 <=> MSB, lvl1 <=> MSB-1, ... - shift = $clog2(TLB_ENTRIES) - lvl; - - // en &= plru_tree_q[idx_base + (i>>shift)] == ((i >> (shift-1)) & 1'b1); - new_index = (i >> (shift-1)) & 32'b1; - if (new_index[0]) begin - en &= plru_tree_q[idx_base + (i>>shift)]; - end else begin - en &= ~plru_tree_q[idx_base + (i>>shift)]; - end - end - replace_en[i] = en; - end - end - - // sequential process - always_ff @(posedge clk_i or negedge rst_ni) begin - if(~rst_ni) begin - tags_q <= '{default: 0}; - content_q <= '{default: 0}; - plru_tree_q <= '{default: 0}; - end else begin - tags_q <= tags_n; - content_q <= content_n; - plru_tree_q <= plru_tree_n; - end - end - //-------------- - // Sanity checks - //-------------- - - //pragma translate_off - `ifndef VERILATOR - - initial begin : p_assertions - assert ((TLB_ENTRIES % 2 == 0) && (TLB_ENTRIES > 1)) - else begin $error("TLB size must be a multiple of 2 and greater than 1"); $stop(); end - assert (ASID_WIDTH >= 1) - else begin $error("ASID width must be at least 1"); $stop(); end - end - - // Just for checking - function int countSetBits(logic[TLB_ENTRIES-1:0] vector); - automatic int count = 0; - foreach (vector[idx]) begin - count += vector[idx]; - end - return count; - endfunction - - assert property (@(posedge clk_i)(countSetBits(lu_hit) <= 1)) - else begin $error("More then one hit in TLB!"); $stop(); end - assert property (@(posedge clk_i)(countSetBits(replace_en) <= 1)) - else begin $error("More then one TLB entry selected for next replace!"); $stop(); end - - `endif - //pragma translate_on -""" -#endmodule -# -# diff --git a/parse_sv.py b/parse_sv.py index 6a153ff..9ca18f6 100644 --- a/parse_sv.py +++ b/parse_sv.py @@ -2350,6 +2350,11 @@ def p_number_1(p): if(parse_debug): print('number_1', list(p)) + p[1] = p[1].replace("'b", "0b") + p[1] = p[1].replace("'x", "0x") + num = Leaf(token.NUMBER, "%s" % (p[1])) + p[0] = num + # { p[0] = p[1]; based_size = 0;} () @@ -2359,6 +2364,8 @@ def p_number_2(p): '''number : DEC_NUMBER ''' if(parse_debug): print('number_2', list(p)) + p[1] = p[1].replace("'b", "0b") + p[1] = p[1].replace("'x", "0x") num = Leaf(token.NUMBER, "%s" % (p[1])) p[0] = num @@ -2371,7 +2378,11 @@ def p_number_3(p): '''number : DEC_NUMBER BASED_NUMBER ''' if(parse_debug): print('number_3', list(p)) - num = Leaf(token.NUMBER, "%s:%s" % (p[1], p[2])) + + p[2] = p[2].replace("'b", "0b") + p[2] = p[2].replace("'x", "0x") + + num = Leaf(token.NUMBER, "%s" % (p[2])) p[0] = num @@ -6237,8 +6248,11 @@ def p_expression_46(p): if(parse_debug): print('expression_46', list(p)) - p[0] = Node(syms.atom, [p[1], Leaf(token.STRING, ' ? '), - p[4], Leaf(token.STRING, ' : '), p[6]]) + try: + p[0] = Node(syms.atom, [p[1], Leaf(token.STRING, ' ? '), + p[4], Leaf(token.STRING, ' : '), p[6]]) + except: + p[0] = "error in PETernary" # { PETernary*tmp = new PETernary(p[1], p[4], p[6]); @@ -7648,6 +7662,9 @@ def p_hierarchy_identifier_3(p): if(parse_debug): print('hierarchy_identifier_3', list(p)) + p[0] = Node(syms.atom, [p[1], Leaf( + token.STRING, '['), p[3], Leaf(token.STRING, ']')]) + # { pform_name_t * tmp = p[1]; # name_component_t&tail = tmp->back(); @@ -9148,6 +9165,8 @@ def p_module_item_40(p): if(parse_debug): print('module_item_40', list(p)) + absyn.always_ff(p[3], p[1]) + # { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_FF, p[3], p[1]); # FILE_NAME(tmp, @2); @@ -12279,6 +12298,8 @@ def p_statement_item_30(p): if(parse_debug): print('statement_item_30', list(p)) + p[0] = [p[1], p[2]] + # { PEventStatement*tmp = p[1]; # if (tmp == 0) { @@ -12365,6 +12386,8 @@ def p_statement_item_35(p): if(parse_debug): print('statement_item_35', list(p)) + p[0] = absyn.assign3(p[1], p[2], p[3]) + # { PAssignNB*tmp = new PAssignNB(p[1],p[3]); # FILE_NAME(tmp, @1);