OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 175 to Rev 176
    Reverse comparison

Rev 175 → Rev 176

/zipcpu/trunk/rtl/core/pfcache.v
44,8 → 44,8
input i_clear_cache;
input i_stall_n;
input [(AW-1):0] i_pc;
output reg [(BUSW-1):0] o_i;
output reg [(AW-1):0] o_pc;
output wire [(BUSW-1):0] o_i;
output wire [(AW-1):0] o_pc;
output wire o_v;
//
output reg o_wb_cyc, o_wb_stb;
64,8 → 64,7
assign o_wb_we = 1'b0;
assign o_wb_data = 0;
 
reg r_v;
(* ram_style = "distributed" *)
wire r_v;
reg [(BUSW-1):0] cache [0:((1<<CW)-1)];
reg [(AW-CW-1):0] tags [0:((1<<(CW-PW))-1)];
reg [((1<<(CW-PW))-1):0] vmask;
72,33 → 71,56
 
reg [(AW-1):0] lastpc;
reg [(CW-1):0] rdaddr;
reg [(AW-1):CW] tagval;
reg [(AW-1):CW] tagvalipc, tagvallst;
wire [(AW-1):CW] tagval;
wire [(AW-1):PW] lasttag;
reg illegal_valid;
reg [(AW-1):PW] illegal_cache;
 
initial o_i = 32'h76_00_00_00; // A NOOP instruction
initial o_pc = 0;
// initial o_i = 32'h76_00_00_00; // A NOOP instruction
// initial o_pc = 0;
reg [(BUSW-1):0] r_pc_cache, r_last_cache;
reg [(AW-1):0] r_pc, r_lastpc;
reg isrc;
always @(posedge i_clk)
if (~r_v)
begin
o_i <= cache[lastpc[(CW-1):0]];
o_pc <= lastpc;
end else if ((i_stall_n)||(i_new_pc))
begin
o_i <= cache[i_pc[(CW-1):0]];
o_pc <= i_pc;
end
begin
// We don't have the logic to select what to read, we must
// read both the value at i_pc and lastpc. cache[i_pc] is
// the value we return if the cache is good, cacne[lastpc] is
// the value we return if we've been stalled, weren't valid,
// or had to wait a clock or two. (Remember i_pc can't stop
// changing for a clock, so we need to keep track of the last
// one from before it stopped.)
//
// Here we keep track of which answer we want/need
isrc <= ((r_v)&&(i_stall_n))||(i_new_pc);
 
initial tagval = 0;
// Here we read both, and select which was write using isrc
// on the next clock.
r_pc_cache <= cache[i_pc[(CW-1):0]];
r_last_cache <= cache[lastpc[(CW-1):0]];
r_pc <= i_pc;
r_lastpc <= lastpc;
end
assign o_pc = (isrc) ? r_pc : r_lastpc;
assign o_i = (isrc) ? r_pc_cache : r_last_cache;
 
reg tagsrc;
always @(posedge i_clk)
// It may be possible to recover a clock once the cache line
// has been filled, but our prior attempt to do so has lead
// to a race condition, so we keep this logic simple.
if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
tagval <= tags[i_pc[(CW-1):PW]];
tagsrc <= 1'b1;
else
tagval <= tags[lastpc[(CW-1):PW]];
tagsrc <= 1'b0;
initial tagvalipc = 0;
always @(posedge i_clk)
tagvalipc <= tags[i_pc[(CW-1):PW]];
initial tagvallst = 0;
always @(posedge i_clk)
tagvallst <= tags[lastpc[(CW-1):PW]];
assign tagval = (tagsrc)?tagvalipc : tagvallst;
 
// i_pc will only increment when everything else isn't stalled, thus
// we can set it without worrying about that. Doing this enables
111,16 → 133,12
lastpc <= i_pc;
 
assign lasttag = lastpc[(AW-1):PW];
// initial lasttag = 0;
// always @(posedge i_clk)
// if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
// lasttag <= i_pc[(AW-1):PW];
 
wire r_v_from_pc, r_v_from_last;
assign r_v_from_pc = ((i_pc[(AW-1):PW] == lasttag)
&&(tagval == i_pc[(AW-1):CW])
wire w_v_from_pc, w_v_from_last;
assign w_v_from_pc = ((i_pc[(AW-1):PW] == lasttag)
&&(tagvalipc == i_pc[(AW-1):CW])
&&(vmask[i_pc[(CW-1):PW]]));
assign r_v_from_last = (
assign w_v_from_last = (
//(lastpc[(AW-1):PW] == lasttag)&&
(tagval == lastpc[(AW-1):CW])
&&(vmask[lastpc[(CW-1):PW]]));
128,23 → 146,54
reg [1:0] delay;
 
initial delay = 2'h3;
initial r_v = 1'b0;
reg rvsrc;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache)||(i_new_pc)||((r_v)&&(i_stall_n)))
begin
r_v <= r_v_from_pc;
// r_v <= r_v_from_pc;
rvsrc <= 1'b1;
delay <= 2'h2;
end else if (~r_v) begin // Otherwise, r_v was true and we were
r_v <= r_v_from_last; // stalled, hence only if ~r_v
// stalled, hence only if ~r_v
rvsrc <= 1'b0;
if (o_wb_cyc)
delay <= 2'h2;
else if (delay != 0)
delay <= delay + 2'b11; // i.e. delay -= 1;
end
reg r_v_from_pc, r_v_from_last;
always @(posedge i_clk)
r_v_from_pc <= w_v_from_pc;
always @(posedge i_clk)
r_v_from_last <= w_v_from_last;
 
