Program counter
What Are Program Counters?
They are simply a register that holds a value. And in this case, the value is the address of the instruction to fetch.
You can think of it as something that takes 2 things: next instruction and reset. There is another input clk that says you can also do something when according to me.
Then what are the actions? If the reset signal is high, then it stores the value 32b'0 or simply resets to 0. This means the next instruction to fetch is at the start of the program, and the program starts from the top again.
Otherwise, if it is low, then PC will now have the next instruction.
What clk does in all of this? Well, when you have always @(posedge clk), then you are simply telling program counter “Hey, whatever you do, just do it when the clock signal is on the rising edge”. Or, when you have always @(negedge clk), then you tell the PC “Hey, do your thing when the clock signal is on the falling edge :D”.
Having a clk is very important in digital logic circuits, this helps us avoid glitches and racing conditions. For now, you can just think that this prevents some errors and provides predictibility.
How to Write a Pc?
Here is a sample code for a simple pc in verilog:
// pc.v
module pc (
input wire clk, // Clock signal
input wire reset, // Asynchronous reset, active high
input wire [31:0] next_pc, // Next PC value (from adder/MUX)
output reg [31:0] current_pc // Holds the current PC value
);
// On the rising edge of clk or an asserted reset...
always @(posedge clk or posedge reset) begin
if (reset)
current_pc <= 32'b0; // Initialize PC to 0 after reset
else
current_pc <= next_pc; // Otherwise, load next_pc
end
endmoduleThe current_pc here is just the value our pc holds and next_pc is the address of the next instruction. This is fed from an adder or a MUX, depending on your program logic. If you are doing something linear (a sequential flow), then the next_pc is just current_pc + 4. But if you have some subroutines (which means you are jumping to another branch, or in a simpler term, if you have conditionals like if in your code), then this comes from MUX. To understand more about branching you can read Branching in RISC V
Program counters are main part of fetch cycle along with instruction memory.