| /********************************************************************************* |
| SPDX-FileCopyrightText: 2021 , Dinesh Annayya |
| |
| 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. |
| SPDX-License-Identifier: Apache-2.0 |
| SPDX-FileContributor: Created by Dinesh Annayya <dinesh.annayya@gmail.com> |
| |
| ***********************************************************************************/ |
| /********************************************************************************** |
| |
| FPU Register Interface matching to RISCV DMEM i/f |
| |
| Description: |
| |
| To Do: |
| |
| Author(s): |
| - Dinesh Annayya, dinesh.annayya@gmail.com |
| |
| Revision : |
| 0.0 - Nov 9, 2022 |
| Initial Version |
| |
| |
| ************************************************************************************/ |
| |
| module fpu_reg ( |
| input logic mclk , |
| input logic rst_n , |
| |
| |
| input logic dmem_req, |
| input logic dmem_cmd, |
| input logic [1:0] dmem_width, |
| input logic [4:0] dmem_addr, |
| input logic [31:0] dmem_wdata, |
| output logic dmem_req_ack, |
| output logic [31:0] dmem_rdata, |
| output logic [1:0] dmem_resp, |
| |
| |
| // Encription Reg Interface |
| output logic cfg_fpu_val , |
| input logic fpu_done , |
| output logic [3:0] cfg_fpu_cmd , |
| output logic [31:0] cfg_fpu_din1 , |
| output logic [31:0] cfg_fpu_din2 , |
| input logic [31:0] fpu_result |
| |
| |
| ); |
| |
| //----------------------------------------------------------------------- |
| // Internal Wire Declarations |
| //----------------------------------------------------------------------- |
| |
| logic sw_cs ; |
| logic sw_rd_en ; |
| logic sw_wr_en ; |
| logic [2:0] sw_addr ; |
| logic [31:0] sw_reg_wdata ; |
| logic [3:0] sw_be ; |
| |
| logic [31:0] reg_out ; |
| logic [31:0] reg_0 ; |
| logic [31:0] reg_1 ; |
| logic [31:0] reg_2 ; |
| logic [31:0] reg_3 ; |
| logic cfg_fpu_req ; |
| logic cfg_fpu_req_l ; |
| logic [1:0] dmem_addr_l ; |
| logic [1:0] dmem_width_l ; |
| |
| //Generate Byte Select |
| function automatic logic[3:0] conv_bsel ( |
| input logic [1:0] hwidth, |
| input logic [1:0] haddr |
| ); |
| logic [3:0] bsel; |
| begin |
| bsel = 'x; |
| case (hwidth) |
| 2'b00 : begin |
| case (haddr) |
| 2'b00 : bsel = 4'b0001; |
| 2'b01 : bsel = 4'b0010; |
| 2'b10 : bsel = 4'b0100; |
| 2'b11 : bsel = 4'b1000; |
| endcase |
| end |
| 2'b01 : begin |
| case (haddr[1]) |
| 1'b0 : bsel = 4'b0011; |
| 1'b1 : bsel = 4'b1100; |
| endcase |
| end |
| 2'b10 : begin |
| bsel = 4'b1111; |
| end |
| default : begin |
| end |
| endcase |
| conv_bsel = bsel; |
| end |
| endfunction |
| |
| |
| //Generate wdata based on width and address[1:0] |
| function automatic logic[31:0] conv_wdata ( |
| input logic [1:0] dmem_width, |
| input logic [1:0] dmem_addr, |
| input logic [31:0] dmem_wdata |
| ); |
| logic [31:0] tmp; |
| begin |
| tmp = 'x; |
| case (dmem_width) |
| 2'b00 : begin |
| case (dmem_addr) |
| 2'b00 : begin |
| tmp[7:0] = dmem_wdata[7:0]; |
| end |
| 2'b01 : begin |
| tmp[15:8] = dmem_wdata[7:0]; |
| end |
| 2'b10 : begin |
| tmp[23:16] = dmem_wdata[7:0]; |
| end |
| 2'b11 : begin |
| tmp[31:24] = dmem_wdata[7:0]; |
| end |
| default : begin |
| end |
| endcase |
| end |
| 2'b01 : begin |
| case (dmem_addr[1]) |
| 1'b0 : begin |
| tmp[15:0] = dmem_wdata[15:0]; |
| end |
| 1'b1 : begin |
| tmp[31:16] = dmem_wdata[15:0]; |
| end |
| default : begin |
| end |
| endcase |
| end |
| 2'b10 : begin |
| tmp = dmem_wdata; |
| end |
| default : begin |
| end |
| endcase |
| conv_wdata = tmp; |
| end |
| endfunction |
| |
| //Generate rdata based on width and address[1:0] |
| function automatic logic[31:0] conv_rdata ( |
| input logic [1:0] hwidth, |
| input logic [1:0] haddr, |
| input logic [31:0] hrdata |
| ); |
| logic [31:0] tmp; |
| begin |
| tmp = 'x; |
| case (hwidth) |
| 2'b00 : begin |
| case (haddr) |
| 2'b00 : tmp[7:0] = hrdata[7:0]; |
| 2'b01 : tmp[7:0] = hrdata[15:8]; |
| 2'b10 : tmp[7:0] = hrdata[23:16]; |
| 2'b11 : tmp[7:0] = hrdata[31:24]; |
| default : begin |
| end |
| endcase |
| end |
| 2'b01 : begin |
| case (haddr[1]) |
| 1'b0 : tmp[15:0] = hrdata[15:0]; |
| 1'b1 : tmp[15:0] = hrdata[31:16]; |
| default : begin |
| end |
| endcase |
| end |
| 2'b10 : begin |
| tmp = hrdata; |
| end |
| default : begin |
| end |
| endcase |
| conv_rdata = tmp; |
| end |
| endfunction |
| |
| |
| always_ff @(negedge rst_n, posedge mclk) begin |
| if (~rst_n) begin |
| sw_cs <= '0; |
| dmem_req_ack <= '0; |
| sw_rd_en <= '0; |
| sw_wr_en <= '0; |
| sw_addr <= '0; |
| sw_be <= '0; |
| sw_reg_wdata <= '0; |
| dmem_addr_l <= '0; |
| dmem_width_l <= '0; |
| end else begin |
| sw_cs <= (dmem_req) && (dmem_req_ack == 0) ; |
| dmem_req_ack <= dmem_req & (dmem_req_ack ==0) ; |
| sw_rd_en <= (dmem_cmd == 0); |
| sw_wr_en <= (dmem_cmd == 1); |
| sw_addr <= dmem_addr[4:2]; |
| dmem_addr_l <= dmem_addr[1:0]; |
| dmem_width_l <= dmem_width[1:0]; |
| sw_be <= conv_bsel(dmem_width,dmem_addr[1:0]); |
| sw_reg_wdata <= conv_wdata(dmem_width,dmem_addr[1:0],dmem_wdata); |
| end |
| end |
| |
| //----------------------------------------------------------------------- |
| // register read enable and write enable decoding logic |
| //----------------------------------------------------------------------- |
| wire sw_wr_en_0 = sw_cs & sw_wr_en & (sw_addr == 3'h0); |
| wire sw_wr_en_1 = sw_cs & sw_wr_en & (sw_addr == 3'h1); |
| wire sw_wr_en_2 = sw_cs & sw_wr_en & (sw_addr == 3'h2); |
| wire sw_wr_en_3 = sw_cs & sw_wr_en & (sw_addr == 3'h3); |
| |
| wire sw_rd_en_0 = sw_cs & sw_rd_en & (sw_addr == 3'h0); |
| wire sw_rd_en_1 = sw_cs & sw_rd_en & (sw_addr == 3'h1); |
| wire sw_rd_en_2 = sw_cs & sw_rd_en & (sw_addr == 3'h2); |
| wire sw_rd_en_3 = sw_cs & sw_rd_en & (sw_addr == 3'h3); |
| |
| |
| |
| always @ (posedge mclk or negedge rst_n) |
| begin : preg_out_Seq |
| if (rst_n == 1'b0) begin |
| dmem_resp <= 2'b00; |
| dmem_rdata <= 'h0; |
| end else if (sw_cs && sw_rd_en) begin |
| dmem_rdata <= conv_rdata(dmem_width_l,dmem_addr_l[1:0],reg_out); |
| dmem_resp <= 2'b01; |
| end else if (sw_cs && sw_wr_en) begin |
| dmem_resp <= 2'b01; |
| end else begin |
| dmem_resp <= 2'b00; |
| end |
| end |
| |
| //----------------------------------------------------------------------- |
| // Register Read Path Multiplexer instantiation |
| //----------------------------------------------------------------------- |
| |
| always_comb |
| begin |
| reg_out [31:0] = 32'h0; |
| |
| case (sw_addr [2:0]) |
| 3'b000 : reg_out [31:0] = reg_0 [31:0]; |
| 3'b001 : reg_out [31:0] = reg_1 [31:0]; |
| 3'b010 : reg_out [31:0] = reg_2 [31:0]; |
| 3'b011 : reg_out [31:0] = reg_3 [31:0]; |
| default : reg_out [31:0] = 32'h0; |
| endcase |
| end |
| |
| |
| assign cfg_fpu_val = (cfg_fpu_req && !cfg_fpu_req_l); |
| |
| always @ (posedge mclk or negedge rst_n) |
| begin |
| if (rst_n == 1'b0) begin |
| cfg_fpu_req_l <= 1'b0; |
| end else begin |
| cfg_fpu_req_l <= cfg_fpu_req; |
| end |
| end |
| assign reg_0[31] = cfg_fpu_req; |
| assign reg_0[30:4] = 'h0; |
| assign reg_0[3:0] = cfg_fpu_cmd; |
| |
| |
| assign cfg_fpu_din1 = reg_1; |
| assign cfg_fpu_din2 = reg_2; |
| assign reg_3 = fpu_result; |
| |
| // Register-0 |
| generic_register #(4,0 ) u_reg0_3_0 ( |
| .we ({4{sw_wr_en_0 & |
| sw_be[0] }} ), |
| .data_in (sw_reg_wdata[3:0] ), |
| .reset_n (rst_n ), |
| .clk (mclk ), |
| |
| //List of Outs |
| .data_out (cfg_fpu_cmd ) |
| ); |
| |
| req_register #(0 ) u_reg0_31 ( |
| .cpu_we ({sw_wr_en_0 & |
| sw_be[3] }), |
| .cpu_req (sw_reg_wdata[31] ), |
| .hware_ack (fpu_done ), |
| .reset_n (rst_n ), |
| .clk (mclk ), |
| |
| //List of Outs |
| .data_out (cfg_fpu_req ) |
| ); |
| |
| |
| // Register-1 |
| gen_32b_reg #(32'h0) u_reg_1 ( |
| //List of Inputs |
| .reset_n (rst_n ), |
| .clk (mclk ), |
| .cs (sw_wr_en_1 ), |
| .we (sw_be ), |
| .data_in (sw_reg_wdata ), |
| |
| //List of Outs |
| .data_out (reg_1 ) |
| ); |
| |
| // Register-2 |
| gen_32b_reg #(32'h0) u_reg_2 ( |
| //List of Inputs |
| .reset_n (rst_n ), |
| .clk (mclk ), |
| .cs (sw_wr_en_2 ), |
| .we (sw_be ), |
| .data_in (sw_reg_wdata ), |
| |
| //List of Outs |
| .data_out (reg_2 ) |
| ); |
| |
| |
| endmodule |