def get_module_sizes(module, *args, **kwargs): rtlil_text = rtlil.convert(module, *args, **kwargs) script = """ read_ilang <<rtlil {} rtlil expose top synth_xilinx -abc9 """.format(rtlil_text) popen = subprocess.Popen(["yosys", "-s", "-"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8") output, error = popen.communicate(script) return { re.findall("== (.*?) ===", section)[0]: re.findall("Estimated number of LCs:\\W*(\\d+)", section)[0] for section in re.findall("== .*? ===.*?=", output, flags=re.DOTALL) }
def cover_pending_counter(bld: Builder): m = Module() m.submodules.pc = pc = PendingCounter(3, 5) was_full = Signal() was_emptied = Signal() m.d.comb += pc.i_remove.eq(AnySeq(1)) m.d.comb += Assume(~(pc.i_remove & ~pc.o_any)) m.d.comb += Assume(~(~pc.i_remove & pc.o_full)) with m.If(pc.o_full): m.d.sync += was_full.eq(1) with m.If(~pc.o_any & was_full): m.d.sync += was_emptied.eq(1) m.d.comb += Cover(was_emptied) with bld.temp_open("formal.il") as f: il_text = rtlil.convert(m, ports=[pc.pending, pc.timer]) f.write(il_text) sby.verify( bld, "formal.sby", "formal.il", sby.Task("sby", "cover", depth=40, engines=["smtbmc", "yices"]), )
def build(self, elaboratable, *, build_dir, **kwargs): sim = Simulator(elaboratable) os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() try: os.chdir(build_dir) with open("top.il", "w", encoding="utf-8") as f: f.write(rtlil.convert(elaboratable)) with open("top.v", "w", encoding="utf-8") as f: f.write(verilog.convert(elaboratable)) for name, number in self.resources: clock = self.lookup(name, number).clock if clock is not None: sim.add_clock(clock.period, domain=name) for process in self.processes: sim.add_sync_process(process) for domain, sync_processes in self.sync_processes.items(): for sync_process in sync_processes: sim.add_sync_process(sync_process, domain=domain) with sim.write_vcd("top.vcd"): sim.run() finally: os.chdir(cwd)
def main(cls, filename="toplevel.il"): """Runs a file in simulate or generate mode. Add this to your file: from util import main if __name__ == "__main__": main(YourClass) Then, you can run the file in simulate or generate mode: python <file.py> sim will run YourClass.sim and output to whatever vcd file you wrote to. python <file.py> gen will run YourClass.formal and output in RTLIL format to toplevel.il. You can then formally verify using sby -f <file.sby>. """ if len(sys.argv) < 2 or (sys.argv[1] != "sim" and sys.argv[1] != "gen"): print(f"Usage: python3 {sys.argv[0]} sim|gen") sys.exit(1) if sys.argv[1] == "sim": cls.sim() else: design, ports = cls.formal() fragment = Fragment.get(design, None) output = rtlil.convert(fragment, ports=ports) with open(filename, "w") as f: f.write(output)
def get_size(module, *args, **kwargs): rtlil_text = rtlil.convert(module, *args, **kwargs) script = """ read_ilang <<rtlil {} rtlil flatten synth_ecp5 -abc9 """.format(rtlil_text) popen = subprocess.Popen(["yosys", "-s", "-"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8") output, error = popen.communicate(script) print(output) try: cells = int(re.search("LUT4\\W*(\\d+)", output).group(1)) except: cells = 0 return cells
def assert_formal(spec, mode="bmc", depth=1): functions = [] test_class = None caller_path = "" stack = inspect.stack() for frame in stack[1:]: if "unittest" in frame.filename: filename = "__".join(reversed(functions)) if test_class: filename = f'{test_class}__{filename}' break functions.append(frame.function) try: test_class = frame.frame.f_locals['self'].__class__.__name__ except: pass caller_path = frame.filename target_dir = Path(caller_path).parent / ".sim_results" target_dir.mkdir(exist_ok=True) if (target_dir / filename).exists(): rmtree(target_dir / filename) if mode == "hybrid": # A mix of BMC and k-induction, as per personal communication with Claire Wolf. script = "setattr -unset init w:* a:nmigen.sample_reg %d" mode = "bmc" else: script = "" config = textwrap.dedent("""\ [options] mode {mode} depth {depth} wait on [engines] smtbmc [script] read_ilang top.il prep {script} [file top.il] {rtlil} """).format(mode=mode, depth=depth, script=script, rtlil=rtlil.convert(Fragment.get(spec, platform=FormalPlatform))) with subprocess.Popen([require_tool("sby"), "-f", "-d", filename], cwd=str(target_dir), universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc: stdout, stderr = proc.communicate(config) if proc.returncode != 0: assert False, "Formal verification failed:\n" + stdout + "\n\n" + f"vcd: {str(target_dir / filename)}/engine_0/trace.vcd"
def assertFormal(self, spec, mode="bmc", depth=1): stack = traceback.extract_stack() for frame in reversed(stack): if os.path.dirname(__file__) not in frame.filename: break caller = frame spec_root, _ = os.path.splitext(caller.filename) spec_dir = os.path.dirname(spec_root) spec_name = "{}_{}".format( os.path.basename(spec_root).replace("test_", "spec_"), caller.name.replace("test_", "")) # The sby -f switch seems not fully functional when sby is reading from stdin. if os.path.exists(os.path.join(spec_dir, spec_name)): shutil.rmtree(os.path.join(spec_dir, spec_name)) if mode == "hybrid": # A mix of BMC and k-induction, as per personal communication with Claire Wolf. script = "setattr -unset init w:* a:nmigen.sample_reg %d" mode = "bmc" else: script = "" config = textwrap.dedent("""\ [options] mode {mode} depth {depth} wait on [engines] smtbmc [script] read_ilang top.il prep {script} [file top.il] {rtlil} """).format(mode=mode, depth=depth, script=script, rtlil=rtlil.convert(Fragment.get(spec, platform="formal"))) with subprocess.Popen([require_tool("sby"), "-f", "-d", spec_name], cwd=spec_dir, env={ **os.environ, "PYTHONWARNINGS": "ignore" }, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc: stdout, stderr = proc.communicate(config) if proc.returncode != 0: self.fail("Formal verification failed:\n" + stdout)
def build(self, elaboratable, *, build_dir, **kwargs): print("Here") os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() try: os.chdir(build_dir) with open("top.il", "w", encoding="utf-8") as f: f.write(rtlil.convert(elaboratable)) finally: os.chdir(cwd)
def assertFormal(self, spec, mode="bmc", depth=1): """ mode: bmc, prove """ caller, *_ = traceback.extract_stack(limit=2) spec_root, _ = os.path.splitext(caller.filename) spec_dir = os.path.dirname(spec_root) spec_name = "{}_{}".format( os.path.basename(spec_root).replace("test_", "spec_"), caller.name.replace("test_", "")) # The sby -f switch seems not fully functional when sby is reading from stdin. if os.path.exists(os.path.join(spec_dir, spec_name)): shutil.rmtree(os.path.join(spec_dir, spec_name)) config = textwrap.dedent("""\ [options] mode {mode} depth {depth} wait on [engines] smtbmc [script] read_ilang top.il prep [file top.il] {rtlil} """).format(mode=mode, depth=depth, rtlil=rtlil.convert(Fragment.get(spec, platform="formal"))) f = open(os.path.join(spec_dir, spec_name + '.script'), "w") f.write(config) f.close() with subprocess.Popen([require_tool("sby"), "-f", "-d", spec_name], cwd=spec_dir, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc: stdout, stderr = proc.communicate(config) if proc.returncode != 0: self.fail("Formal verification failed:\n" + stdout)
def bmc_pending_counter(bld: Builder): m = Module() m.submodules.pc = pc = PendingCounter(3, 5) m.d.comb += pc.i_remove.eq(AnySeq(1)) m.d.comb += Assume(~(pc.i_remove & ~pc.o_any)) m.d.comb += Assume(~(~pc.i_remove & pc.o_full)) with bld.temp_open("formal.il") as f: il_text = rtlil.convert(m, ports=[pc.pending, pc.timer]) f.write(il_text) sby.verify( bld, "formal.sby", "formal.il", sby.Task("sby", "bmc", depth=40, engines=["smtbmc", "yices"]), )
def build_formal_pipe(bld: Builder): m = Module() in_data = AnySeq(8) en_data = AnySeq(1) hsync = AnySeq(1) vsync = AnySeq(1) enc_char_comb = Signal(10) enc_char_pipe = Signal(10) m.submodules.enc_comb = enc_comb = TMDSEncoder(pipeline=False) m.submodules.enc_pipe = enc_pipe = TMDSEncoder(pipeline=True) m.d.comb += [ enc_pipe.i_data.eq(in_data), enc_pipe.i_en_data.eq(en_data), enc_pipe.i_hsync.eq(hsync), enc_pipe.i_vsync.eq(vsync), enc_char_pipe.eq(enc_pipe.o_char), ] m.d.sync += [ enc_comb.i_data.eq(in_data), enc_comb.i_en_data.eq(en_data), enc_comb.i_hsync.eq(hsync), enc_comb.i_vsync.eq(vsync), ] m.d.comb += [ enc_char_comb.eq(enc_comb.o_char), ] with m.If(~Initial()): m.d.comb += [ Assert(enc_char_pipe == enc_char_comb), Assert(enc_pipe.dc_bias == enc_comb.dc_bias), ] with bld.temp_open("formal.il") as f: il_text = rtlil.convert(m, ports=[enc_char_comb, enc_char_pipe]) f.write(il_text)
def synth(core, ports): plat = EmptyPlatform() frag = Fragment.get(core, plat) rtlil_text = rtlil.convert(frag, ports=ports) yosys_cmd = '' with tempfile.TemporaryDirectory() as temp_dir: with open(temp_dir + '/top.il', 'w') as f: f.write(rtlil_text) for file_name, content in plat.extra_files.items(): with open(temp_dir + '/' + file_name, 'wb') as f: f.write(content) yosys_cmd += "read_verilog {}\n".format(file_name) yosys_cmd += 'read_ilang {}\n'.format('top.il') yosys_cmd += 'synth_xilinx -top top\n' with open(temp_dir + '/top.ys', 'w') as f: f.write(yosys_cmd) subprocess.check_call([require_tool("yosys"), 'top.ys'], cwd=temp_dir)
def _generate(self): args = self.args fragment = Fragment.get(self.design, self.platform) generate_type = args.generate_type if generate_type is None and args.generate_file: if args.generate_file.name.endswith(".v"): generate_type = "v" if args.generate_file.name.endswith(".il"): generate_type = "il" if generate_type is None: parser.error("specify file type explicitly with -t") if generate_type == "il": output = rtlil.convert(fragment, name=self.name, ports=self._get_ports()) if generate_type == "v": output = verilog.convert(fragment, name=self.name, ports=self._get_ports()) if args.generate_file: args.generate_file.write(output) else: print(output)
def check(nmigen_module, ports): with TemporaryDirectory() as tmpdirname: temp_path = pathlib.Path(tmpdirname) with open(temp_path / 'out.il', 'w') as f: f.write(rtlil.convert(nmigen_module, ports=ports)) sby_data = f''' [options] mode bmc [engines] smtbmc z3 [script] read_ilang out.il prep -top top [files] {temp_path/'out.il'}''' with open(temp_path/'out.sby', 'w') as f: f.write(sby_data) yosys_path = shutil.which('yowasp-yosys') smt_path = shutil.which('yowasp-yosys-smtbmc') process = subprocess.run([ 'yowasp-sby', '-f', '-d', temp_path / 'work', '--yosys', yosys_path, '--smtbmc', smt_path, temp_path/'out.sby'], stdout=subprocess.PIPE) stdout = str(process.stdout) if process.returncode == 0: return BMC_Result(Result.PASS, stdout) if process.returncode == 1: return _get_failure_info(stdout, temp_path / 'work/engine_0/trace.vcd') else: return BMC_Result(Result.ERROR, stdout)
ports = [ dda.i_x0, dda.i_y0, dda.i_r0, dda.i_g0, dda.i_b0, dda.i_x1, dda.i_y1, dda.i_r1, dda.i_g1, dda.i_b1, dda.i_start, dda.i_next, dda.o_x, dda.o_y, dda.o_valid, dda.o_last ] gtkw = open("sim.gtkw", "w") vcd = open("sim.vcd", "w") with open("line.v", "w") as f: f.write(verilog.convert(dda, ports=ports)) with open("line.il", "w") as f: f.write(rtlil.convert(dda, ports=ports)) def line_test(start, end, points): print("// ", start, "-> ", end) yield dda.i_x0.eq(start[0] << 4) yield dda.i_y0.eq(start[1] << 4) yield dda.i_x1.eq(end[0] << 4) yield dda.i_y1.eq(end[1] << 4) yield dda.i_start.eq(1) yield dda.i_next.eq(0) # Wait for setup yield; yield yield dda.i_start.eq(0) yield; yield; yield
# Load the immediate register self.o_immediate.eq(imm16), self.o_use_imm.eq(1), # Select the appropriate ALU op. self.o_adder_op.eq(ALUAdder.Add), # These are legal instructions. self.o_ri_except.eq(0), # "signed" instructions trap on overflow here. self.o_ovf_check.eq(is_signed) ] with m.Case(Instruction.SLTI, Instruction.SLTIU): is_signed = Signal() m.d.comb += [ is_signed.eq(funct.matches(Function.SLTI)), # Load the immediate register self.o_immediate.eq(imm16), self.o_use_imm.eq(1), # Implement comparisons in terms of subtraction. self.o_adder_op.eq(ALUAdder.Sub), # These are legal instructions. self.o_emu_abort.eq(0) ] return m rtlil.convert(Decoder())
def __init__(self, width): self.v = Signal(width, reset=2**width - 1) self.o = Signal() self.en = Signal() def elaborate(self, platform): m = Module() m.d.sync += self.v.eq(self.v + 1) m.d.comb += self.o.eq(self.v[-1]) return EnableInserter(self.en)(m) ctr = Counter(width=16) #print(verilog.convert(ctr, ports=[ctr.o, ctr.en])) print(rtlil.convert(ctr, ports=[ctr.o, ctr.en])) sim = pysim.Simulator(ctr) sim.add_clock(1e-6) def ce_proc(): yield yield yield yield ctr.en.eq(1) yield yield yield yield ctr.en.eq(0) yield
from m68000 import m68000 from nmigen.back import rtlil mod = m68000() ports = [sig for attr, sig in vars(mod).items() if attr[:2] in ("i_", "o_")] rtlil_text = rtlil.convert(mod, platform=None, name="m68000", ports=ports) print(""" read_ilang <<rtlil {} rtlil proc flatten memory_collect opt -full clean -purge write_cxxrtl -O3 """.format(rtlil_text))
from via6522 import via6522 from nmigen.back import rtlil mod = via6522() ports = [sig for attr, sig in vars(mod).items() if attr[:2] in ("i_", "o_")] rtlil_text = rtlil.convert(mod, platform=None, name="via6522", ports=ports) print(""" read_ilang <<rtlil {} rtlil proc flatten memory_collect opt -full clean -purge write_cxxrtl -O3 """.format(rtlil_text))
with m.If(self.i_enable & (self.i_fbpxfmt != PixelFormat.PSMCT24)): m.d.comb += test.eq(self.i_alpha[7] == self.i_mode) with m.Else(): m.d.comb += test.eq(1) m.d.sync += [ self.o_rgbrndr.eq(self.i_rgbrndr & test), self.o_arndr.eq(self.i_arndr & test), self.o_zrndr.eq(self.i_zrndr & test) ] return m if __name__ == "__main__": atst = DestinationAlphaTest() ports = [ atst.i_enable, atst.i_mode, atst.i_rgbrndr, atst.i_arndr, atst.i_zrndr, atst.i_x_coord, atst.i_y_coord, atst.i_z_coord, atst.i_red, atst.i_green, atst.i_blue, atst.i_alpha, atst.i_fbpxfmt, atst.o_rgbrndr, atst.o_arndr, atst.o_zrndr, atst.o_x_coord, atst.o_y_coord, atst.o_z_coord, atst.o_red, atst.o_green, atst.o_blue, atst.o_alpha, ] print(rtlil.convert(atst, ports=ports))
def build_formal(bld: Builder): m = Module() in_data = AnySeq(8) en_data = AnySeq(1) hsync = AnySeq(1) vsync = AnySeq(1) enc_char = Signal(10) real_chr_bias = Signal(signed(5)) real_dc_bias = Signal(signed(5)) m.submodules.enc = enc = TMDSEncoder() m.submodules.dec = dec = TMDSDecoder() m.d.comb += [ enc.i_data.eq(in_data), enc.i_en_data.eq(en_data), enc.i_hsync.eq(hsync), enc.i_vsync.eq(vsync), dec.i_char.eq(enc.o_char), enc_char.eq(enc.o_char), ] m.d.comb += [ real_chr_bias.eq(popcount(enc.o_char) - 5), Assert(real_dc_bias >= -5), Assert(real_dc_bias <= +5), Assert(real_dc_bias[:4] == enc.dc_bias), ] m.d.sync += [ real_dc_bias.eq(real_dc_bias + real_chr_bias), ] with m.If(~enc.i_en_data): m.d.sync += real_dc_bias.eq(real_dc_bias) m.d.comb += Cover( (Past(dec.o_en_data, 4) & (Past(enc.o_char, 4)[8:10] == 0b00)) & (Past(dec.o_en_data, 3) & (Past(enc.o_char, 3)[8:10] == 0b01)) & (Past(dec.o_en_data, 2) & (Past(enc.o_char, 2)[8:10] == 0b10)) & (Past(dec.o_en_data, 1) & (Past(enc.o_char, 1)[8:10] == 0b11)) & (dec.o_vsync)) m.d.comb += Assert(dec.o_en_data == enc.i_en_data) with m.If(dec.o_en_data): m.d.comb += Assert(dec.o_data == enc.i_data) # Check that XNOR choice matches reference algorithm in_pop = Signal(4) use_xnor = Signal() m.d.comb += [ in_pop.eq(popcount(in_data)), use_xnor.eq((in_pop > 4) | ((in_pop == 4) & (in_data[0] == 0))), Assert(enc.o_char[8] == ~use_xnor), ] with m.Else(): m.d.comb += [ Assert(dec.o_hsync == enc.i_hsync), Assert(dec.o_vsync == enc.i_vsync), ] with bld.temp_open("formal.il") as f: il_text = rtlil.convert(m, ports=[enc_char, real_chr_bias, real_dc_bias]) f.write(il_text)
ablend.i_blend_c, ablend.i_blend_d, ablend.i_fbred, ablend.i_fbgreen, ablend.i_fbblue, ablend.i_fbalpha, ablend.i_rgbrndr, ablend.i_arndr, ablend.i_zrndr, ablend.i_x_coord, ablend.i_y_coord, ablend.i_z_coord, ablend.i_red, ablend.i_green, ablend.i_blue, ablend.i_alpha, ablend.i_fbpxfmt, ablend.o_rgbrndr, ablend.o_arndr, ablend.o_zrndr, ablend.o_x_coord, ablend.o_y_coord, ablend.o_z_coord, ablend.o_red, ablend.o_green, ablend.o_blue, ablend.o_alpha, ] print(rtlil.convert(ablend, ports=ports))
# You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the 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. # # SPDX-License-Identifier: Apache-2.0 from nmigen import * from nmigen.back import rtlil class Counter(Elaboratable): def __init__(self, width): self.v = Signal(width, reset=2**width-1) self.o = Signal() def elaborate(self, platform): m = Module() m.d.sync += self.v.eq(self.v + 1) m.d.comb += self.o.eq(self.v[-1]) return m ctr = Counter(width=16) print(rtlil.convert(ctr, ports=[ctr.o]))
def main(): top = Top() output = rtlil.convert(Fragment.get(top, None), ports=(top.clk100, top.serial_tx)) print(output)