About Me
Welcome to my blog! This is where I collect my observations and notes on programming and technology. The main subjects range from implementation details to broader ideas about programming.
Main Topics
- Engineering Projects: Exploring implementation details and how technical systems work.
- C/C++: Notes on language features and programming techniques.
- The Programmer’s Perspective: Ideas about developing a career and a way of thinking as a programmer.
For more, visit the categories page.
Contact
If you have questions or would like to discuss something, please get in touch through the About page.
Thank you for reading and for your support. I hope these notes help you on your own technical journey!
Fundamental RISC-V Design Principles
Why parallelism matters
Programmers need a clear understanding of explicit parallel programming. Parallelism appears at instruction, data, and thread levels, with corresponding responsibilities in hardware, compilers, and operating systems.
Dynamic power depends on load capacitance, voltage squared, and clock frequency. Historically, lowering voltage helped control power while increasing frequency improved performance. The power wall makes further voltage reduction difficult.
Open observations: single-core performance and power are tied to instruction-level parallelism and long memory latency. Hierarchical multiprocessor interconnects also raise questions about power and ground distribution.
The practical difficulties of parallel execution include balancing work and minimizing communication and synchronization costs.
Diminishing returns and Amdahl’s law
Improving one part of a computer does not improve total performance by the same factor. The achievable benefit is limited by the fraction of execution affected. Amdahl’s law estimates this bound, including the maximum benefit of parallelizing a program.
Two tempting claims deserve rejection: low utilization does not necessarily mean proportionally low power, and performance-oriented and energy-oriented design are not unrelated. Even if an optimized component consumes more power, a shorter execution time can reduce total system energy.
Performance should be evaluated using instruction count, CPI, and clock-cycle time together. MIPS is another rate measure:
MIPS = instruction count / (execution time × 10^6)
It does not by itself capture differences in instruction work or program behavior. A central design idea is to make the common case fast.
Three hardware design principles
Simplicity favors regularity
RISC-V arithmetic instructions have regular operand roles, commonly two source registers and one destination. This regularity helps implementation; it does not mean every instruction has exactly the same operands.
Smaller can be faster
A larger register file can increase access delay, including longer signal paths. Arithmetic operates on register operands, so data in memory must first be transferred with load instructions.
RISC-V uses byte addresses. Adjacent 64-bit doublewords are eight bytes apart, and a doubleword address identifies a byte location in that object. These notes use a little-endian execution environment: the least significant byte occupies the lowest address.
Good design requires compromises
The instruction formats illustrate a balance between regular fields and useful operand ranges.
From R-type to I-type
An R-type instruction has three register fields, each five bits wide, identifying registers x0 through x31. Its 32-bit layout is:
| Field | funct7 | rs2 | rs1 | funct3 | rd | opcode |
|---|---|---|---|---|---|---|
| Bits | 7 | 5 | 5 | 3 | 5 | 7 |
A five-bit field is too small for many useful constants. I-type instructions provide a 12-bit immediate and two register fields, supporting operations such as addi and loads:
| Field | imm | rs1 | funct3 | rd | opcode |
|---|---|---|---|---|---|
| Bits | 12 | 5 | 3 | 5 | 7 |
Editorial clarification: the source’s I-type diagram labels the source register rs2; it is rs1.
S-type instructions
Stores need two source registers and an immediate, but no destination register:
| Field | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode |
|---|---|---|---|---|---|---|
| Bits | 7 | 5 | 5 | 3 | 5 | 7 |
The split immediate allows rs1 and rs2 to retain their usual positions. Keeping register fields fixed reduces decoding complexity.
An original study question asks why S-type and I-type divide their fields differently despite both using immediates. Their register roles explain the distinction: I-type needs rd and rs1; S-type needs rs1 and rs2.
Another observation is that addi uses a signed two’s-complement immediate. Adding a representable negative immediate covers the usual role of a separate subtract-immediate instruction.
Stored programs and decisions
Two fundamental ideas underlie the stored-program computer: instructions have numerical representations, and programs reside in memory just as data do. Decision-making distinguishes a programmable computer from a simple calculator.
A basic block is a straight-line instruction sequence with no internal branch entry or exit; its boundaries may contain a branch target or terminating branch. Dividing a program into basic blocks is a basic compiler task.
Conditional branches such as beq, bne, blt, bge, bltu, and bgeu use B-type encoding. Although they include an immediate displacement, they are not I-type instructions.
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !