`default_nettype none

`define CACHE_SETS 8
`define CACHE_BLOCK_SIZE 'd16

`define WORD_POISON 32'hBADF00D
`define CACHE_PHYSICAL_TAG_POISON 22'h277BAD

typedef logic [5:0] CacheIndex_t;
typedef logic [3:0] CacheBlockOffset_t;
typedef logic [19:0] CacheVirtualTag_t;
typedef logic [21:0] CachePhysicalTag_t;
typedef logic [$clog2(`CACHE_SETS)-1:0] CacheSetNumber_t;
typedef logic [31:0] Word_t;

typedef enum {CACHE_READ, CACHE_WRITE, CACHE_DRAM_FILL} CacheRequestType_t;

`define CACHE_REQUEST_WIDTH 104

typedef struct packed {
    CacheIndex_t             index      ;
    CacheBlockOffset_t       blockOffset;
    // This field is only valid if requestType is a write
    CachePhysicalTag_t            tag        ;
    Word_t                   writeData     ;
    CacheRequestType_t       requestType;
    logic                    isValid    ;
    logic              [3:0] writeEnable;
    // The user must ensure that this set is safe to write to using the memory
    // locking system.
    CacheSetNumber_t writeSet;
} CacheRequest_t;

module CacheHelper (
    input logic [5:0] index,
    input logic [3:0] offset,
    output logic [`CACHE_REQUEST_WIDTH-1:0] flatRequest
);

    generate
        if($bits(CacheRequest_t) != `CACHE_REQUEST_WIDTH)
            BadTypeLayout foo();
    endgenerate

    function automatic CacheRequest_t readRequestManual(CacheIndex_t index, CacheBlockOffset_t offset);
        return '{
            index: index,
            blockOffset: offset,
            tag: `CACHE_PHYSICAL_TAG_POISON,
            writeData: `WORD_POISON,
            requestType: CACHE_READ,
            isValid: 1'b1,
            writeEnable: 0,
            // This is effectively 32-bits wide which is sufficient, but not technically correct. The "compiler" will truncate the bits to the width of 'writeSet'
            writeSet: '0
        };
    endfunction

    CacheRequest_t request;

    assign request = readRequestManual(index, offset);

    assign flatRequest = request;

endmodule