//  *********************************************************************************************
//  Project Version  : v1.0
//  Project          : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
//  -----
//  Copyright (c)    : 2025 Fraunhofer IIS, Department IDS
//  Created          : 12.Jun.2025  by Lund University   [commit 5b1e415]
//  Last Modified    : 23.Oct.2025  by Aliakbar Merchant [commit 2f8f03d]
//  -----
//  HISTORY          : Date         By          Comments
//                     -----------  ----------  -------------------------------------------------
//                     22.Oct.2025  A.Merchant  Added reset handling condition for Instr. read logic
//                     22.Oct.2025  A.Merchant  Added reset handling condition for data write logic
//  *********************************************************************************************



module main_mem #(
  parameter int      ABits         = 3    // Number of address bits
  //parameter string   MEM_INIT_FILE = ""     // Optional memory initializations file
 )( 
  input  logic       clk,                   // Clock
  input  logic       reset,                 // Active high sync reset
  input  logic[31:0] DAddr,                 // Data Address
  input  logic[31:0] IAddr,                 // Instruction Address
  input  logic[31:0] DWData,                // Data to write
  output logic[31:0] DRData,                // Data read
  output logic[31:0] IRData,                // Instruction read
  input  logic       DWE,                   // Data write enable, 1=Write
  input  logic [1:0] DWidth                 // Access width (byte, half word, word)
);

  // Local Parameter
  localparam logic[1:0] _byte   = 2'b00;    // byte:  8 bits
  localparam logic[1:0] _half   = 2'b01;    // half: 16 bits
  localparam logic[1:0] _word   = 2'b10;    // word: 32 bits

  // Local Signals
  logic[31:0] RAM[2**(ABits-2)-1:0];        // Memory array 8KB(8192): ignores lowest 2 bits as 32bit-word
  logic[31:0] drTmp;                        // Temporary register to hold the data read from RAM.

  // memory initilizations
//  initial begin
 //if (MEM_INIT_FILE != "") begin
   //   $readmemh(MEM_INIT_FILE, RAM);
    //end
 // end

  //---------------------------------------------------------------------------//
  //---------------------------   DATA WRITE LOGIC  ---------------------------//
  //---------------------------------------------------------------------------//

  always_ff @(negedge clk) begin
    if (!reset) begin
      if (DWE) begin
        // RAM[DAddr[(ABits-1):2]] <= DWData;
        case (DWidth)
          _word:
            RAM[DAddr[(ABits-1):2]] <= DWData;
          _half:
            case (DAddr[1])
              1'b0: RAM[DAddr[(ABits-1):2]][31:16] <= DWData[15:0];
              1'b1: RAM[DAddr[(ABits-1):2]][15: 0] <= DWData[15:0];
            endcase
          _byte:
            case (DAddr[1:0])
              2'b00: RAM[DAddr[(ABits-1):2]][31:24] <= DWData[7:0];
              2'b01: RAM[DAddr[(ABits-1):2]][23:16] <= DWData[7:0];
              2'b10: RAM[DAddr[(ABits-1):2]][15: 8] <= DWData[7:0];
              2'b11: RAM[DAddr[(ABits-1):2]][ 7: 0] <= DWData[7:0];
            endcase
          default: ;
        endcase
      end
    end
  end

  //---------------------------------------------------------------------------//
  //---------------------------   DATA READ LOGIC  ----------------------------//
  //---------------------------------------------------------------------------//

  always_ff @(negedge clk) begin
      drTmp <= RAM[DAddr[(ABits-1):2]];
      end

  always_comb begin
    case (DWidth)
      _word:
        DRData = drTmp;
      _half:
        case (DAddr[1])
          1'b0: DRData = {16'b0, drTmp[31:16]};
          1'b1: DRData = {16'b0, drTmp[15: 0]};
        endcase
      _byte:
        case (DAddr[1:0])
          2'b00: DRData = {24'b0, drTmp[31:24]};
          2'b01: DRData = {24'b0, drTmp[23:16]};
          2'b10: DRData = {24'b0, drTmp[15: 8]};
          2'b11: DRData = {24'b0, drTmp[ 7: 0]};
        endcase
      default: ;
    endcase
  end

  //---------------------------------------------------------------------------//
  //-----------------------   INSTRUCTION READ LOGIC  -------------------------//
  //---------------------------------------------------------------------------//
  //
  //fetch intrcution from memory into IRData
  always_ff @(posedge clk) begin
    if (reset)
      IRData <= RAM[0];
    else
      IRData <= RAM[IAddr[(ABits-1):2]];
  end

endmodule
