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

news2024/11/17 1:51:58

直接映射

先看懂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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Proxyman 现代直观的 HTTP 调试代理应用程序

Proxyman 是一款现代而直观的 HTTP 调试代理应用程序&#xff0c;它的功能强大&#xff0c;使您可以轻松捕获、检查和操作 HTTP(s) 流量。不再让繁杂的网络调试工具阻碍您的工作&#xff0c;使用 Proxyman&#xff0c;您将轻松应对网络调试的挑战。 下载地址&#xff1a;https…

el-table 固定前n行

el-table 固定前n行 第一种&#xff0c;通过设置前几行粘性布局 <el-table:data"tableData2"borderheight"calc(98% - 40px)"// 设置行样式:row-class-name"TableRowClassName"selection-change"handleSelectionChange" ><…

计网期末复习指南(四):网络层(IP协议、IPv4、IPv6、CIDR、ARP、ICMP)

前言&#xff1a;本系列文章旨在通过TCP/IP协议簇自下而上的梳理大致的知识点&#xff0c;从计算机网络体系结构出发到应用层&#xff0c;每一个协议层通过一篇文章进行总结&#xff0c;本系列正在持续更新中... 计网期末复习指南&#xff08;一&#xff09;&#xff1a;计算…

Java 初识

Java 的发展历程 Sun 公司。 Oracle 公司。 普通版本&#xff0c;也叫过渡版本。 正式版本&#xff0c;也叫长期支持版本&#xff08;LTS&#xff09;。 Java SE&#xff0c;Java EE&#xff0c;Java ME Java 技术体系分为三个平台&#xff1a;Java SE&#xff0c;Java EE&a…

【全开源】Fastflow工作流系统(FastAdmin+ThinkPHP)

&#x1f680;Fastflow工作流系统&#xff1a;高效协作&#xff0c;流程无忧​ 一款基于FastAdminThinkPHP开发的可视化工作流程审批插件&#xff0c;帮助用户基于企业业务模式和管理模式自行定义所需的各种流程应用&#xff0c;快速构建企业自身的流程管控体系&#xff0c;快…

Windows mstsc

windows mstsc 局域网远程计算机192.168.0.113为例&#xff0c;远程控制命令mstsc

【mysql】数据报错: incorrect datetime value ‘0000-00-00 00:00:00‘ for column

一、问题原因 时间字段在导入值0000-00-00 00:00:00或者添加 NOT NULL的时间字段时&#xff0c;会往mysql添加0值&#xff0c;此时可能出现此报错。 这是因为当前的MySQL不支持datetime为0&#xff0c;在MySQL5.7版本以上&#xff0c;默认设置sql_mode模式包含NO_ZERO_DATE, N…

SQL Server数据库xp_cmdshell提权笔记

文章目录 一、简介二、搭建环境三、利用条件1、查询 xp_cmdshell 是否开启&#xff0c;返回为1则证明存在2、判断权限是不是sa&#xff0c;回是1说明是sa3、开启xp_cmdshell4、关闭xp_cmdshell 四、获取数据库权限1、成功获取sqlserver&#xff0c;进行登陆2、开启xp_cmdshell权…

记录汇川:红绿灯与HMI-ST

项目要求&#xff1a; 子程序&#xff1a; 子程序&#xff1a; 实际动作如下&#xff1a; 红绿灯与HMI-ST

ChatGPT交卷2024年高考新课标I卷语文关于AI方面的作文试题

2024年新课标I卷作文试题&#xff1a; 阅读下面的材料&#xff0c;根据要求写作。&#xff08;60分&#xff09; 随着互联网的普及、人工智能的应用&#xff0c;越来越多的问题能很快得到答案。那么&#xff0c;我们的问题是否会越来越少&#xff1f; 以上材料引发了你怎样的…

DBeaver入门教学,开源免费,链接数据库的软件

这个可爱的头像就是它 为什么要用这个&#xff0c;小公司一般都用navicat什么的&#xff0c;因为别人一般不会告你&#xff0c;因为告你也没啥钱&#xff0c;但是公司大了有知名度了&#xff0c;用盗版软件就会被告。所以很多好不容易从小做到大的公司&#xff0c;是不允许这种…

使用智谱 GLM-4-9B 和 SiliconCloud 云服务快速构建一个编码类智能体应用

本篇文章我将介绍使用智谱 AI 最新开源的 GLM-4-9B 模型和 GenAI 云服务 SiliconCloud 快速构建一个 RAG 应用&#xff0c;首先我会详细介绍下 GLM-4-9B 模型的能力情况和开源限制&#xff0c;以及 SiliconCloud 的使用介绍&#xff0c;最后构建一个编码类智能体应用作为测试。…

前端解析文件流格式数据异常时并给提示

把后端返回的文件流格式转换成正常数据格式 断点调试返回值 network查看返回值 一、blob类型 let stringData:any await this.blobToString(res); blobToString(blob) { return new Promise((resolve, reject) > { const reader new FileReader(); reader.onloadend (…

Oracle EBS AP发票创建会计科目提示:APP-SQLAP-10710:无法联机创建会计分录

系统版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状: 提交“创建会计科目”请求提示错误信息如下: APP-SQLAP-10710:无法联机创建会计分录。 请提交应付款管理系统会计流程,而不要为此事务处理创建会计分录解决方法 数据修复SQL脚本: UPDATE ap_invoi…

ChatGPT-4o独家揭秘:全国一卷高考语文作文如何轻松斩获满分?

​一、2024年全国一卷高考 二、2018年全国一卷高考 三、2016年全国一卷高考 一、2024年全国一卷高考 技术进步的悖论&#xff1a;我们的问题真的在减少吗&#xff1f; 引言 随着互联网的普及和人工智能的应用&#xff0c;越来越多的问题能够快速得到解答。然而&#xff0c;这引…

二叉树-堆的详解

一&#xff0c;树的概念 1&#xff0c;树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有…

继承-进阶

父子类成员共享 普通成员对象/父子间不共享&#xff0c; 成员独立 函数成员共享&#xff08;函数不存储在对象中&#xff09; 子类由两部分构成&#xff1a;父类中继承的成员和子类中新定义成员 继承方式 子类中存在父类private成员但不可直接访问&#xff08;及时在类中&am…

C语言| 输出菱形*(梳理篇II)

C语言| 输出菱形*-CSDN博客 凡事还是得自己独立思考后&#xff0c;写一遍程序才能发现问题所在。 容易犯的错误&#xff1a; 【完整程序注释】 运行结果 /* 输出菱形 1 总行数 n为奇数&#xff0c;分上三角形下三角形&#xff0c;只考虑左边的空格和星号* 2 上三角形 行数…

【慢慢理解Vue的设计思想】

# 理解Vue的设计思想 MVVM框架的三要素:数据响应式、模板引擎及其渲染数据响应式:监听数据变化并在视图中更新 Object.defineProperty()Proxy模版引擎:提供描述视图的模版语法 插值:{{}}指令:v-bind&#xff0c;v-on&#xff0c;v-model&#xff0c;v-for&#xff0c;v-if渲染:…

能把试卷上的字消除的软件有哪些?推荐三款好用的

能把试卷上的字消除的软件有哪些&#xff1f;在数字化时代&#xff0c;我们越来越依赖科技手段来解决生活中的各种问题。其中&#xff0c;试卷上的字消除问题&#xff0c;就是一个备受关注的痛点。幸运的是&#xff0c;现在市面上已经出现了多款能够轻松消除试卷上字迹的软件&a…