assign o_v = (r_v)&&(~i_new_pc);
assign r_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last));
assign o_v = (((rvsrc)?(r_v_from_pc):(r_v_from_last))
||((o_illegal)&&(~o_wb_cyc)))
&&(~i_new_pc)&&(~i_rst);
 
reg last_ack;
initial last_ack = 1'b0;
always @(posedge i_clk)
last_ack <= (o_wb_cyc)&&(
(rdaddr[(PW-1):1]=={(PW-1){1'b1}})
&&((rdaddr[0])||(i_wb_ack)));
 
reg needload;
initial needload = 1'b0;
always @(posedge i_clk)
needload <= ((~r_v)&&(delay==0)
&&((tagvallst != lastpc[(AW-1):CW])
||(~vmask[lastpc[(CW-1):PW]]))
&&((~illegal_valid)
||(lastpc[(AW-1):PW] != illegal_cache)));
 
reg last_addr;
initial last_addr = 1'b0;
always @(posedge i_clk)
last_addr <= (o_wb_cyc)&&(o_wb_addr[(PW-1):1] == {(PW-1){1'b1}})
&&((~i_wb_stall)|(o_wb_addr[0]));
 
initial o_wb_cyc = 1'b0;
initial o_wb_stb = 1'b0;
initial o_wb_addr = {(AW){1'b0}};
158,53 → 207,72
begin
if (i_wb_err)
o_wb_stb <= 1'b0;
else if ((o_wb_stb)&&(~i_wb_stall))
begin
if (o_wb_addr[(PW-1):0] == {(PW){1'b1}})
o_wb_stb <= 1'b0;
else
o_wb_addr[(PW-1):0] <= o_wb_addr[(PW-1):0]+1;
end
else if ((o_wb_stb)&&(~i_wb_stall)&&(last_addr))
o_wb_stb <= 1'b0;
 
if (i_wb_ack)
begin
rdaddr <= rdaddr + 1;
tags[o_wb_addr[(CW-1):PW]] <= o_wb_addr[(AW-1):CW];
end
 
if (((i_wb_ack)&&(rdaddr[(PW-1):0]=={(PW){1'b1}}))||(i_wb_err))
if (((i_wb_ack)&&(last_ack))||(i_wb_err))
o_wb_cyc <= 1'b0;
 
// else if (rdaddr[(PW-1):1] == {(PW-1){1'b1}})
// tags[lastpc[(CW-1):PW]] <= lastpc[(AW-1):CW];
 
end else if ((~r_v)&&(delay==0)
&&((tagval != lastpc[(AW-1):CW])
||(~vmask[lastpc[(CW-1):PW]]))
&&((~illegal_valid)||(lastpc[(AW-1):PW] != illegal_cache)))
end else if (needload)
begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
o_wb_addr <= { lastpc[(AW-1):PW], {(PW){1'b0}} };
rdaddr <= { lastpc[(CW-1):PW], {(PW){1'b0}} };
end
 
always @(posedge i_clk)
if (o_wb_cyc) // &&(i_wb_ack)
tags[o_wb_addr[(CW-1):PW]] <= o_wb_addr[(AW-1):CW];
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
rdaddr <= rdaddr + 1;
else if (~o_wb_cyc)
rdaddr <= { lastpc[(CW-1):PW], {(PW){1'b0}} };
always @(posedge i_clk)
if ((o_wb_stb)&&(~i_wb_stall)&&(~last_addr))
o_wb_addr[(PW-1):0] <= o_wb_addr[(PW-1):0]+1;
else if (~o_wb_cyc)
o_wb_addr <= { lastpc[(AW-1):PW], {(PW){1'b0}} };
 
// Can't initialize an array, so leave cache uninitialized
// We'll also never get an ack without sys being active, so skip
// that check. Or rather, let's just use o_wb_cyc instead. This
// will work because multiple writes to the same address, ending with
// a valid write, aren't a problem.
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
if (o_wb_cyc) // &&(i_wb_ack)
cache[rdaddr] <= i_wb_data;
 
// VMask ... is a section loaded?
// Note "svmask". It's purpose is to delay the vmask setting by one
// clock, so that we can insure the right value of the cache is loaded
// before declaring that the cache line is valid. Without this, the
// cache line would get read, and the instruction would read from the
// last cache line.
reg svmask;
initial vmask = 0;
initial svmask = 1'b0;
reg [(CW-PW-1):0] saddr;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
begin
vmask <= 0;
svmask<= 1'b0;
end
else begin
if ((o_wb_cyc)&&(i_wb_ack)&&(rdaddr[(PW-1):0] == {(PW){1'b1}}))
vmask[rdaddr[(CW-1):PW]] <= 1'b1;
if ((~r_v)&&(tagval != lastpc[(AW-1):CW])&&(delay == 0))
svmask <= ((o_wb_cyc)&&(i_wb_ack)&&(last_ack));
if (svmask)
vmask[saddr] <= 1'b1;
if ((~o_wb_cyc)&&(needload))
vmask[lastpc[(CW-1):PW]] <= 1'b0;
end
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
saddr <= rdaddr[(CW-1):PW];
 
initial illegal_cache = 0;
initial illegal_valid = 0;
221,7 → 289,7
 
initial o_illegal = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
if ((i_rst)||(i_clear_cache)||(o_wb_cyc))
o_illegal <= 1'b0;
else
o_illegal <= (illegal_valid)

powered by: WebSVN 2.1.0

© copyright 1999-2022 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.