summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tb/avalon.hpp12
-rw-r--r--tb/avalon.impl.hpp47
-rw-r--r--tb/top/conspiracion.cpp72
3 files changed, 100 insertions, 31 deletions
diff --git a/tb/avalon.hpp b/tb/avalon.hpp
index 323bd47..a2cc348 100644
--- a/tb/avalon.hpp
+++ b/tb/avalon.hpp
@@ -4,6 +4,7 @@
#include <cassert>
#include <cstdint>
#include <cstdio>
+#include <stdexcept>
#include <vector>
namespace taller::avalon
@@ -108,13 +109,22 @@ namespace taller::avalon
std::uint32_t status() noexcept;
};
+ class avl_bus_error : public std::runtime_error
+ {
+ public:
+ using std::runtime_error::runtime_error;
+ };
+
template<class Platform>
class interconnect
{
public:
interconnect(Platform &plat) noexcept;
- bool tick(bool clk);
+ bool tick(bool clk) noexcept;
+ void tick_rising();
+ void tick_falling() noexcept;
+
void attach(slave &dev);
void attach_intc(interrupt_controller &intc);
void bail() noexcept;
diff --git a/tb/avalon.impl.hpp b/tb/avalon.impl.hpp
index e04c7b0..992f949 100644
--- a/tb/avalon.impl.hpp
+++ b/tb/avalon.impl.hpp
@@ -31,9 +31,9 @@ namespace taller::avalon
}
template<class Platform>
- bool interconnect<Platform>::tick(bool clk)
+ bool interconnect<Platform>::tick(bool clk) noexcept
{
- if(!plat.reset_reset_n) [[unlikely]]
+ if(!plat.reset_reset_n)
{
active = nullptr;
plat.avl_irq = 0;
@@ -58,14 +58,26 @@ namespace taller::avalon
if(!clk)
{
- if(!plat.avl_waitrequest)
- {
- active = nullptr;
- }
+ tick_falling();
+ return true;
+ } else if(!active)
+ {
+ assert(!avl_read || !avl_write);
+ }
+ try
+ {
+ tick_rising();
return true;
+ } catch(const avl_bus_error&)
+ {
+ return false;
}
+ }
+ template<class Platform>
+ void interconnect<Platform>::tick_rising()
+ {
for(auto &binding : devices)
{
binding.dev.tick();
@@ -84,10 +96,9 @@ namespace taller::avalon
avl_writedata = plat.avl_writedata;
avl_byteenable = plat.avl_byteenable;
- assert(!avl_read || !avl_write);
if(!avl_read && !avl_write)
{
- return true;
+ return;
}
for(auto &binding : devices)
@@ -99,21 +110,20 @@ namespace taller::avalon
}
}
- if(!active)
+ if(!active) [[unlikely]]
{
bail();
const char *op = avl_read ? "read" : "write";
fprintf(stderr, "[avl] attempt to %s memory hole at 0x%08x\n", op, avl_address);
- return false;
- }
- if(avl_address & active->word_mask())
+ throw avl_bus_error{"memory hole addressed"};
+ } else if(avl_address & active->word_mask()) [[unlikely]]
{
bail();
-
fprintf(stderr, "[avl] unaligned address: 0x%08x\n", avl_address);
- return false;
+
+ throw avl_bus_error{"unaligned address"};
}
}
@@ -128,8 +138,15 @@ namespace taller::avalon
{
plat.avl_waitrequest = !active->write(pos, avl_writedata, avl_byteenable);
}
+ }
- return true;
+ template<class Platform>
+ void interconnect<Platform>::tick_falling() noexcept
+ {
+ if(!plat.avl_waitrequest)
+ {
+ active = nullptr;
+ }
}
template<class Platform>
diff --git a/tb/top/conspiracion.cpp b/tb/top/conspiracion.cpp
index e1095f2..0286cfc 100644
--- a/tb/top/conspiracion.cpp
+++ b/tb/top/conspiracion.cpp
@@ -229,7 +229,7 @@ int main(int argc, char **argv)
args::ValueFlag<unsigned> cycles
(
- parser, "cycles", "Max number of core cycles to run", {"cycles"}, UINT_MAX
+ parser, "cycles", "Max number of core cycles to run", {"cycles"}, 0
);
args::ValueFlag<int> control_fd
@@ -425,11 +425,6 @@ int main(int argc, char **argv)
{
tick();
tick();
-
- if(top.breakpoint || (!(time & ((1 << 8) - 1)) && async_halt)) [[unlikely]]
- {
- top.halt = 1;
- }
};
if(!no_tty)
@@ -564,22 +559,69 @@ int main(int argc, char **argv)
core.fetch->explicit_branch__VforceVal = 1;
- unsigned i = 0;
- // Abuse unsigned overflow (cycles is UINT_MAX by default)
- while(!failed && i + 1 <= *cycles)
+ auto maybe_halt = [&]()
+ {
+ if(top.breakpoint || async_halt)
+ {
+ top.halt = 1;
+ }
+
+ return top.halt;
+ };
+
+ auto loop_fast = [&]()
{
do
{
- cycle();
- if(failed || top.cpu_halted) [[unlikely]]
+ for(unsigned iters = 0; iters < 1024 && !top.breakpoint; ++iters)
{
- goto halt_or_fail;
+ top.clk_clk = 0;
+ top.eval();
+ avl.tick_falling();
+
+ top.clk_clk = 1;
+ top.eval();
+
+ // This is free most of the time
+ try
+ {
+ avl.tick_rising();
+ } catch(const avl_bus_error&)
+ {
+ failed = true;
+ break;
+ }
}
- } while(++i + 1 <= *cycles);
+ } while(!maybe_halt());
+ };
+
+ unsigned i = 0;
+ auto loop_accurate = [&]()
+ {
+ do
+ {
+ cycle();
+ maybe_halt();
+ } while(!failed && !top.cpu_halted && (*cycles == 0 || ++i < *cycles));
+ };
+
+ const bool slow_path = *cycles > 0 || enable_accurate_video || enable_trace;
- break;
+ while(true)
+ {
+ if(slow_path || top.halt || top.step)
+ {
+ loop_accurate();
+ } else
+ {
+ loop_fast();
+ }
+
+ if(failed || (*cycles > 0 && i >= *cycles))
+ {
+ break;
+ }
-halt_or_fail:
top.step = 0;
core.fetch->target__VforceVal = core.control->pc;