refactor rtlir backend
This commit is contained in:
parent
3f1546c323
commit
68306885d7
|
@ -2,13 +2,85 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futilehdl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"structopt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
|
@ -32,8 +104,146 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lazy_static",
|
||||
"structopt-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
|
@ -7,3 +7,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
nom = "7.1.0"
|
||||
structopt = "0.3.25"
|
||||
|
|
10
identity.fut
10
identity.fut
|
@ -1,4 +1,10 @@
|
|||
module top ( input wire x, output wire y )
|
||||
module halfadd (
|
||||
input wire a,
|
||||
input wire b,
|
||||
output wire sum,
|
||||
output wire carry
|
||||
)
|
||||
{
|
||||
assign x = y;
|
||||
assign sum = xor(a, b);
|
||||
assign carry = and(a, b);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ mod parser;
|
|||
mod rtlil;
|
||||
|
||||
use nom::error::{convert_error, VerboseError};
|
||||
use structopt::StructOpt;
|
||||
|
||||
// custom IResult type for verboseerror
|
||||
pub type IResult<I, O, E = VerboseError<I>> = nom::IResult<I, O, E>;
|
||||
|
|
|
@ -3,8 +3,7 @@ use nom::{
|
|||
bytes::complete::tag,
|
||||
character::complete::{alpha1, alphanumeric1, char, multispace0, multispace1},
|
||||
combinator::{map, opt, recognize},
|
||||
error::ParseError,
|
||||
error::{context, convert_error, VerboseError},
|
||||
error::{context, ParseError},
|
||||
multi::{many0, many1, separated_list0},
|
||||
sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
|
||||
};
|
||||
|
@ -58,7 +57,7 @@ pub struct PortDecl {
|
|||
pub struct Module {
|
||||
pub name: String,
|
||||
pub ports: Vec<PortDecl>,
|
||||
pub statements: Vec<Assign>,
|
||||
pub statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -80,8 +79,8 @@ pub enum Operation {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Call {
|
||||
name: String,
|
||||
params: Vec<Expression>,
|
||||
pub name: String,
|
||||
pub args: Vec<Expression>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -142,10 +141,17 @@ fn call_item(input: &str) -> IResult<&str, Call> {
|
|||
map(
|
||||
tuple((
|
||||
ws0(identifier),
|
||||
delimited(char('('), ws0(separated_list0(char(','), expression)), char(')'))
|
||||
delimited(
|
||||
char('('),
|
||||
ws0(separated_list0(char(','), expression)),
|
||||
char(')'),
|
||||
),
|
||||
)),
|
||||
|(name, params)| Call { name: name.into(), params }
|
||||
)(input)
|
||||
|(name, args)| Call {
|
||||
name: name.into(),
|
||||
args,
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn expression(input: &str) -> IResult<&str, Expression> {
|
||||
|
@ -156,16 +162,18 @@ fn expression(input: &str) -> IResult<&str, Expression> {
|
|||
))(input)
|
||||
}
|
||||
|
||||
fn assign_statement(input: &str) -> IResult<&str, Assign> {
|
||||
fn assign_statement(input: &str) -> IResult<&str, Statement> {
|
||||
context(
|
||||
"assignment",
|
||||
delimited(
|
||||
ws0(terminated(tag("assign"), multispace1)),
|
||||
map(
|
||||
separated_pair(ws0(identifier), char('='), ws0(expression)),
|
||||
|(lhs, expr)| Assign {
|
||||
lhs: lhs.into(),
|
||||
expr: expr.into(),
|
||||
|(lhs, expr)| {
|
||||
Statement::Assign(Assign {
|
||||
lhs: lhs.into(),
|
||||
expr: expr.into(),
|
||||
})
|
||||
},
|
||||
),
|
||||
ws0(char(';')),
|
||||
|
@ -228,5 +236,6 @@ mod test {
|
|||
fn test_call() {
|
||||
call_item("thing ( )").unwrap();
|
||||
call_item("thing ( a , b , c )").unwrap();
|
||||
call_item("thing(a,b,c)").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
162
src/rtlil.rs
162
src/rtlil.rs
|
@ -37,18 +37,91 @@ impl ILWriter {
|
|||
}
|
||||
|
||||
// the proper way
|
||||
#[derive(Debug)]
|
||||
pub enum WireOption {
|
||||
Input(i32),
|
||||
Output(i32),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Wire {
|
||||
id: String,
|
||||
options: Vec<()>,
|
||||
options: Vec<WireOption>,
|
||||
}
|
||||
|
||||
struct Module {}
|
||||
impl Wire {
|
||||
fn new(id: impl Into<String>) -> Self {
|
||||
Wire {
|
||||
id: id.into(),
|
||||
options: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_rtlil(&self, writer: &mut ILWriter) {
|
||||
let mut line = String::from("wire ");
|
||||
|
||||
for option in &self.options {
|
||||
let option_str = match option {
|
||||
WireOption::Input(num) => format!("input {} ", num),
|
||||
WireOption::Output(num) => format!("output {} ", num),
|
||||
};
|
||||
|
||||
line += &option_str;
|
||||
}
|
||||
|
||||
line += &self.id;
|
||||
writer.write_line(&line);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Module {
|
||||
name: String,
|
||||
wires: Vec<Wire>,
|
||||
cells: Vec<Cell>,
|
||||
connections: Vec<(String, String)>,
|
||||
gen_id: i32,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
fn new(name: impl Into<String>) -> Self {
|
||||
Module {
|
||||
name: name.into(),
|
||||
wires: Default::default(),
|
||||
cells: Default::default(),
|
||||
connections: Default::default(),
|
||||
gen_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_wire(&mut self, wire: Wire) {
|
||||
self.wires.push(wire)
|
||||
}
|
||||
|
||||
fn write_rtlil(&self, writer: &mut ILWriter) {
|
||||
writer.write_line(&format!("module {}", self.name));
|
||||
writer.indent();
|
||||
for wire in &self.wires {
|
||||
wire.write_rtlil(writer);
|
||||
}
|
||||
for cell in &self.cells {
|
||||
cell.write_rtlil(writer);
|
||||
}
|
||||
for conn in &self.connections {
|
||||
writer.write_line(&format!("connect {} {}", conn.0, conn.1))
|
||||
}
|
||||
writer.dedent();
|
||||
writer.write_line("end");
|
||||
}
|
||||
|
||||
fn make_genid(&mut self, stem: &str) -> String {
|
||||
let res = format!("${}${}", stem, self.gen_id);
|
||||
self.gen_id += 1;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Cell {
|
||||
id: String,
|
||||
celltype: String,
|
||||
|
@ -88,6 +161,19 @@ impl Cell {
|
|||
}
|
||||
}
|
||||
|
||||
fn xor_cell(id: &str, a: &str, b: &str, y: &str) -> Cell {
|
||||
let mut cell = Cell::new(id, "$xor");
|
||||
cell.add_param("\\A_SIGNED", "0");
|
||||
cell.add_param("\\A_WIDTH", "1");
|
||||
cell.add_param("\\B_SIGNED", "0");
|
||||
cell.add_param("\\B_WIDTH", "1");
|
||||
cell.add_param("\\Y_WIDTH", "1");
|
||||
cell.add_connection("\\A", a);
|
||||
cell.add_connection("\\B", b);
|
||||
cell.add_connection("\\Y", y);
|
||||
cell
|
||||
}
|
||||
|
||||
fn adder_cell(id: &str, a: &str, b: &str, y: &str) -> Cell {
|
||||
let mut cell = Cell::new(id, "$and");
|
||||
cell.add_param("\\A_SIGNED", "0");
|
||||
|
@ -103,24 +189,66 @@ fn adder_cell(id: &str, a: &str, b: &str, y: &str) -> Cell {
|
|||
|
||||
// the hacky way
|
||||
|
||||
pub fn lower_module(module: parser::Module) -> String {
|
||||
fn make_pubid(id: &str) -> String {
|
||||
"\\".to_owned() + id
|
||||
}
|
||||
|
||||
fn lower_expression(module: &mut Module, expr: &parser::Expression) -> String {
|
||||
match expr {
|
||||
parser::Expression::Ident(ident) => make_pubid(&ident),
|
||||
parser::Expression::Call(call) => {
|
||||
let output_gen_id = module.make_genid("cell");
|
||||
module.add_wire(Wire::new(&output_gen_id));
|
||||
|
||||
let mut args_resolved = call.args.iter().map(|expr| lower_expression(module, expr));
|
||||
|
||||
let arg_a = args_resolved.next().unwrap();
|
||||
let arg_b = args_resolved.next().unwrap();
|
||||
|
||||
let cell = match call.name.as_str() {
|
||||
"and" => {
|
||||
let cell_id = module.make_genid("and");
|
||||
adder_cell(&cell_id, &arg_a, &arg_b, &output_gen_id)
|
||||
},
|
||||
"xor" => {
|
||||
let cell_id = module.make_genid("xor");
|
||||
xor_cell(&cell_id, &arg_a, &arg_b, &output_gen_id)
|
||||
},
|
||||
_ => todo!(),
|
||||
};
|
||||
module.cells.push(cell);
|
||||
output_gen_id
|
||||
}
|
||||
parser::Expression::Operation(op) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_assignment(module: &mut Module, assignment: parser::Assign) {
|
||||
let target_id = make_pubid(&assignment.lhs);
|
||||
let return_wire = lower_expression(module, &assignment.expr);
|
||||
module.connections.push((target_id, return_wire))
|
||||
}
|
||||
|
||||
pub fn lower_module(pa_module: parser::Module) -> String {
|
||||
let mut writer = ILWriter::new();
|
||||
let mut ir_module = Module::new(format!("\\{}", pa_module.name));
|
||||
writer.write_line("autoidx 1");
|
||||
writer.write_line(&format!("module \\{}", module.name));
|
||||
writer.indent();
|
||||
for (num, port) in module.ports.iter().enumerate() {
|
||||
writer.write_line(&format!(
|
||||
"wire {} {} \\{}",
|
||||
"output",
|
||||
(num + 1),
|
||||
port.net.name
|
||||
))
|
||||
for (idx, port) in pa_module.ports.iter().enumerate() {
|
||||
let dir_option = match port.direction {
|
||||
parser::PortDirection::Input => WireOption::Input(idx as i32 + 1),
|
||||
parser::PortDirection::Output => WireOption::Output(idx as i32 + 1),
|
||||
};
|
||||
let wire = Wire {
|
||||
id: make_pubid(&port.net.name),
|
||||
options: vec![dir_option],
|
||||
};
|
||||
ir_module.wires.push(wire);
|
||||
}
|
||||
for stmt in module.statements {
|
||||
// writer.write_line(&format!("connect \\{} \\{}", stmt.lhs, stmt.expr));
|
||||
for stmt in pa_module.statements {
|
||||
match stmt {
|
||||
parser::Statement::Assign(assignment) => lower_assignment(&mut ir_module, assignment),
|
||||
}
|
||||
}
|
||||
adder_cell("\\my_and", "\\a", "\\b", "\\y").write_rtlil(&mut writer);
|
||||
writer.dedent();
|
||||
writer.write_line("end");
|
||||
ir_module.write_rtlil(&mut writer);
|
||||
writer.finish()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue