input [31:0] op2,
input [31:0] spsr,
input [31:0] cpsr,
+ input cpsrup,
input write_reg,
input [3:0] write_num,
input [31:0] write_data,
output reg [3:0] out_write_num = 4'bxxxx,
output reg [31:0] out_write_data = 32'hxxxxxxxx,
output reg [31:0] outspsr = 32'hxxxxxxxx,
- output reg [31:0] outcpsr = 32'hxxxxxxxx
+ output reg [31:0] outcpsr = 32'hxxxxxxxx,
+ output reg outcpsrup = 1'hx
);
reg [31:0] addr, raddr, prev_raddr, next_regdata, next_outcpsr;
+ reg next_outcpsrup;
reg [31:0] prevaddr;
reg [3:0] next_regsel, cur_reg, prev_reg;
reg next_writeback;
reg [3:0] next_write_num;
reg [31:0] next_write_data;
- reg [1:0] lsr_state = 2'b01, next_lsr_state;
+ reg [2:0] lsr_state = 3'b001, next_lsr_state;
reg [31:0] align_s1, align_s2, align_rddata;
- reg [1:0] lsrh_state = 2'b01, next_lsrh_state;
+ reg [2:0] lsrh_state = 3'b001, next_lsrh_state;
reg [31:0] lsrh_rddata;
reg [15:0] lsrh_rddata_s1;
reg [7:0] lsrh_rddata_s2;
reg [15:0] regs, next_regs;
- reg [2:0] lsm_state = 3'b001, next_lsm_state;
+ reg [3:0] lsm_state = 4'b0001, next_lsm_state;
reg [5:0] offset, prev_offset, offset_sel;
reg [31:0] swp_oldval, next_swp_oldval;
out_write_data <= next_write_data;
regs <= next_regs;
prev_reg <= cur_reg;
- prev_offset <= offset;
+ if (!rw_wait)
+ prev_offset <= offset;
prev_raddr <= raddr;
outcpsr <= next_outcpsr;
outspsr <= spsr;
+ outcpsrup <= next_outcpsrup;
swp_state <= next_swp_state;
lsm_state <= next_lsm_state;
lsr_state <= next_lsr_state;
cp_rnw = 1'bx;
cp_write = 32'hxxxxxxxx;
offset = prev_offset;
- next_outcpsr = lsm_state == 3'b010 ? outcpsr : cpsr;
+ next_outcpsr = lsm_state == 4'b0010 ? outcpsr : cpsr;
+ next_outcpsrup = cpsrup;
lsrh_rddata = 32'hxxxxxxxx;
lsrh_rddata_s1 = 16'hxxxx;
lsrh_rddata_s2 = 8'hxx;
next_swp_state = 2'b10;
next_swp_oldval = rd_data;
end
+ $display("SWP: read stage");
end
2'b10: begin
wr_req = 1'b1;
next_write_data = insn[22] ? {24'b0, swp_oldval[7:0]} : swp_oldval;
if(!rw_wait)
next_swp_state = 2'b01;
+ $display("SWP: write stage");
end
default: begin end
endcase
end
+ `DECODE_ALU_MULT: begin end
`DECODE_ALU_HDATA_REG,
`DECODE_ALU_HDATA_IMM: if(!inbubble) begin
next_outbubble = rw_wait;
endcase
case(lsrh_state)
- 2'b01: begin
+ 3'b001: begin
rd_req = insn[20];
wr_req = ~insn[20];
next_write_num = insn[15:12];
if(insn[21] | !insn[24]) begin
outstall = 1'b1;
if(!rw_wait)
- next_lsrh_state = 2'b10;
+ next_lsrh_state = 3'b010;
end
+ $display("ALU_LDRSTRH: rd_req %d, wr_req %d", rd_req, wr_req);
end
- 2'b10: begin
+ 3'b010: begin
+ next_outbubble = 1'b0;
next_write_reg = 1'b1;
next_write_num = insn[19:16];
next_write_data = addr;
- next_lsrh_state = 2'b10;
+ next_lsrh_state = 3'b100;
+ end
+ 3'b100: begin
+ outstall = 0;
+ next_lsrh_state = 3'b001;
end
default: begin end
endcase
+
+ if ((lsrh_state == 3'b001) && flush) begin /* Reject it. */
+ outstall = 1'b0;
+ next_lsrh_state = 3'b001;
+ end
end
`DECODE_LDRSTR_UNDEFINED: begin end
`DECODE_LDRSTR: if(!inbubble) begin
wr_data = insn[22] ? {4{op2[7:0]}} : op2; /* XXX need to actually store just a byte */
data_size = insn[22] ? 3'b001 : 3'b100;
case(lsr_state)
- 2'b01: begin
- rd_req = insn[20];
- wr_req = ~insn[20];
- next_write_reg = 1'b1;
+ 3'b001: begin
+ rd_req = insn[20] /* L */;
+ wr_req = ~insn[20] /* L */;
+ next_write_reg = insn[20] /* L */;
next_write_num = insn[15:12];
- if(insn[20]) begin
+ if(insn[20] /* L */) begin
next_write_data = align_rddata;
end
- if(insn[21] | !insn[24]) begin
+ if(insn[21] /* W */ | !insn[24] /* P */) begin
outstall = 1'b1;
if(!rw_wait)
- next_lsr_state = 2'b10;
+ next_lsr_state = 3'b010;
end
$display("LDRSTR: rd_req %d, wr_req %d, raddr %08x, wait %d", rd_req, wr_req, raddr, rw_wait);
end
- 2'b10: begin
+ 3'b010: begin
+ outstall = 1;
+ next_outbubble = 0;
next_write_reg = 1'b1;
next_write_num = insn[19:16];
next_write_data = addr;
- next_lsr_state = 2'b01;
+ next_lsr_state = 3'b100;
+ end
+ 3'b100: begin
+ outstall = 0;
+ next_lsr_state = 3'b001;
end
default: begin end
endcase
+
+ if ((lsr_state == 3'b001) && flush) begin /* Reject it. */
+ outstall = 1'b0;
+ next_lsr_state = 3'b001;
+ end
end
/* XXX ldm/stm incorrect in that stupid case where one of the listed regs is the base reg */
`DECODE_LDMSTM: if(!inbubble) begin
next_outbubble = rw_wait;
data_size = 3'b100;
case(lsm_state)
- 3'b001: begin
+ 4'b0001: begin
// next_regs = insn[23] ? op1[15:0] : op1[0:15];
/** verilator can suck my dick */
$display("LDMSTM: Round 1: base register: %08x, reg list %b", op0, op1[15:0]);
op1[8], op1[9], op1[10], op1[11], op1[12], op1[13], op1[14], op1[15]};
offset = 6'b0;
outstall = 1'b1;
- next_lsm_state = 3'b010;
+ next_lsm_state = 4'b0010;
end
- 3'b010: begin
+ 4'b0010: begin
rd_req = insn[20];
wr_req = ~insn[20];
casez(regs)
cur_reg = insn[23] ? cur_reg : 4'hF - cur_reg;
if(cur_reg == 4'hF && insn[22]) begin
next_outcpsr = spsr;
+ next_outcpsrup = 1;
end
- if (rw_wait)
- offset = prev_offset; /* whoops, do this one again */
- else
- offset = prev_offset + 6'h4;
+ offset = prev_offset + 6'h4;
offset_sel = insn[24] ? offset : prev_offset;
raddr = insn[23] ? op0 + {26'b0, offset_sel} : op0 - {26'b0, offset_sel};
if(insn[20]) begin
outstall = 1'b1;
if(next_regs == 16'b0) begin
- next_lsm_state = 3'b100;
+ next_lsm_state = 4'b0100;
end
end
- 3'b100: begin
+ 4'b0100: begin
+ outstall = 1;
+ next_outbubble = 0;
next_write_reg = insn[21] /* writeback */;
next_write_num = insn[19:16];
next_write_data = insn[23] ? op0 + {26'b0, prev_offset} : op0 - {26'b0, prev_offset};
- next_lsm_state = 3'b001;
+ next_lsm_state = 4'b1000;
$display("LDMSTM: Stage 3: Writing back");
end
+ 4'b1000: begin
+ outstall = 0;
+ next_lsm_state = 4'b0001;
+ end
default: $stop;
endcase
+ if ((lsm_state == 4'b0001) && flush) begin /* Reject it. */
+ outstall = 1'b0;
+ next_lsm_state = 4'b0001;
+ end
$display("LDMSTM: Decoded, bubble %d, insn %08x, lsm state %b -> %b, stall %d", inbubble, insn, lsm_state, next_lsm_state, outstall);
end
`DECODE_LDCSTC: if(!inbubble) begin
next_write_reg = 1'b1;
next_write_num = insn[15:12];
next_write_data = cp_read;
- end else
+ end else begin
next_outcpsr = {cp_read[31:28], cpsr[27:0]};
+ next_outcpsrup = 1;
+ end
end
if (cp_busy) begin
outstall = 1;