Simulasi cache langsung dipetakan sederhana pada FPGA
Artikel ini adalah bagian dari kursus untuk mahasiswa sarjana tahun pertama dari Innopolis University. Semua pekerjaan dilakukan dalam satu tim. Tujuan artikel ini adalah untuk menunjukkan pemahaman tentang topik, atau untuk membantu memahaminya menggunakan simulasi.
Git tautan repositori
Prinsip kerja tetapi dari sisi pengguna harus terlihat seperti:
- Untuk menulis data apa pun dalam memori, Anda perlu mengakses RAM dengan data dan alamat tempat kami ingin menulis.
- Untuk mengakses data, kita harus alamat cache. Jika cache tidak dapat menemukan data yang diperlukan, maka cache mengakses RAM dengan menyalin data dari sana.
Ketika bekerja dengan Verilog, harus dipahami bahwa masing-masing blok program diwakili sebagai modul. Seperti yang Anda ketahui, cache bukanlah bagian independen dari memori cepat, dan untuk pengoperasian yang tepat, ia perlu mengambil data dari blok memori lain - RAM. Oleh karena itu, untuk mensimulasikan pekerjaan cache di FPGA, kita harus mensimulasikan modul RAM keseluruhan yang termasuk cache juga, tetapi poin utamanya adalah simulasi cache.
Implementasinya terdiri dari beberapa modul:
- ram.v - modul memori RAM
- cache.v - Modul memori cache
- cache_and_ram.v - modul yang beroperasi dengan data dan memori.
- testbench.v dan testbench2.v - modul untuk menunjukkan bahwa modul utama bekerja dengan sempurna.
Modul RAM:
Kodemodule ram(); parameter size = 4096; //size of a ram in bits reg [31:0] ram [0:size-1]; //data matrix for ram endmodule
DeskripsiModul merupakan memori yang digunakan sebagai RAM. Ini memiliki 4096 sel addressable 32-bit untuk menyimpan beberapa data.

Modul cache:
Kode module cache(); parameter size = 64; // cache size parameter index_size = 6; // index size reg [31:0] cache [0:size - 1]; //registers for the data in cache reg [11 - index_size:0] tag_array [0:size - 1]; // for all tags in cache reg valid_array [0:size - 1]; //0 - there is no data 1 - there is data initial begin: initialization integer i; for (i = 0; i < size; i = i + 1) begin valid_array[i] = 6'b000000; tag_array[i] = 6'b000000; end end endmodule
DeskripsiJadi cache berisi lebih dari sekadar salinan data di
memori ia juga memiliki bit untuk membantu kami menemukan data di dalam cache dan
verifikasi validitasnya.

Modul cache dan RAM:
Kode module cache_and_ram( input [31:0] address, input [31:0] data, input clk, input mode, //mode equal to 1 when we write and equal to 0 when we read output [31:0] out ); //previous values reg [31:0] prev_address, prev_data; reg prev_mode; reg [31:0] temp_out; reg [cache.index_size - 1:0] index; // for keeping index of current address reg [11 - cache.index_size:0] tag; // for keeping tag of ceurrent address ram ram(); cache cache(); initial begin index = 0; tag = 0; prev_address = 0; prev_data = 0; prev_mode = 0; end always @(posedge clk) begin //check if the new input is updated if (prev_address != address || prev_data != data || prev_mode != mode) begin prev_address = address % ram.size; prev_data = data; prev_mode = mode; tag = prev_address >> cache.index_size; // tag = first bits of address except index ones (In our particular case - 6) index = address % cache.size; // index value = last n (n = size of cache) bits of address if (mode == 1) begin ram.ram[prev_address] = data; //write new data to the relevant cache block if there is such one if (cache.valid_array[index] == 1 && cache.tag_array[index] == tag) cache.cache[index] = data; end else begin //write new data to the relevant cache's block, because the one we addressing to will be possibly addressed one more time soon if (cache.valid_array[index] != 1 || cache.tag_array[index] != tag) begin cache.valid_array[index] = 1; cache.tag_array[index] = tag; cache.cache[index] = ram.ram[prev_address]; end temp_out = cache.cache[index]; end end end assign out = temp_out; endmodule
DeskripsiMerupakan operasi untuk bekerja dengan data dalam modul memori. Mendapat input pada setiap clock positive edge. Memeriksa apakah ada input baru - tergantung pada mode (1 untuk tulis / 0 untuk dibaca) menjalankan operasi yang relevan. Jika mode adalah 1 (tulis):
• Tulis data ke alamat, lalu periksa apakah alamat input ada dalam cache, jika demikian - ganti data, jika tidak, berhenti dulu.
Jika mode adalah 0 (baca):
• Periksa apakah alamat input ada dalam cache, Jika demikian - kembalikan data, jika tidak, dapatkan data dari ram. Refresh alamat dalam cache dengan data baru.
Testbenches:
Kode1 module testbench; reg [31:0] address, data; reg mode, clk; wire [31:0] out; cache_and_ram tb( .address(address), .data(data), .mode(mode), .clk(clk), .out(out) ); initial begin clk = 1'b1; address = 32'b00000000000000000000000000000000; // 0 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b1; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000010000000100001010101; // 526421 mode = 1'b1; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000001100000110001101100010110; // 25369366 mode = 1'b1; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b1; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b1; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000000000000000000000000000000; // 0 mode = 1'b0; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000000000000000000000000; // 0 mode = 1'b0; #200 address = 32'b00000000000000000000000000000000; // 0 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b0; end initial $monitor("address = %d data = %d mode = %d out = %d", address % 4096, data, mode, out); always #25 clk = ~clk; endmodule
Kode2 module testbench2; reg [31:0] address, data; reg mode, clk; wire [31:0] out; cache_and_ram tb( .address(address), .data(data), .mode(mode), .clk(clk), .out(out) ); initial begin clk = 1'b1; address = 32'b00000000000000000000000000000000; // 0 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b1; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000010000000100001010101; // 526421 mode = 1'b1; #200 address = 32'b00000000000000000000000000000000; // 0 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b0; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000010000000100001010101; // 526421 mode = 1'b0; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000001100000110001101100010110; // 25369366 mode = 1'b1; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000001100000110001101100010110; // 25369366 mode = 1'b0; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b1; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000000000000000011100011000000; // 14528 mode = 1'b1; #200 address = 32'b00000000000011110100011111010001; // 1001425 % size = 2001 data = 32'b00000000000000000000000000000000; // 0 mode = 1'b0; #200 address = 32'b10100111111001011111101111011100; // 2816867292 % size = 3036 data = 32'b00000000000000000000000000000000; // 0 mode = 1'b0; end initial $monitor("address = %d data = %d mode = %d out = %d", address % 4096, data, mode, out); always #25 clk = ~clk; endmodule
DeskripsiUntuk menjalankan testbench, muat semua file ke proyek ModelSim dan jalankan simulasi salah satu file testbench.