Skip to content

connection #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 36 additions & 28 deletions Documentation/01_Module_Docs/14_L1_Instruction_Cache.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,49 @@
# THIS MODULE IS NOT YET OUTLINED #

# L1 Instruction Cache #
(Any Notes would go here)

## Contents
* [Inputs](#inputs)
* [Outputs](#outputs)
* [Functionality](#functionality)
* [Registers](#registers)
* [Clk](#on-posedge-clk)
* [Active low reset](#asynchronous-active-low-reset)
* Inputs
* Outputs
* Functionality
* Registers
* Clk
* Active low reset

## Inputs
|Name|Bits wide|
|:---|:---:|
|```name```|#-bit|
|```name```|#-bit|
| Name | Bits wide |
|:--------------------|:----------------:|
| `clk` | 1-bit |
| `rstn` | 1-bit |
| `read_enable` | 1-bit |
| `request_address` | ADDR_WIDTH-bit |
| `mem_response_data` | DATA_WIDTH-bit |
| `mem_ready` | 1-bit |

## Outputs
|Name|Bits wide|
|:---|:---:|
|```name```|#-bit|
|```name```|#-bit|
| Name | Bits wide |
|:--------------------|:----------------:|
| `response_data` | DATA_WIDTH-bit |
| `mem_request` | 1-bit |
| `mem_address` | ADDR_WIDTH-bit |
| `c_state` | 2-bit |

## Functionality
### Registers
- #-bit ```name``` register
- #-bit ```name``` register
- `valid_bits`: Indicates whether a cache line is valid.
- `tag_array`: Holds the tag for each cache line.
- `lru_bits`: Maintains the least recently used (LRU) replacement policy.

### On posedge clk
- ```somebranch = someval```
- Use a table when necessary if statements are used:
- ```name```
|Name|Bits wide|
|---|---|
|```name == 0```|```reg = val```|
|```name == 1```|```reg = val```|

- If `read_enable` is high:
- Check whether the cache has a hit or miss.
- If it’s a hit, set `response_data` to the instruction stored in the cache.
- If it’s a miss, generate a memory request by setting `mem_request` to 1 and load data from the address stored in `mem_address`.

- Use the LRU algorithm to select which cache line to replace:
| Name | Condition |
|----------------|-------------------------|
| `lru_bits == 0`| Replace the first cache line |
| `lru_bits == 1`| Replace the second cache line |

### Asynchronous active low reset
- Register values reset to 0
- All `valid_bits` and `lru_bits` are reset to 0.
- The `tag_array` is cleared.
35 changes: 19 additions & 16 deletions dv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@ find_package(nyu-util REQUIRED CONFIG)

add_executable(tests)
target_sources(tests PRIVATE
alu.cpp
#alu.cpp

branch_addr_calc.cpp
branch_eval.cpp
branch_manager.cpp
branch_predictor.cpp
#branch_addr_calc.cpp
#branch_eval.cpp
#branch_manager.cpp
#branch_predictor.cpp

con_branch_cont.cpp
con_ex.cpp
con_id.cpp
#con_branch_cont.cpp
#con_ex.cpp
#con_id.cpp

data_cache_manager.cpp
exmem.cpp
#data_cache_manager.cpp
#exmem.cpp

gpr.cpp
idex.cpp
ifid.cpp
#gpr.cpp
#idex.cpp
#ifid.cpp

# Failing
# l1_data_cache.cpp
l1_ins_cache.cpp

memwb.cpp
pc.cpp
pipeline_reset.cpp
#memwb.cpp
#pc.cpp
#pipeline_reset.cpp
)

nyu_link_sv(tests PRIVATE core)
Expand Down Expand Up @@ -54,6 +55,8 @@ nyu_target_verilate(tests
# Failing
# L1_Data_Cache

L1_Instruction_Cache

MEMWB
PC
Pipeline_Reset
Expand Down
202 changes: 202 additions & 0 deletions dv/l1_ins_cache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#include <cstdint>

#include <catch2/catch_test_macros.hpp>
#include <NyuTestUtil.hpp>

#include <L1_Instruction_Cache.h>

const int BLOCK_SIZE = 4;
const int CACHE_SIZE = 1024; // 1 KB
const int ASSOCIATIVITY = 2;
const int NUM_SETS = CACHE_SIZE / (BLOCK_SIZE * ASSOCIATIVITY);
const int DATA_WIDTH = 32;
const int ADDR_WIDTH = 32;
const int INDEX_WIDTH = 7;
const int TAG_WIDTH = ADDR_WIDTH-INDEX_WIDTH;

struct ins_ram{
std::uint32_t data[2048]={0};
bool ready=1;
std::uint32_t res_data=0;
void read(uint32_t address){
res_data=data[address];
}
void reset(){
for(size_t i {0};i<2048;i++){
data[i]=0;

}
res_data=0;
}
};


class CacheSimulator {
public:
std::vector<std::vector<uint32_t>> memory;
std::vector<std::vector<bool>> valid_bits;
std::vector<std::vector<uint32_t>> tags;
std::vector<std::vector<int>> lru_counters;
std::uint32_t output;
CacheSimulator() {
memory.resize(NUM_SETS, std::vector<uint32_t>(ASSOCIATIVITY, 0));
valid_bits.resize(NUM_SETS, std::vector<bool>(ASSOCIATIVITY, false));
tags.resize(NUM_SETS, std::vector<uint32_t>(ASSOCIATIVITY, 0));
lru_counters.resize(NUM_SETS, std::vector<int>(ASSOCIATIVITY, 0));
}

void reset() {
for (int i = 0; i < NUM_SETS; ++i) {
for (int j = 0; j < ASSOCIATIVITY; ++j) {
memory[i][j] = 0;
valid_bits[i][j] = false;
tags[i][j] = 0;
lru_counters[i][j] = j;
//lru_counters[i][j] = 1;
}
}
}

void accessCache(uint32_t address, bool write,bool read, uint32_t write_data,ins_ram &mem) {
uint32_t tag = address >> (ADDR_WIDTH-TAG_WIDTH);
uint32_t index = address & ((1 << INDEX_WIDTH) - 1);

bool hit = false;
int way = 0;

// hit check
for (int i = 0; i < ASSOCIATIVITY; ++i) {
if (valid_bits[index][i] && tags[index][i] == tag) {
hit = true;
way = i;
break;
}
}

if (hit) {
if (read) {
output=memory[index][way];
}
updateLRU(index, way);
} else {
if (read) {
way = findLRUWay(index);
memory[index][way] = mem.data[address];
tags[index][way] = tag;
valid_bits[index][way] = true;
updateLRU(index, way);
}
}
}

private:

uint32_t address;
uint32_t tag;
uint32_t index;

int findLRUWay(int set_index) {
int lru_way = 0, max_usage = 0;
for (int i = 0; i < ASSOCIATIVITY; ++i) {
if (lru_counters[set_index][i] > max_usage) {
max_usage = lru_counters[set_index][i];
lru_way = i;
}
}
return lru_way;
}

void updateLRU(int set_index, int accessed_way) {
for (int i = 0; i < ASSOCIATIVITY; ++i) {
if (i == accessed_way) {
lru_counters[set_index][i] = 0;
} else {
lru_counters[set_index][i]++;
}
}
}
};

static void init(auto& L1) {
L1.rstn = 0;
L1.clk = 0;
nyu::eval(L1);
L1.rstn = 1;
nyu::eval(L1);
}

static void read_eval(auto& L1, CacheSimulator& sim_cache, ins_ram& memory, std::uint32_t request_address) {
// Set up initial conditions
L1.read_enable = 1;
L1.request_address = request_address;
L1.mem_ready = 0;
L1.mem_response_data = 0;
L1.mem_request = 0;
L1.mem_write_enable = 0;

// De-assert read_enable after one cycle
L1.clk = 1;
nyu::eval(L1);
L1.clk = 0;
nyu::eval(L1);
L1.read_enable = 0;

bool response_valid = false;
int max_cycles = 100; // prevent infinite loops
int cycles = 0;
uint32_t response_data = 0;

while (!response_valid && cycles < max_cycles) {
L1.clk = !L1.clk; // Toggle clock
nyu::eval(L1);

// Simulate memory interaction
if (L1.mem_request) {
// Simulate memory latency if needed
L1.mem_ready = 1;
L1.mem_response_data = memory.data[L1.mem_address];
} else {
L1.mem_ready = 0;
}

// Check if response_data is valid
if (L1.c_state == 0 && !L1.read_enable && !L1.mem_request) {
response_data = L1.response_data;
response_valid = true;
}

cycles++;
}

// Use the CacheSimulator to get the expected output
sim_cache.accessCache(request_address, /*write=*/false, /*read=*/true, /*write_data=*/0, memory);

// Compare outputs
REQUIRE(response_valid); // Ensure that we got a response
REQUIRE(response_data == sim_cache.output);
}

// Test case using Catch2 framework
TEST_CASE("Cache read test") {
// Create instances
L1_Instruction_Cache L1;
CacheSimulator sim_cache;
ins_ram memory;

// Initialize cache and memory
init(L1);
sim_cache.reset();
memory.reset();

// Initialize RAM with some data
for (size_t i = 0; i < 2048; ++i) {
memory.data[i] = i * 4; // Sample data
}

// Addresses to test
std::uint32_t addresses[] = {0x00000000, 0x00000004, 0x00000008, 0x0000000C};

for (auto address : addresses) {
read_eval(L1, sim_cache, memory, address);
}
}
2 changes: 1 addition & 1 deletion rtl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
nyu_add_sv(core

Con_ID.sv Con_EX.sv Alu.sv Con_Branch_Cont.sv Branch_Eval.sv PC.sv IFID.sv MEMWB.sv GPR.sv EXMEM.sv Branch_Addr_Calc.sv IDEX.sv Branch_Predictor.sv Pipeline_Reset.sv Branch_Manager.sv Data_Cache_Manager.sv L1_Data_Cache.sv
Con_ID.sv Con_EX.sv Alu.sv Con_Branch_Cont.sv Branch_Eval.sv PC.sv IFID.sv MEMWB.sv GPR.sv EXMEM.sv Branch_Addr_Calc.sv IDEX.sv Branch_Predictor.sv Pipeline_Reset.sv Branch_Manager.sv Data_Cache_Manager.sv L1_Data_Cache.sv L1_Instruction_Cache.sv

)
Loading
Loading