127 lines
3.0 KiB
Rust
127 lines
3.0 KiB
Rust
|
use crate::parser;
|
||
|
use std::collections::HashMap;
|
||
|
|
||
|
#[derive(Debug, Default)]
|
||
|
pub struct ILWriter {
|
||
|
data: String,
|
||
|
indent: usize,
|
||
|
}
|
||
|
|
||
|
// this would be much nicer if indent gave you a new writer
|
||
|
// which would indent things
|
||
|
impl ILWriter {
|
||
|
fn new() -> Self {
|
||
|
Default::default()
|
||
|
}
|
||
|
|
||
|
fn write_line(&mut self, line: &str) {
|
||
|
self.data += &"\t".repeat(self.indent);
|
||
|
self.data += line;
|
||
|
self.data += "\n";
|
||
|
}
|
||
|
|
||
|
fn indent(&mut self) {
|
||
|
self.indent += 1
|
||
|
}
|
||
|
|
||
|
fn dedent(&mut self) {
|
||
|
self.indent = self
|
||
|
.indent
|
||
|
.checked_sub(1)
|
||
|
.expect("tried to dedent negative amount")
|
||
|
}
|
||
|
|
||
|
fn finish(self) -> String {
|
||
|
self.data
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// the proper way
|
||
|
pub enum WireOption {
|
||
|
Input(i32),
|
||
|
Output(i32),
|
||
|
}
|
||
|
|
||
|
pub struct Wire {
|
||
|
id: String,
|
||
|
options: Vec<()>,
|
||
|
}
|
||
|
|
||
|
struct Module {}
|
||
|
|
||
|
struct Cell {
|
||
|
id: String,
|
||
|
celltype: String,
|
||
|
parameters: Vec<(String, String)>,
|
||
|
connections: Vec<(String, String)>,
|
||
|
}
|
||
|
|
||
|
impl Cell {
|
||
|
fn new(id: &str, celltype: &str) -> Self {
|
||
|
Cell {
|
||
|
id: id.into(),
|
||
|
celltype: celltype.into(),
|
||
|
parameters: Vec::new(),
|
||
|
connections: Vec::new(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn add_param(&mut self, name: &str, value: &str) {
|
||
|
self.parameters.push((name.into(), value.into()))
|
||
|
}
|
||
|
|
||
|
fn add_connection(&mut self, from: &str, to: &str) {
|
||
|
self.connections.push((from.into(), to.into()))
|
||
|
}
|
||
|
|
||
|
fn write_rtlil(&self, writer: &mut ILWriter) {
|
||
|
writer.write_line(&format!("cell {} {}", self.celltype, self.id));
|
||
|
writer.indent();
|
||
|
for param in &self.parameters {
|
||
|
writer.write_line(&format!("parameter {} {}", param.0, param.1))
|
||
|
}
|
||
|
for conn in &self.connections {
|
||
|
writer.write_line(&format!("connect {} {}", conn.0, conn.1))
|
||
|
}
|
||
|
writer.dedent();
|
||
|
writer.write_line("end");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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");
|
||
|
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
|
||
|
}
|
||
|
|
||
|
// the hacky way
|
||
|
|
||
|
pub fn lower_module(module: parser::Module) -> String {
|
||
|
let mut writer = ILWriter::new();
|
||
|
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 stmt in module.statements {
|
||
|
// writer.write_line(&format!("connect \\{} \\{}", stmt.lhs, stmt.expr));
|
||
|
}
|
||
|
adder_cell("\\my_and", "\\a", "\\b", "\\y").write_rtlil(&mut writer);
|
||
|
writer.dedent();
|
||
|
writer.write_line("end");
|
||
|
writer.finish()
|
||
|
}
|