Aditya Patel
The Program Counter (PC) is a fundamental component of any processor, responsible for tracking which instruction should be fetched and executed next. This implementation provides:
- 10-bit address space (1024 instruction addresses)
- Multiple control flow mechanisms (branches, jumps, JAL)
- Pipeline stall support for hazard management
- Scan chain integration for design-for-testability (DFT)
- Synchronous operation with clock and reset
- This design was synthesized and used to generate an APR (Automatic Place and Route) layout using:
Cadence Virtuoso - Physical design and verification Synopsys Design Compiler - RTL synthesis and optimization
This program counter design provides all the functionality:
- Sequential Execution: Automatic increment by 1 for normal instruction flow
- Conditional Branching: PC-relative branches based on condition flags
- Unconditional Jumps: Register-indirect jumps (JCOND)
- Jump and Link (JAL): Subroutine call support with return address
- Pipeline Stall: Holds current PC value during data hazards
- Signed Displacement: 8-bit sign-extended branch offsets
- Scan Chain Support: Full DFT integration for manufacturing test
┌─────────────────────────────────────┐ │ │ │ Program Counter │ │ (10-bit) │ │ │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────┐ │ Next PC Calculation Logic │ │ (Combinational) │ │ │ │ Priority: │ │ 1. Scan Enable → Shift │ │ 2. Stall → Hold │ │ 3. BCOND → PC + Displacement │ │ 4. JCOND → Register Value │ │ 5. JAL → Register Value │ │ 6. Default → PC + 1 │ └──────────────┬──────────────────┘ │ ┌──────────────▼──────────────────┐ │ PC Register (Sequential) │ │ @ posedge clk │ └──────────────┬──────────────────┘ │ ┌──────────────▼──────────────────┐ │ pc_out[9:0] │ │ (Current Instruction Address) │ └─────────────────────────────────┘
Timing Diagrams and Example execution of different modes:
Sequential Execution:
Operation: PC = PC + 1 Condition: No control signals active Example: PC = 0x010 → Next PC = 0x011
Clock : |‾‾||‾‾||‾‾||‾‾||‾‾||‾‾| Reset : ‾‾||_________________________ Control : ________________________________ (all low) PC : X | 000 | 001 | 002 | 003 | 004 |
Branch Condition(BCOND):
Operation: PC = PC + sign_extend(disp[7:0]) Condition: bcond = 1 Example: PC = 0x020, disp = 0xFC (-4) → Next PC = 0x01C
Clock : |‾‾||‾‾||‾‾||‾‾||‾‾| bcond : |‾‾‾‾|______________ disp : ----< +5 >-------------------- PC : X | 010 | 011 | 016 | 017 | (branch taken at 011 → 016)
Jump condition (JCOND):
Operation: PC = rdest[9:0] Condition: jcond = 1 Example: PC = 0x100, rdest = 0x2F5 → Next PC = 0x2F5
Clock : |‾‾||‾‾||‾‾||‾‾| jcond : |‾‾‾‾|________ rdest : ----<200>------------ PC : X | 040 | 200 | 201 | PC+1 : ----<041>------------- (041 stored as return address)
Jump and Link Condition:
Operation: PC = rdest[9:0] Side Effect: pc_plus_1 = old_PC + 1 (available for link register) Condition: jal = 1 Example: PC = 0x040, rdest = 0x200 → Next PC = 0x200, pc_plus_1 = 0x041
Clock : |‾‾||‾‾||‾‾||‾‾| jal : |‾‾‾‾|________ rdest : ----<200>------------ PC : X | 040 | 200 | 201 | PC+1 : ----<041>------------- (041 stored as return address) Note: A separate register called "Rlink" will also icnrement by 1 for JAL operation, which is not shown here.
Stall(a No operation (noop) can be manually put into the IMEM machine code file to save some hardware costs):
Operation: PC = PC (hold current value) Condition: stall = 1 Example: PC = 0x055 → Next PC = 0x055 (unchanged)
Clock : |‾‾||‾‾||‾‾||‾‾|__|‾‾| stall : |‾‾‾‾‾‾‾‾‾‾‾‾|______ PC : X | 050 | 050 | 050 | 051 | (PC frozen during stall)
Scan Chain Mode(DFT):
Operation: PC = {PC[8:0], scan_in} Output: scan_out = PC[9] Condition: scan_en = 1