Encode in q0 LSB if interrupted instruction is compressed

This commit is contained in:
Clifford Wolf 2016-06-01 12:39:00 +02:00
parent fd18475e23
commit 490a734519
3 changed files with 35 additions and 16 deletions

View File

@ -463,6 +463,10 @@ address and `q1` contains a bitmask of all IRQs to be handled. This means one
call to the interrupt handler needs to service more than one IRQ when more than
one bit is set in `q1`.
When support for compressed instructions is enabled, then the LSB of q0 is set
when the interrupted instruction is a compressed instruction. This can be used if
the IRQ handler wants to decode the interrupted instruction.
Registers `q2` and `q3` are uninitialized and can be used as temporary storage
when saving/restoring register values in the IRQ handler.

View File

@ -13,6 +13,27 @@ uint32_t *irq(uint32_t *regs, uint32_t irqs)
static unsigned int ext_irq_5_count = 0;
static unsigned int timer_irq_count = 0;
// checking compressed isa q0 reg handling
{
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
uint32_t instr = *(uint16_t*)pc;
if ((instr & 3) == 3)
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
if (((instr & 3) != 3) != (regs[0] & 1)) {
print_str("Mismatch between q0 LSB and decoded instruction word! q0=0x");
print_hex(regs[0], 8);
print_str(", instr=0x");
if ((instr & 3) == 3)
print_hex(instr, 8);
else
print_hex(instr, 4);
print_str("\n");
__asm__ volatile ("sbreak");
}
}
if ((irqs & (1<<4)) != 0) {
ext_irq_4_count++;
// print_str("[EXT-IRQ-4]");
@ -30,21 +51,11 @@ uint32_t *irq(uint32_t *regs, uint32_t irqs)
if ((irqs & 6) != 0)
{
uint32_t pc = regs[0] - 2;
uint16_t *instr_hwords = (uint16_t*)pc;
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
uint32_t instr = *(uint16_t*)pc;
if ((*instr_hwords & 3) == 3) {
pc -= 2;
instr = (instr << 16) | *(uint16_t*)pc;
} else {
int cnt_3 = 0;
while ((*(--instr_hwords) & 3) == 3 && cnt_3 < 20) cnt_3++;
if ((cnt_3 & 1) != 0) {
pc -= 2;
instr = (instr << 16) | *(uint16_t*)pc;
}
}
if ((instr & 3) == 3)
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
print_str("\n");
print_str("------------------------------------------------------------\n");

View File

@ -128,6 +128,7 @@ module picorv32 #(
wire [31:0] next_pc;
reg irq_delay;
reg irq_active;
reg [31:0] irq_mask;
reg [31:0] irq_pending;
@ -1093,7 +1094,7 @@ module picorv32 #(
clear_prefetched_high_word = COMPRESSED_ISA;
end
assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_active || !(irq_pending & ~irq_mask));
assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask));
always @(posedge clk) begin
trap <= 0;
@ -1155,6 +1156,7 @@ module picorv32 #(
pcpi_valid <= 0;
pcpi_timeout <= 0;
irq_active <= 0;
irq_delay <= 0;
irq_mask <= ~0;
next_irq_pending = 0;
irq_state <= 0;
@ -1186,7 +1188,7 @@ module picorv32 #(
cpuregs[latched_rd] <= latched_stalu ? alu_out_q : reg_out;
end
ENABLE_IRQ && irq_state[0]: begin
cpuregs[latched_rd] <= current_pc;
cpuregs[latched_rd] <= current_pc | latched_compr;
current_pc = PROGADDR_IRQ;
irq_active <= 1;
mem_do_rinst <= 1;
@ -1210,10 +1212,11 @@ module picorv32 #(
latched_rd <= decoded_rd;
latched_compr <= compressed_instr;
if (ENABLE_IRQ && ((decoder_trigger && !irq_active && |(irq_pending & ~irq_mask)) || irq_state)) begin
if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin
irq_state <=
irq_state == 2'b00 ? 2'b01 :
irq_state == 2'b01 ? 2'b10 : 2'b00;
latched_compr <= latched_compr;
if (ENABLE_IRQ_QREGS)
latched_rd <= irqregs_offset | irq_state[0];
else
@ -1230,6 +1233,7 @@ module picorv32 #(
end else
if (decoder_trigger) begin
`debug($display("-- %-0t", $time);)
irq_delay <= irq_active;
reg_next_pc <= current_pc + (compressed_instr ? 2 : 4);
if (ENABLE_COUNTERS) begin
count_instr <= count_instr + 1;