krabo0om / pauloBlaze

A plain VHDL implementation of a small microprocessor fully compatible with the ISA of the well known PicoBlaze by Ken Chapman.
Apache License 2.0
21 stars 10 forks source link

Interrupt processing does not work correctly #10

Open jotego opened 3 years ago

jotego commented 3 years ago

BRAM memories in FPGA tend to have an output register, so they behave like:

always @(posedge clk) data <= memory[ address ];

If you remove the register the memory element will get synthesized as logic elements (instead of a BRAM). That is something we should avoid.

When operated off a BRAM with output register, pauloBlaze seems to lose track of internal signals upon returning from an interrupt:

image

iaddr (instruction address) correctly goes back to 2 upon returning from the interrupt. But when the program tries to output to a port the three signals in orange won't overlap, so the write_strobe does not occur, and the program fails.

If I remove the register output and resimulate I get:

image

In this case, the signals in orange get correctly aligned after returning from the interrupt, and the write_strobe occurs.

I have not verified this with the original picoblaze6, but I guess the original 2-clock per instruction approach may have been related to enabling this type of BRAM. It looks like most of pauloBlaze work correctly with a registered BRAM, so it may only need a minor tweak to correct this behaviour.

I guess this may also happen when returning from a call, but I didn't test that case.

jotego commented 3 years ago

Looking more into this, it actually looks like the interrupt is not processed correctly with the asynchronous RAM (the RAM without the ouput register)

In this plot you can see the registered RAM at the top (the instruction bus changes one cycle after the iaddr bus changes) and asynchronous one at the bottom (the instruction bus changes with iaddr). The interrupt jump is not parsed correctly and iaddr goes from 3FF to 400, 401, 402... but because I am using a 10 bit memory, 400 is actually the same as 10'h000, so the program had just restarted. Thus, the asynchronous RAM is not working either -I'm fine with that, though. image

Going back to the synchronous case, you can see how it gets lost at the interruption. All instructions had been executing at 2 cycles per instruction but when the interrupt comes there is an extra cycle after iaddr=3FF where iaddr=400. That one clock extra cycle seems to be what makes clk2 go out of phase and beaks the system.