Valid_Ready 握手

RISCV的流水线设计需要许多模块共同协作,在外部看来是流水线连续处理指令。对于流水线而言,各阶段也需要模块单独进行处理,处理完毕后交给下一级。各模块之间如何进行交流,从而得知前一级的工作已完成?设计中的valid_ready 协议通过两个信号 validready 实现双向握手,确保数据在双方都准备好时才传输:

  • valid 表示 发送端已经准备好 发送数据,数据是有效的;
  • ready 表示 接收端已经准备好 接收数据。

只有当 valid == 1ready == 1 时,数据才真正被“传输”。

握手设计

对于前后级模块,不分主从,但为了方便,将发送Ready的前一级与接受Valid的后一级规定为Master,发送Valid的前一级与接受Ready的后一级定为Slave。

对于流水线模块的状态判断,采用四模式的状态机,包含RUNIDLEWAITSAVE

  • RUN:正常运行状态,接收指令并执行。当上游结果可用并且下游流水级可以接收本级结果,则进入此状态;
  • IDLE:空闲状态,等待新的指令输入。如果上游结果不可用或者是下游流水级忙碌,则进入此状态;
  • WAIT:等待状态,此时模块忙碌。
    • 不同流水级对本状态的实现不同,据此,我们将流水级控制状态机分为 I 型、II 型、III 型。
    • I 型被实现为等待内存读写返回结果,状态机对于此状态何时结束未知;
    • II 型被实现为等待长指令返回结果,状态机维护一个计时器来判断此状态如何结束;
    • III 型被实现为等待数据冒险结束,状态机观察本级维护的前三条指令以确认冒险何时结束。
  • SAVE:保存状态,保存当前指令信息以备后续使用。

不考虑流水线冲刷的情况下,我们可以很简单地写出状态切换的状态机:

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
assign next_state = 
(cur_state == `RUN)?
(
(wait_start)?`WAIT:
(s_ready & m_valid)?`RUN:
(!m_valid)?`IDLE:
`SAVE
):
(cur_state == `IDLE)?
(
(s_ready & m_valid)?`RUN:
(m_valid)?`SAVE:
`IDLE
):
(cur_state == `WAIT)?
(
(!wait_finish)?`WAIT:
(s_ready & m_valid)?`RUN:
`IDLE
):
(cur_state == `SAVE)?
(
(s_ready & m_valid)?`RUN:
`IDLE
):
`IDLE;

流水线冲刷