当前位置:   article > 正文

【RISC-V设计-08】- RISC-V处理器设计K0A之BMU

【RISC-V设计-08】- RISC-V处理器设计K0A之BMU

【RISC-V设计-08】- RISC-V处理器设计K0A之BMU

1.简介

总线管理单元(Bus Management Unit,简称 BMU)是 CPU 中负责取指以及数据加载与存储的模块。其主要涵盖两个功能:其一为指令获取,当 CPU 开始运行,BMU 模块会依据程序计数器 PC,依序逐步加载指令,随后交付给译码、执行单元处理。其二是数据的加载与存储,当执行到加载指令时,按照译码、执行单元的指示,向总线发起读请求,所读取到的数据会返回至通用寄存器组;而在执行到数据的存储指令时,同样依据译码、执行单元的指示,向总线发起写请求。在 BMU 的设计当中,数据的加载与存储具备高优先级,而指令的获取则具有低优先级。

2.顶层设计

3.端口说明

序号端口位宽方向说明
1core_clk1input内核时钟
2core_rstn1input内核复位信号,低有效
3bus_avalid1output总线的地址有效信号
4bus_aready1input总线的地址就绪信号
5bus_write1output总线的写使能信号
6bus_addr18output总线地址
7bus_strb4output总线写字节有效信号
8bus_wdata32output总线写数据
9bus_rvalid1input总线读有效信号
10bus_rready1output总线读就绪信号
11bus_rdata32input总线读数据
12idu2bmu_pc_set1input程序计数器设置
13idu2bmu_pc_new18input新的程序计数器
14bmu2idu_pc_ack1output程序计数器应答
15idu2bmu_ls_req1input加载与存储请求
16idu2bmu_ls_cmd1input加载与存储命令,1写0读
17idu2bmu_ls_size2input加载与存储写数据字节数
18idu2bmu_ls_addr20input加载与存储的地址
19idu2bmu_ls_wdata32input加载与存储的写数据
20bmu2idu_ls_rdata32output加载与存储的读数据
21bmu2idu_valid1output指令有效指示
22bmu2idu_instr32output需要执行的指令
23bmu2idu_pc_cur18output当前指令的PC
24bmu2idu_pc_nxt18output下一条指令的PC

4.总线时序

此总线分为两个通道,分别是主机向丛机传输的地址和写数据通道,丛机向数据传输的读数据通道。两个通道均采用双向握手机制,在valid和ready同时为高时,通道内数据(包含地址、控制信号)传输完成。

4.1 总线写时序

在上图中,第一次传输为单次写操作,数据、地址同时发出,bus_avalid和bus_aready同时为高时,写数据传输完成。第二次传输时,bus_aready为低,在等到bus_aready为高时,写数据传输完成。第三次传输为连续写操作。第四次传输由于bus_aready为低,之后主机并未保持传输,而是切换为第五次传输,所有第四次传输被取消,数据D4不会被写入。

4.2 总线读时序

在上图中,第一次传输为单次读操作,地址发出后,bus_avalid和bus_aready同时为高时,读地址被接受,同时开始数据传输,在遇到bus_rvalid和bus_rready同时为高时,数据传输完成。第二次传输时,bus_aready为低,在等到bus_aready为高时,读地址被接受。第三次传输为连续读操作。第四次传输由于bus_aready为低,之后主机并未保持传输,而是切换为第五次传输,所有第四次传输被取消,数据D4不会被读出。

5.代码设计

// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
//             1. Bus Management Unit
// -------------------------------------------------------------------------------------------------

module k0a_core_bmu (
    input  wire         core_clk         ,
    input  wire         core_rstn        ,

    output reg          bus_avalid       ,
    input  wire         bus_aready       ,
    output wire         bus_write        ,
    output wire [17:0]  bus_addr         ,
    output wire [3:0]   bus_strb         ,
    output wire [31:0]  bus_wdata        ,
    input  wire         bus_rvalid       ,
    output wire         bus_rready       ,
    input  wire [31:0]  bus_rdata        ,

    input  wire         idu2bmu_pc_set   ,
    input  wire [17:0]  idu2bmu_pc_new   ,
    output wire         bmu2idu_pc_ack   ,

    input  wire         idu2bmu_ls_req   ,
    input  wire         idu2bmu_ls_cmd   ,
    input  wire [1:0]   idu2bmu_ls_size  ,
    input  wire [19:0]  idu2bmu_ls_addr  ,
    input  wire [31:0]  idu2bmu_ls_wdata ,
    output wire [31:0]  bmu2idu_ls_rdata ,

    output wire         bmu2idu_valid    ,
    output wire [31:0]  bmu2idu_instr    ,
    output reg  [17:0]  bmu2idu_pc_cur   ,
    output wire [17:0]  bmu2idu_pc_nxt
);

reg             discard;
reg             load_data;
reg  [17:0]     prefetch_pc;

