-
Notifications
You must be signed in to change notification settings - Fork 0
Home
//explain
This is a special register that keeps track of the memory address of the next instruction to be fetched and executed. After each instruction is fetched, the PC is typically incremented to point to the next sequential instruction. The PC is an ordinary 32 bit register. Its output PC points to the current instruction. Its input PC_Next indicates the address of the next instruction.
always @(posedge clk)
begin
if(~rst)
PC <= {32{1'b0}};
else
PC <= PC_Next;
end
While theinstruction is being executed, the processor must compute the address of the next instruction, PCNext. Because instructions are 32 bits = 4 bytes, the next instruction is at PC + 4. Figure below shows that datapath uses another adder to increment the PC by 4. The new address is written into the program counter on the next rising edge of the clock
module PC_Adder (a,b,c);
input [31:0]a,b;
output [31:0]c;
assign c = a + b;
endmodule
This is where the program's instructions are stored. It's assumed to have fixed contents, meaning the instructions cannot be modified during normal operation. This type of memory is often referred to as read-only memory (ROM). The instruction memory is accessed by providing it with an address (typically from the PC), and it outputs the instruction stored at that address.
The instruction memory behaves like a combinational circuit, meaning it produces an output based solely on its inputs (the address) without the need for a clock signal. This is because the fetching of instructions doesn't involve any internal state changes or sequential logic; it's a direct mapping from addresses to instructions.
The 32-element × 32-bit register file has two read ports and one write port. The read ports take 5-bit address inputs, A1 and A2, each specifying one of 2 = 32 registers as source 5 operands. They read the 32-bit register values onto read data outputs RD1 and RD2, respectively. The write port takes a 5-bit address input, A3; a 32-bit write data input, WD; a write enable input, WE3; and a clock. If the write enable is 1, the register file writes the data into the specified register on the rising edge of the clock.
Two inputs (operands) are sent to the Arithmetic Logic Unit (ALU) for processing, resulting in an output. The ALU performs operations based on instructions, which are determined by opcode (bits 0 to 6) and function fields (bits 31 to 25 and bits 14 to 12).
- Datapath designed to support data transfers required by instrutions
- Controller causes correct transfers to happen
- RISC-V consists of defining the following instruction formats: R-type, I-type, S-Type, B-Type, U-type, and J-type. R-type instructions operate on three registers

- R-type instructions use three registers as operands: two as sources, and one as a destination
- The 32-bit instruction has six fields: op, rs1, rs2, rd, funct3, and funct7.
- Each field is five or seven bits, as indicated. All R-type instructions have an opcode of 33.
- R-type instructions can handle add, sub, and, or and slt.
- All of these instructions read two registers from the register file, perform some ALU operation on them, and write the result back to a third register in the register file.
Instruction Format for some of the R-type instructions is shown below:
Ex: ADD X8,X12,X11
hexa format:
32'h00B60933; // 0000_0000_1011_0110_0111_0100_0011_0011
The control unit computes the control signals based on the opcode and funct fields of the instruction, Instr[31:25], Instr[14:12] and Instr[6:0].
All R-type instructions use the same main decoder values; they differ only in the ALU decoder output
assign RegWrite = (Op == 7'b0000011 | Op == 7'b0110011) ? 1'b1 :
1'b0 ;
assign ImmSrc = (Op == 7'b0100011) ? 2'b01 :
(Op == 7'b1100011) ? 2'b10 :
2'b00 ;
assign ALUSrc = (Op == 7'b0000011 | Op == 7'b0100011) ? 1'b1 :
1'b0 ;
assign MemWrite = (Op == 7'b0100011) ? 1'b1 :
1'b0 ;
assign ResultSrc = (Op == 7'b0000011) ? 1'b1 :
1'b0 ;
assign Branch = (Op == 7'b1100011) ? 1'b1 :
1'b0 ;
assign ALUOp = (Op == 7'b0110011) ? 2'b10 :
(Op == 7'b1100011) ? 2'b01 :
2'b00 ;
The main decoder computes most of the outputs from the opcode. It also determines a 2-bit ALUOp signal.When ALUOp is 00 or 01, the ALU should add or subtract, respectively. When ALUOp is 10, the decoder examines the function fields and operand bit to determine the ALUControl. The control signals for each instruction were described as we built the datapath.
assign ALUControl = (ALUOp == 2'b00) ? 3'b000 :
(ALUOp == 2'b01) ? 3'b001 :
((ALUOp == 2'b10) & (funct3 == 3'b000) & ({op[5],funct7[5]} == 2'b11)) ? 3'b001 :
((ALUOp == 2'b10) & (funct3 == 3'b000) & ({op[5],funct7[5]} != 2'b11)) ? 3'b000 :
((ALUOp == 2'b10) & (funct3 == 3'b010)) ? 3'b101 :
((ALUOp == 2'b10) & (funct3 == 3'b110)) ? 3'b011 :
((ALUOp == 2'b10) & (funct3 == 3'b111)) ? 3'b010 :
((ALUOp == 2'b10) & (funct3 == 3'b100)) ? 3'b111 :
3'b000 ;
//block diagram of alu and explanation with flags
assign {Cout,Sum} = (ALUControl[0] == 1'b0) ? A + B :
(A + ((~B)+1)) ;
assign Result = (ALUControl == 3'b000) ? Sum :
(ALUControl == 3'b001) ? Sum :
(ALUControl == 3'b010) ? A & B :
(ALUControl == 3'b011) ? A | B :
(ALUControl == 3'b101) ? {{31{1'b0}},(Sum[31])} :
(ALUControl == 3'b111) ? A ^ B : {32{1'b0}};
assign OverFlow = ((Sum[31] ^ A[31]) &
(~(ALUControl[0] ^ B[31] ^ A[31])) &
(~ALUControl[1]));
assign Carry = ((~ALUControl[1]) & Cout);
assign Zero = &(~Result);
assign Negative = Result[31];