URL
https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk
Subversion Repositories xulalx25soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/xulalx25soc/trunk/rtl/cpu
- from Rev 98 to Rev 113
- ↔ Reverse comparison
Rev 98 → Rev 113
/div.v
57,6 → 57,11
reg r_sign, pre_sign, r_z, r_c, last_bit; |
reg [(LGBW-1):0] r_bit; |
|
reg zero_divisor; |
initial zero_divisor = 1'b0; |
always @(posedge i_clk) |
zero_divisor <= (r_divisor == 0)&&(r_busy); |
|
initial r_busy = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
63,7 → 68,7
r_busy <= 1'b0; |
else if (i_wr) |
r_busy <= 1'b1; |
else if ((last_bit)||(o_err)) |
else if ((last_bit)||(zero_divisor)) |
r_busy <= 1'b0; |
|
initial o_busy = 1'b0; |
72,7 → 77,7
o_busy <= 1'b0; |
else if (i_wr) |
o_busy <= 1'b1; |
else if (((last_bit)||(o_err))&&(~r_sign)) |
else if (((last_bit)&&(~r_sign))||(zero_divisor)) |
o_busy <= 1'b0; |
else if (~r_busy) |
o_busy <= 1'b0; |
82,21 → 87,22
o_valid <= 1'b0; |
else if (r_busy) |
begin |
if ((last_bit)||(o_err)) |
o_valid <= (o_err)||(~r_sign); |
if ((last_bit)||(zero_divisor)) |
o_valid <= (zero_divisor)||(~r_sign); |
end else if (r_sign) |
begin |
// if (o_err), o_valid is already one. |
// if not, o_valid has not yet become one. |
o_valid <= (~o_err); // 1'b1; |
o_valid <= (~zero_divisor); // 1'b1; |
end else |
o_valid <= 1'b0; |
|
initial o_err = 1'b0; |
always @(posedge i_clk) |
if((i_rst)||(o_valid)) |
o_err <= 1'b0; |
else if (o_busy) |
o_err <= (r_divisor == 0); |
else if (((r_busy)||(r_sign))&&(zero_divisor)) |
o_err <= 1'b1; |
else |
o_err <= 1'b0; |
|
initial last_bit = 1'b0; |
always @(posedge i_clk) |
172,6 → 178,7
o_quotient[r_bit[(LGBW-1):0]] <= 1'b1; |
r_z <= 1'b0; |
end |
r_sign <= (r_sign)&&(~zero_divisor); |
end else if (r_sign) |
begin |
r_sign <= 1'b0; |
/zipbones.v
45,7 → 45,7
i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr, i_dbg_data, |
o_dbg_ack, o_dbg_stall, o_dbg_data |
`ifdef DEBUG_SCOPE |
, o_zip_debug |
, o_cpu_debug |
`endif |
); |
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=32, |
71,7 → 71,7
output wire [31:0] o_dbg_data; |
// |
`ifdef DEBUG_SCOPE |
output wire [31:0] o_zip_debug; |
output wire [31:0] o_cpu_debug; |
`endif |
|
// |
119,12 → 119,8
|
initial cmd_clear_pf_cache = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
cmd_clear_pf_cache <= 1'b0; |
else if (dbg_cmd_write) |
cmd_clear_pf_cache <= i_dbg_data[11]; |
else |
cmd_clear_pf_cache <= 1'b0; |
cmd_clear_pf_cache = (~i_rst)&&(dbg_cmd_write) |
&&((i_dbg_data[11])||(i_dbg_data[6])); |
// |
initial cmd_step = 1'b0; |
always @(posedge i_clk) |
176,10 → 172,10
cpu_lcl_cyc, cpu_lcl_stb, |
o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data, |
(i_wb_err)||((cpu_lcl_cyc)&&(cpu_lcl_stb)), |
(i_wb_err)||(cpu_lcl_cyc), |
cpu_op_stall, cpu_pf_stall, cpu_i_count |
`ifdef DEBUG_SCOPE |
, o_zip_debug |
, o_cpu_debug |
`endif |
); |
|
188,7 → 184,7
initial o_dbg_ack = 1'b0; |
always @(posedge i_clk) |
o_dbg_ack <= (i_dbg_cyc)&&((~i_dbg_addr)||(~o_dbg_stall)); |
assign o_dbg_stall=(i_dbg_cyc)&&(cpu_dbg_stall)&&(i_dbg_addr); |
assign o_dbg_stall= 1'b0; //(i_dbg_cyc)&&(cpu_dbg_stall)&&(i_dbg_addr); |
|
assign o_ext_int = (cmd_halt) && (~i_wb_stall); |
|
/cpudefs.v
273,6 → 273,10
// |
// |
`define DEBUG_SCOPE |
`endif |
`else // XULA25 |
`ifdef VERILATOR |
`define DEBUG_SCOPE |
`endif // VERILATOR |
`endif // XULA25 |
// |
`endif // CPUDEFS_H |
/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) |
/idecode.v
104,7 → 104,7
wire [3:0] w_cond; |
wire w_wF, w_dcdM, w_dcdDV, w_dcdFP; |
wire w_wR, w_rA, w_rB, w_wR_n; |
wire w_ljmp; |
wire w_ljmp, w_ljmp_dly; |
wire [31:0] iword; |
|
|
148,7 → 148,9
// If the result register is either CC or PC, and this would otherwise |
// be a floating point instruction with floating point opcode of 0, |
// then this is a NOOP. |
assign w_noop = (w_op[4:0] == 5'h18)&&(w_dcdR[3:1] == 3'h7); |
assign w_noop = (w_op[4:0] == 5'h18)&&( |
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1] == 3'h7)) |
||(IMPLEMENT_FPU==0)); |
|
// 4 LUTs |
assign w_dcdB = { ((~iword[31])&&(w_mov)&&(~i_gie))?iword[13]:i_gie, |
249,9 → 251,10
reg r_phase; |
initial r_phase = 1'b0; |
always @(posedge i_clk) |
if (i_rst) // When no instruction is in the pipe, phase is zero |
if ((i_rst) // When no instruction is in the pipe, phase is zero |
||(o_early_branch)||(w_ljmp_dly)) |
r_phase <= 1'b0; |
else if (i_ce) |
else if ((i_ce)&&(i_pf_valid)) |
r_phase <= (o_phase)? 1'b0:(i_instruction[31]); |
// Phase is '1' on the first instruction of a two-part set |
// But, due to the delay in processing, it's '1' when our output is |
276,7 → 279,7
`else |
o_illegal <= ((i_illegal) || (i_instruction[31])); |
`endif |
if ((IMPLEMENT_MPY!=1)&&(w_op[4:1]==4'h5)) |
if ((IMPLEMENT_MPY==0)&&((w_op[4:1]==4'h5)||(w_op[4:0]==5'h08))) |
o_illegal <= 1'b1; |
|
if ((IMPLEMENT_DIVIDE==0)&&(w_dcdDV)) |
357,10 → 360,14
o_M <= w_dcdM; |
o_DV <= w_dcdDV; |
o_FP <= w_dcdFP; |
|
o_break <= (w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)&&(w_op[2:0]==3'b001); |
|
o_break <= (w_op[4:0]==5'b11001)&&( |
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7)) |
||(IMPLEMENT_FPU==0)); |
`ifdef OPT_PIPELINED |
r_lock <= (w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)&&(w_op[2:0]==3'b010); |
r_lock <= (w_op[4:0]==5'b11010)&&( |
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7)) |
||(IMPLEMENT_FPU==0)); |
`endif |
`ifdef OPT_VLIW |
r_nxt_half <= { iword[31], iword[13:5], |
426,9 → 433,11
+ {{(AW-1){1'b0}},1'b1}; |
end |
|
assign w_ljmp_dly = r_ljmp; |
assign o_early_branch = r_early_branch; |
assign o_branch_pc = r_branch_pc; |
end else begin |
assign w_ljmp_dly = 1'b0; |
assign o_early_branch = 1'b0; |
assign o_branch_pc = {(AW){1'b0}}; |
assign o_ljmp = 1'b0; |
/pipefetch.v
257,10 → 257,10
|
initial r_addr_set = 1'b0; |
always @(posedge i_clk) |
if ((i_rst)||(i_clear_cache)) |
if ((i_rst)||(i_new_pc)) |
r_addr_set <= 1'b1; |
else if (i_clear_cache) |
r_addr_set <= 1'b0; |
else if (i_new_pc) |
r_addr_set <= 1'b1; |
|
// Now, read from the cache |
wire w_cv; // Cache valid, address is in the cache |
293,7 → 293,7
if ((o_wb_cyc)&&(i_wb_err)) |
ill_address <= o_wb_addr - {{(AW-LGCACHELEN-1){1'b0}}, r_acks_waiting}; |
|
assign o_illegal = (o_pc == ill_address); |
assign o_illegal = (o_pc == ill_address)&&(~i_rst)&&(~i_new_pc)&&(~i_clear_cache); |
|
|
endmodule |
/zipsystem.v
308,7 → 308,7
always @(posedge i_clk) |
cmd_reset <= ((dbg_cmd_write)&&(dbg_idata[6])); |
// |
initial cmd_halt = 1'b1; |
initial cmd_halt = START_HALTED; |
always @(posedge i_clk) |
if (i_rst) |
cmd_halt <= (START_HALTED == 1)? 1'b1 : 1'b0; |
317,6 → 317,7
else if ((cmd_step)||(cpu_break)) |
cmd_halt <= 1'b1; |
|
initial cmd_clear_pf_cache = 1'b0; |
always @(posedge i_clk) |
cmd_clear_pf_cache = (~i_rst)&&(dbg_cmd_write) |
&&((dbg_idata[11])||(dbg_idata[6])); |
/busdelay.v
23,7 → 23,7
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
55,11 → 55,12
input [(AW-1):0] i_wb_addr; |
input [(DW-1):0] i_wb_data; |
output reg o_wb_ack; |
output wire o_wb_stall; |
output reg o_wb_stall; |
output reg [(DW-1):0] o_wb_data; |
output wire o_wb_err; |
output reg o_wb_err; |
// Delayed bus |
output reg o_dly_cyc, o_dly_stb, o_dly_we; |
output reg o_dly_cyc, o_dly_we; |
output wire o_dly_stb; |
output reg [(AW-1):0] o_dly_addr; |
output reg [(DW-1):0] o_dly_data; |
input i_dly_ack; |
67,24 → 68,29
input [(DW-1):0] i_dly_data; |
input i_dly_err; |
|
reg loaded; |
initial o_dly_cyc = 1'b0; |
initial o_dly_stb = 1'b0; |
initial loaded = 1'b0; |
|
always @(posedge i_clk) |
o_dly_cyc <= i_wb_cyc; |
o_wb_stall <= (loaded)&&(i_dly_stall); |
|
initial o_dly_cyc = 1'b0; |
always @(posedge i_clk) |
o_dly_cyc <= (i_wb_cyc); |
// Add the i_wb_cyc criteria here, so we can simplify the o_wb_stall |
// criteria below, which would otherwise *and* these two. |
always @(posedge i_clk) |
if (~o_wb_stall) |
o_dly_stb <= ((i_wb_cyc)&&(i_wb_stb)); |
loaded <= (i_wb_stb)||((loaded)&&(i_dly_stall)&&(~i_dly_err)&&(i_wb_cyc)); |
assign o_dly_stb = loaded; |
always @(posedge i_clk) |
if (~o_wb_stall) |
if (~i_dly_stall) |
o_dly_we <= i_wb_we; |
always @(posedge i_clk) |
if (~o_wb_stall) |
if (~i_dly_stall) |
o_dly_addr<= i_wb_addr; |
always @(posedge i_clk) |
if (~o_wb_stall) |
if (~i_dly_stall) |
o_dly_data <= i_wb_data; |
always @(posedge i_clk) |
o_wb_ack <= (i_dly_ack)&&(o_dly_cyc)&&(i_wb_cyc); |
91,11 → 97,7
always @(posedge i_clk) |
o_wb_data <= i_dly_data; |
|
// Our only non-delayed line, yet still really delayed. Perhaps |
// there's a way to register this? |
// o_wb_stall <= (i_wb_cyc)&&(i_wb_stb) ... or some such? |
// assign o_wb_stall=((i_wb_cyc)&&(i_dly_stall)&&(o_dly_stb));//&&o_cyc |
assign o_wb_stall = ((i_dly_stall)&&(o_dly_stb));//&&o_cyc |
assign o_wb_err = i_dly_err; |
always @(posedge i_clk) |
o_wb_err <= (i_dly_err)&&(o_dly_cyc)&&(i_wb_cyc); |
|
endmodule |
/cpuops.v
53,11 → 53,19
assign w_rol_result = w_rol_tmp[63:32]; // Won't set flags |
|
// Shift register pre-logic |
wire [32:0] w_lsr_result, w_asr_result; |
wire [32:0] w_lsr_result, w_asr_result, w_lsl_result; |
wire signed [32:0] w_pre_asr_input, w_pre_asr_shifted; |
assign w_pre_asr_input = { i_a, 1'b0 }; |
assign w_pre_asr_shifted = w_pre_asr_input >>> i_b[4:0]; |
assign w_asr_result = (|i_b[31:5])? {(33){i_a[31]}} |
: ( {i_a, 1'b0 } >>> (i_b[4:0]) );// ASR |
assign w_lsr_result = (|i_b[31:5])? 33'h00 |
: ( { i_a, 1'b0 } >> (i_b[4:0]) );// LSR |
: w_pre_asr_shifted;// ASR |
assign w_lsr_result = ((|i_b[31:6])||(i_b[5]&&(i_b[4:0]!=0)))? 33'h00 |
:((i_b[5])?{32'h0,i_a[31]} |
|
: ( { i_a, 1'b0 } >> (i_b[4:0]) ));// LSR |
assign w_lsl_result = ((|i_b[31:6])||(i_b[5]&&(i_b[4:0]!=0)))? 33'h00 |
:((i_b[5])?{i_a[0], 32'h0} |
: ({1'b0, i_a } << i_b[4:0])); // LSL |
|
// Bit reversal pre-logic |
wire [31:0] w_brev_result; |
116,7 → 124,7
4'b0011: o_c <= i_a | i_b; // Or |
4'b0100: o_c <= i_a ^ i_b; // Xor |
4'b0101:{o_c,c } <= w_lsr_result[32:0]; // LSR |
4'b0110:{c,o_c } <= (|i_b[31:5])? 33'h00 : {1'b0, i_a } << i_b[4:0]; // LSL |
4'b0110:{c,o_c } <= w_lsl_result[32:0]; // LSL |
4'b0111:{o_c,c } <= w_asr_result[32:0]; // ASR |
`ifndef LONG_MPY |
4'b1000: o_c <= { i_b[15: 0], i_a[15:0] }; // LODIHI |
296,7 → 304,7
4'b0011: o_c <= i_a | i_b; // Or |
4'b0100: o_c <= i_a ^ i_b; // Xor |
4'b0101:{o_c,c } <= w_lsr_result[32:0]; // LSR |
4'b0110:{c,o_c } <= (|i_b[31:5])? 33'h00 : {1'b0, i_a } << i_b[4:0]; // LSL |
4'b0110:{c,o_c } <= w_lsl_result[32:0]; // LSL |
4'b0111:{o_c,c } <= w_asr_result[32:0]; // ASR |
`ifdef LONG_MPY |
4'b1000: o_c <= r_mpy_result[31:0]; // MPY |
/zipcpu.v
103,6 → 103,8
// |
`define CPU_CC_REG 4'he |
`define CPU_PC_REG 4'hf |
`define CPU_CLRCACHE_BIT 14 // Floating point error flag, set on error |
`define CPU_PHASE_BIT 13 // Floating point error flag, set on error |
`define CPU_FPUERR_BIT 12 // Floating point error flag, set on error |
`define CPU_DIVERR_BIT 11 // Divide error flag, set on divide by zero |
`define CPU_BUSERR_BIT 10 // Bus error flag, set on error |
203,13 → 205,16
// Condition codes |
// (BUS, TRAP,ILL,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z |
reg [3:0] flags, iflags; |
wire [13:0] w_uflags, w_iflags; |
reg trap, break_en, step, gie, sleep, r_halted; |
wire [14:0] w_uflags, w_iflags; |
reg trap, break_en, step, gie, sleep, r_halted, |
break_pending; |
wire w_clear_icache; |
`ifdef OPT_ILLEGAL_INSTRUCTION |
reg ill_err_u, ill_err_i; |
`else |
wire ill_err_u, ill_err_i; |
`endif |
reg ubreak; |
reg ibus_err_flag, ubus_err_flag; |
wire idiv_err_flag, udiv_err_flag; |
wire ifpu_err_flag, ufpu_err_flag; |
226,7 → 231,7
reg [(AW-1):0] pf_pc; |
reg new_pc; |
wire clear_pipeline; |
assign clear_pipeline = new_pc || i_clear_pf_cache; |
assign clear_pipeline = new_pc; |
|
wire dcd_stalled; |
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err; |
281,7 → 286,7
wire [31:0] w_opA, w_opB; |
wire [31:0] opA_nowait, opB_nowait, opA, opB; |
reg opR_wr, opR_cc, opF_wr, op_gie; |
wire [13:0] opFl; |
wire [14:0] opFl; |
reg [5:0] r_opF; |
wire [7:0] opF; |
wire op_ce, op_phase, op_pipe, op_change_data_ce; |
349,12 → 354,7
&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy) |
&&(set_cond); |
|
// ALU, DIV, or FPU CE ... equivalent to the OR of all three of these |
wire adf_ce, adf_ce_unconditional; |
assign adf_ce_unconditional = (master_ce)&&(~clear_pipeline)&&(opvalid) |
&&(~opvalid_mem)&&(~mem_rdbusy)&&(~div_busy) |
&&(~fpu_busy); |
assign adf_ce = (adf_ce_unconditional)&&(set_cond); |
wire adf_ce_unconditional; |
|
// |
// |
361,7 → 361,8
// PIPELINE STAGE #5 :: Write-back |
// Variable declarations |
// |
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc; |
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc, |
wr_write_scc, wr_write_ucc; |
wire [4:0] wr_reg_id; |
wire [31:0] wr_gpreg_vl, wr_spreg_vl; |
wire w_switch_to_interrupt, w_release_from_interrupt; |
400,6 → 401,14
// Calculate stall conditions |
wire op_lock_stall; |
`ifdef OPT_PIPELINED |
reg cc_invalid_for_dcd; |
always @(posedge i_clk) |
cc_invalid_for_dcd <= (wr_flags_ce) |
||(wr_reg_ce)&&(wr_reg_id[3:0] == `CPU_CC_REG) |
||(opvalid)&&((opF_wr)||((opR_wr)&&(opR[3:0] == `CPU_CC_REG))) |
||((alF_wr)||((alu_wr)&&(alu_reg[3:0] == `CPU_CC_REG))) |
||(mem_busy)||(div_busy)||(fpu_busy); |
|
assign op_stall = (opvalid)&&( // Only stall if we're loaded w/validins |
// Stall if we're stopped, and not allowed to execute |
// an instruction |
418,6 → 427,7
// that cannot be pipelined, and the memory is |
// already busy |
||(mem_stalled) // &&(opvalid_mem) part of mem_stalled |
||(opR_cc) |
) |
||(dcdvalid)&&( |
// Stall if we need to wait for an operand A |
433,6 → 443,8
||(dcdF_stall) |
); |
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~op_stall)&&(~clear_pipeline); |
|
|
// BUT ... op_ce is too complex for many of the data operations. So |
// let's make their circuit enable code simpler. In particular, if |
// op_ doesn't need to be preserved, we can change it all we want |
460,17 → 472,14
// the ALU. |
`ifdef OPT_PIPELINED |
assign alu_stall = (((~master_ce)||(mem_rdbusy)||(alu_busy))&&(opvalid_alu)) //Case 1&2 |
// Old case #3--this isn't an ALU stall though ... |
||((opvalid_alu)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie) |
&&(wr_write_cc)) // Case 3 |
||((opvalid)&&(op_lock)&&(op_lock_stall)) |
||((opvalid)&&(op_break)) |
||(wr_reg_ce)&&(wr_write_cc) |
||(div_busy)||(fpu_busy); |
assign alu_ce = (master_ce)&&(opvalid_alu)&&(~alu_stall) |
&&(~clear_pipeline); |
`else |
assign alu_stall = ((~master_ce)&&(opvalid_alu)) |
||((opvalid_alu)&&(op_break)); |
assign alu_stall = (opvalid_alu)&&((~master_ce)||(op_break)); |
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal))&&(~alu_stall)&&(~clear_pipeline); |
`endif |
// |
520,6 → 529,11
`endif |
`endif |
|
// ALU, DIV, or FPU CE ... equivalent to the OR of all three of these |
assign adf_ce_unconditional = (master_ce)&&(~clear_pipeline)&&(opvalid) |
&&(~opvalid_mem)&&(~mem_rdbusy) |
&&((~opvalid_alu)||(~alu_stall))&&(~op_break) |
&&(~div_busy)&&(~fpu_busy)&&(~clear_pipeline); |
|
// |
// |
542,7 → 556,7
if ((i_rst)||(clear_pipeline)) |
r_dcdvalid <= 1'b0; |
else if (dcd_ce) |
r_dcdvalid <= (pf_valid); |
r_dcdvalid <= (pf_valid)||(pf_illegal); |
else if (op_ce) |
r_dcdvalid <= 1'b0; |
assign dcdvalid = r_dcdvalid; |
552,7 → 566,7
`ifdef OPT_TRADITIONAL_PFCACHE |
pfcache #(LGICACHE, ADDRESS_WIDTH) |
pf(i_clk, i_rst, (new_pc)||((dcd_early_branch)&&(~clear_pipeline)), |
i_clear_pf_cache, |
w_clear_icache, |
// dcd_pc, |
~dcd_stalled, |
((dcd_early_branch)&&(~clear_pipeline)) |
563,8 → 577,8
pf_illegal); |
`else |
pipefetch #(RESET_ADDRESS, LGICACHE, ADDRESS_WIDTH) |
pf(i_clk, i_rst, (new_pc)||((dcd_early_branch)&&(~clear_pipeline)), |
i_clear_pf_cache, ~dcd_stalled, |
pf(i_clk, i_rst, (new_pc)||(dcd_early_branch), |
w_clear_icache, ~dcd_stalled, |
(new_pc)?pf_pc:dcd_branch_pc, |
instruction, instruction_pc, pf_valid, |
pf_cyc, pf_stb, pf_we, pf_addr, pf_data, |
581,10 → 595,10
|
initial r_dcdvalid = 1'b0; |
always @(posedge i_clk) |
if ((i_rst)||(clear_pipeline)) |
if ((i_rst)||(clear_pipeline)||(w_clear_icache)) |
r_dcdvalid <= 1'b0; |
else if (dcd_ce) |
r_dcdvalid <= (pf_valid)&&(~dcd_ljmp)&&((~r_dcdvalid)||(~dcd_early_branch)); |
r_dcdvalid <= (pf_valid)&&(~dcd_ljmp)&&(~dcd_early_branch); |
else if (op_ce) |
r_dcdvalid <= 1'b0; |
assign dcdvalid = r_dcdvalid; |
591,10 → 605,12
`endif |
|
`ifdef OPT_NEW_INSTRUCTION_SET |
|
// If not pipelined, there will be no opvalid_ anything, and the |
idecode #(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE, |
IMPLEMENT_FPU) |
instruction_decoder(i_clk, (i_rst)||(clear_pipeline), |
dcd_ce, dcd_stalled, instruction, instruction_gie, |
(~dcdvalid)||(~op_stall), dcd_stalled, instruction, instruction_gie, |
instruction_pc, pf_valid, pf_illegal, dcd_phase, |
dcd_illegal, dcd_pc, dcd_gie, |
{ dcdR_cc, dcdR_pc, dcdR }, |
735,7 → 751,7
else if (dcdA_pc) |
r_opA <= w_pcA_v; |
else if (dcdA_cc) |
r_opA <= { w_cpu_info, w_opA[22:14], (dcdA[4])?w_uflags:w_iflags }; |
r_opA <= { w_cpu_info, w_opA[22:15], (dcdA[4])?w_uflags:w_iflags }; |
else |
r_opA <= w_opA; |
`ifdef OPT_PIPELINED |
761,7 → 777,7
assign w_opBnI = (~dcdB_rd) ? 32'h00 |
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_gpreg_vl |
: ((dcdB_pc) ? w_pcB_v |
: ((dcdB_cc) ? { w_cpu_info, w_opB[22:14], // w_opB[31:14], |
: ((dcdB_cc) ? { w_cpu_info, w_opB[22:15], // w_opB[31:14], |
(dcdB[4])?w_uflags:w_iflags} |
: w_opB))); |
|
825,6 → 841,8
opvalid <= 1'b0; |
opvalid_alu <= 1'b0; |
opvalid_mem <= 1'b0; |
opvalid_div <= 1'b0; |
opvalid_fpu <= 1'b0; |
end else if (op_ce) |
begin |
// Do we have a valid instruction? |
835,9 → 853,9
// Hence, the test on dcd_stalled here. If we must |
// wait until our operands are valid, then we aren't |
// valid yet until then. |
opvalid<= w_opvalid; |
opvalid<= (w_opvalid)||(dcd_illegal)&&(dcdvalid); |
`ifdef OPT_ILLEGAL_INSTRUCTION |
opvalid_alu <= ((dcdALU)||(dcd_illegal))&&(w_opvalid); |
opvalid_alu <= (w_opvalid)&&((dcdALU)||(dcd_illegal)); |
opvalid_mem <= (dcdM)&&(~dcd_illegal)&&(w_opvalid); |
opvalid_div <= (dcdDV)&&(~dcd_illegal)&&(w_opvalid); |
opvalid_fpu <= (dcdFP)&&(~dcd_illegal)&&(w_opvalid); |
868,7 → 886,7
initial op_break = 1'b0; |
always @(posedge i_clk) |
if (i_rst) op_break <= 1'b0; |
else if (op_ce) op_break <= (dcd_break); |
else if (op_ce) op_break <= (dcd_break); // &&(dcdvalid) |
else if ((clear_pipeline)||(~opvalid)) |
op_break <= 1'b0; |
|
913,11 → 931,13
op_illegal <= 1'b0; |
else if(op_ce) |
`ifdef OPT_PIPELINED |
op_illegal <=(dcd_illegal)||((dcd_lock)&&(IMPLEMENT_LOCK == 0)); |
op_illegal <= (dcdvalid)&&((dcd_illegal)||((dcd_lock)&&(IMPLEMENT_LOCK == 0))); |
`else |
op_illegal <= (dcd_illegal)||(dcd_lock); |
op_illegal <= (dcdvalid)&&((dcd_illegal)||(dcd_lock)); |
`endif |
`endif |
else if(alu_ce) |
op_illegal <= 1'b0; |
|
// No generate on EARLY_BRANCHING here, since if EARLY_BRANCHING is not |
// set, dcd_early_branch will simply be a wire connected to zero and |
989,7 → 1009,8
assign dcdA_stall = (dcdA_rd) // &&(dcdvalid) is checked for elsewhere |
&&((opvalid)||(mem_rdbusy) |
||(div_busy)||(fpu_busy)) |
&&((opF_wr)&&(dcdA_cc)); |
&&(((opF_wr)||(cc_invalid_for_dcd))&&(dcdA_cc)) |
||((dcdA_rd)&&(dcdA_cc)&&(cc_invalid_for_dcd)); |
`else |
// There are no pipeline hazards, if we aren't pipelined |
assign dcdA_stall = 1'b0; |
1042,11 → 1063,12
// Stall following any instruction that will |
// set the flags, if we're going to need the |
// flags (CC) register for opB. |
||((opF_wr)&&(dcdB_cc)) |
||(((opF_wr)||(cc_invalid_for_dcd))&&(dcdB_cc)) |
// Stall on any ongoing memory operation that |
// will write to opB -- captured above |
// ||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB)&&(~dcd_zI)) |
); |
) |
||((dcdB_rd)&&(dcdB_cc)&&(cc_invalid_for_dcd)); |
assign dcdF_stall = ((~dcdF[3]) |
||((dcdA_rd)&&(dcdA_cc)) |
||((dcdB_rd)&&(dcdB_cc))) |
1082,7 → 1104,7
opA, opB, div_busy, div_valid, div_error, div_result, |
div_flags); |
end else begin |
assign div_error = 1'b1; |
assign div_error = 1'b0; // Can't be high unless div_valid |
assign div_busy = 1'b0; |
assign div_valid = 1'b0; |
assign div_result= 32'h00; |
1097,13 → 1119,13
// opA, opB, fpu_busy, fpu_valid, fpu_err, fpu_result, |
// fpu_flags); |
// |
assign fpu_error = 1'b1; |
assign fpu_error = 1'b0; // Must only be true if fpu_valid |
assign fpu_busy = 1'b0; |
assign fpu_valid = 1'b0; |
assign fpu_result= 32'h00; |
assign fpu_flags = 4'h0; |
end else begin |
assign fpu_error = 1'b1; |
assign fpu_error = 1'b0; |
assign fpu_busy = 1'b0; |
assign fpu_valid = 1'b0; |
assign fpu_result= 32'h00; |
1173,11 → 1195,15
reg r_alu_illegal; |
initial r_alu_illegal = 0; |
always @(posedge i_clk) |
if (clear_pipeline) |
if ((i_rst)||(clear_pipeline)) |
r_alu_illegal <= 1'b0; |
else if ((alu_ce)||(mem_ce)) |
else if (alu_ce) |
r_alu_illegal <= op_illegal; |
else |
r_alu_illegal <= 1'b0; |
assign alu_illegal = (alu_illegal_op)||(r_alu_illegal); |
`else |
assign alu_illegal = 1'b0; |
`endif |
|
initial r_alu_pc_valid = 1'b0; |
1299,6 → 1325,8
assign wr_reg_id = (alu_wr|div_valid|fpu_valid)?alu_reg:mem_wreg; |
// Are we writing to the CC register? |
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG); |
assign wr_write_scc = (wr_reg_id[4:0] == {1'b0, `CPU_CC_REG}); |
assign wr_write_ucc = (wr_reg_id[4:0] == {1'b1, `CPU_CC_REG}); |
// Are we writing to the PC? |
assign wr_write_pc = (wr_reg_id[3:0] == `CPU_PC_REG); |
// What value to write? |
1317,11 → 1345,11
// When shall we write to our flags register? alF_wr already |
// includes the set condition ... |
assign wr_flags_ce = ((alF_wr)||(div_valid)||(fpu_valid))&&(~clear_pipeline)&&(~alu_illegal); |
assign w_uflags = { uhalt_phase, ufpu_err_flag, |
assign w_uflags = { 1'b0, uhalt_phase, ufpu_err_flag, |
udiv_err_flag, ubus_err_flag, trap, ill_err_u, |
1'b0, step, 1'b1, sleep, |
ubreak, step, 1'b1, sleep, |
((wr_flags_ce)&&(alu_gie))?alu_flags:flags }; |
assign w_iflags = { ihalt_phase, ifpu_err_flag, |
assign w_iflags = { 1'b0, ihalt_phase, ifpu_err_flag, |
idiv_err_flag, ibus_err_flag, trap, ill_err_i, |
break_en, 1'b0, 1'b0, sleep, |
((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags }; |
1330,7 → 1358,7
// What value to write? |
always @(posedge i_clk) |
// If explicitly writing the register itself |
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_cc)) |
if ((wr_reg_ce)&&(wr_write_ucc)) |
flags <= wr_gpreg_vl[3:0]; |
// Otherwise if we're setting the flags from an ALU operation |
else if ((wr_flags_ce)&&(alu_gie)) |
1338,7 → 1366,7
: alu_flags); |
|
always @(posedge i_clk) |
if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_cc)) |
if ((wr_reg_ce)&&(wr_write_scc)) |
iflags <= wr_gpreg_vl[3:0]; |
else if ((wr_flags_ce)&&(~alu_gie)) |
iflags <= (div_valid)?div_flags:((fpu_valid)?fpu_flags |
1354,8 → 1382,8
// if ((break_en) AND (break_instruction)) // user mode or not |
// HALT CPU |
// else if (break_instruction) // only in user mode |
// set an interrupt flag, go to supervisor mode |
// allow supervisor to step the CPU. |
// set an interrupt flag, set the user break bit, |
// go to supervisor mode, allow supervisor to step the CPU. |
// Upon a CPU halt, any break condition will be reset. The |
// external debugger will then need to deal with whatever |
// condition has taken place. |
1363,29 → 1391,26
always @(posedge i_clk) |
if ((i_rst)||(i_halt)) |
break_en <= 1'b0; |
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_cc)) |
else if ((wr_reg_ce)&&(wr_write_scc)) |
break_en <= wr_spreg_vl[`CPU_BREAK_BIT]; |
`ifdef OPT_ILLEGAL_INSTRUCTION |
assign o_break = ((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~alu_busy) |
&&(~div_busy)&&(~fpu_busy) |
|
initial break_pending = 1'b0; |
always @(posedge i_clk) |
if ((i_rst)||(clear_pipeline)||(~opvalid)) |
break_pending <= 1'b0; |
else if (op_break) |
break_pending <= (~alu_busy)&&(~div_busy)&&(~fpu_busy)&&(~mem_busy); |
else |
break_pending <= 1'b0; |
|
|
assign o_break = ((break_en)||(~op_gie))&&(break_pending) |
&&(~clear_pipeline) |
||((~alu_gie)&&(bus_err)) |
||((~alu_gie)&&(div_valid)&&(div_error)) |
||((~alu_gie)&&(fpu_valid)&&(fpu_error)) |
||((~alu_gie)&&(alu_pc_valid)&&(alu_illegal)); |
`else |
assign o_break = (((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~alu_busy)&&(~div_busy)&&(~fpu_busy) |
&&(~clear_pipeline)) |
||((~alu_gie)&&(bus_err)) |
||((~alu_gie)&&(div_valid)&&(div_error)) |
||((~alu_gie)&&(fpu_valid)&&(fpu_error)); |
`endif |
||((~alu_gie)&&(div_error)) |
||((~alu_gie)&&(fpu_error)) |
||((~alu_gie)&&(alu_illegal)); |
|
|
// The sleep register. Setting the sleep register causes the CPU to |
// sleep until the next interrupt. Setting the sleep register within |
// interrupt mode causes the processor to halt until a reset. This is |
1416,7 → 1441,7
always @(posedge i_clk) |
if ((i_rst)||(w_switch_to_interrupt)) |
step <= 1'b0; |
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_reg_id[4])&&(wr_write_cc)) |
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_write_ucc)) |
step <= wr_spreg_vl[`CPU_STEP_BIT]; |
else if (((alu_pc_valid)||(mem_pc_valid))&&(step)&&(gie)) |
step <= 1'b0; |
1429,18 → 1454,19
||(((alu_pc_valid)||(mem_pc_valid))&&(step)&&(~alu_phase)&&(~bus_lock)) |
// If we encounter a break instruction, if the break |
// enable isn't set. |
||((master_ce)&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy) |
&&(op_break)&&(~break_en)) |
||((master_ce)&&(break_pending)&&(~break_en)) |
`ifdef OPT_ILLEGAL_INSTRUCTION |
// On an illegal instruction |
||((alu_pc_valid)&&(alu_illegal)) |
||(alu_illegal) |
`endif |
// On division by zero. If the divide isn't |
// implemented, div_valid and div_error will be short |
// circuited and that logic will be bypassed |
||((div_valid)&&(div_error)) |
// Same thing on a floating point error. |
||((fpu_valid)&&(fpu_error)) |
||(div_error) |
// Same thing on a floating point error. Note that |
// fpu_error must *never* be set unless fpu_valid is |
// also set as well, else this will fail. |
||(fpu_error) |
// |
||(bus_err) |
// If we write to the CC register |
1448,9 → 1474,9
&&(wr_reg_id[4])&&(wr_write_cc)) |
); |
assign w_release_from_interrupt = (~gie)&&(~i_interrupt) |
// Then if we write the CC register |
// Then if we write the sCC register |
&&(((wr_reg_ce)&&(wr_spreg_vl[`CPU_GIE_BIT]) |
&&(~wr_reg_id[4])&&(wr_write_cc)) |
&&(wr_write_scc)) |
); |
always @(posedge i_clk) |
if (i_rst) |
1462,16 → 1488,24
|
initial trap = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
if ((i_rst)||(w_release_from_interrupt)) |
trap <= 1'b0; |
else if (w_release_from_interrupt) |
trap <= 1'b0; |
else if ((alu_gie)&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT]) |
&&(wr_write_cc)) // &&(wr_reg_id[4]) implied |
&&(wr_write_ucc)) // &&(wr_reg_id[4]) implied |
trap <= 1'b1; |
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_reg_id[4])) |
trap <= wr_spreg_vl[`CPU_TRAP_BIT]; |
else if ((wr_reg_ce)&&(wr_write_ucc)&&(~alu_gie)) |
trap <= (trap)&&(wr_spreg_vl[`CPU_TRAP_BIT]); |
|
initial ubreak = 1'b0; |
always @(posedge i_clk) |
if ((i_rst)||(w_release_from_interrupt)) |
ubreak <= 1'b0; |
else if ((op_gie)&&(break_pending)&&(w_switch_to_interrupt)) |
ubreak <= 1'b1; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc)) |
ubreak <= (ubreak)&&(wr_spreg_vl[`CPU_BREAK_BIT]); |
|
|
`ifdef OPT_ILLEGAL_INSTRUCTION |
initial ill_err_i = 1'b0; |
always @(posedge i_clk) |
1478,25 → 1512,21
if (i_rst) |
ill_err_i <= 1'b0; |
// Only the debug interface can clear this bit |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_spreg_vl[`CPU_ILL_BIT])) |
ill_err_i <= 1'b0; |
else if ((alu_pc_valid)&&(alu_illegal)&&(~alu_gie)) |
else if ((dbgv)&&(wr_write_scc)) |
ill_err_i <= (ill_err_i)&&(wr_spreg_vl[`CPU_ILL_BIT]); |
else if ((alu_illegal)&&(~alu_gie)) |
ill_err_i <= 1'b1; |
initial ill_err_u = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
ill_err_u <= 1'b0; |
// The bit is automatically cleared on release from interrupt |
else if (w_release_from_interrupt) |
// or reset |
if ((i_rst)||(w_release_from_interrupt)) |
ill_err_u <= 1'b0; |
// If the supervisor writes to this register, clearing the |
// bit, then clear it |
else if (((~alu_gie)||(dbgv)) |
&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_ILL_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
ill_err_u <= 1'b0; |
else if ((alu_pc_valid)&&(alu_illegal)&&(alu_gie)) |
// If the supervisor (or debugger) writes to this register, |
// clearing the bit, then clear it |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc)) |
ill_err_u <=((ill_err_u)&&(wr_spreg_vl[`CPU_ILL_BIT])); |
else if ((alu_illegal)&&(alu_gie)) |
ill_err_u <= 1'b1; |
`else |
assign ill_err_u = 1'b0; |
1508,9 → 1538,8
always @(posedge i_clk) |
if (i_rst) |
ibus_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_spreg_vl[`CPU_BUSERR_BIT])) |
ibus_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_write_scc)) |
ibus_err_flag <= (ibus_err_flag)&&(wr_spreg_vl[`CPU_BUSERR_BIT]); |
else if ((bus_err)&&(~alu_gie)) |
ibus_err_flag <= 1'b1; |
// User bus error flag -- if ever set, it will cause an interrupt to |
1517,14 → 1546,10
// supervisor mode. |
initial ubus_err_flag = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
if ((i_rst)||(w_release_from_interrupt)) |
ubus_err_flag <= 1'b0; |
else if (w_release_from_interrupt) |
ubus_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_spreg_vl[`CPU_BUSERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
ubus_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc)) |
ubus_err_flag <= (ubus_err_flag)&&(wr_spreg_vl[`CPU_BUSERR_BIT]); |
else if ((bus_err)&&(alu_gie)) |
ubus_err_flag <= 1'b1; |
|
1540,24 → 1565,20
always @(posedge i_clk) |
if (i_rst) |
r_idiv_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_spreg_vl[`CPU_DIVERR_BIT])) |
r_idiv_err_flag <= 1'b0; |
else if ((div_error)&&(div_valid)&&(~alu_gie)) |
else if ((dbgv)&&(wr_write_scc)) |
r_idiv_err_flag <= (r_idiv_err_flag)&&(wr_spreg_vl[`CPU_DIVERR_BIT]); |
else if ((div_error)&&(~alu_gie)) |
r_idiv_err_flag <= 1'b1; |
// User divide (by zero) error flag -- if ever set, it will |
// cause a sudden switch interrupt to supervisor mode. |
initial r_udiv_err_flag = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
if ((i_rst)||(w_release_from_interrupt)) |
r_udiv_err_flag <= 1'b0; |
else if (w_release_from_interrupt) |
r_udiv_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_spreg_vl[`CPU_DIVERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
r_udiv_err_flag <= 1'b0; |
else if ((div_error)&&(alu_gie)&&(div_valid)) |
&&(wr_write_ucc)) |
r_udiv_err_flag <= (r_udiv_err_flag)&&(wr_spreg_vl[`CPU_DIVERR_BIT]); |
else if ((div_error)&&(alu_gie)) |
r_udiv_err_flag <= 1'b1; |
|
assign idiv_err_flag = r_idiv_err_flag; |
1577,9 → 1598,8
always @(posedge i_clk) |
if (i_rst) |
r_ifpu_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_spreg_vl[`CPU_FPUERR_BIT])) |
r_ifpu_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_write_scc)) |
r_ifpu_err_flag <= (r_ifpu_err_flag)&&(wr_spreg_vl[`CPU_FPUERR_BIT]); |
else if ((fpu_error)&&(fpu_valid)&&(~alu_gie)) |
r_ifpu_err_flag <= 1'b1; |
// User floating point error flag -- if ever set, it will cause |
1586,14 → 1606,11
// a sudden switch interrupt to supervisor mode. |
initial r_ufpu_err_flag = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
if ((i_rst)&&(w_release_from_interrupt)) |
r_ufpu_err_flag <= 1'b0; |
else if (w_release_from_interrupt) |
r_ufpu_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_spreg_vl[`CPU_FPUERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
r_ufpu_err_flag <= 1'b0; |
&&(wr_write_ucc)) |
r_ufpu_err_flag <= (r_ufpu_err_flag)&&(wr_spreg_vl[`CPU_FPUERR_BIT]); |
else if ((fpu_error)&&(alu_gie)&&(fpu_valid)) |
r_ufpu_err_flag <= 1'b1; |
|
1610,13 → 1627,17
initial r_ihalt_phase = 0; |
initial r_uhalt_phase = 0; |
always @(posedge i_clk) |
if (~alu_gie) |
if (i_rst) |
r_ihalt_phase <= 1'b0; |
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline)) |
r_ihalt_phase <= alu_phase; |
always @(posedge i_clk) |
if (alu_gie) |
if ((i_rst)||(w_release_from_interrupt)) |
r_uhalt_phase <= 1'b0; |
else if ((alu_gie)&&(alu_pc_valid)) |
r_uhalt_phase <= alu_phase; |
else if (w_release_from_interrupt) |
r_uhalt_phase <= 1'b0; |
else if ((~alu_gie)&&(wr_reg_ce)&&(wr_write_ucc)) |
r_uhalt_phase <= wr_spreg_vl[`CPU_PHASE_BIT]; |
|
assign ihalt_phase = r_ihalt_phase; |
assign uhalt_phase = r_uhalt_phase; |
1656,9 → 1677,9
always @(posedge i_clk) |
if (i_rst) |
pf_pc <= RESET_ADDRESS; |
else if (w_switch_to_interrupt) |
else if ((w_switch_to_interrupt)||((~gie)&&(w_clear_icache))) |
pf_pc <= ipc; |
else if (w_release_from_interrupt) |
else if ((w_release_from_interrupt)||((gie)&&(w_clear_icache))) |
pf_pc <= upc; |
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc)) |
pf_pc <= wr_spreg_vl[(AW-1):0]; |
1687,6 → 1708,21
else |
new_pc <= 1'b0; |
|
`ifdef OPT_PIPELINED |
reg r_clear_icache; |
initial r_clear_icache = 1'b1; |
always @(posedge i_clk) |
if ((i_rst)||(i_clear_pf_cache)) |
r_clear_icache <= 1'b1; |
else if ((wr_reg_ce)&&(wr_write_scc)) |
r_clear_icache <= wr_spreg_vl[`CPU_CLRCACHE_BIT]; |
else |
r_clear_icache <= 1'b0; |
assign w_clear_icache = r_clear_icache; |
`else |
assign w_clear_icache = 1'b0; |
`endif |
|
// |
// The debug interface |
generate |
1699,7 → 1735,8
o_dbg_reg <= {{(32-AW){1'b0}},(i_dbg_reg[4])?upc:ipc}; |
else if (i_dbg_reg[3:0] == `CPU_CC_REG) |
begin |
o_dbg_reg[13:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
o_dbg_reg[14:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
o_dbg_reg[31:23] <= w_cpu_info; |
o_dbg_reg[`CPU_GIE_BIT] <= gie; |
end |
end |
1711,7 → 1748,8
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc; |
else if (i_dbg_reg[3:0] == `CPU_CC_REG) |
begin |
o_dbg_reg[13:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
o_dbg_reg[14:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
o_dbg_reg[31:23] <= w_cpu_info; |
o_dbg_reg[`CPU_GIE_BIT] <= gie; |
end |
end |
1722,11 → 1760,15
|
always @(posedge i_clk) |
r_halted <= (i_halt)&&( |
(pf_cyc)||(mem_cyc_gbl)||(mem_cyc_lcl)||(mem_busy) |
||(alu_busy)||(div_busy)||(fpu_busy) |
||((~opvalid)&&(~i_rst)&&(~dcd_illegal)) |
||((~dcdvalid)&&(~i_rst)&&(~pf_illegal))); |
assign o_dbg_stall = r_halted; |
// To be halted, any long lasting instruction must |
// be completed. |
(~pf_cyc)&&(~mem_busy)&&(~alu_busy) |
&&(~div_busy)&&(~fpu_busy) |
// Operations must either be valid, or illegal |
&&((opvalid)||(i_rst)||(dcd_illegal)) |
// Decode stage must be either valid, in reset, or ill |
&&((dcdvalid)||(i_rst)||(pf_illegal))); |
assign o_dbg_stall = ~r_halted; |
|
// |
// |
1739,7 → 1781,17
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline); |
|
`ifdef DEBUG_SCOPE |
reg [31:0] r_stack; |
always @(posedge i_clk) |
if ((wr_reg_ce)&&(wr_reg_id == 5'h0d)) |
r_stack <= wr_gpreg_vl; |
reg r_stack_pre, r_stack_post; |
always @(posedge i_clk) |
r_stack_pre <= (r_stack == 32'h03fff); |
always @(posedge i_clk) |
r_stack_post <= (r_stack == 32'h03eeb); |
|
always @(posedge i_clk) |
o_debug <= { |
/* |
o_break, i_wb_err, pf_pc[1:0], |
1766,7 → 1818,7
pf_pc[7:0], pf_addr[7:0] |
*/ |
|
i_wb_err, gie, alu_illegal, |
(i_wb_err)||(r_stack_post), (gie)||(r_stack_pre), (alu_illegal)||(r_stack_post), |
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)), |
mem_busy, |
(mem_busy)?{ (o_wb_gbl_stb|o_wb_lcl_stb), o_wb_we, |
1786,5 → 1838,28
*/ |
}; |
`endif |
|
/* |
always @(posedge i_clk) |
o_debug <= { |
// External control interaction (4b) |
i_halt, i_rst, i_clear_cache, o_break, |
// Bus interaction (8b) |
pf_cyc,(o_wb_gbl_cyc|o_wb_lcl_cyc), o_wb_gbl_stb, o_wb_lcl_stb, |
o_wb_we, i_wb_ack, i_wb_stall, i_wb_err, |
// PC control (4b) |
gie, new_pc, dcd_early_branch, 1'b0, |
// Our list of pipeline stage values (8b) |
pf_valid, pf_illegal, dcdvalid, opvalid, alu_valid, mem_valid, |
alu_pc_valid, mem_pc_valid, |
// Our list of circuit enables ... (8b) |
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)), |
dcd_ce, op_ce, alu_ce, mem_ce, wr_reg_ce, wr_flags_ce, |
1'b0, |
// Useful PC values (64b) |
((dcd_early_branch)&&(~clear_pipeline)) |
? dcd_branch_pc[15:0]:pf_pc[15:0], |
(gie)?upc[15:0]:ipc[15:0], instruction_pc[15:0], instruction[31:16] }; |
*/ |
|
endmodule |