Vivado 使用 ROM ip输出未知值
/**
*cache driver
*TODO 搜索整个组, 确定是否有效
*TODO 读命中的活动
*TODO 读缺失的活动
*/
`timescale 1ns / 1ps
module cache_top (//
input clk,
input resetn,
//Sram-Like接口信号定义
input cpu_req,//cpu 读信号
input[31:0] cache_addr,// cpu 给出的cache地址
output[31:0] cache_rdata,// cpu 读出数据
output cache_addr_ok,// 若命中, 则为1
output cache_data_ok,// 数据准备完毕, 则为1
//AXI接口信号定义 暂时可以不用管下列接口(2022年11月22日)
output[3:0] arid,
output arvalid,
input arready,
input[3:0] rid,
input[31:0] rdata,
input rlast,
input rvalid,
output rready
);
wire rst=~resetn;
/**DFA
*IDLE:空转->random stat
*RUN:运行状态
*SEL_WAY:未命中
*MISS:这个状态时,cache会更新LRU, 并发起AXI请求, 从存储器中读取未命中的行, 如果允许读,就转向REFILE
*FINISH:数据传输完成,Cache在下一个状态回到IDLE状态
*RESETN:重置DFA,持续128个周期,直到专用计数器为127时回到IDLE状态
*/
localparam IDLE = 4'b0000,
RUN = 4'b0001,
WAIT = 4'b0010,
SEL_WAY = 4'b0011,
MISS = 4'b0100,
REFILL2=4'b101,
FINISH = 4'b0110,
REFILL = 4'b0111,
RESETN = 4'b1000,
CACHE_GROUP_NUM=2047,
WAIT_LATENCY=4'ha;
reg[3:0] cur_stat;
reg[3:0] next_stat;
reg[6:0] rst_latency;
// reg[1:0] LRU[0:2047][0:1];
reg[1:0] LRU[0:2047];
// cache_line[161:0] [valid(1) |tag(16) |block(64)|valid(1)|tag(16)|block(64)]
// cpu_addr [tag(16) |group idx(11)|block offset(5)]
wire[161:0] cache_line;
wire[10:0] idx_from_cpu=cache_addr[15:5];// 组号
wire[15:0] tag_from_cpu=cache_addr[31:16];// cpu给出的tag
wire[4:0] ofs_from_cpu=cache_addr[4:0];// 块内偏移
wire valid1_from_cache=cache_line[161:161];
wire valid2_from_cache=cache_line[80:80];// 有效位
wire[15:0] tag1_from_cache=cache_line[160:145];
wire[15:0] tag2_from_cache=cache_line[79:64];// cache读出的tag
reg replaceOver=0;
wire hit =(((tag1_from_cache==tag_from_cpu)||(tag2_from_cache==tag_from_cpu)) && (cur_stat==RUN) && (valid1_from_cache||valid2_from_cache));
wire miss = !hit;
reg cache_data_ok_reg=0;
assign cache_data_ok = cache_data_ok_reg;
assign cache_addr_ok = cur_stat==RUN;
reg[161:0] data_to_mem=162'b0;
reg wea=0;
reg[31:0] reg4b=0;
wire[63:0] data_from_rom=0;
assign cache_rdata=hit?((tag1_from_cache==tag_from_cpu)?cache_line[144-ofs_from_cpu-:32]:cache_line[63-ofs_from_cpu-:32]):data_from_rom[63-ofs_from_cpu-:32];
wire tag_match_flag=(tag1_from_cache==tag_from_cpu)||(tag2_from_cache==tag_from_cpu);
reg axiOver;
reg[6:0] initCnt=0;
wire initEnd=(initCnt==31);
// 复位
always @(posedge clk) begin
if(cur_stat==RESETN) initCnt<=initCnt+1;
else if(initEnd) initCnt<=0;
else initCnt<=initCnt;
end
// DFA
always @(posedge clk or negedge resetn) begin
if(!resetn) cur_stat<=RESETN;
else cur_stat<=next_stat;
end
always@(*)begin
case (cur_stat)
IDLE: begin
next_stat=RUN;
cache_data_ok_reg=0;
replaceOver=0;
end
RUN: if(hit&&cpu_req) begin//握手成功
next_stat=FINISH;
cache_data_ok_reg=0;
replaceOver=0;
end
else if(cpu_req&&miss) begin // miss
next_stat=SEL_WAY;
cache_data_ok_reg=0;
replaceOver=0;
end
else begin
next_stat=RUN;
cache_data_ok_reg=0;
replaceOver=0;
end
SEL_WAY:begin
next_stat=MISS;
cache_data_ok_reg=0;
replaceOver=0;
end
MISS:
begin
next_stat=REFILL;
cache_data_ok_reg=0;
replaceOver=1;
end
REFILL: begin
next_stat=REFILL2;
cache_data_ok_reg=0;
replaceOver=1;
end
REFILL2:begin
next_stat=FINISH;
cache_data_ok_reg=0;
replaceOver=0;
end
RESETN: if(initEnd) begin
next_stat=IDLE;
cache_data_ok_reg=0;
replaceOver=0;
end
else begin
next_stat=RESETN;
cache_data_ok_reg=0;
replaceOver=0;
end
FINISH: begin
next_stat=IDLE;
cache_data_ok_reg=1;//持续两个周期?
replaceOver=0;
end
// default: next_stat=next_stat;
endcase
end
// 读命中,读时序
// HERE with A BUG TODO
// 给存储器的地址, 理论上只有命中了之后才会执行,
cache_mem mem(
.clka (clk ),
.addra (idx_from_cpu ),
.dina (data_to_mem ),
.wea (wea ),
.douta (cache_line )
);
/********************************
*这里处理缺失的相关处理
*********************************/
reg free_way=0;
//LRU
generate
genvar i;
for(i=0;i<2047;i=i+1)begin:lru_generator
always @(negedge resetn) begin
if(!resetn)begin
LRU[i]<=2'b0;
end else if(cur_stat==RUN&&next_stat==FINISH)begin
if(i==idx_from_cpu) LRU[i]<=(tag1_from_cache==tag_from_cpu)?2'b10:2'b01;
else LRU[i]<=LRU[i];
end
end
end
endgenerate
always @(negedge resetn or posedge clk) begin
if(!resetn)begin
free_way<=0;
end else if(cur_stat==SEL_WAY)begin
free_way<=(LRU[idx_from_cpu][1]==0);
end else if(cur_stat==RUN&&next_stat==FINISH)begin
free_way<=0;
end else free_way<=free_way;
end
/**
*将从rom中读取的数据写入mem
*/
always @(posedge clk) begin
if(cur_stat==REFILL&&next_stat==REFILL2)begin
wea<=1;
data_to_mem<=data_to_mem;
end
else if(cur_stat==MISS&&next_stat==REFILL)begin
wea<=0;
data_to_mem<=free_way? {cache_line[161:81], 1'b1,tag_from_cpu[15:0],data_from_rom[63:0]}:{1'b1,tag_from_cpu[15:0],data_from_rom[63:0],cache_line[80:0]};
end
else begin
wea<=0;
data_to_mem<=0;
end
end
/*
*REFILL TODO
*/
main_mem1 rom(
.clka (clk ),
.addra (tag_from_cpu ),
// .ena (replaceOver ),
.douta (data_from_rom)
);
endmodule
似乎和时序没有关系?