OpenCores
URL https://opencores.org/ocsvn/fwrisc/fwrisc/trunk

Subversion Repositories fwrisc

[/] [fwrisc/] [trunk/] [rtl/] [fwrisc.sv] - Rev 2

Compare with Previous | Blame | View Log

/****************************************************************************
 * fwrisc.sv
 *
 * Copyright 2018 Matthew Ballance
 * 
 * Licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.  See
 * the License for the specific language governing
 * permissions and limitations under the License.
 ****************************************************************************/
`include "fwrisc_defines.vh"


/**
 * Module: fwrisc
 * 
 * TODO: Add module documentation
 */
module fwrisc (
                input                   clock,
                input                   reset,
                
                output[31:0]    iaddr,
                input[31:0]             idata,
                output                  ivalid,
                input                   iready,
                
                output[31:0]    daddr,
                output[31:0]    dwdata,
                input[31:0]             drdata,
                output[3:0]             dstrb,
                output                  dwrite,
                output                  dvalid,
                input                   dready
                );

        reg[31:0]                       instr;
        
        
        reg[3:0]                        state;
        reg[31:2]                       pc;
        reg[4:0]                        shift_amt;
        wire[31:2]                      pc_plus4;
        reg[31:2]                       pc_next;
        
        assign pc_plus4 = (pc + 1'b1);

        assign iaddr = {pc, 2'b0};
        assign ivalid = (state == `FETCH && !reset);

        /****************************************************************
         * Instruction and Cycle counters
         ****************************************************************/
        reg [7:0]                       cycle_counter = 1;
        wire                            cycle_counter_ovf = cycle_counter[7];
        reg [7:0]                       instr_counter = 0;
        always @(posedge clock) begin
                if (reset || state == `CYCLE_COUNT_UPDATE_1) begin
                        cycle_counter <= 1;
                end else begin
                        cycle_counter <= cycle_counter + 1;
                end
        end
        
        always @(posedge clock) begin
                if (reset || state == `INSTR_COUNT_UPDATE_1) begin
                        instr_counter <= 0;
                end else if (state == `EXECUTE) begin
                        instr_counter <= instr_counter + 1;
                end
        end
        
        // ALU signals
        reg[31:0]                                       alu_op_a;
        reg[31:0]                                       alu_op_b;
        reg[2:0]                                        alu_op;
        wire[31:0]                                      alu_out;
        wire                                            alu_carry;
        wire                                            alu_eqz;
        
        always @(posedge clock) begin
                if (reset) begin
                        state <= `FETCH;
                        instr <= 0;
                        pc <= (32'h8000_0000 >> 2);
                end else begin
                        if (ivalid && iready) begin
                                instr <= idata;
                        end
                        
                        case (state)
                                default /*`FETCH*/: begin
                                        if (ivalid && iready) begin
                                                state <= `DECODE;
                                                instr <= idata;
                                        end
                                end
                                
                                `DECODE: begin
                                        // NOP: wait for decode to occur
                                        if (op_csr) begin
                                                state <= `CSR_1;
                                        end else if (op_shift) begin
                                                state <= `SHIFT_1;
                                        end else begin
                                                state <= `EXECUTE;
                                        end
                                end
                                
                                `CSR_1: begin
                                        state <= `CSR_2;
                                end
                                
                                `CSR_2: begin
                                        state <= `EXECUTE;
                                end
                                
                                `EXECUTE: begin
                                        if (exception) begin
                                                // Exception Handling:
                                                // - Write the address to MTVAL in EXECUTE
                                                // - Write the cause to MTCAUSE in EXECEPTION_1
                                                // - Jump to FETCH to execute vector address
                                                state <= `EXCEPTION_1;
                                        end else if (op_ld) begin
                                                state <= `MEMR;
                                        end else if (op_st) begin
                                                state <= `MEMW;
                                        end else if (cycle_counter_ovf) begin
                                                pc <= pc_next;
                                                state <= `CYCLE_COUNT_UPDATE_1;
                                        end else begin
                                                pc <= pc_next;
                                                state <= `FETCH;
                                        end
                                end
                                
                                `MEMW, `MEMR: begin
                                        if (dvalid && dready) begin
                                                pc <= pc_next;
                                                // Steal a few cycles to update the cycle counter
                                                if (cycle_counter[7]) begin
                                                        state <= `CYCLE_COUNT_UPDATE_1;
                                                end else begin
                                                        state <= `FETCH;
                                                end
                                        end
                                end
                        
                                // Capture the fault address
                                `EXCEPTION_1: begin
                                        state <= `EXCEPTION_2;
                                end
                        
                                // Capture the EPC
                                `EXCEPTION_2: begin
                                        // Contains MTVEC
                                        pc <= ra_rdata[31:2];
                                        state <= `FETCH;
                                end
                        
                                // Latch the shift amount into the shift_amt register
                                `SHIFT_1: begin
                                        if (op_shift_reg) begin
                                                shift_amt <= (rb_rdata[4:0] - 1'b1);
                                                if (|rb_rdata[4:0]) begin
                                                        state <= `SHIFT_2;
                                                end else begin
                                                        state <= `EXECUTE;
                                                end
                                        end else begin
                                                shift_amt <= (rs2 - 1'b1);
                                                if (|rs2) begin
                                                        state <= `SHIFT_2;
                                                end else begin
                                                        state <= `EXECUTE;
                                                end
                                        end
                                end
                                
                                `SHIFT_2: begin
                                        // Shift 
                                        if (|shift_amt) begin
                                                shift_amt <= shift_amt - 1;
                                        end else begin
                                                state <= `EXECUTE;
                                        end
                                end
                        
                                /**
                                 * Write the cycle count to CSR_tmp. 
                                 * Setup a read of CSR_tmp and the counter CSR
                                 */
                                `CYCLE_COUNT_UPDATE_1: begin
                                        state <= `CYCLE_COUNT_UPDATE_2;
                                end
                        
                                /**
                                 * Add CSR_tmp and the counter CSR
                                 */
                                `CYCLE_COUNT_UPDATE_2: begin
                                        state <= `INSTR_COUNT_UPDATE_1;
                                end
                                
                                `INSTR_COUNT_UPDATE_1: begin
                                        state <= `FETCH;
                                end
                                
                        endcase
                end
        end
        

        wire op_branch_ld_st_arith = (instr[3:0] == 4'b0011);
        wire op_fence     = (instr[3:0] == 4'b1111);
        wire op_ld        = (op_branch_ld_st_arith && instr[6:4] == 3'b000);
        wire op_arith_imm = (op_branch_ld_st_arith && instr[6:4] == 3'b001);
        wire op_shift_imm = (op_arith_imm && instr[13:12] == 2'b01);
        wire op_shift_reg = (op_arith_reg && instr[13:12] == 2'b01);
        wire op_shift     = (op_shift_imm || op_shift_reg);
        wire op_st        = (op_branch_ld_st_arith && instr[6:4] == 3'b010);
        wire op_ld_st     = (op_ld || op_st);
        wire op_arith_reg = (op_branch_ld_st_arith && instr[6:4] == 3'b011);
        wire op_branch    = (op_branch_ld_st_arith && instr[6:4] == 3'b110);
        wire op_jal       = (instr[6:0] == 7'b1101111);
        wire op_jalr      = (instr[6:0] == 7'b1100111);
        wire op_auipc     = (instr[6:0] == 7'b0010111);
        wire op_lui       = (instr[6:0] == 7'b0110111);
        wire op_sys       = (op_branch_ld_st_arith && instr[6:4] == 3'b111);
        wire op_sys_prv   = !(|instr[14:12]);
//      wire op_ecall     = (op_sys && op_sys_prv && instr[24:21] == 4'b0000);
        wire op_ecall     = (op_sys && op_sys_prv && !instr[28]);
        // Seems the compiler that Zephyr uses encodes eret as 0x10000073
//      wire op_eret      = (op_sys && op_sys_prv && instr[24:20] == 5'b00010);
        wire op_eret      = (op_sys && op_sys_prv && instr[28]);
        
        wire op_csr       = (op_sys && |instr[14:12]);
        wire op_csrr_cs   = (op_csr && instr[13]);
        wire op_csrrc     = (op_csr && instr[13:12] == 2'b11);
        wire op_csrrs     = (op_csr && instr[13:12] == 2'b10);
        wire [11:0]     csr   = instr[31:20];
        reg [5:0]       csr_addr;

        wire[5:0] CSR_MTVEC   = 6'h25;
        wire[5:0] CSR_MEPC    = 6'h29;
        wire[5:0] CSR_MCAUSE  = 6'h2A;
        wire[5:0] CSR_MTVAL   = 6'h2B;
        wire[5:0] CSR_MCYCLE  = 6'h36;
        wire[5:0] CSR_MINSTR  = 6'h37;
        wire[5:0] CSR_MCYCLEH = 6'h38;
        wire[5:0] CSR_MINSTRH = 6'h39;
        wire[5:0] CSR_tmp     = 6'h3F;
        // 0x300-0x306 => 0x20-0x26 (32-38)
        // 0x340-0x344 => 0x28-0x2C (40-44)
        // 0xF11-0xF14 => 0x31-0x34 (49-52)
        // 0xB00       => 0x36
        // 0xB02       => 0x37
        // 0xB80       => 0x38
        // 0xB82       => 0x39
        // CSR_tmp     => 0x3F (63)
        always @* begin
                case (csr[11:8])
                        4'h3: begin
                                if (csr[7:4] == 3'b0) begin
                                        csr_addr = {2'b10, csr[3:0]};
                                end else begin
                                        csr_addr = {3'b101, csr[2:0]};
                                end
                        end
                        4'hb: begin // counters
                                if (csr[7]) begin // 0xB8x
                                        csr_addr = {2'd3, 3'b100, csr[1]};
                                end else begin
                                        csr_addr = {2'd3, 3'b011, csr[1]};
                                end
                        end
                        default: begin // 4'hf
                                csr_addr = {2'b11, csr[3:0]};
                        end
                endcase
        end
        
        wire[31:0]      jal_off = (instr[31])?{{21{1'b1}}, instr[31], instr[19:12], instr[20], instr[30:21],1'b0}:
                                                                                        {{21{1'b0}}, instr[31], instr[19:12], instr[20], instr[30:21],1'b0};
        wire[31:0]      auipc_imm_31_12 = {instr[31:12], {12{1'b0}}};
        wire[31:0]      imm_11_0 = (instr[31])?{{22{1'b1}}, instr[31:20]}:{{22{1'b0}}, instr[31:20]};
        wire[31:0]      st_imm_11_0 = (instr[31])?
                {{22{1'b1}}, instr[31:25], instr[11:7]}:
                {{22{1'b0}}, instr[31:25], instr[11:7]};
        
        wire[31:0]      imm_lui = {instr[31:12], 12'h000};
        wire[31:0]              imm_branch = (instr[31])?
                {{19{1'b1}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0}:
                {{19{1'b0}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0};
        wire[31:0]              zero = 32'h00000000;
        
        // RS1, RS2, and RD are always in the same place
        wire[4:0]               rs1 = instr[19:15];
        wire[4:0]               rs2 = instr[24:20];
        wire[4:0]               rd  = instr[11:7];
        

        reg[5:0]                ra_raddr;
        reg[5:0]                rb_raddr;
        wire[31:0]              ra_rdata;
        wire[31:0]              rb_rdata;
        reg[5:0]                rd_waddr;
        reg[31:0]               rd_wdata;
        reg                             rd_wen;
        
        
        // Comparator signals
        wire[31:0]                                      comp_op_a = ra_rdata;
        reg[31:0]                                       comp_op_b;
        reg[1:0]                                        comp_op;
        wire                                            comp_out;
        wire                                            branch_cond;
        
        // Exception signals
        wire                                            exception;
        reg                                             misaligned_addr;
        
        fwrisc_comparator u_comp (
                .clock  (clock          ), 
                .reset  (reset          ), 
                .in_a   (comp_op_a  ), 
                .in_b   (comp_op_b  ), 
                .op     (comp_op    ), 
                .out    (comp_out   ));
        
        always @* begin
                if (op_arith_imm) begin
                        comp_op_b = imm_11_0;
                end else begin
                        comp_op_b = rb_rdata;
                end
                if (op_arith_imm || op_arith_reg) begin
                        if (instr[14:12] == 3'b010) begin
                                comp_op = `COMPARE_LT;  // SLT, SLTI
                        end else begin
                                comp_op = `COMPARE_LTU; // SLTU, SLTUI
                        end
                end else begin
                        case (instr[14:13]) 
                                2'b00: comp_op = `COMPARE_EQ;  // BEQ, BNE
                                2'b10: comp_op = `COMPARE_LT;  // BLT, BGE
                                default: /*2'b11: */comp_op = `COMPARE_LTU; // BLTU BGEU
                        endcase
                end
        end
        assign branch_cond = (instr[12])?!comp_out:comp_out;

        /****************************************************************
         * Selection of ra_raddr, rb_raddr, and rd_waddr
         ****************************************************************/
        always @* begin
                case (state)
                        `DECODE: begin
                                if (op_csr) begin
                                        ra_raddr = rs1;
                                        if (op_csrrc) begin
                                                rb_raddr = csr_addr;
                                        end else begin
                                                rb_raddr = zero;
                                        end
                                        rd_waddr = 0;
                                end else if (op_eret) begin
                                        // ERET sets up 
                                        ra_raddr = CSR_MEPC;
                                        rb_raddr = zero;
                                        rd_waddr = zero;
                                end else begin
                                        // Normal instructions setup read during DECODE
                                        ra_raddr = rs1;
                                        rb_raddr = rs2;
                                        rd_waddr = rd;                                  
                                end
                        end
                                
                        `CSR_1: begin
                                ra_raddr = csr_addr; // CSR
                                rb_raddr = zero;
                                rd_waddr = CSR_tmp; // write RS1 to CSR_tmp
                        end
                                
                        `CSR_2: begin
                                ra_raddr = CSR_tmp;
                                if (op_csrrc || op_csrrs) begin
                                        rb_raddr = csr_addr;
                                end else begin
                                        rb_raddr = zero;
                                end                             
                                rd_waddr = rd;
                        end
                        
                        `EXCEPTION_1: begin
                                ra_raddr = CSR_MTVEC;
                                rb_raddr = zero;
                                rd_waddr = CSR_MEPC;
                        end
                        
                        `EXCEPTION_2: begin
                                ra_raddr = zero;
                                rb_raddr = zero;
                                rd_waddr = CSR_MCAUSE; // Need to write the cause
                        end
                        
                        `SHIFT_1, `SHIFT_2: begin
                                // rs1 has been read as ra_rdata
                                // write to CSR_tmp
                                ra_raddr = CSR_tmp;
                                rb_raddr = zero;
                                rd_waddr = CSR_tmp;
                        end
                        
                        `CYCLE_COUNT_UPDATE_1: begin
                                ra_raddr = CSR_tmp;    // Read CSR_tmp in the next cycle
                                rb_raddr = CSR_MCYCLE; // Read MCYCLE in the next cycle
                                rd_waddr = CSR_tmp;    // Write the current count to CSR_tmp
                        end
                        
                        `CYCLE_COUNT_UPDATE_2: begin
                                ra_raddr = zero;  // Temp
                                rb_raddr = CSR_MINSTR;  // Setup a read for the next cycle
                                rd_waddr = CSR_MCYCLE; // Write back the new count
                        end
                        
                        `INSTR_COUNT_UPDATE_1: begin
                                ra_raddr = zero;  // Temp
                                rb_raddr = zero;  // Temp
                                rd_waddr = CSR_MINSTR; // Write back the new count
                        end
                        
                        default: /* EXECUTE, MEMR, MEMW */
                                if (exception) begin
                                        ra_raddr = 0; // Future: PC
                                        rb_raddr = 0; 
                                        if (op_ecall) begin
                                                rd_waddr = zero; // Don't save an exception address on ECALL
                                        end else begin
                                                rd_waddr = CSR_MTVAL; 
                                        end
                                end else if (op_csr) begin
                                        ra_raddr = 0;
                                        rb_raddr = 0;
                                        if (op_csrr_cs && |rs1 == 0) begin
                                                // CSRRC and CSRRS don't modify the CSR is RS1==0
                                                rd_waddr = zero;
                                        end else begin
                                                rd_waddr = csr_addr;
                                        end
                                end else if (op_shift) begin
                                        ra_raddr = CSR_tmp;
                                        rb_raddr = zero;
                                        rd_waddr = rd;
                                end else begin
                                        ra_raddr = rs1; 
                                        rb_raddr = rs2; 
                                        rd_waddr = rd;
                                end
                endcase
        end

        reg[31:0]                       read_data_wb;
        always @* begin
        case (instr[13:12]) 
                2'b00: begin // LB, LBU
                        case (alu_out[1:0]) 
                                2'b00: begin
                                        if (!instr[14] && drdata[7]) begin
                                                read_data_wb = {{24{1'b1}}, drdata[7:0]};
                                        end else begin
                                                read_data_wb = {{24{1'b0}}, drdata[7:0]};
                                        end
                                end
                                2'b01: begin
                                        if (!instr[14] && drdata[15]) begin
                                                read_data_wb = {{24{1'b1}}, drdata[15:8]};
                                        end else begin
                                                read_data_wb = {{24{1'b0}}, drdata[15:8]};
                                        end
                                end 
                                2'b10: begin
                                        if (!instr[14] && drdata[23]) begin
                                                read_data_wb = {{24{1'b1}}, drdata[23:16]};
                                        end else begin
                                                read_data_wb = {{24{1'b0}}, drdata[23:16]};
                                        end
                                end 
                                default: /*2'b11*/ begin
                                        if (!instr[14] && drdata[31]) begin
                                                read_data_wb = {{24{1'b1}}, drdata[31:24]};
                                        end else begin
                                                read_data_wb = {{24{1'b0}}, drdata[31:24]};
                                        end
                                end 
                        endcase
                end
                2'b01: begin // LH, LHU
                        if (alu_out[1]) begin
                                if (!instr[14] && drdata[31]) begin
                                        read_data_wb = {{16{1'b1}}, drdata[31:16]};
                                end else begin
                                        read_data_wb = {{16{1'b0}}, drdata[31:16]};
                                end
                        end else begin
                                if (!instr[14] && drdata[15]) begin
                                        read_data_wb = {{16{1'b1}}, drdata[15:0]};
                                end else begin
                                        read_data_wb = {{16{1'b0}}, drdata[15:0]};
                                end
                        end
                end
                // LW and default
                default: read_data_wb = drdata; 
        endcase 
        end

        reg[3:0] exc_code;
        always @* begin
                if (op_ecall) begin
                        exc_code = (instr[20])?4'h3:4'hb;
                end else if (op_ld) begin
                        exc_code = 4'h4;
                end else if (op_st) begin
                        exc_code = 4'h6;
                end else begin
                        exc_code = 4'h0;
                end
                        
        end
        
        // Selection of rd_wdata
        // 1+4+7+1+1+1+5 => 20 taps
        // {pc, 2'b0} (EXCEPTION_1)
        // MCAUSE (EXCEPTION_2)
        // 
        always @* begin
                case (state)
                        
                        `EXCEPTION_1: 
                                rd_wdata = {pc, 2'b0}; // Exception PC
                                
                        `EXCEPTION_2: begin
                                // Write the cause
                                rd_wdata = {{24{1'b0}}, exc_code};
//                              if (op_ecall) begin
//                                      // EBREAK, ECALL
//                                      rd_wdata = (instr[20])?32'h0000_0003:32'h0000_000b;
//                              end else if (op_ld) begin
//                                      rd_wdata = 32'h0000_0004; // misaligned load address
//                              end else if (op_st) begin
//                                      rd_wdata = 32'h0000_0006; // misaligned store address
//                              end else begin
//                                      rd_wdata = zero; // instruction address misaligned
//                              end                             
                        end
                        
                        `MEMR: begin
                                rd_wdata = read_data_wb;
//                              case (instr[14:12]) 
//                                      3'b000,3'b100: begin // LB, LBU
//                                              case (alu_out[1:0]) 
//                                                      2'b00: rd_wdata = (!instr[14] && drdata[7])?{{24{1'b1}}, drdata[7:0]}:{{24{1'b0}}, drdata[7:0]};
//                                                      2'b01: rd_wdata = (!instr[14] && drdata[15])?{{24{1'b1}}, drdata[15:8]}:{{24{1'b0}}, drdata[15:8]};
//                                                      2'b10: rd_wdata = (!instr[14] && drdata[23])?{{24{1'b1}}, drdata[23:16]}:{{24{1'b0}}, drdata[23:16]};
//                                                      default: /*2'b11:*/ rd_wdata = (!instr[14] && drdata[31])?{{24{1'b1}}, drdata[31:24]}:{{24{1'b0}}, drdata[31:24]};
//                                              endcase
//                                      end
//                                      3'b001, 3'b101: begin // LH, LHU
//                                              if (alu_out[1]) begin
//                                                      rd_wdata = (!instr[14] & drdata[31])?{{16{1'b1}}, drdata[31:16]}:{{16{1'b0}}, drdata[31:16]};
//                                              end else begin
//                                                      rd_wdata = (!instr[14] & drdata[15])?{{16{1'b1}}, drdata[15:0]}:{{16{1'b0}}, drdata[15:0]};
//                                              end
//                                      end
//                                      // LW and default
//                                      default: rd_wdata = drdata; 
//                              endcase                         
                        end
                        
                        `CYCLE_COUNT_UPDATE_1: begin
                                rd_wdata = {24'b0, cycle_counter};
                        end
                        
                        `CYCLE_COUNT_UPDATE_2: begin
                                rd_wdata = alu_out;
                        end
                        
                        `SHIFT_1: begin
                                rd_wdata = ra_rdata;
                        end
                        
                        default: /*EXECUTE: */ begin
                                if (exception) begin
                                        // Write badaddr
                                        if (instr[6:5] == 3'b11 /*op_jal || op_jalr || op_branch*/) begin
                                                rd_wdata = {alu_out[31:1], 1'b0}; 
                                        end else begin
                                                rd_wdata = alu_out; 
                                        end
                                end else if (op_jal || op_jalr) begin
                                        rd_wdata = {pc_plus4, 2'b0};
                                end else if ((op_arith_imm || op_arith_reg) && instr[14:13] == 2'b01) begin
                                        // SLT, SLTU, SLTI, SLTUI
                                        rd_wdata = {{31{1'b0}}, comp_out};
                                end else begin
                                        rd_wdata = alu_out;
                                end                             
                        end                     
                endcase
        end

        /****************************************************************
         * Selection of wd_wen
         ****************************************************************/
        always @* begin
                case (state)
                        `FETCH, `DECODE:
                                rd_wen = 0; // TODO:
                                
                        `EXECUTE:
                                rd_wen = ((!op_branch && !op_ld_st) || exception || op_shift) && |rd_waddr;
                                
                        `MEMR: 
                                rd_wen = (|rd_waddr && dready);
                                
                        `MEMW:
                                rd_wen = 0;
                                
                        default:
                                rd_wen = |rd_waddr;
                                
                endcase
        end
        
        fwrisc_regfile u_regfile (
                .clock     (clock    ), 
                .reset     (reset    ), 
                .ra_raddr  (ra_raddr ), 
                .ra_rdata  (ra_rdata ), 
                .rb_raddr  (rb_raddr ), 
                .rb_rdata  (rb_rdata ), 
                .rd_waddr  (rd_waddr ), 
                .rd_wdata  (rd_wdata ), 
                .rd_wen    (rd_wen   ));
        
//      reg[31:0]               imm;
//      always @* begin
//              if (op_ui) begin
//                      imm_a = imm_lui;
//              end else if (op_auipc) begin
//                      imm_a = auipc_imm_31_12;
//              end else if (op_branch) begin
//                      
//      end
//      
        
        always @* begin
        
                case (state) 
                        `CSR_1: begin
                                if (instr[14]) begin
                                        alu_op_a = rs1;
                                end else begin
                                        alu_op_a = ra_rdata;
                                end
                        end
                        
                        `CYCLE_COUNT_UPDATE_2: alu_op_a = ra_rdata;
                        
                        `INSTR_COUNT_UPDATE_1: alu_op_a = {24'b0, instr_counter};
                                
                        default: begin
                                if (op_lui) begin
                                        alu_op_a = imm_lui;
                                end else if (op_auipc) begin
                                        alu_op_a = auipc_imm_31_12;
                                end else if (op_jal) begin
                                        alu_op_a = jal_off;
                                end else if (op_branch) begin
                                        alu_op_a = imm_branch;
                                end else begin
                                        alu_op_a = ra_rdata;
                                end
                        end
                endcase
                
                case (state)
                        `CYCLE_COUNT_UPDATE_2, `INSTR_COUNT_UPDATE_1: begin
                                alu_op_b = rb_rdata;
                        end
                        
                        default: begin
                                if (op_lui) begin
                                        alu_op_b = zero;
                                end else if (op_auipc || op_jal || op_branch) begin
                                        alu_op_b = {pc, 2'b0};
                                end else if (op_jalr || op_ld || (op_arith_imm && !op_shift)) begin
                                        alu_op_b = imm_11_0;
                                end else if (op_st) begin
                                        alu_op_b = st_imm_11_0;
                                end else begin
                                        alu_op_b = rb_rdata;
                                end
                        end
                endcase
                
                case (state)
                        `EXECUTE: begin
                                if (op_arith_imm || op_arith_reg) begin
                                        case (instr[14:12]) 
                                                3'b000: begin // ADDI, ADD, SUB
                                                        if (op_arith_reg) begin
                                                                alu_op = (instr[30])?`OP_SUB:`OP_ADD;
                                                        end else begin
                                                                alu_op = `OP_ADD;
                                                        end
                                                end
                                                3'b100: begin // XOR
                                                        alu_op = `OP_XOR;
                                                end
                                                3'b001, 3'b101, 3'b110: begin // SLL, SRA, SRL, OR
                                                        alu_op = `OP_OR;
                                                end
                                                default: /*3'b111: */begin // AND
                                                        alu_op = `OP_AND;
                                                end
                                        endcase
                                end else if (op_csrrc) begin
                                        alu_op = `OP_XOR;
                                end else if (op_sys) begin
                                        alu_op = `OP_OR;
                                end else begin
                                        alu_op = `OP_ADD;
                                end
                        end
                        
                        `CYCLE_COUNT_UPDATE_2, `INSTR_COUNT_UPDATE_1: 
                                alu_op = `OP_ADD;
                        
                        `SHIFT_2:
                                alu_op = (instr[14])?
                                        (instr[30])?`OP_SRA:`OP_SRL:
                                        `OP_SLL;
                        
                        `CSR_1: begin
                                if (op_csrrc) begin
                                        alu_op = `OP_AND;
                                end else begin
                                        alu_op = `OP_OR;
                                end
                        end
                        
                        `MEMR, `MEMW: alu_op = `OP_ADD;
                        
                        default: /* DECODE */
                                alu_op = `OP_OR;
                endcase
        end
        
        fwrisc_alu u_alu (
                .clock  (clock     ), 
                .reset  (reset     ), 
                .op_a   (alu_op_a  ), 
                .op_b   (alu_op_b  ), 
                .op     (alu_op    ), 
                .out    (alu_out   ),
                .carry  (alu_carry ),
                .eqz    (alu_eqz   ));

        /****************************************************************
         * pc_next selection
         ****************************************************************/
        always @* begin : pc_next_sel
                if (op_jal || op_jalr || (op_branch && branch_cond)) begin
                        pc_next = alu_out[31:2];
                end else if (op_eret || exception) begin
                        pc_next = ra_rdata[31:2];
                end else begin
                        pc_next = pc_plus4;
                end
        end
        
        // Handle data-access control signals
        fwrisc_dbus_if u_dbus_if (
                .clock     (clock    ), 
                .instr     (instr    ),
                .rb_rdata  (rb_rdata ), 
                .alu_out   (alu_out  ), 
                .state     (state    ), 
                .daddr     (daddr    ), 
                .dvalid    (dvalid   ), 
                .dwrite    (dwrite   ), 
                .dwdata    (dwdata   ), 
                .dstrb     (dstrb    ), 
                .dready    (dready   ));
        
        
        always @* begin
                if (op_st || op_ld) begin
                        case (instr[13:12]) 
                                2'b00: begin // SB
                                        misaligned_addr = 0;
                                end
                                2'b01: begin // SH
                                        misaligned_addr = op_ld_st && alu_out[0];
                                end
                                // SW and default
                                default: begin
                                        misaligned_addr = op_ld_st && |alu_out[1:0];
                                end
                        endcase         
                end else if (op_jal || op_jalr || (op_branch && branch_cond)) begin
                        misaligned_addr = alu_out[1]; // the low-bit is always cleared on jump
                end else begin
                        misaligned_addr = 0;
                end
        end

        assign exception = (state == `EXECUTE && (op_ecall || misaligned_addr));

        /**
         * The tracer is used during simulation to inspect operation of the core
         */
        fwrisc_tracer u_tracer (
                .clock   (clock                         ), 
                .reset   (reset                         ), 
                .addr    ({pc, 2'b0}            ), 
                .instr   (instr                         ), 
                .ivalid  ((state == `EXECUTE)), 
                .raddr   (rd_waddr                      ), 
                .rdata   (rd_wdata                      ), 
                .rwrite  (rd_wen                        ),
                .maddr   (daddr                         ),
                .mdata   ((dwrite)?dwdata:drdata),
                .mstrb   (dstrb                         ),
                .mwrite  (dwrite                        ),
                .mvalid  ((dvalid && dready))
                );
        
endmodule

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.