:letsgo3:
We provide a Yosys plugin, which can output Churchroad IR from Yosys. Please see the README in that directory for information on building and using the plugin.
License: MIT License
:letsgo3:
We provide a Yosys plugin, which can output Churchroad IR from Yosys. Please see the README in that directory for information on building and using the plugin.
Has not been updated to new syntax.
Recently, a commit broke something (see: #51 ) broke something that could've been caught if the tests also ran typechecking.
Please also run typechecking as part of tests - to make sure that new commits don't break anything. Thanks.
According to the Yosys documentation:
The $shift cell performs a right logical shift if the second operand is positive (or unsigned), and a left logical shift if it is negative. The $shiftx cell performs the same operation as the $shift cell, but the vacated bit positions are filled with undef (x) bits, and corresponds to the Verilog indexed part-select expression.
Because Churchroad doesn't support X bits, for now we'll encode both to a regular right shift, but this is something to potentially keep in mind.
Verilator is becoming the bane of my existence
We are doing weird things on Mac though, using brew LLVM etc.
There's a chance Verilator should just work with default MacOS clang. I need to do more testing on this. With Lakeroad I could always get things to work, but it seems like I can't anymore.
Start replicating whatever benchmarks are listed in #76
The Verilator tests will sometimes fail with this error, but if the tests are rerun, they'll pass. I'm unsure why that's happening.
`timescale 1 ps / 1 ps
//
// LUT6 primitive for Xilinx FPGAs
// Compatible with Verilator tool (www.veripool.org)
// Copyright (c) 2019-2020 Frédéric REQUIN
// License : BSD
//
module LUT6
#(
parameter [64:0] INIT = 64'h0000000000000000
)
(
input wire I0, I1, I2, I3, I4, I5,
output wire O
);
wire [5:0] _w_idx = { I5, I4, I3, I2, I1, I0 };
assign O = INIT[_w_idx];
endmodule
produces
;;; generated with `yosys -p 'plugin -i churchroad; "read_verilog -sv <lut6.sv> prep -top LUT6; pmuxtree; write_lakeroad"`
; wire declarations
; $auto$splice.cc:140:get_spliced_signal$3
(let v0 (Wire "v0" 2))
; $auto$splice.cc:140:get_spliced_signal$5
(let v1 (Wire "v1" 3))
; $auto$splice.cc:140:get_spliced_signal$7
(let v2 (Wire "v2" 4))
; $auto$splice.cc:140:get_spliced_signal$9
(let v3 (Wire "v3" 5))
; I0
(let v4 (Wire "v4" 1))
; I1
(let v5 (Wire "v5" 1))
; I2
(let v6 (Wire "v6" 1))
; I3
(let v7 (Wire "v7" 1))
; I4
(let v8 (Wire "v8" 1))
; I5
(let v9 (Wire "v9" 1))
; O
(let v10 (Wire "v10" 1))
; _w_idx
(let v11 (Wire "v11" 6))
; cells
(union v11 (Op2 (Concat) v3 v9))
(union v0 (Op2 (Concat) v4 v5))
(union v1 (Op2 (Concat) v0 v6))
(union v2 (Op2 (Concat) v1 v7))
(union v3 (Op2 (Concat) v2 v8))
; 64'0000000000000000000000000000000000000000000000000000000000000000
(let v12 (Op0 (BV 0 64)))
(let v13 (Op1 (Extract 0 0) v12))
(union v10 (Op2 (Shr) v13 v11))
; inputs
(let I0 (Var "I0" 1))
(union v4 I0)
(let I1 (Var "I1" 1))
(union v5 I1)
(let I2 (Var "I2" 1))
(union v6 I2)
(let I3 (Var "I3" 1))
(union v7 I3)
(let I4 (Var "I4" 1))
(union v8 I4)
(let I5 (Var "I5" 1))
(union v9 I5)
; outputs
(let O v10)
; delete wire expressions
(delete (Wire "v0" 2))
(delete (Wire "v1" 3))
(delete (Wire "v2" 4))
(delete (Wire "v3" 5))
(delete (Wire "v4" 1))
(delete (Wire "v5" 1))
(delete (Wire "v6" 1))
(delete (Wire "v7" 1))
(delete (Wire "v8" 1))
(delete (Wire "v9" 1))
(delete (Wire "v10" 1))
(delete (Wire "v11" 6))
which seems wrong, because the shift/extract seem to be in the wrong order.
the RTLIL is
# Generated by Yosys 0.35+36 (git sha1 c95298225, aarch64-apple-darwin20.2-clang 10.0.0-4ubuntu1 -fPIC -Os)
autoidx 2
attribute \top 1
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:9.1-21.10"
module \LUT6
parameter \INIT 64'0000000000000000000000000000000000000000000000000000000000000000
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:14.17-14.19"
wire input 1 \I0
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:14.21-14.23"
wire input 2 \I1
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:14.25-14.27"
wire input 3 \I2
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:14.29-14.31"
wire input 4 \I3
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:14.33-14.35"
wire input 5 \I4
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:14.37-14.39"
wire input 6 \I5
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:15.17-15.18"
wire output 7 \O
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:17.16-17.22"
wire width 6 \_w_idx
attribute \src "/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:0.0-0.0"
cell $shiftx $shiftx$/Users/andrew/research/lakeroad/verilog/simulation/xilinx-ultrascale-plus/LUT6.v:0$1
parameter \A_SIGNED 0
parameter \A_WIDTH 64
parameter \B_SIGNED 0
parameter \B_WIDTH 6
parameter \Y_WIDTH 1
connect \A 64'0000000000000000000000000000000000000000000000000000000000000000
connect \B { \I5 \I4 \I3 \I2 \I1 \I0 }
connect \Y \O
end
connect \_w_idx { \I5 \I4 \I3 \I2 \I1 \I0 }
end
The user has to run splice/splitnets -driver before compiling to Churchroad. We should be able to detect whether they've done this by e.g. making sure that the inputs to an AND are the same width, and are the width of their output.
A simple first smoketest would be to use Churchroad to compile a design which Lakeroad can already synthesize by itself: a multiply narrow enough to fit on a single DSP.
Essentially, the steps are this:
(Op2 (Mul) a b)
of <18 bits.(rewrite (Op2 (Mul) a b [of a certain bitwidth]) (PrimitiveInterface (DSP <params>) a b)
When using the Churchroad Yosys plugin, I'm seeing that there are multiple ZeroExtend
s that aren't correct. Consider the following module:
module my_module(
input a,
input b,
output[1:0] o,
);
assign o = {a, b};
endmodule
Running yosys -m $CHURCHROAD_DIR/yosys-plugin/churchroad.so -q -p "read_verilog -sv my-module.v; prep -top my_module; pmuxtree; write_lakeroad"
yields:
; wire declarations
; a
(let v0 (Wire "v0" 1))
; b
(let v1 (Wire "v1" 1))
; o
(let v2 (Wire "v2" 2))
; cells
; TODO not handling signedness
(let v3 (Op1 (ZeroExtend 2) v1))
; TODO not handling signedness
(let v4 (Op1 (ZeroExtend 2) v0))
(union v2 (Op2 (Concat) v3 v4))
; inputs
(let a (Var "a" 1))
(IsPort "" "a" (Input) a)
(union v0 a)
(let b (Var "b" 1))
(IsPort "" "b" (Input) b)
(union v1 b)
; outputs
(let o v2)
(IsPort "" "o" (Output) o)
; delete wire expressions
(delete (Wire "v0" 1))
(delete (Wire "v1" 1))
(delete (Wire "v2" 2))
v2
, which is the output of the module, is being assigned the concatenation of v3
and v4
, each of which are respectively a
and b
zero-extended to be of bitwidth 2. This means that we're unioning two things of different bitwidth!
The following example is a 2-bit ripple-carry adder in Verilog.
module top
(
i_a,
i_b,
o_s,
o_c
);
input [1:0] i_a;
input [1:0] i_b;
output [1:0] o_s;
output o_c;
wire [1:0] c;
assign o_s[0] = i_a[0] ^ i_b[0] ^ 1'b0;
assign c[0] = (i_a[0] & i_b[0]) | (i_b[0] & 1'b0) | (i_a[0] & 1'b0);
assign o_s[1] = i_a[1] ^ i_b[1] ^ c[0];
assign c[1] = (i_a[1] & i_b[1]) | (i_b[1] & c[0]) | (i_a[1] & c[0]);
assign o_c = c[1];
endmodule
The generated Churchroad has lots of (seemingly?) unnecessary Concat and ZeroExtend expressions.
(Edit: Can recreate using the Churchroad web demo: https://sampl.cs.washington.edu/churchroad-web-demo/)
For example:
; TODO not handling signedness
(let v16 (Op1 (ZeroExtend 2) v3))
; TODO not handling signedness
(let v17 (Op1 (ZeroExtend 2) v4))
(union v15 (Op2 (Concat) v16 v17))
But I don't know that it makes sense to ZeroExtend wires like v3
and v4
as they are just from 1-bit Xor expressions:
(union v3 (Op2 (Xor) v5 v6))
(union v4 (Op2 (Xor) v10 v11))
And v15
is declared as a 2-bit wire, but the Concat expression makes it seem like the result is 4 bits (from the ZeroExtend).
These generated expressions seem to come from this commit: 3b48098
For example, Yosys's $add
cell has inputs A and B, and their bitwidths do not necessarily match. However, Churchroad currently assumes they do. This has already led to bugs (e.g. in Andrew's usecases).
There are a few things to consider at the same time:
This should get fixed in #35.
This is definitely non-essential.
There's a lot of noise in the repo commit data because we forked this repo from Lakeroad. One simple way to fix this would be to start the git history at c24f10e4c9d3950ecab9fc7aa3c3d96eabcef1bc
. There's still a bunch of intervening Lakeroad work between that commit and the real start of the Churchroad repo, though.
The other option is to start it at 01388887c9e97056d2e7a343c70d5afd396d5f62
, where we convert the repo to Churchroad. In that case, though, I want to make sure Thanawat gets credit for his contributions still.
For Churchroad, we currently assume that at t=0, it doesn't matter what the clk value is -- we will always return the default value. However, some of these results from Verilator seem to imply that Verilator's semantics say that a register getting 1 as its initial input will count that as a positive edge and clock in a new value.
For the decompilation application, we need to turn the modules that we find back into verilog instantiations of the module (i.e. unflatten
). Right now, I instantiate my module like:
(function ALU ( Expr Expr Expr ) Expr :cost 0)
which is the "simplest" solution for now. However, I'd need to be able to turn this expression:
(ALU i_bit1 i_bit2 i_op)
Into the verilog:
// may probably need to declare a wire for the output of the ALU or something
wire o_out;
alu alu(
.i_a (o_a),
.i_b (o_b),
.i_control (i_op),
.o_res (o_out)
);
when we do the decompilation and turn the Egglog expression back into the verilog again.
There are probably some other complications with this - but this is the idea for now.
(.venv) (.venv) fortyfort ➜ churchroad git:(ninehusky-even-more-operators) ✗ yosys -m yosys-plugin/churchroad.so -p 'read_verilog -sv tests/interpreter_tests/verilog/xilinx_ultrascale_plus/LUT6-modified.v; write_lakeroad'
/----------------------------------------------------------------------------\
| |
| yosys -- Yosys Open SYnthesis Suite |
| |
| Copyright (C) 2012 - 2020 Claire Xenia Wolf <[email protected]> |
| |
| Permission to use, copy, modify, and/or distribute this software for any |
| purpose with or without fee is hereby granted, provided that the above |
| copyright notice and this permission notice appear in all copies. |
| |
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
\----------------------------------------------------------------------------/
Yosys 0.36+42 (git sha1 70d35314d, clang 15.0.0 -fPIC -Os)
-- Running command `read_verilog -sv tests/interpreter_tests/verilog/xilinx_ultrascale_plus/LUT6-modified.v; write_lakeroad' --
1. Executing Verilog-2005 frontend: tests/interpreter_tests/verilog/xilinx_ultrascale_plus/LUT6-modified.v
Parsing SystemVerilog input from `tests/interpreter_tests/verilog/xilinx_ultrascale_plus/LUT6-modified.v' to AST representation.
Generating RTLIL representation for module `\LUT6'.
Successfully finished Verilog frontend.
2. Executing Lakeroad egglog backend.
3. Executing SPLICE pass (creating cells for signal splicing).
Splicing signals in module LUT6:
Created spliced signal: { \I5 \I4 \I3 \I2 \I1 \I0 } -> $auto$splice.cc:140:get_spliced_signal$11
4. Executing SPLITNETS pass (splitting up multi-bit signals).
Removed 0 unused cells and 3 unused wires.
; wire declarations
dyld[83653]: missing symbol called
[1] 83653 abort yosys -m yosys-plugin/churchroad.so -p
We've done most of the heavy conversion lifting in #2, but there's still cleanup to be done.
I suspect it might not be needed at all; currently, we're using it all over the place.
My understanding of sigmap
has changed a lot. It seems like its main purpose is to generate a canonical representation of a wire, including tasks like inserting constant bits when one of the bits is known to be constant. That's not exactly what we need.
For example:
https://github.com/uwsampl/churchroad/blob/4a2a170d4a85cef4a35d2674336d6f154981e617/yosys-plugin/churchroad.cc#L1448
Inside churchroad.cc
, here and here I think Churchroad's producing egglog code of the form (Extract hi lo Expr)
, when it should be ((Op1 (Extract high low) expr)
as defined in lakeroad.egg.
Getting Egglog to try and parse the former results in an Arity mismatch, expected 2 args: (Extract 8 8 v0)
.
If the design has a wire that is never assigned to anything, then it will produce an eclass with just a Wire in it. Later, that Wire will be deleted, and anything that pointed to that eclass will now be syntactically incorrect.
Thanks to @thiskappaisgrey for finding this.
Subtasks:
splice; splitnets -driver
passes before Churchroad backend, either by running them explicitly, or via documentation. Also add checks to see whether they've been run.
For example, if you have:
(let set (Var "set" 1))
This is an Egglog syntax error.
This'll be a blast!
The Yosys Churchroad backend produces Regs that have a clock. The documentation in churchroad.egg suggests that it takes a clock. However, the typechecking rules expect no clock.
There should be a way to run the Churchroad interpreter directly on Churchroad source code (i.e., src.egg
).
We need extraction with cycles for various reasons.
This was mentioned by @dpetrisko.
Apparently Vivado is failing to map wide FMAs to DSPs efficiently.
Lakeroad alone probably can't do this -- once a solver query needs to figure out that some combination of bvmuls == one wide bvmul, they all seem to choke. There may be solver tricks to do this (reasoning about multiplies is a known hard problem; I would think solvers like cvc5 would have done research on this). However, there's an even more obvious way around this: use equality saturation (ie Churchroad) to block up the FMA via rewrites, and then run Lakeroad synthesis on the smaller FMAs that result. Assuming the smaller FMAs are sized to fit on a single DSP, then this should work great.
Subtasks:
cc @dpetrisko
I'll use this issue to collect benchmarks from Dan. These should be examples where Vivado produces mappings that Dan suspects we can improve upon.
We need a way to interpret Churchroad programs so that we can ensure the Verilog -> Churchroad translation is correct (and probably for other reasons too).
This needs to be fixed in the long term. It seems like this will also be an issue with Lakeroad.
The primary issue is that our CI pushes an image, and public forks can't get write
permissions to packages. It can be enabled in settings I think, but I'm unsure whether that's actually a sane idea.
Currently prototyped by both me and Thanawat in a few different places:
Currently the function doesn't work in the presence of cycles, because egglog::EGraph::function_to_dag
uses find_best
, which doesn't work with cycles.
We currently run some passes (splice; splitnets -driver; clean
) to put the design into a certain state before generating output. We should explicitly check that the design meets certain requirements before generating output, though.
These passes fundamentally change the design. It's probably better to enforce that they're run before writing out the design. Alternatively, if there was a way to undo the changes easily after the pass is complete.
Given an egraph with a primitive interface present inside of it, call out to Lakeroad to attempt to synthesize the primtive interface(s).
Probably easier to just start with the following functions:
Hi,
I believe that the Var
node is the only node that is used for inputs anyways(but having a naming convention is still good so that we can search for which variables are inputs in the code?), so it doesn't matter too much, but I need output egglog variables to be prefixed with o_
so I can automatically find which ones to extract when creating the rewrite rule. I've been prefixing them manually but adding them to the plugin would be nicer. I just realize that some projects don't follow the convention of prefixing input variables with i_
and output variables with o_
and there's no way to search for them in code the output egglog otherwise.
Thanks.
Is adjacent to #2 .
Currently we have tests that test the first arrow, and tests that test the second arrow, but we need to do end-to-end, because the plugin and the egglog language definition can get out of sync. This is exactly why #6 occurred.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.