ruverta/
module.rs

1use crate::stmt::Stmt;
2
3pub trait Extension {
4    fn add(self, module: Module) -> Module;
5}
6
7// ----------------------------------------------------------------------------
8
9#[derive(Debug, Clone)]
10pub struct Module {
11    name: String,
12    params: Vec<Param>,
13    ports: Vec<Port>,
14    blocks: Vec<Block>,
15    pub(crate) clock: String, // (name, pos/neg)
16    pub(crate) reset: String, // (name, pos/neg, sync/async)
17}
18
19impl Module {
20    pub fn new(name: impl ToString, clock: impl ToString, reset: impl ToString) -> Self {
21        Self {
22            name: name.to_string(),
23            params: vec![],
24            ports: vec![],
25            blocks: vec![],
26            clock: clock.to_string(),
27            reset: reset.to_string(),
28        }
29    }
30    pub fn input(mut self, name: impl ToString, width: usize) -> Self {
31        assert!(width > 0);
32        self.ports.push(Port::input(name, width, 1));
33        self
34    }
35    pub fn output(mut self, name: impl ToString, width: usize) -> Self {
36        assert!(width > 0);
37        self.ports.push(Port::output(name, width, 1));
38        self
39    }
40    pub fn inout(mut self, name: impl ToString, width: usize) -> Self {
41        assert!(width > 0);
42        self.ports.push(Port::inout(name, width, 1));
43        self
44    }
45    pub fn param(mut self, name: impl ToString, default: Option<impl ToString>) -> Self {
46        self.params.push(Param::new(name, default));
47        self
48    }
49    pub fn lparam(mut self, name: impl ToString, val: impl ToString) -> Self {
50        self.blocks.push(Block::LocalParam(LocalParam::new(
51            name.to_string(),
52            val.to_string(),
53        )));
54        self
55    }
56    pub fn logic(mut self, name: impl ToString, bit: usize, len: usize) -> Self {
57        self.blocks.push(Block::Logic(Logic::new(name, bit, len)));
58        self
59    }
60    pub fn instant(mut self, inst: Instant) -> Self {
61        self.blocks.push(Block::Instant(inst));
62        self
63    }
64    pub fn always_comb(mut self, stmt: Stmt) -> Self {
65        self.blocks.push(Block::AlwaysComb(AlwaysComb::new(stmt)));
66        self
67    }
68    pub fn always_ff(mut self, edges: Sens, stmt: Stmt) -> Self {
69        self.blocks
70            .push(Block::AlwaysFF(AlwaysFF::new(edges, stmt)));
71        self
72    }
73
74    pub fn add<E: Extension>(self, ext: E) -> Self {
75        ext.add(self)
76    }
77}
78
79impl Module {
80    pub fn verilog(&self) -> Vec<String> {
81        let mut code: Vec<String> = vec![];
82        code.extend(self.module_header());
83
84        for stmt in &self.blocks {
85            for line in stmt.verilog() {
86                code.push(format!("  {line}"))
87            }
88        }
89
90        code.extend(self.module_footer());
91        code
92    }
93
94    pub fn verilog_sorted(&self) -> Vec<String> {
95        let mut code: Vec<String> = vec![];
96        code.extend(self.module_header());
97
98        // LocalParams
99        for stmt in &self.blocks {
100            if matches!(stmt, Block::LocalParam(_)) {
101                for line in stmt.verilog() {
102                    code.push(format!("  {line}"))
103                }
104            }
105        }
106
107        // Logic
108        for stmt in &self.blocks {
109            if matches!(stmt, Block::Logic(_)) {
110                for line in stmt.verilog() {
111                    code.push(format!("  {line}"))
112                }
113            }
114        }
115
116        // Instant / AlwaysFF / AlwaysComb
117        for stmt in &self.blocks {
118            if matches!(stmt, Block::Instant(_))
119                | matches!(stmt, Block::AlwaysFF(_))
120                | matches!(stmt, Block::AlwaysComb(_))
121            {
122                for line in stmt.verilog() {
123                    code.push(format!("  {line}"))
124                }
125            }
126        }
127
128        code.extend(self.module_footer());
129        code
130    }
131
132    fn module_header(&self) -> Vec<String> {
133        let mut code: Vec<String> = Vec::new();
134        code.push(format!("module {}", self.name));
135
136        // Params
137        if self.params.len() > 0 {
138            code.push(format!("#("));
139            for (i, param) in self.params.iter().enumerate() {
140                if i < self.params.len() - 1 {
141                    code.push(format!("  {},", param.verilog()));
142                } else {
143                    code.push(format!("  {}", param.verilog()));
144                }
145            }
146            code.push(format!(")"));
147        }
148
149        // Ports
150        if self.ports.len() > 0 {
151            code.push(format!("("));
152            for (i, port) in self.ports.iter().enumerate() {
153                if i < self.ports.len() - 1 {
154                    code.push(format!("  {},", port.verilog()));
155                } else {
156                    code.push(format!("  {}", port.verilog()));
157                }
158            }
159            code.push(format!(")"));
160        }
161
162        code.push(format!(";"));
163        code
164    }
165
166    fn module_footer(&self) -> Vec<String> {
167        vec![format!("endmodule")]
168    }
169}
170
171// ----------------------------------------------------------------------------
172
173#[derive(Debug, Clone)]
174struct Port {
175    name: String,
176    direct: Direct,
177    bit: usize,
178    len: usize,
179}
180
181impl Port {
182    fn input(name: impl ToString, bit: usize, len: usize) -> Self {
183        Self {
184            name: name.to_string(),
185            direct: Direct::In,
186            bit,
187            len,
188        }
189    }
190    fn output(name: impl ToString, bit: usize, len: usize) -> Self {
191        Self {
192            name: name.to_string(),
193            direct: Direct::Out,
194            bit,
195            len,
196        }
197    }
198    fn inout(name: impl ToString, bit: usize, len: usize) -> Self {
199        Self {
200            name: name.to_string(),
201            direct: Direct::InOut,
202            bit,
203            len,
204        }
205    }
206}
207
208impl Port {
209    fn verilog(&self) -> String {
210        let bit = if self.bit == 1 {
211            format!("       ")
212        } else {
213            format!("[{:>2}:0] ", self.bit - 1)
214        };
215        let len = if self.len == 1 {
216            format!("")
217        } else {
218            format!("[{:>2}:0]", self.len - 1)
219        };
220        format!(
221            "{:<6} logic {}{}{}",
222            self.direct.verilog(),
223            bit,
224            self.name,
225            len
226        )
227    }
228}
229
230#[derive(Debug, Clone, Copy)]
231enum Direct {
232    In,
233    Out,
234    InOut,
235}
236
237impl Direct {
238    fn verilog(&self) -> String {
239        match self {
240            Direct::In => format!("input"),
241            Direct::Out => format!("output"),
242            Direct::InOut => format!("inout"),
243        }
244    }
245}
246
247// ----------------------------------------------------------------------------
248
249#[derive(Debug, Clone)]
250struct Param {
251    name: String,
252    default: Option<String>,
253}
254
255impl Param {
256    fn new(name: impl ToString, default: Option<impl ToString>) -> Self {
257        Self {
258            name: name.to_string(),
259            default: default.map(|s| s.to_string()),
260        }
261    }
262    fn verilog(&self) -> String {
263        match &self.default {
264            Some(default) => format!("parameter {} = {}", self.name, default),
265            None => format!("parameter {}", self.name),
266        }
267    }
268}
269
270// ----------------------------------------------------------------------------
271
272#[derive(Debug, Clone)]
273enum Block {
274    LocalParam(LocalParam),
275    Logic(Logic),
276    Instant(Instant),
277    AlwaysFF(AlwaysFF),
278    AlwaysComb(AlwaysComb),
279}
280
281impl Block {
282    fn verilog(&self) -> Vec<String> {
283        match self {
284            Block::LocalParam(e) => e.verilog(),
285            Block::Logic(e) => e.verilog(),
286            Block::Instant(e) => e.verilog(),
287            Block::AlwaysFF(e) => e.verilog(),
288            Block::AlwaysComb(e) => e.verilog(),
289        }
290    }
291}
292
293// ----------------------------------------------------------------------------
294
295#[derive(Debug, Clone)]
296struct LocalParam {
297    name: String,
298    val: String,
299}
300
301impl LocalParam {
302    fn new<S: ToString>(name: S, val: S) -> Self {
303        Self {
304            name: name.to_string(),
305            val: val.to_string(),
306        }
307    }
308}
309
310impl LocalParam {
311    fn verilog(&self) -> Vec<String> {
312        vec![format!("localparam {} = {};", self.name, self.val)]
313    }
314}
315
316// ----------------------------------------------------------------------------
317
318#[derive(Debug, Clone)]
319struct Logic {
320    name: String,
321    bit: usize,
322    len: usize,
323}
324
325impl Logic {
326    fn new(name: impl ToString, bit: usize, len: usize) -> Self {
327        Self {
328            name: name.to_string(),
329            bit,
330            len,
331        }
332    }
333}
334
335impl Logic {
336    fn verilog(&self) -> Vec<String> {
337        let bit = if self.bit == 1 {
338            format!("       ")
339        } else {
340            format!("[{:>2}:0] ", self.bit - 1)
341        };
342        let len = if self.len == 1 {
343            format!("")
344        } else {
345            format!("[{:>2}:0]", self.len - 1)
346        };
347        vec![format!("logic {}{}{};", bit, self.name, len)]
348    }
349}
350
351// ----------------------------------------------------------------------------
352
353#[derive(Debug, Clone)]
354pub struct Instant {
355    name: String,
356    module: String,
357    params: Vec<(String, String)>,
358    ports: Vec<(String, String)>,
359}
360
361impl Instant {
362    pub fn new(name: impl ToString, module: impl ToString) -> Self {
363        Self {
364            name: name.to_string(),
365            module: module.to_string(),
366            params: vec![],
367            ports: vec![],
368        }
369    }
370    pub fn param(mut self, param: impl ToString, val: impl ToString) -> Self {
371        self.params.push((param.to_string(), val.to_string()));
372        self
373    }
374    pub fn port(mut self, port: impl ToString, wire: impl ToString) -> Self {
375        self.ports.push((port.to_string(), wire.to_string()));
376        self
377    }
378}
379
380impl Instant {
381    fn verilog(&self) -> Vec<String> {
382        let mut code: Vec<String> = Vec::new();
383
384        code.push(format!("{} #(", self.module));
385
386        for (i, (param, value)) in self.params.iter().enumerate() {
387            let sep = if i < self.params.len() - 1 { "," } else { "" };
388            code.push(format!("  .{}({}){}", param, value, sep));
389        }
390
391        code.push(format!(") {} (", self.name));
392
393        for (i, (port, value)) in self.ports.iter().enumerate() {
394            let sep = if i < self.ports.len() - 1 { "," } else { "" };
395            code.push(format!("  .{}({}){}", port, value, sep));
396        }
397
398        code.push(format!(");"));
399
400        code
401    }
402}
403
404#[test]
405fn test_instant() {
406    let obj = Instant::new("i_hoge", "hoge")
407        .port("clk", "clk")
408        .port("rstn", "rstn")
409        .param("a", "hoge");
410    println!("{}", obj.verilog().join("\n"));
411}
412
413// ----------------------------------------------------------------------------
414
415#[derive(Debug, Clone)]
416pub struct AlwaysFF {
417    sens: Sens,
418    stmt: Stmt,
419}
420
421impl AlwaysFF {
422    pub fn new(sens: Sens, stmt: Stmt) -> Self {
423        Self { sens, stmt }
424    }
425}
426
427impl AlwaysFF {
428    fn verilog(&self) -> Vec<String> {
429        let mut code = Vec::<String>::new();
430        code.push(format!("always_ff @({})", self.sens.verilog()));
431        code.extend(self.stmt.blocking().iter().map(|s| format!("  {s}")));
432        code
433    }
434}
435
436#[derive(Debug, Clone)]
437pub struct Sens {
438    edges: Vec<Edge>,
439}
440
441impl Sens {
442    pub fn new() -> Self {
443        Self { edges: vec![] }
444    }
445    pub fn posedge(mut self, wire: impl ToString) -> Self {
446        self.edges.push(Edge::Posedge(wire.to_string()));
447        self
448    }
449    pub fn negedge(mut self, wire: impl ToString) -> Self {
450        self.edges.push(Edge::Negedge(wire.to_string()));
451        self
452    }
453    pub fn bothedge(mut self, wire: impl ToString) -> Self {
454        self.edges.push(Edge::Bothedge(wire.to_string()));
455        self
456    }
457}
458
459impl Sens {
460    fn verilog(&self) -> String {
461        self.edges
462            .iter()
463            .map(|edge| edge.verilog())
464            .collect::<Vec<_>>()
465            .join(" or ")
466    }
467}
468
469#[derive(Debug, Clone)]
470enum Edge {
471    Posedge(String),
472    Negedge(String),
473    Bothedge(String),
474}
475
476impl Edge {
477    fn verilog(&self) -> String {
478        match self {
479            Edge::Posedge(s) => format!("posedge {s}"),
480            Edge::Negedge(s) => format!("negedge {s}"),
481            Edge::Bothedge(s) => format!("{s}"),
482        }
483    }
484}
485
486// ----------------------------------------------------------------------------
487
488#[derive(Debug, Clone)]
489pub struct AlwaysComb {
490    stmt: Stmt,
491}
492
493impl AlwaysComb {
494    pub fn new(stmt: Stmt) -> Self {
495        Self { stmt }
496    }
497}
498
499impl AlwaysComb {
500    fn verilog(&self) -> Vec<String> {
501        let mut code = Vec::<String>::new();
502        code.push(format!("always_comb"));
503        code.extend(self.stmt.nonblocking().iter().map(|s| format!("  {s}")));
504        code
505    }
506}