I made a single-cycle RISC CPU in Verilog, and it works well on a real FPGA I have. It has multiple components that communicate over an internal bus. One of these components is a programmable timer, that has a prescaler and counter, and has multiple ways of counting time. It works fine, and can generate PWM output (verified).
My problem lies with the concept of timer generated interrupts: Many microcontrollers can generate internal interrupt signal when the timer counter resets, and so does my timer. It has an interrupt line, that it pulls low when it wraps around:
always @(posedge clk or negedge reset) begin if(!reset) begin timer_irq <= 1'b1; end else begin if ((prescaler_value >= (prescaler_threshold)) && (counter_value >= (counter_threshold))) begin timer_irq <= 1'b0; end else begin timer_irq <= 1'b1; end end end
This logic works fine conceptionally (verified in simulator and with a logic analyzer on real hardware: The interrupt signal is generated when it should be), but it will not be sampled by my CPU, since it also samples the interrupts in the write-back phase on rising clock edge:
always @(posedge clk) begin // ... if (((~irq_sources & irq_mask) != 3'b0) && (in_isr == 1'b0)) begin ipc <= pc_next; pc <= irq_target; in_isr <= 1'b1; end else begin pc <= pc_next; end end
So the interrupt goes low when my clock goes high, and the FPGA does not sample this as an interrupt. It basically "just misses" the interrupt. My interrupt implementation works fine with external interrupts. Maybe the problem appears because of propagation times? Does anybody have a hint how I could design this better?
Here is a GTKWave plot of the problem: The interrupt is only "sampled" one clock cycle later (the main program is idling at address 0x0028, and the ISR is at address 0x002C)