计算机组成实验---Cache的实现

直接映射

先看懂cache的映射原理,根据cache大小与主存大小来计算各个信号线的位数

各个信号线位数

主存地址在逻辑上分为区号、块号、块内地址

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)为真,则可以发送主存读所需要的地址和使能信号(注意只提供一个时钟周期)

错误总结:

  1. 一直在思考如何让发送给主存的信号只有一个时钟周期,由于有 mem_rrdy 的限制,以及不符合打两拍的场景,所以打两拍操作最后是不行的(打两拍可参照inst_valid和inst_out单周期有效的方法,打两拍的应用场景:要在单位信号从0到1,的属于1的那个周期里,发送一个周期的有效信号)
  2. 还有,块是整块取,块的取址地址要是模四为零的。
  3. 忘了mem_addr的有效时间只有一个周期,在后面也使用到了它,哭哭。

贴一个完整代码

`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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/687951.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

问题:当频点数大于载波数时,() #学习方法#知识分享

问题&#xff1a;当频点数大于载波数时&#xff0c;&#xff08;&#xff09; A.基带跳频可以执行&#xff0c;混合跳频可以执行 B.基带跳频不可以执行&#xff0c;混合跳频可以执行 C.基带跳频可以执行&#xff0c;混合跳频不可以执行 D.基带跳频不可以执行&#xff0c;混…

2024-06-07 Unity 编辑器开发之编辑器拓展8 —— Scene 窗口拓展

文章目录 1 Handles 类1.1 Scene 响应函数1.2 自定义窗口中监听 Scene1.3 Handles 常用 API2.2.1 颜色控制2.2.2 文本2.2.3 线段2.2.4 虚线2.2.5 圆弧2.2.6 圆2.2.7 立方体2.2.8 几何体2.2.9 移动、旋转、缩放2.2.10 自由移动 / 旋转 2 Scene 窗口中显示 GUI3 HandleUtility4 G…

React 18

创建 React 18 脚手架项目 全局安装 create-react-app npm install -g create-react-app yarn global add create-react-app . 确认是否已安装 create-react-app npm list -g create-react-app yarn global list | grep create-react-app . 如果安装失败 有时&#xff0…

YOLOv8---seg实例分割(制作数据集,训练模型,预测结果)

YOLOv8----seg实例分割&#xff08;制作数据集&#xff0c;训练模型&#xff0c;预测结果&#xff09; 内容如下&#xff1a;【需要软件及工具&#xff1a;pycharm、labelme、anaconda、云主机&#xff08;跑训练&#xff09;】 1.制作自己的数据集 2.在yolo的预训练模型的基础…

Linux系统下 安装 Nginx

一、下载Nginx安装包 压缩包下载地址&#xff1a;nginx: download 服务器有外网&#xff0c;可直接使用命令下载 wget -c https://nginx.org/download/nginx-1.24.0.tar.gz 二、安装Nginx 1、解压 tar -zxvf nginx-1.24.0.tar.gz 2、安装Nginx所需依赖 yum install -y gc…

顶顶通呼叫中心中间件-asr录音路径修改(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-asr录音路径修改(mod_cti基于FreeSWITCH) 录音路径模板。如果不是绝对路径&#xff0c;会把这个路径追加到FreeSWITCH的recordings后面。支持变量&#xff0c;比如日期 ${strftime(%Y-%m-%d)}。最后一个录音文件路径会保存到变量 ${cti_asr_last_record_…

[职场] 项目实施工程师的工作前景 #笔记#经验分享

项目实施工程师的工作前景 项目实施工程师是负责将软件产品或解决方案实施到客户现场并确保项目成功落地的工作岗位。他们要负责整个项目的规划、组织、执行和控制&#xff0c;确保项目按照预定的进度、质量和预算完成。 一&#xff0e;工作内容 1. 项目规划&#xff1a;确定…

docker部署fastdfs

我的镜像包地址 链接&#xff1a;https://pan.baidu.com/s/1j5E5O1xdyQVfJhsOevXvYg?pwdhcav 提取码&#xff1a;hcav docker load -i gofast.tar.gz拉取gofast docker pull sjqzhang/go-fastdfs启动gofast docker run -d --name fastdfs -p 8080:8080 -v /opt/lijia/lijia…

耐酸碱腐蚀可溶性聚四氟乙烯(PFA)溶样罐

PFA溶样罐也叫PFA溶样瓶&#xff0c;可直接放在加热板上及油浴里加热&#xff0c;也可液氮下长期保存&#xff0c;使用温度-200—260℃。 根据不同实验的需求&#xff0c;PFA溶样罐有U型、V型、平底3种设计。V型底的设计&#xff0c;更加方便少量样品的集中收集。溶样罐广泛用…

Linux-桌面操作系统在服务器上未关闭休眠机制,使其开机半小时左右死机无法远程ssh连接

故障表述 操作系统:ubuntu desktop 18.04 异常描述:开机半小时左右死机 1、登录iBMC查看硬件无异常 2、登录ubuntu desktop 18.04操作系统,导出日志文件syslog、dmesg、lastlog(路径:/var/log),操作系统在11月8号~11月9号之间出现异常 经分析操作系统日志文件,操作系…

项目经理进入职场都会经历的三个阶段

对于项目经理而言&#xff0c;进入职场是一个不断学习和成长的过程。在这个过程中&#xff0c;项目经理通常会经历三个主要阶段&#xff0c;每个阶段都有其独特的特点和挑战。 一、基础建设与学习阶段 对于新入行的项目经理来说&#xff0c;最初的阶段主要是基础技能的积累和…

利用keepalived对zabbix-server做高可用,部署安装keepalived

有2台机器&#xff0c;每台都有1个zabbix-server&#xff0c;然后再每台上再装一个keepalived https://www.keepalived.org/download.html 1&#xff0c;创建安装路径 mkdir /usr/share/keepalived/2&#xff0c;在这个安装路径下面下载keepalived的软件包 我选的版本是1.3…

k8s-pod参数详解

目录 概述创建Pod编写一个简单的Pod添加常用参数为Pod的容器分配资源网络相关Pod健康检查启动探针存活探针就绪探针 作用整个Pod参数配置创建docker-registry 卷挂载 结束 概述 k8s中的pod参数详解。官方文档   版本 k8s 1.27.x 、busybox:stable-musl、nginx:stable-alpine3…

记忆++入门01

1.数字编码 2. 地点桩 1. 卧室 2.婴儿房 3.卫生间 4.次卧 5.书房 6.厨房 7.餐厅 8.客厅 9.阳台左 10.阳台右

ssh远程转发22端口,使用shell工具进行连接|使用服务器地址ssh连接本地ubuntu|端口映射

☆ 问题描述 我在内网主机中&#xff0c;使用docker创建了多个虚拟机&#xff0c;我希望能通过我的公网ip服务器端口进行shell访问 ★ 解决方案 我创建一个新的虚拟机为例 1. 创建并打开容器 docker run -itd --name test ubuntu2. 进入容器 docker exec -it test /bin/b…

先激活还是先插卡?流量卡的激活顺序你知道吗?

拿到流量卡后&#xff0c;先激活还是先插卡吗&#xff1f;你知道是流量卡的激活顺序吗&#xff1f; 在这里&#xff0c;小编提醒大家&#xff0c;拿到卡后先别着急着操作&#xff0c;一定要先看一遍激活流程。 以下为流量卡的激活方法&#xff1a; 如果你是快递激活的话&…

28、pxe自动装机

一、pxe 1.1、pxe自动装机 服务端和客户端 pxe c/s模式&#xff1a;允许客户端通过网络从远程服务器&#xff08;服务端&#xff09;下载引导镜像&#xff0c;加装安装文件&#xff0c;实现自动化安装操作系统。 无人值守&#xff1a;无人值守&#xff0c;就是安装选项不需…

将web项目打包成electron桌面端教程(一)vue3+vite+js

说明&#xff1a;后续项目需要web端和桌面端&#xff0c;为了提高开发效率&#xff0c;准备直接将web端的代码打包成桌面端&#xff0c;在此提前记录一下demo打包的过程&#xff0c;需要注意的是vue2或者vue3的打包方式各不同&#xff0c;如果你的项目不是vue3vitejs&#xff0…

MySQL进阶——索引使用规则

在上篇文章我们学习了MySQL进阶——索引&#xff0c;这篇文章学习MySQL进阶——索引使用规则。 索引使用规则 在使用索引时&#xff0c;需要遵守一些使用规则&#xff0c;否则索引会部分失效或全部失效。 最左前缀法则 最左前缀法则是查询从索引的最左列开始&#xff0c;并…

在 Windows 7 中安装 .NET Framework 时遇到错误:无法建立到信任根颁发机构的证书链

当全新安装 Windows 7 SP1 后&#xff0c;在未安装任何补丁&#xff0c;也未进行联网的状态下&#xff0c;安装 .NET Framework 4.6/4.7 或更高的版本时&#xff0c; 应该会遇到错误提示&#xff1a;无法建立到信任根颁发机构的证书链。 解决方法 1.下载证书 地址&#xff1…