1use crate::code_writer;
2use crate::graph;
3
4use std::io::{Result, Write};
5
6pub struct NodeDecl {
7 pub net_type: NetType,
8 pub name: String,
9 pub bit_width: u32,
10}
11
12impl NodeDecl {
13 pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
14 w.append_indent()?;
15 self.net_type.write(w)?;
16 w.append(" ")?;
17 if self.bit_width > 1 {
18 w.append(&format!("[{}:{}] ", self.bit_width - 1, 0))?;
19 }
20 w.append(&format!("{};", self.name))?;
21 w.append_newline()?;
22
23 Ok(())
24 }
25}
26
27pub enum NetType {
28 Reg,
29 Wire,
30}
31
32impl NetType {
33 pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
34 w.append(match self {
35 NetType::Reg => "reg",
36 NetType::Wire => "wire",
37 })
38 }
39}
40
41pub struct AssignmentContext {
42 assignments: Vec<Assignment>,
43 local_decls: Vec<NodeDecl>,
44}
45
46impl AssignmentContext {
47 pub fn new() -> AssignmentContext {
48 AssignmentContext {
49 assignments: Vec::new(),
50 local_decls: Vec::new(),
51 }
52 }
53
54 pub fn gen_temp(&mut self, expr: Expr, bit_width: u32) -> Expr {
55 let name = format!("__temp_{}", self.local_decls.len());
56
57 self.local_decls.push(NodeDecl {
58 net_type: NetType::Wire,
59 name: name.clone(),
60 bit_width,
61 });
62
63 self.assignments.push(Assignment {
64 target_name: name.clone(),
65 expr,
66 });
67
68 Expr::Ref { name }
69 }
70
71 pub fn is_empty(&self) -> bool {
72 self.assignments.is_empty()
73 }
74
75 pub fn push(&mut self, assignment: Assignment) {
76 self.assignments.push(assignment);
77 }
78
79 pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
80 if !self.local_decls.is_empty() {
81 for node_decl in self.local_decls.iter() {
82 node_decl.write(w)?;
83 }
84 w.append_newline()?;
85 }
86
87 for assignment in self.assignments.iter() {
88 assignment.write(w)?;
89 }
90
91 Ok(())
92 }
93}
94
95pub struct Assignment {
96 pub target_name: String,
97 pub expr: Expr,
98}
99
100impl Assignment {
101 fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
102 w.append_indent()?;
103 w.append(&format!("assign {}", self.target_name))?;
104 w.append(" = ")?;
105 self.expr.write(w)?;
106 w.append(";")?;
107 w.append_newline()?;
108
109 Ok(())
110 }
111}
112
113#[derive(Clone)]
114pub enum Expr {
115 BinOp {
116 lhs: Box<Expr>,
117 rhs: Box<Expr>,
118 op: BinOp,
119 },
120 Bits {
121 source: Box<Expr>,
122 range_high: u32,
123 range_low: u32,
124 },
125 Concat {
126 lhs: Box<Expr>,
127 rhs: Box<Expr>,
128 },
129 Constant {
130 bit_width: u32,
131 value: u128,
132 },
133 Ref {
134 name: String,
135 },
136 Repeat {
137 source: Box<Expr>,
138 count: u32,
139 },
140 Signed {
141 source: Box<Expr>,
142 },
143 Ternary {
144 cond: Box<Expr>,
145 when_true: Box<Expr>,
146 when_false: Box<Expr>,
147 },
148 UnOp {
149 source: Box<Expr>,
150 op: UnOp,
151 },
152}
153
154impl Expr {
155 pub fn from_constant(value: &graph::Constant, bit_width: u32) -> Expr {
156 Expr::Constant {
157 bit_width,
158 value: value.numeric_value(),
159 }
160 }
161
162 pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Result<()> {
163 match self {
164 Expr::BinOp { lhs, rhs, op } => {
165 lhs.write(w)?;
166 w.append(&format!(
167 " {} ",
168 match op {
169 BinOp::Add => "+",
170 BinOp::BitAnd => "&",
171 BinOp::BitOr => "|",
172 BinOp::BitXor => "^",
173 BinOp::Equal => "==",
174 BinOp::NotEqual => "!=",
175 BinOp::LessThan => "<",
176 BinOp::LessThanEqual => "<=",
177 BinOp::GreaterThan => ">",
178 BinOp::GreaterThanEqual => ">=",
179 BinOp::Shl => "<<",
180 BinOp::Shr => ">>",
181 BinOp::ShrArithmetic => ">>>",
182 BinOp::Sub => "-",
183 BinOp::Mul => "*",
184 }
185 ))?;
186 rhs.write(w)?;
187 }
188 Expr::Bits {
189 source,
190 range_high,
191 range_low,
192 } => {
193 source.write(w)?;
194 if range_high != range_low {
195 w.append(&format!("[{}:{}]", range_high, range_low))?;
196 } else {
197 w.append(&format!("[{}]", range_high))?;
198 }
199 }
200 Expr::Concat { lhs, rhs } => {
201 w.append("{")?;
202 lhs.write(w)?;
203 w.append(", ")?;
204 rhs.write(w)?;
205 w.append("}")?;
206 }
207 Expr::Constant { bit_width, value } => {
208 w.append(&format!("{}'h{:x}", bit_width, value))?;
209 }
210 Expr::Ref { name } => {
211 w.append(name)?;
212 }
213 Expr::Repeat { source, count } => {
214 w.append(&format!("{{{}{{", count))?;
215 source.write(w)?;
216 w.append("}}")?;
217 }
218 Expr::Signed { source } => {
219 w.append("$signed(")?;
220 source.write(w)?;
221 w.append(")")?;
222 }
223 Expr::Ternary {
224 cond,
225 when_true,
226 when_false,
227 } => {
228 cond.write(w)?;
229 w.append(" ? ")?;
230 when_true.write(w)?;
231 w.append(" : ")?;
232 when_false.write(w)?;
233 }
234 Expr::UnOp { source, op } => {
235 w.append(match op {
236 UnOp::Not => "~",
237 })?;
238 source.write(w)?;
239 }
240 }
241
242 Ok(())
243 }
244}
245
246#[derive(Clone)]
247pub enum BinOp {
248 Add,
249 BitAnd,
250 BitOr,
251 BitXor,
252 Equal,
253 NotEqual,
254 LessThan,
255 LessThanEqual,
256 GreaterThan,
257 GreaterThanEqual,
258 Shl,
259 Shr,
260 ShrArithmetic,
261 Sub,
262 Mul,
263}
264
265#[derive(Clone)]
266pub enum UnOp {
267 Not,
268}