221 lines
5.1 KiB
Rust
221 lines
5.1 KiB
Rust
mod sync;
|
|
|
|
pub use sync::{CaseRule, Process, SwitchRule, SyncCond, SyncRule};
|
|
|
|
#[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 {
|
|
pub fn new() -> Self {
|
|
Default::default()
|
|
}
|
|
|
|
pub fn write_line(&mut self, line: &str) {
|
|
self.data += &"\t".repeat(self.indent);
|
|
self.data += line;
|
|
self.data += "\n";
|
|
}
|
|
|
|
// TODO: make this actually take an iterator
|
|
pub fn write_iter(&mut self, iter: &[impl RtlilWrite]) {
|
|
for item in iter {
|
|
item.write_rtlil(self)
|
|
}
|
|
}
|
|
|
|
pub fn indent(&mut self) {
|
|
self.indent += 1
|
|
}
|
|
|
|
pub fn dedent(&mut self) {
|
|
self.indent = self
|
|
.indent
|
|
.checked_sub(1)
|
|
.expect("tried to dedent negative amount")
|
|
}
|
|
|
|
pub fn finish(self) -> String {
|
|
self.data
|
|
}
|
|
}
|
|
|
|
pub trait RtlilWrite {
|
|
fn write_rtlil(&self, writer: &mut ILWriter);
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum SigSpec {
|
|
Const(i64, u32),
|
|
Wire(String),
|
|
}
|
|
|
|
impl SigSpec {
|
|
pub fn wire(id: &str) -> Self {
|
|
Self::Wire(id.to_owned())
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for SigSpec {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
SigSpec::Const(val, width) => write!(f, "{}'{}", width, val)?,
|
|
SigSpec::Wire(id) => write!(f, "{}", id)?,
|
|
};
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Wire {
|
|
/// rtlil ID
|
|
id: String,
|
|
/// width in bits
|
|
width: u32,
|
|
/// Port info if this is a port
|
|
port_info: Option<PortOption>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum PortOption {
|
|
Input(i32),
|
|
Output(i32),
|
|
}
|
|
|
|
impl Wire {
|
|
pub fn new(id: impl Into<String>, width: u32, port_info: Option<PortOption>) -> Self {
|
|
Self {
|
|
id: id.into(),
|
|
width,
|
|
port_info,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl RtlilWrite for Wire {
|
|
fn write_rtlil(&self, writer: &mut ILWriter) {
|
|
let mut line = String::from("wire ");
|
|
|
|
if let Some(option) = &self.port_info {
|
|
let port_str = match option {
|
|
PortOption::Input(num) => format!("input {} ", num),
|
|
PortOption::Output(num) => format!("output {} ", num),
|
|
};
|
|
line += &port_str;
|
|
};
|
|
|
|
if self.width > 1 {
|
|
line += &format!("width {} ", self.width);
|
|
}
|
|
|
|
line += &self.id;
|
|
writer.write_line(&line);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Module {
|
|
name: String,
|
|
wires: Vec<Wire>,
|
|
cells: Vec<Cell>,
|
|
processes: Vec<Process>,
|
|
connections: Vec<(SigSpec, SigSpec)>,
|
|
gen_id: i32,
|
|
}
|
|
|
|
impl Module {
|
|
pub fn new(name: impl Into<String>) -> Self {
|
|
Self {
|
|
name: name.into(),
|
|
wires: Default::default(),
|
|
cells: Default::default(),
|
|
connections: Default::default(),
|
|
processes: Default::default(),
|
|
gen_id: 0,
|
|
}
|
|
}
|
|
|
|
pub fn add_wire(&mut self, wire: Wire) {
|
|
self.wires.push(wire)
|
|
}
|
|
|
|
pub fn add_connection(&mut self, target: &SigSpec, source: &SigSpec) {
|
|
self.connections.push((target.clone(), source.clone()))
|
|
}
|
|
|
|
pub fn add_cell(&mut self, cell: Cell) {
|
|
self.cells.push(cell)
|
|
}
|
|
|
|
pub fn add_process(&mut self, proc: Process) {
|
|
self.processes.push(proc)
|
|
}
|
|
|
|
pub fn make_genid(&mut self, stem: &str) -> String {
|
|
let res = format!("${}${}", stem, self.gen_id);
|
|
self.gen_id += 1;
|
|
res
|
|
}
|
|
}
|
|
|
|
impl RtlilWrite for Module {
|
|
fn write_rtlil(&self, writer: &mut ILWriter) {
|
|
writer.write_line(&format!("module {}", self.name));
|
|
writer.indent();
|
|
writer.write_iter(&self.wires);
|
|
writer.write_iter(&self.cells);
|
|
writer.write_iter(&self.processes);
|
|
for conn in &self.connections {
|
|
writer.write_line(&format!("connect {} {}", conn.0, conn.1))
|
|
}
|
|
writer.dedent();
|
|
writer.write_line("end");
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Cell {
|
|
id: String,
|
|
celltype: String,
|
|
parameters: Vec<(String, String)>,
|
|
connections: Vec<(SigSpec, SigSpec)>,
|
|
}
|
|
|
|
impl Cell {
|
|
pub fn new(id: &str, celltype: &str) -> Self {
|
|
Self {
|
|
id: id.into(),
|
|
celltype: celltype.into(),
|
|
parameters: Vec::new(),
|
|
connections: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add_param(&mut self, name: &str, value: &str) {
|
|
self.parameters.push((name.into(), value.into()))
|
|
}
|
|
|
|
pub fn add_connection(&mut self, from: &str, to: &SigSpec) {
|
|
self.connections.push((SigSpec::wire(from), to.clone()))
|
|
}
|
|
}
|
|
|
|
impl RtlilWrite for Cell {
|
|
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");
|
|
}
|
|
}
|