赞
踩
先看懂cache的映射原理,根据cache大小与主存大小来计算各个信号线的位数
状态机:“三段式”实现 6.3 Verilog 状态机 | 菜鸟教程 (runoob.com)
// TODO: 编写状态机现态的更新逻辑
// TODO: 编写状态机的状态转移逻辑
// TODO: 生成状态机的输出信号
再分析并确定各个状态下的输入输出,完善状态机。
这个类似模板了
- // TODO: 编写状态机现态的更新逻辑
- always @(posedge cpu_clk or posedge cpu_rst) begin
- if(cpu_rst) begin
- sta <= 2'b0;
- end
- else begin
- sta <= nex_sta;
- end
- end
需要以下变量:新的访问请求信号、命中信号、缺失(不命中)、主存数据已返回
- // TODO: 编写状态机的状态转移逻辑
- always@(*) begin
- if(cpu_rst) begin
- nex_sta = IDLE;
- end
- else begin
- case(sta)
- IDLE: begin
- if(inst_rreq == 1'b1) begin
- nex_sta = TAG_CHECK;
- end
- else begin
- nex_sta = IDLE;
- end
- end
- TAG_CHECK:begin
- if(hit) begin
- nex_sta = IDLE;
- end
- else begin
- nex_sta = REFILL;
- end
- end
- REFILL: begin
- if(mem_rvalid) begin
- nex_sta = TAG_CHECK;
- end
- else begin
- nex_sta = REFILL;
- end
- end
- default: nex_sta = IDLE;
- endcase
- end
- end
分为向主存输出和向cpu输出
IDLE状态下是赋默认值
TAG_CHECK状态下是看否命中,来确定输出(若未命中,要从主存里读东西出来,放到cache里面,再从cahce里来一次是否命中的判断)
REFILL状态下,如果主存准备信号(mem_rrdy)为真,则可以发送主存读所需要的地址和使能信号(注意只提供一个时钟周期)
贴一个完整代码
- `timescale 1ns / 1ps
-
- `define BLK_LEN 4
- `define BLK_SIZE (`BLK_LEN*32)
-
-
- module ICache(
- input wire cpu_clk,
- input wire cpu_rst, // high active
- // Interface to CPU
- input wire inst_rreq, // 来自CPU的取指请求
- input wire [31:0] inst_addr, // 来自CPU的取指地址
- output reg inst_valid, // 输出给CPU的指令有效信号(读指令命中)
- output reg [31:0] inst_out, // 输出给CPU的指令
- // Interface to Read Bus
- input wire mem_rrdy, // 主存就绪信号(高电平表示主存可接收ICache的读请求)
- output reg [ 3:0] mem_ren, // 输出给主存的读使能信号
- output reg [31:0] mem_raddr, // 输出给主存的读地址
- input wire mem_rvalid, // 来自主存的数据有效信号
- input wire [`BLK_SIZE-1:0] mem_rdata // 来自主存的读数据
- );
-
- `ifdef ENABLE_ICACHE /******** 不要修改此行代码 ********/
-
- wire [4:0] tag_from_cpu = inst_addr[14:10]; // 主存地址的TAG
- wire [3:0] offset = inst_addr[3:0]; // 32位字偏移量
- wire valid_bit = cache_line_r[`BLK_SIZE + 5]; // Cache行的有效位
- wire [4:0] tag_from_cache = cache_line_r[`BLK_SIZE + 4 : `BLK_SIZE]; // Cache行的TAG
-
- // TODO: 定义ICache状态机的状态变量
- parameter IDLE = 2'b00;
- parameter TAG_CHECK = 2'b01;
- parameter REFILL = 2'b10;
- reg [1:0] sta, nex_sta;
- wire hit = (sta == TAG_CHECK) ? (valid_bit && (tag_from_cache == tag_from_cpu)) : 1'b0;
- wire[6:0] offset_bit = {offset,3'b000};
- wire[`BLK_SIZE + 5:0] data_out = cache_line_r >> offset_bit;
- always @(*) begin
- if(hit & hit_n) begin
- inst_valid = 1'b1;
- inst_out = data_out[31:0];
- /* TODO: 根据字偏移,选择Cache行中的某个32位字输出指令 */
- end
- else begin
- inst_valid = 1'b0;
- inst_out = 32'b0;
- end
- end
-
- reg hit_n ;
- always@(posedge cpu_clk) begin
- hit_n <= ~hit;
- end
-
- reg inst_addr_reg;
-
-
- wire cache_we = mem_rvalid; // ICache存储体的写使能信号
- wire [5:0] cache_index = inst_addr[9:4]; // 主存地址的Cache索引 / ICache存储体的地址
- wire [`BLK_SIZE + 5:0] cache_line_w = {1'b1,inst_addr[14:10],mem_rdata}; // 待写入ICache的Cache行
- wire [`BLK_SIZE + 5:0] cache_line_r; // 从ICache读出的Cache行
- //135 = 1(有效位) + 7(TAG的位数) + 128(数据位数)
- // ICache存储体:Block MEM IP核
- blk_mem_gen_1 U_isram (
- .clka (cpu_clk),
- .wea (cache_we),
- .addra (cache_index),
- .dina (cache_line_w),
- .douta (cache_line_r)
- );
- // TODO: 编写状态机现态的更新逻辑
- always @(posedge cpu_clk or posedge cpu_rst) begin
- if(cpu_rst) begin
- sta <= 2'b0;
- end
- else begin
- sta <= nex_sta;
- end
- end
-
-
- // TODO: 编写状态机的状态转移逻辑
- always@(*) begin
- if(cpu_rst) begin
- nex_sta = IDLE;
- end
- else begin
- case(sta)
- IDLE: begin
- if(inst_rreq == 1'b1) begin
- nex_sta = TAG_CHECK;
- end
- else begin
- nex_sta = IDLE;
- end
- end
- TAG_CHECK:begin
- if(hit) begin
- nex_sta = IDLE;
- end
- else begin
- nex_sta = REFILL;
- end
- end
- REFILL: begin
- if(mem_rvalid) begin
- nex_sta = TAG_CHECK;
- end
- else begin
- nex_sta = REFILL;
- end
- end
- default: nex_sta = IDLE;
- endcase
- end
- end
- // reg mem_rrdy_n;
- reg mem_ren_pulse;
- always @(posedge cpu_clk or posedge cpu_rst) begin
- if(cpu_rst) begin
- mem_ren_pulse <= 1'b0;
- end
- else if(sta == REFILL) begin
- if(mem_rrdy && !mem_ren_pulse) begin
- mem_ren_pulse <= 1'b1;
- end
- end
- else begin
- mem_ren_pulse <= 1'b0;
- end
- end
-
- // TODO: 生成状态机的输出信号
- always @(*) begin
- if(cpu_rst) begin
- mem_ren = 4'b0;
- mem_raddr = 32'b0;
- // mem_rrdy_n <= 1'b1;
- end
- else begin
- case(sta)
- IDLE : begin
- mem_ren = 4'b0;
- mem_raddr = 32'b0;
- // mem_rrdy_n <= 1'b1;
- end
- TAG_CHECK : begin
- mem_ren = 4'b0;
- mem_raddr = 32'b0;
- // mem_rrdy_n <= 1'b1;
- end
- REFILL: begin
- if(mem_rrdy && !mem_ren_pulse) begin
- mem_ren = 4'b1111;
- mem_raddr = {inst_addr[31:4],4'b0000};
- // mem_rrdy_n <= 1'b0;
- end
- else begin
- mem_ren = 4'b0;
- mem_raddr = 32'b0;
- end
- end
- default: begin
- mem_ren = 4'b0;
- mem_raddr = 32'b0;
- // mem_rrdy_n <= 1'b1;
- end
- endcase
- end
- end
- /******** 不要修改以下代码 ********/
- `else
- localparam IDLE = 2'b00;
- localparam STAT0 = 2'b01;
- localparam STAT1 = 2'b11;
- reg [1:0] state, nstat;
-
- always @(posedge cpu_clk or posedge cpu_rst) begin
- state <= cpu_rst ? IDLE : nstat;
- end
-
- always @(*) begin
- case (state)
- IDLE: nstat = inst_rreq ? (mem_rrdy ? STAT1 : STAT0) : IDLE;
- STAT0: nstat = mem_rrdy ? STAT1 : STAT0;
- STAT1: nstat = mem_rvalid ? IDLE : STAT1;
- default: nstat = IDLE;
- endcase
- end
-
- always @(posedge cpu_clk or posedge cpu_rst) begin
- if (cpu_rst) begin
- inst_valid <= 1'b0;
- mem_ren <= 4'h0;
- end else begin
- case (state)
- IDLE: begin
- inst_valid <= 1'b0;
- mem_ren <= (inst_rreq & mem_rrdy) ? 4'hF : 4'h0;
- mem_raddr <= inst_rreq ? inst_addr : 32'h0;
- end
- STAT0: begin
- mem_ren <= mem_rrdy ? 4'hF : 4'h0;
- end
- STAT1: begin
- mem_ren <= 4'h0;
- inst_valid <= mem_rvalid ? 1'b1 : 1'b0;
- inst_out <= mem_rvalid ? mem_rdata[31:0] : 32'h0;
- end
- default: begin
- inst_valid <= 1'b0;
- mem_ren <= 4'h0;
- end
- endcase
- end
- end
-
- `endif
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。