diff --git a/FemtoRV/FIRMWARE/EXAMPLES/test_ir_remote.c b/FemtoRV/FIRMWARE/EXAMPLES/test_ir_remote.c index ecad6bc5..c01ed446 100644 --- a/FemtoRV/FIRMWARE/EXAMPLES/test_ir_remote.c +++ b/FemtoRV/FIRMWARE/EXAMPLES/test_ir_remote.c @@ -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(); diff --git a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/README.md b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/README.md index 93aedb1d..de11e766 100644 --- a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/README.md +++ b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/README.md @@ -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). diff --git a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/pipelineZ.v b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/pipelineZ.v index e3bdaea2..ee80ce74 100644 --- a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/pipelineZ.v +++ b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/pipelineZ.v @@ -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 diff --git a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/riscv_disassembly.v b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/riscv_disassembly.v index d2d801f3..7935f6c9 100644 --- a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/riscv_disassembly.v +++ b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/riscv_disassembly.v @@ -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 diff --git a/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/step7_with_disasm.v b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/step7_with_disasm.v new file mode 100644 index 00000000..af2926f6 --- /dev/null +++ b/FemtoRV/TUTORIALS/FROM_BLINKER_TO_RISCV/step7_with_disasm.v @@ -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 +