赞
踩
总线管理单元(Bus Management Unit,简称 BMU)是 CPU 中负责取指以及数据加载与存储的模块。其主要涵盖两个功能:其一为指令获取,当 CPU 开始运行,BMU 模块会依据程序计数器 PC,依序逐步加载指令,随后交付给译码、执行单元处理。其二是数据的加载与存储,当执行到加载指令时,按照译码、执行单元的指示,向总线发起读请求,所读取到的数据会返回至通用寄存器组;而在执行到数据的存储指令时,同样依据译码、执行单元的指示,向总线发起写请求。在 BMU 的设计当中,数据的加载与存储具备高优先级,而指令的获取则具有低优先级。
序号 | 端口 | 位宽 | 方向 | 说明 |
---|---|---|---|---|
1 | core_clk | 1 | input | 内核时钟 |
2 | core_rstn | 1 | input | 内核复位信号,低有效 |
3 | bus_avalid | 1 | output | 总线的地址有效信号 |
4 | bus_aready | 1 | input | 总线的地址就绪信号 |
5 | bus_write | 1 | output | 总线的写使能信号 |
6 | bus_addr | 18 | output | 总线地址 |
7 | bus_strb | 4 | output | 总线写字节有效信号 |
8 | bus_wdata | 32 | output | 总线写数据 |
9 | bus_rvalid | 1 | input | 总线读有效信号 |
10 | bus_rready | 1 | output | 总线读就绪信号 |
11 | bus_rdata | 32 | input | 总线读数据 |
12 | idu2bmu_pc_set | 1 | input | 程序计数器设置 |
13 | idu2bmu_pc_new | 18 | input | 新的程序计数器 |
14 | bmu2idu_pc_ack | 1 | output | 程序计数器应答 |
15 | idu2bmu_ls_req | 1 | input | 加载与存储请求 |
16 | idu2bmu_ls_cmd | 1 | input | 加载与存储命令,1写0读 |
17 | idu2bmu_ls_size | 2 | input | 加载与存储写数据字节数 |
18 | idu2bmu_ls_addr | 20 | input | 加载与存储的地址 |
19 | idu2bmu_ls_wdata | 32 | input | 加载与存储的写数据 |
20 | bmu2idu_ls_rdata | 32 | output | 加载与存储的读数据 |
21 | bmu2idu_valid | 1 | output | 指令有效指示 |
22 | bmu2idu_instr | 32 | output | 需要执行的指令 |
23 | bmu2idu_pc_cur | 18 | output | 当前指令的PC |
24 | bmu2idu_pc_nxt | 18 | output | 下一条指令的PC |
此总线分为两个通道,分别是主机向丛机传输的地址和写数据通道,丛机向数据传输的读数据通道。两个通道均采用双向握手机制,在valid和ready同时为高时,通道内数据(包含地址、控制信号)传输完成。
在上图中,第一次传输为单次写操作,数据、地址同时发出,bus_avalid和bus_aready同时为高时,写数据传输完成。第二次传输时,bus_aready为低,在等到bus_aready为高时,写数据传输完成。第三次传输为连续写操作。第四次传输由于bus_aready为低,之后主机并未保持传输,而是切换为第五次传输,所有第四次传输被取消,数据D4不会被写入。
在上图中,第一次传输为单次读操作,地址发出后,bus_avalid和bus_aready同时为高时,读地址被接受,同时开始数据传输,在遇到bus_rvalid和bus_rready同时为高时,数据传输完成。第二次传输时,bus_aready为低,在等到bus_aready为高时,读地址被接受。第三次传输为连续读操作。第四次传输由于bus_aready为低,之后主机并未保持传输,而是切换为第五次传输,所有第四次传输被取消,数据D4不会被读出。
// ------------------------------------------------------------------------------------------------- // 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
本文设计了总线管理单元,内部包含了2个指令缓存,电路结构简单。通过精细的逻辑控制和状态管理,实现了与外部总线的高效交互,支持指令的预取和数据的加载存储操作,是处理器设计中重要的组成部分。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。