0%

CPU设计03-总线设计实现

本文是学习总线结构原理的笔记;总线协议发展到目前业已很复杂,但是对一个能够实现且能简单讲清楚的总线原理,的确不是很容易,本篇笔记首先讲清楚原理,然后用verilog实现,然后使用verilog的测试用例进行功能测试;因为还是缺乏从verilog到逻辑综合的经验,总线结构在电路图的层面上不是很直观,我尝试过使用logicsim实现一版电路结构图,不够严谨,但在画的过程中也能受益良多,后续有时间仍然会尝试进行逻辑综合。

1. 原理图

一句话讲清:

  • 总线主控请求使用总线,并发送具体指令给主控多路复用器;
  • 总线仲裁器仲裁并应答可以使用总线,发送许可信号给主控多路复用器;
  • 主控多路复用器收到信号后开放数据通路到总线从属;
  • 总线从属收到具体处理信息并将处理结果回复到从属多路复用器;
  • 地址解码器根据从属地址信息发送许可信号给从属多路复用器开放数据通路
  • 总线主控收到结果

这里总线仲裁器和地址解码器就像两个开关一样,控制这数据的流向;这张图并没有清晰的画出数据通路和控制通路.

2. 时序图分析

  • 读时序图
    • 变量后面接下划线的表示电平低电平有效.
    • 请求总线req_在第一个上升沿开始有效;
    • 若干个时钟周期后的一个上升沿grnt_回复低电平,表示允许使用总线;
    • as_选通并且rw模式为读模式.
    • rdy_回复低电平并回复读取数据
  • 写时序图
    • 和读不同的地方是rw模式为写模式,并在wr_data带上写的数据.

3. 代码实现

3.1 总线仲裁器
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
// 总线仲裁器的实现
module bus_arbiter (input wire clk,input wire reset,
input wire m0_req_,output reg m0_grnt_);
reg [`BusOwnerBus] owner; // 总线当前所有者

// 组合逻辑部分
always @(*) begin
// 总线许可信号初始化
m0_grnt_ = `DISABLE_;
m1_grnt_ = `DISABLE_;
m2_grnt_ = `DISABLE_;
m3_grnt_ = `DISABLE_;
// 根据所有者是谁设置许可总线信号
case (owner)
`BUS_OWNER_MASTER_0 : begin // 0号总线所有者
m0_grnt_ = `ENABLE_;
end
`BUS_OWNER_MASTER_1 : begin
m1_grnt_ = `ENABLE_;
end
`BUS_OWNER_MASTER_2 : begin
m2_grnt_ = `ENABLE_;
end
`BUS_OWNER_MASTER_3 : begin
m3_grnt_ = `ENABLE_;
end
endcase
end

// 时序逻辑部分
// 仲裁的实现
always @(posedge clk or `RESET_EDGE reset) begin
if (reset == `RESET_ENABLE) begin
// 重置时将总线所有权默认为0号总线
owner <= #1 `BUS_OWNER_MASTER_0;
end else begin
// 根据当前所有者判断优先级
case (owner)
`BUS_OWNER_MASTER_0 : begin // 当前所有者为0号总线时
if (m0_req_ == `ENABLE_) begin
// 0号请求时仍然给0号
owner <= #1 `BUS_OWNER_MASTER_0;
end else if (m1_req_ == `ENABLE_) begin
// 1号请求时给1号(0号未请求)
owner <= #1 `BUS_OWNER_MASTER_1;
end else if (m2_req_ == `ENABLE_) begin
// 2号请求时给2号(0,1号未请求)
owner <= #1 `BUS_OWNER_MASTER_2;
end else if (m3_req_ == `ENABLE_) begin
// 3号请求时给3号(0,1,2未请求)
owner <= #1 `BUS_OWNER_MASTER_3;
end
end
// 当为其他所有者时类似处理...
endcase
end
end

endmodule

总线仲裁器实现了类似优先编码器的功能;谁先请求谁优先的原则.

3.2 地址编码器

基于总线主控输出的地址信号,选择总线从属许可信号;

1
2
// 通过传进来的s_addr地址选择总线从属
wire [`BusSlaveIndexBus] s_index = s_addr[`BusSlaveIndexLoc];

地址如下:

4. 电路实现

下载这个文件,如上图所示总线仲裁器电路实现;这个是用logisim软件实现的;电路图一共分为三部分,上部分为时序电路,中间为组合电路,左下角为寄存器;左中m0req到m3req为输入;右下m0grnt为输出;电路需要注意的是寄存器的初始化,并且当所有总线主控没有请求时没有任何总线是被允许的;当m1~m3请求时仲裁只能优先响应m1总线主控.

接下来将花费了更多的时间来测试总线的各个模块的实现,已保证对电路的深刻理解。