reg             instr_wsel;
reg             instr_rsel;
reg  [1:0]      instr_size;
reg  [31:0]     instr_buf0;
reg  [31:0]     instr_buf1;

wire bus_addr_fire = bus_avalid & bus_aready;
wire bus_resp_fire = bus_rvalid & bus_rready;
wire bus_data_fire = bus_resp_fire & ~discard &  load_data;
wire bus_inst_fire = bus_resp_fire & ~discard & ~load_data;

wire bus_load_fire  = idu2bmu_ls_req & ~idu2bmu_ls_cmd & bus_data_fire;
wire bus_store_fire = idu2bmu_ls_req &  idu2bmu_ls_cmd & bus_addr_fire;
wire instr_out_fire = bmu2idu_valid & (bus_store_fire | bus_load_fire | ~idu2bmu_ls_req);

wire byte_at_0 = idu2bmu_ls_size[1] | idu2bmu_ls_size[0] & ~idu2bmu_ls_addr[1] | idu2bmu_ls_addr[1:0] == 2'd0;
wire byte_at_1 = idu2bmu_ls_size[1] | idu2bmu_ls_size[0] & ~idu2bmu_ls_addr[1] | idu2bmu_ls_addr[1:0] == 2'd1;
wire byte_at_2 = idu2bmu_ls_size[1] | idu2bmu_ls_size[0] &  idu2bmu_ls_addr[1] | idu2bmu_ls_addr[1:0] == 2'd2;
wire byte_at_3 = idu2bmu_ls_size[1] | idu2bmu_ls_size[0] &  idu2bmu_ls_addr[1] | idu2bmu_ls_addr[1:0] == 2'd3;

wire pc_set_fire = idu2bmu_pc_set & bmu2idu_pc_ack;

assign bmu2idu_pc_ack = instr_out_fire;

assign bus_write = idu2bmu_ls_cmd;

assign bus_strb  = {byte_at_3, byte_at_2, byte_at_1, byte_at_0};

assign bus_addr  = idu2bmu_ls_req & ~load_data ? idu2bmu_ls_addr[19:2] : prefetch_pc;

assign bus_wdata = idu2bmu_ls_wdata;

assign bus_rready = 1'b1;

assign bmu2idu_ls_rdata = bus_rdata;

assign bmu2idu_valid = |instr_size;

assign bmu2idu_instr = instr_rsel ? instr_buf1 : instr_buf0;

assign bmu2idu_pc_nxt = bmu2idu_pc_cur + 1'b1;

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        discard <= 1'b0;
    else if(pc_set_fire)
        discard <= 1'b1;
    else if(bus_addr_fire)
        discard <= 1'b0;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        load_data <= 1'b0;
    else if(bus_addr_fire & idu2bmu_ls_req & ~load_data & ~idu2bmu_ls_cmd)
        load_data <= 1'b1;
    else if(bus_data_fire)
        load_data <= 1'b0;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        prefetch_pc <= 18'd0;
    else if(pc_set_fire)
        prefetch_pc <= idu2bmu_pc_new;
    else if(bus_addr_fire & (~idu2bmu_ls_req | load_data))
        prefetch_pc <= prefetch_pc + 1'b1;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        bus_avalid <= 1'b0;
    else
        bus_avalid <= 1'b1;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        bmu2idu_pc_cur <= 18'd0;
    else if(pc_set_fire)
        bmu2idu_pc_cur <= idu2bmu_pc_new;
    else if(instr_out_fire)
        bmu2idu_pc_cur <= bmu2idu_pc_nxt;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        instr_wsel <= 1'b0;
    else if(pc_set_fire)
        instr_wsel <= 1'b0;
    else if(bus_inst_fire)
        instr_wsel <= ~instr_wsel;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        instr_rsel <= 1'b0;
    else if(pc_set_fire)
        instr_rsel <= 1'b0;
    else if(instr_out_fire)
        instr_rsel <= ~instr_rsel;
end

always @(posedge core_clk or negedge core_rstn)
begin
    if(!core_rstn)
        instr_size <= 2'd0;
    else if(pc_set_fire)
        instr_size <= 2'd0;
    else
        instr_size <= instr_size + bus_inst_fire - instr_out_fire;
end

always @(posedge core_clk)
begin
    if(~instr_wsel & bus_inst_fire)
        instr_buf0 <= bus_rdata;
end

always @(posedge core_clk)
begin
    if(instr_wsel & bus_inst_fire)
        instr_buf1 <= bus_rdata;
end

endmodule
  • 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
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187

6.总结

本文设计了总线管理单元,内部包含了2个指令缓存,电路结构简单。通过精细的逻辑控制和状态管理,实现了与外部总线的高效交互,支持指令的预取和数据的加载存储操作,是处理器设计中重要的组成部分。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/973786
推荐阅读
相关标签
  

闽ICP备14008679号