kaze 0.1.19

An HDL embedded in Rust
Documentation
use crate::code_writer;
use crate::graph;

use std::io::{Result, Write};

pub struct NodeDecl {
    pub net_type: NetType,
    pub name: String,
    pub bit_width: u32,
}

impl NodeDecl {
    pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
        w.append_indent()?;
        self.net_type.write(w)?;
        w.append(" ")?;
        if self.bit_width > 1 {
            w.append(&format!("[{}:{}] ", self.bit_width - 1, 0))?;
        }
        w.append(&format!("{};", self.name))?;
        w.append_newline()?;

        Ok(())
    }
}

pub enum NetType {
    Reg,
    Wire,
}

impl NetType {
    pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
        w.append(match self {
            NetType::Reg => "reg",
            NetType::Wire => "wire",
        })
    }
}

pub struct AssignmentContext {
    assignments: Vec<Assignment>,
    local_decls: Vec<NodeDecl>,
}

impl AssignmentContext {
    pub fn new() -> AssignmentContext {
        AssignmentContext {
            assignments: Vec::new(),
            local_decls: Vec::new(),
        }
    }

    pub fn gen_temp(&mut self, expr: Expr, bit_width: u32) -> Expr {
        let name = format!("__temp_{}", self.local_decls.len());

        self.local_decls.push(NodeDecl {
            net_type: NetType::Wire,
            name: name.clone(),
            bit_width,
        });

        self.assignments.push(Assignment {
            target_name: name.clone(),
            expr,
        });

        Expr::Ref { name }
    }

    pub fn is_empty(&self) -> bool {
        self.assignments.is_empty()
    }

    pub fn push(&mut self, assignment: Assignment) {
        self.assignments.push(assignment);
    }

    pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
        if !self.local_decls.is_empty() {
            for node_decl in self.local_decls.iter() {
                node_decl.write(w)?;
            }
            w.append_newline()?;
        }

        for assignment in self.assignments.iter() {
            assignment.write(w)?;
        }

        Ok(())
    }
}

pub struct Assignment {
    pub target_name: String,
    pub expr: Expr,
}

impl Assignment {
    fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
        w.append_indent()?;
        w.append(&format!("assign {}", self.target_name))?;
        w.append(" = ")?;
        self.expr.write(w)?;
        w.append(";")?;
        w.append_newline()?;

        Ok(())
    }
}

#[derive(Clone)]
pub enum Expr {
    BinOp {
        lhs: Box<Expr>,
        rhs: Box<Expr>,
        op: BinOp,
    },
    Bits {
        source: Box<Expr>,
        range_high: u32,
        range_low: u32,
    },
    Concat {
        lhs: Box<Expr>,
        rhs: Box<Expr>,
    },
    Constant {
        bit_width: u32,
        value: u128,
    },
    Ref {
        name: String,
    },
    Repeat {
        source: Box<Expr>,
        count: u32,
    },
    Signed {
        source: Box<Expr>,
    },
    Ternary {
        cond: Box<Expr>,
        when_true: Box<Expr>,
        when_false: Box<Expr>,
    },
    UnOp {
        source: Box<Expr>,
        op: UnOp,
    },
}

impl Expr {
    pub fn from_constant(value: &graph::Constant, bit_width: u32) -> Expr {
        Expr::Constant {
            bit_width,
            value: value.numeric_value(),
        }
    }

    pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
        match self {
            Expr::BinOp { lhs, rhs, op } => {
                lhs.write(w)?;
                w.append(&format!(
                    " {} ",
                    match op {
                        BinOp::Add => "+",
                        BinOp::BitAnd => "&",
                        BinOp::BitOr => "|",
                        BinOp::BitXor => "^",
                        BinOp::Equal => "==",
                        BinOp::NotEqual => "!=",
                        BinOp::LessThan => "<",
                        BinOp::LessThanEqual => "<=",
                        BinOp::GreaterThan => ">",
                        BinOp::GreaterThanEqual => ">=",
                        BinOp::Shl => "<<",
                        BinOp::Shr => ">>",
                        BinOp::ShrArithmetic => ">>>",
                        BinOp::Sub => "-",
                        BinOp::Mul => "*",
                    }
                ))?;
                rhs.write(w)?;
            }
            Expr::Bits {
                source,
                range_high,
                range_low,
            } => {
                source.write(w)?;
                if range_high != range_low {
                    w.append(&format!("[{}:{}]", range_high, range_low))?;
                } else {
                    w.append(&format!("[{}]", range_high))?;
                }
            }
            Expr::Concat { lhs, rhs } => {
                w.append("{")?;
                lhs.write(w)?;
                w.append(", ")?;
                rhs.write(w)?;
                w.append("}")?;
            }
            Expr::Constant { bit_width, value } => {
                w.append(&format!("{}'h{:x}", bit_width, value))?;
            }
            Expr::Ref { name } => {
                w.append(name)?;
            }
            Expr::Repeat { source, count } => {
                w.append(&format!("{{{}{{", count))?;
                source.write(w)?;
                w.append("}}")?;
            }
            Expr::Signed { source } => {
                w.append("$signed(")?;
                source.write(w)?;
                w.append(")")?;
            }
            Expr::Ternary {
                cond,
                when_true,
                when_false,
            } => {
                cond.write(w)?;
                w.append(" ? ")?;
                when_true.write(w)?;
                w.append(" : ")?;
                when_false.write(w)?;
            }
            Expr::UnOp { source, op } => {
                w.append(match op {
                    UnOp::Not => "~",
                })?;
                source.write(w)?;
            }
        }

        Ok(())
    }
}

#[derive(Clone)]
pub enum BinOp {
    Add,
    BitAnd,
    BitOr,
    BitXor,
    Equal,
    NotEqual,
    LessThan,
    LessThanEqual,
    GreaterThan,
    GreaterThanEqual,
    Shl,
    Shr,
    ShrArithmetic,
    Sub,
    Mul,
}

#[derive(Clone)]
pub enum UnOp {
    Not,
}