diff options
| -rw-r--r-- | tb/avalon.hpp | 61 | ||||
| -rw-r--r-- | tb/mem.cpp | 50 | ||||
| -rw-r--r-- | tb/mem.hpp | 29 | ||||
| -rw-r--r-- | tb/mem.impl.hpp | 81 | ||||
| -rw-r--r-- | tb/top/conspiracion.cpp | 16 |
5 files changed, 139 insertions, 98 deletions
diff --git a/tb/avalon.hpp b/tb/avalon.hpp index a2cc348..40bfe9a 100644 --- a/tb/avalon.hpp +++ b/tb/avalon.hpp @@ -9,6 +9,21 @@ namespace taller::avalon { + union line + { + __int128 qword; + + struct + { + std::uint64_t lo, hi; + }; + + struct + { + std::uint32_t words[4]; + }; + }; + class slave { public: @@ -57,8 +72,50 @@ namespace taller::avalon inline virtual void bail() noexcept {} - virtual bool read(std::uint32_t addr, std::uint32_t &data) = 0; - virtual bool write(std::uint32_t addr, std::uint32_t data, unsigned byte_enable) = 0; + virtual bool read(std::uint32_t addr, std::uint32_t &data) + { + line line_data; + if (!this->read_line(addr >> 2, line_data)) + return false; + + data = line_data.words[addr & 0b11]; + return true; + } + + virtual bool read_line(std::uint32_t addr, line &data) + { + data.hi = 0; + data.lo = 0; + + return this->read(addr << 2, data.words[0]); + } + + virtual bool write + ( + std::uint32_t addr, std::uint32_t data, unsigned byte_enable = 0b1111 + ) { + line line_data; + line_data.words[addr & 0b11] = data; + + return this->write_line(addr >> 2, line_data, byte_enable << ((addr & 0b11) * 4)); + } + + virtual bool write_line(std::uint32_t addr, const line &data, unsigned byte_enable) { + unsigned offset = 0; + if (byte_enable & 0x00f0) + offset = 1; + else if (byte_enable & 0x0f00) + offset = 2; + else if (byte_enable & 0xf000) + offset = 3; + + return this->write + ( + (addr << 2) + offset, + data.words[offset], + (byte_enable >> (offset * 4)) & 0b1111 + ); + } inline virtual bool irq() noexcept { diff --git a/tb/mem.cpp b/tb/mem.cpp new file mode 100644 index 0000000..47073ab --- /dev/null +++ b/tb/mem.cpp @@ -0,0 +1,50 @@ +#include <cassert> +#include <cstdint> +#include <memory> + +#include "avalon.hpp" +#include "mem.hpp" + +namespace taller::avalon +{ + mem::mem(std::uint32_t base, std::uint32_t size) + : slave(base, size, 4), + block(std::make_unique<line[]>(size >> 4)) + {} + + bool mem::read_line(std::uint32_t addr, line &data) + { + data = block[addr]; + return true;/*ready();*/ + } + + bool mem::write_line(std::uint32_t addr, const line &data, unsigned byte_enable) + { + for (unsigned i = 0; i < 4; ++i) { + std::uint32_t bytes = 0; + + if (byte_enable & 0b1000) + bytes |= 0xff << 24; + + if (byte_enable & 0b0100) + bytes |= 0xff << 16; + + if (byte_enable & 0b0010) + bytes |= 0xff << 8; + + if (byte_enable & 0b0001) + bytes |= 0xff; + + byte_enable >>= 4; + block[addr].words[i] = (data.words[i] & bytes) | (block[addr].words[i] & ~bytes); + } + + return true;/*ready();*/ + } + + bool mem::ready() noexcept + { + count = count > 0 ? count - 1 : 2; + return count == 0; + } +} @@ -8,30 +8,45 @@ namespace taller::avalon { - template<typename Cell> class mem : public slave { public: mem(std::uint32_t base, std::uint32_t size); - virtual bool read(std::uint32_t addr, std::uint32_t &data) final override; + virtual bool read_line(std::uint32_t addr, line &data) final override; - virtual bool write + virtual bool write_line ( - std::uint32_t addr, std::uint32_t data, unsigned byte_enable = 0b1111 + std::uint32_t addr, const line &data, unsigned byte_enable ) final override; template<typename F> void load(F loader, std::size_t offset = 0); private: - std::unique_ptr<Cell[]> block; + std::unique_ptr<line[]> block; unsigned count = 0; bool ready() noexcept; }; -} -#include "mem.impl.hpp" + template<typename F> + void mem::load(F loader, std::size_t offset) + { + const auto base = base_address(); + const auto bits = 4; + + std::size_t size = address_span(); + std::size_t addr = base_address() + offset; + + while (addr >= base && addr < base + size) { + std::size_t read = loader(&block[(addr - base) >> bits], (base + size - addr) >> bits); + if (!read) + break; + + addr += read << bits; + } + } +} #endif diff --git a/tb/mem.impl.hpp b/tb/mem.impl.hpp deleted file mode 100644 index e3c11e8..0000000 --- a/tb/mem.impl.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef TALLER_MEM_IMPL_HPP -#define TALLER_MEM_IMPL_HPP - -#include <cassert> -#include <cstdint> -#include <memory> - -namespace taller::avalon -{ - template<typename Cell> - mem<Cell>::mem(std::uint32_t base, std::uint32_t size) - : slave(base, size, sizeof(Cell)), - block(std::make_unique<Cell[]>(size >> word_bits())) - {} - - template<typename Cell> - template<typename F> - void mem<Cell>::load(F loader, std::size_t offset) - { - auto base = base_address(); - auto bits = word_bits(); - std::size_t size = address_span(); - std::size_t addr = base_address() + offset; - - while(addr >= base && addr < base + size) - { - std::size_t read = loader(&block[(addr - base) >> bits], (base + size - addr) >> bits); - if(read == 0) - { - break; - } - - addr += read << bits; - } - } - - template<typename Cell> - bool mem<Cell>::read(std::uint32_t addr, std::uint32_t &data) - { - data = block[addr]; - return true;/*ready();*/ - } - - template<typename Cell> - bool mem<Cell>::write(std::uint32_t addr, std::uint32_t data, unsigned byte_enable) - { - std::uint32_t bytes = 0; - - if(byte_enable & 0b1000) - { - bytes |= 0xff << 24; - } - - if(byte_enable & 0b0100) - { - bytes |= 0xff << 16; - } - - if(byte_enable & 0b0010) - { - bytes |= 0xff << 8; - } - - if(byte_enable & 0b0001) - { - bytes |= 0xff; - } - - block[addr] = (data & bytes) | (block[addr] & ~bytes); - return true;/*ready();*/ - } - - template<typename Cell> - bool mem<Cell>::ready() noexcept - { - count = count > 0 ? count - 1 : 2; - return count == 0; - } -} - -#endif diff --git a/tb/top/conspiracion.cpp b/tb/top/conspiracion.cpp index 0286cfc..ea71dbe 100644 --- a/tb/top/conspiracion.cpp +++ b/tb/top/conspiracion.cpp @@ -299,7 +299,7 @@ int main(int argc, char **argv) trace.open("trace.vcd"); } - mem<std::uint32_t> hps_ddr3(0x0000'0000, 512 << 20); + mem hps_ddr3(0x0000'0000, 512 << 20); jtag_uart ttyJ0(0x3000'0000); interval_timer timer(0x3002'0000); interrupt_controller intc(0x3007'0000); @@ -308,7 +308,7 @@ int main(int argc, char **argv) irq_lines.jtaguart = &ttyJ0; irq_lines.timer = &timer; - mem<std::uint32_t> vram(0x3800'0000, 64 << 20); + mem vram(0x3800'0000, 64 << 20); null vram_null(0x3800'0000, 64 << 20, 2); window vram_window(vram, 0x0000'0000); @@ -355,13 +355,13 @@ int main(int argc, char **argv) FILE *img_file = std::fopen(image->c_str(), "rb"); if(!img_file) { - std::perror("fopen()"); + std::fprintf(stderr, "fopen(\"%s\"): %m\n", image->c_str()); return EXIT_FAILURE; } - hps_ddr3.load([&](std::uint32_t *buffer, std::size_t words) + hps_ddr3.load([&](line *buffer, std::size_t lines) { - return std::fread(buffer, 4, words, img_file); + return std::fread(buffer, sizeof *buffer, lines, img_file); }); std::fclose(img_file); @@ -371,13 +371,13 @@ int main(int argc, char **argv) FILE *img_file = std::fopen(load.filename.c_str(), "rb"); if(!img_file) { - std::perror("fopen()"); + std::fprintf(stderr, "fopen(\"%s\"): %m\n", load.filename.c_str()); return EXIT_FAILURE; } - hps_ddr3.load([&](std::uint32_t *buffer, std::size_t words) + hps_ddr3.load([&](line *buffer, std::size_t lines) { - return std::fread(buffer, 4, words, img_file); + return std::fread(buffer, sizeof *buffer, lines, img_file); }, load.addr); std::fclose(img_file); |
