diff options
| author | Alejandro W. Sior <aho@sior.be> | 2023-08-19 12:08:26 +0200 |
|---|---|---|
| committer | Alejandro W. Sior <aho@sior.be> | 2023-08-19 12:08:26 +0200 |
| commit | 13884426be31ba9cbb298927fcb3727d610a6a22 (patch) | |
| tree | f28c86eb48ff61b515030896f2a41bdab47adfbd | |
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | DRAM.cpp | 59 | ||||
| -rw-r--r-- | DRAM.h | 32 | ||||
| -rw-r--r-- | arbiter.v | 67 | ||||
| -rw-r--r-- | soc.cpp | 51 | ||||
| -rw-r--r-- | system.v | 33 |
6 files changed, 243 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..697cf4f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +obj_dir/ diff --git a/DRAM.cpp b/DRAM.cpp new file mode 100644 index 0000000..5a0faac --- /dev/null +++ b/DRAM.cpp @@ -0,0 +1,59 @@ +#include "DRAM.h" + + +DRAM::DRAM() { + buf = new uint8_t[16*1024]; +} +DRAM::~DRAM() { + delete[] buf; +} +void DRAM::apply( + CData clk, + CData we, + uint64_t claddr, + VlWide<4>* cldata) { + this->prev_clk = this->clk; + this->clk = clk; + this->we = we; + this->claddr = claddr; + this->cldata = cldata; +} + +void DRAM::eval() { + if (!prev_clk && clk) + posedge_clk(); +} + +void DRAM::posedge_clk() { + // Align address on cache line address boundary + claddr &= ~0xF; + + // Get a word based pointer to the memory + uint32_t *base = (uint32_t*)(buf + claddr); + + if (we) { + printf("DRAM: write at %llx: %x%x%x%x\n", + claddr, + cldata->at(3), + cldata->at(2), + cldata->at(1), + cldata->at(0) + ); + + // Write the memory from the bus + for (int i = 0; i < 4; i++) + base[i] = cldata->at(i); + } else { + // Write the bus from the memory + for (int i = 0; i < 4; i++) + cldata->at(i) = base[i]; + + printf("DRAM: read at %llx: %x%x%x%x\n", + claddr, + cldata->at(3), + cldata->at(2), + cldata->at(1), + cldata->at(0) + ); + } +}
\ No newline at end of file @@ -0,0 +1,32 @@ +#pragma once + +#include <verilated.h> +#include <verilated_vcd_c.h> + +#include <stdio.h> + +/* DRAM + * A basic device simulating DRAM. + */ +struct DRAM { + uint8_t *buf; + + DRAM(); + ~DRAM(); + + CData prev_clk; + CData clk; + CData we; + uint64_t claddr; + VlWide<4>* cldata; + + void apply( + CData clk, + CData we, + uint64_t claddr, + VlWide<4>* cldata); + + void eval(); + + void posedge_clk(); +};
\ No newline at end of file diff --git a/arbiter.v b/arbiter.v new file mode 100644 index 0000000..0e83403 --- /dev/null +++ b/arbiter.v @@ -0,0 +1,67 @@ +/* Arbiter + * A module that grants access to a shared ressource (e.g a bus) + * to an arbitrary amount of drivers. A driver of the shared resource + * has a bit on the `request` line and fires it up when it wants to use + * the resource. The arbiter fires the corresponding `grant` bit when + * the driver is allowed to use the resource */ +module arbiter #( + parameter NUM_CLIENTS = 4 +) ( + input clk, + + // Request bits, each driver has its request line + input[NUM_CLIENTS-1:0] request, + + // Grant bits, each driver has its grant line + output[NUM_CLIENTS-1:0] grant +); + // The current round of the arbiter + reg[NUM_CLIENTS-1:0] round = 1; + + // A circle of wires used by the arbiter to + // indicate that a driver that has the priority + // to use the resource yields it to the next driver + // because it doesn't need to use the resource + wire pass_on_rollover; + /* verilator lint_off UNOPTFLAT */ + logic pass_on; + assign pass_on_rollover = pass_on; // NOTE: assign is applied on last assignment to wire + + // Logic bitfield used to generate the grant bus + logic[NUM_CLIENTS-1:0] grant_gen; + assign grant = grant_gen; + + always @(posedge clk) begin + // Keep current grant as round, allowing a selected driver + // to freeze the arbiter during the entire duration of its + // resource utilization + round <= |grant ? + grant : { round[NUM_CLIENTS-2:0], round[NUM_CLIENTS-1] }; + end + + always_comb begin + pass_on = pass_on_rollover; + + for (integer i = 0; i < NUM_CLIENTS; i++) begin + logic has_priority; + + // Current driver has priority if it's its round + // or previous driver has passed on its + has_priority = round[i] || pass_on; + + // By default, do not grant to driver + grant_gen[i] = 0; + + // By default, do not pass on priority + // to next driver (current may not have it) + pass_on = 0; + + if (has_priority) begin + if (request[i]) + grant_gen[i] = 1; + else + pass_on = 1; + end + end + end +endmodule
\ No newline at end of file @@ -0,0 +1,51 @@ +#include <verilated.h> +#include <verilated_vcd_c.h> +#include "Vsystem.h" +#include <iostream> + +#include "DRAM.h" + +struct Bench { + Vsystem *system; + DRAM *dram; + + Bench() { + system = new Vsystem(); + dram = new DRAM(); + + system->eval(); + eval(); + } + ~Bench() { + delete dram; + delete system; + } + + void eval() { + // Apply signals to the DRAM + dram->apply( + system->clk, + system->mem_we, + system->mem_claddr, + &system->mem_cldata + ); + // Eval the DRAM + dram->eval(); + + // Eval the system + system->eval(); + } + + void tick() { + system->clk ^= 1; + eval(); + } +}; + +int main() { + Bench bench; + + + for (int i = 0; i < 10000; i++) + bench.tick(); +}
\ No newline at end of file diff --git a/system.v b/system.v new file mode 100644 index 0000000..edc7b25 --- /dev/null +++ b/system.v @@ -0,0 +1,33 @@ +`include "arbiter.v" +module system( + input clk, + + // DRAM device + output[63:0] mem_claddr, + output mem_we, + inout[127:0] mem_cldata); + + reg [3:0] request = 'b0001; + + arbiter arbiter( + .clk(clk), + .request(request), + .grant() + ); + + reg[127:0] counter = 0; + assign mem_we = 0; + assign mem_claddr = 17; + assign mem_cldata = 42; + + always @(posedge clk) begin + if (counter > 1100) + request <= 0; + else if (counter > 1050) + request <= 'b0011; + else if (counter > 1000) + request <= 'b0100; + + counter <= counter + 1; + end +endmodule
\ No newline at end of file |
