diff options
Diffstat (limited to 'tb')
| -rw-r--r-- | tb/avalon.hpp | 12 | ||||
| -rw-r--r-- | tb/avalon.impl.hpp | 47 | ||||
| -rw-r--r-- | tb/top/conspiracion.cpp | 72 |
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; |
