summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tb/avalon.hpp61
-rw-r--r--tb/mem.cpp50
-rw-r--r--tb/mem.hpp29
-rw-r--r--tb/mem.impl.hpp81
-rw-r--r--tb/top/conspiracion.cpp16
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;
+ }
+}
diff --git a/tb/mem.hpp b/tb/mem.hpp
index 0943530..4c37b0e 100644
--- a/tb/mem.hpp
+++ b/tb/mem.hpp
@@ -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);