Skip to content

Commit

Permalink
* added step7 with disassembler for testing what happens with Vivado …
Browse files Browse the repository at this point in the history
…(issue #87)

* fixed riscv_disasm that had explicit regerence to pipeline register instead
  of instruction parameter.
  • Loading branch information
BrunoLevy committed Jan 8, 2023
1 parent 9154327 commit 253a2df
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 5 deletions.
4 changes: 2 additions & 2 deletions FemtoRV/FIRMWARE/EXAMPLES/test_ir_remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ uint32_t sharp_read() {

int main() {
ir_init();
femtosoc_tty_init();
GL_set_font(&Font8x16);
// femtosoc_tty_init();
// GL_set_font(&Font8x16);
printf("%s IR remote\n",ir_protocol_name);
for(;;) {
uint32_t cmdaddr = ir_read();
Expand Down
2 changes: 1 addition & 1 deletion FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ It works with the following boards:
- IceStick
- IceBreaker
- ULX3S
- _to be added_ ARTY
- ARTY

If you do not have a board, you can run everything in simulation (but
it is not as fun).
Expand Down
2 changes: 1 addition & 1 deletion FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/pipelineZ.v
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

`define CONFIG_RV32M // RV32M instruction set (MUL,DIV,REM)

//`define CONFIG_DEBUG // debug mode, displays execution
`define CONFIG_DEBUG // debug mode, displays execution
// See "debugger" section in source
// to define breakpoints

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ function riscv_disasm_isLUI; input [31:0] I; riscv_disasm_isLUI =(I[6:0]==7
function riscv_disasm_isLoad; input [31:0] I; riscv_disasm_isLoad =(I[6:0]==7'b0000011); endfunction
function riscv_disasm_isStore; input [31:0] I; riscv_disasm_isStore =(I[6:0]==7'b0100011); endfunction
function riscv_disasm_isSYSTEM; input [31:0] I; riscv_disasm_isSYSTEM=(I[6:0]==7'b1110011); endfunction
function riscv_disasm_isRV32M; input [31:0] I; riscv_disasm_isRV32M=riscv_disasm_isALUreg(I) && FD_instr[25]; endfunction
function riscv_disasm_isRV32M; input [31:0] I; riscv_disasm_isRV32M=riscv_disasm_isALUreg(I) && I[25]; endfunction

/* Utility functions: register indices */
function [4:0] riscv_disasm_rs1Id; input [31:0] I; riscv_disasm_rs1Id = I[19:15]; endfunction
Expand Down
221 changes: 221 additions & 0 deletions FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/step7_with_disasm.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/**
* Step 7: Creating a RISC-V processor
* Assembly
* DONE*
*/

`default_nettype none
`include "clockworks.v"

module SOC (
input CLK, // system clock
input RESET, // reset button
output [4:0] LEDS, // system LEDs
input RXD, // UART receive
output TXD // UART transmit
);

wire clk; // internal clock
wire resetn; // internal reset signal, goes low on reset

// Plug the leds on register 1 to see its contents
reg [4:0] leds;
assign LEDS = leds;

reg [31:0] MEM [0:255];
reg [31:0] PC; // program counter
reg [31:0] instr; // current instruction

`include "riscv_assembly.v"
`include "riscv_disassembly.v"

integer myPC;

initial begin
PC = 0;
ADD(x0,x0,x0);
ADD(x1,x0,x0);
ADDI(x1,x1,1);
ADDI(x1,x1,1);
ADDI(x1,x1,1);
ADDI(x1,x1,1);
ADD(x2,x1,x0);
ADD(x3,x1,x2);
SRLI(x3,x3,3);
SLLI(x3,x3,31);
SRAI(x3,x3,5);
SRLI(x1,x3,26);
EBREAK();

for(myPC=0; myPC<13; myPC++) begin
$write("PC=%d ",myPC);
riscv_disasm(MEM[myPC],myPC);
$write("\n");
end

end

// See the table P. 105 in RISC-V manual

// The 10 RISC-V instructions
wire isALUreg = (instr[6:0] == 7'b0110011); // rd <- rs1 OP rs2
wire isALUimm = (instr[6:0] == 7'b0010011); // rd <- rs1 OP Iimm
wire isBranch = (instr[6:0] == 7'b1100011); // if(rs1 OP rs2) PC<-PC+Bimm
wire isJALR = (instr[6:0] == 7'b1100111); // rd <- PC+4; PC<-rs1+Iimm
wire isJAL = (instr[6:0] == 7'b1101111); // rd <- PC+4; PC<-PC+Jimm
wire isAUIPC = (instr[6:0] == 7'b0010111); // rd <- PC + Uimm
wire isLUI = (instr[6:0] == 7'b0110111); // rd <- Uimm
wire isLoad = (instr[6:0] == 7'b0000011); // rd <- mem[rs1+Iimm]
wire isStore = (instr[6:0] == 7'b0100011); // mem[rs1+Simm] <- rs2
wire isSYSTEM = (instr[6:0] == 7'b1110011); // special

// The 5 immediate formats
wire [31:0] Uimm={ instr[31], instr[30:12], {12{1'b0}}};
wire [31:0] Iimm={{21{instr[31]}}, instr[30:20]};
wire [31:0] Simm={{21{instr[31]}}, instr[30:25],instr[11:7]};
wire [31:0] Bimm={{20{instr[31]}}, instr[7],instr[30:25],instr[11:8],1'b0};
wire [31:0] Jimm={{12{instr[31]}}, instr[19:12],instr[20],instr[30:21],1'b0};

// Source and destination registers
wire [4:0] rs1Id = instr[19:15];
wire [4:0] rs2Id = instr[24:20];
wire [4:0] rdId = instr[11:7];

// function codes
wire [2:0] funct3 = instr[14:12];
wire [6:0] funct7 = instr[31:25];

// The registers bank
reg [31:0] RegisterBank [0:31];
reg [31:0] rs1; // value of source
reg [31:0] rs2; // registers.
wire [31:0] writeBackData; // data to be written to rd
wire writeBackEn; // asserted if data should be written to rd

`ifdef BENCH
integer i;
initial begin
for(i=0; i<32; ++i) begin
RegisterBank[i] = 0;
end
end
`endif

// The ALU
wire [31:0] aluIn1 = rs1;
wire [31:0] aluIn2 = isALUreg ? rs2 : Iimm;
reg [31:0] aluOut;
wire [4:0] shamt = isALUreg ? rs2[4:0] : instr[24:20]; // shift amount

// ADD/SUB/ADDI:
// funct7[5] is 1 for SUB and 0 for ADD. We need also to test instr[5]
// to make the difference with ADDI
//
// SRLI/SRAI/SRL/SRA:
// funct7[5] is 1 for arithmetic shift (SRA/SRAI) and
// 0 for logical shift (SRL/SRLI)
always @(*) begin
case(funct3)
3'b000: aluOut = (funct7[5] & instr[5]) ?
(aluIn1 - aluIn2) : (aluIn1 + aluIn2);
3'b001: aluOut = aluIn1 << shamt;
3'b010: aluOut = ($signed(aluIn1) < $signed(aluIn2));
3'b011: aluOut = (aluIn1 < aluIn2);
3'b100: aluOut = (aluIn1 ^ aluIn2);
3'b101: aluOut = funct7[5]? ($signed(aluIn1) >>> shamt) :
($signed(aluIn1) >> shamt);
3'b110: aluOut = (aluIn1 | aluIn2);
3'b111: aluOut = (aluIn1 & aluIn2);
endcase
end

// The state machine
localparam FETCH_INSTR = 0;
localparam FETCH_REGS = 1;
localparam EXECUTE = 2;
reg [1:0] state = FETCH_INSTR;

// register write back
assign writeBackData = aluOut;
assign writeBackEn = (state == EXECUTE && (isALUreg || isALUimm));

always @(posedge clk) begin
if(!resetn) begin
PC <= 0;
state <= FETCH_INSTR;
end else begin
if(writeBackEn && rdId != 0) begin
RegisterBank[rdId] <= writeBackData;
// For displaying what happens.
if(rdId == 1) begin
leds <= writeBackData;
end
`ifdef BENCH
$display("x%0d <= %b",rdId,writeBackData);
`endif
end
case(state)
FETCH_INSTR: begin
instr <= MEM[PC[31:2]];
state <= FETCH_REGS;
end
FETCH_REGS: begin
rs1 <= RegisterBank[rs1Id];
rs2 <= RegisterBank[rs2Id];
state <= EXECUTE;
end
EXECUTE: begin
if(!isSYSTEM) begin
PC <= PC + 4;
end
state <= FETCH_INSTR;
`ifdef BENCH
if(isSYSTEM) $finish();
`endif
end
endcase
end
end

`ifdef BENCH
always @(posedge clk) begin
if(state == FETCH_REGS) begin
case (1'b1)
isALUreg: $display(
"ALUreg rd=%d rs1=%d rs2=%d funct3=%b",
rdId, rs1Id, rs2Id, funct3
);
isALUimm: $display(
"ALUimm rd=%d rs1=%d imm=%0d funct3=%b",
rdId, rs1Id, Iimm, funct3
);
isBranch: $display("BRANCH");
isJAL: $display("JAL");
isJALR: $display("JALR");
isAUIPC: $display("AUIPC");
isLUI: $display("LUI");
isLoad: $display("LOAD");
isStore: $display("STORE");
isSYSTEM: $display("SYSTEM");
endcase
if(isSYSTEM) begin
$finish();
end
end
end
`endif

// Gearbox and reset circuitry.
Clockworks #(
.SLOW(19) // Divide clock frequency by 2^19
)CW(
.CLK(CLK),
.RESET(RESET),
.clk(clk),
.resetn(resetn)
);

assign TXD = 1'b0; // not used for now

endmodule

0 comments on commit 253a2df

Please sign in to comment.