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) |