【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

6.总结

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

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值