1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Writeback stage.

use super::*;

/// Register file.
pub type Regfile = Array<u32, REGS>;

/// Register.
#[derive(Debug, Clone, Copy)]
pub struct Register {
    /// Address.
    pub addr: U<{ clog2(REGS) }>,

    /// Data.
    pub data: u32,
}

impl Register {
    /// Creates a new register.
    pub fn new(addr: U<{ clog2(REGS) }>, data: u32) -> Self {
        Self { addr, data }
    }
}

/// Hazard from writeback stage to memory stage.
#[derive(Debug, Clone, Copy, Default)]
pub struct WbR {
    /// Bypassed data from WB.
    pub bypass_from_wb: HOption<Register>,

    /// Register file.
    pub rf: Regfile,
}

impl WbR {
    /// Creates a new writeback register.
    pub fn new(bypass_from_wb: HOption<Register>, rf: Regfile) -> Self {
        Self { bypass_from_wb, rf }
    }
}

/// Writeback stage.
pub fn wb(i: I<VrH<MemEP, WbR>, { Dep::Demanding }>) {
    i.map_resolver_inner::<(HOption<MemEP>, Regfile)>(|(p, rf)| WbR::new(p.and_then(|p| p.wb_info), rf))
        .reg_fwd(true)
        .sink_fsm_map(Regfile::default(), |ip, rf| {
            let ir = Ready::valid((ip, rf));
            let rf_next = match ip {
                Some(MemEP { wb_info: Some(r), .. }) => rf.set(r.addr, r.data),
                _ => rf,
            };

            if let Some(p) = ip {
                match p.wb_info {
                    Some(r) => {
                        display!(
                            "retire=[1] pc=[%x] inst=[%x] write=[r%d=%x]",
                            ip.map(|x| x.debug_pc).unwrap_or(0),
                            ip.map(|x| x.debug_inst).unwrap_or(0),
                            r.addr,
                            r.data
                        );
                    }
                    None => {
                        display!(
                            "retire=[1] pc=[%x] inst=[%x]",
                            ip.map(|x| x.debug_pc).unwrap_or(0),
                            ip.map(|x| x.debug_inst).unwrap_or(0)
                        );
                    }
                }
            } else {
                display!("retire=[0]");
            }

            (ir, rf_next)
        })
}