diff options
| author | Alejandro Soto <alejandro@34project.org> | 2022-12-12 14:34:05 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2022-12-16 16:29:10 -0600 |
| commit | 02712d69cdd859d702cc7577e72db27d6f0c9ad5 (patch) | |
| tree | 01d0c36111a99f596588816a2529f661ba56d023 | |
| parent | 397245139af754af07e61a10a91fdc9b9e72153f (diff) | |
Implement fast video
| -rwxr-xr-x | sim/sim.py | 5 | ||||
| -rw-r--r-- | tb/sim/descifrador.py | 1 | ||||
| -rw-r--r-- | tb/top/conspiracion.cpp | 30 | ||||
| -rw-r--r-- | tb/vga.hpp | 16 | ||||
| -rw-r--r-- | tb/vga.impl.hpp | 73 |
5 files changed, 109 insertions, 16 deletions
@@ -342,7 +342,7 @@ do_output = module_get('do_output') if init := module_get('init'): init() -exec_args = [verilated, '--headless', '--dump-regs'] +exec_args = [verilated, '--dump-regs'] cycles = module_get('cycles', 1024) if cycles is not None: @@ -351,6 +351,9 @@ if cycles is not None: if not module_get('enable_tty', False): exec_args.append('--no-tty') +if not module_get('enable_video', False): + exec_args.append('--headless') + for rng in mem_dumps: length = rng.stop - rng.start assert rng.start >= 0 and rng.stop > rng.start \ diff --git a/tb/sim/descifrador.py b/tb/sim/descifrador.py index e754f2a..a77375b 100644 --- a/tb/sim/descifrador.py +++ b/tb/sim/descifrador.py @@ -7,6 +7,7 @@ loads = {START: FILE} consts = {0x30050000: 1, 0x30060000: 0} cycles = 23000000 mem_dumps = [range(START, START + SIZE)] +enable_video = True def final(): words = [] diff --git a/tb/top/conspiracion.cpp b/tb/top/conspiracion.cpp index f0cfaa2..de43952 100644 --- a/tb/top/conspiracion.cpp +++ b/tb/top/conspiracion.cpp @@ -210,6 +210,11 @@ int main(int argc, char **argv) parser, "headless", "Disable video output", {"headless"} ); + args::Flag accurate_video + ( + parser, "accurate-video", "Enable signal-level video emulation", {"accurate-video"} + ); + args::Flag no_tty ( parser, "no-tty", "Disable TTY takeoveer", {"no-tty"} @@ -292,16 +297,21 @@ int main(int argc, char **argv) trace.open("trace.vcd"); } - interconnect<Vconspiracion_platform> avl(*top.conspiracion->plat); - interconnect<Vconspiracion_vga_domain> avl_vga(*top.conspiracion->plat->vga); - mem<std::uint32_t> hps_ddr3(0x0000'0000, 512 << 20); jtag_uart ttyJ0(0x3000'0000); interval_timer timer(0x3002'0000); mem<std::uint32_t> vram(0x3800'0000, 64 << 20); null vram_null(0x3800'0000, 64 << 20, 2); window vram_window(vram, 0x0000'0000); - display<Vconspiracion_vga_domain> vga(*top.conspiracion->plat->vga, 25'175'000); + + display<Vconspiracion_vga_domain> vga + ( + *top.conspiracion->plat->vga, + 0x3800'0000, 25'175'000, 50'000'000 + ); + + interconnect<Vconspiracion_platform> avl(*top.conspiracion->plat); + interconnect<Vconspiracion_vga_domain> avl_vga(*top.conspiracion->plat->vga); std::vector<const_map> consts; for(const auto &init : *const_) @@ -309,7 +319,8 @@ int main(int argc, char **argv) consts.emplace_back(init.addr, init.value); } - bool enable_video = !headless; + bool enable_fast_video = !headless && !accurate_video; + bool enable_accurate_video = !headless && accurate_video; avl.attach(hps_ddr3); avl.attach(ttyJ0); @@ -320,7 +331,10 @@ int main(int argc, char **argv) avl.attach(slave); } - if(enable_video) + if(enable_fast_video) + { + avl.attach(vga); + } else if(enable_accurate_video) { avl.attach(vram); avl_vga.attach(vram_window); @@ -382,14 +396,14 @@ int main(int argc, char **argv) failed = true; } - if(enable_video) + if(enable_accurate_video) { if(!avl_vga.tick(top.clk_clk)) { failed = true; } - vga.tick(top.clk_clk); + vga.signal_tick(top.clk_clk); } if(enable_trace) @@ -8,6 +8,8 @@ #include <SDL2/SDL_surface.h> #include <SDL2/SDL_video.h> +#include "avalon.hpp" + namespace taller::vga { struct timings @@ -26,14 +28,19 @@ namespace taller::vga }; template<class Crtc> - class display + class display : public avalon::slave { public: - display(Crtc &crtc, std::uint32_t clock_hz) noexcept; + display(Crtc &crtc, std::uint32_t base, std::uint32_t clock_hz, std::uint32_t bus_hz = 0) noexcept; ~display() noexcept; - void tick(bool clk) noexcept; + virtual void tick() noexcept final override; + + virtual bool read(std::uint32_t addr, std::uint32_t &data) noexcept final override; + virtual bool write(std::uint32_t addr, std::uint32_t data, unsigned byte_enable) noexcept final override; + + void signal_tick(bool clk) noexcept; inline bool key(std::size_t index) { @@ -41,6 +48,9 @@ namespace taller::vga } private: + unsigned ticks = 0; + unsigned refresh_ticks = 0; + unsigned max_addr = 0; Crtc& crtc; SDL_Window *window = nullptr; const video_mode *mode = nullptr; diff --git a/tb/vga.impl.hpp b/tb/vga.impl.hpp index 9c3294c..988259a 100644 --- a/tb/vga.impl.hpp +++ b/tb/vga.impl.hpp @@ -11,6 +11,8 @@ #include <SDL2/SDL_surface.h> #include <SDL2/SDL_video.h> +#include "avalon.hpp" + namespace { // https://web.mit.edu/6.111/www/s2004/NEWKIT/vga.shtml @@ -35,10 +37,26 @@ namespace namespace taller::vga { template<class Crtc> - display<Crtc>::display(Crtc &crtc, std::uint32_t clock_hz) noexcept - : crtc(crtc), + display<Crtc>::display(Crtc &crtc, std::uint32_t base, std::uint32_t clock_hz, std::uint32_t bus_hz) noexcept + : avalon::slave(base, 64 << 20, 4), + crtc(crtc), clock_hz(clock_hz) - {} + { + if(bus_hz > 0) + { + mode = &MODES[0]; + max_addr = mode->h.active * mode->v.active; + + refresh_ticks = + static_cast<float>(bus_hz) + / mode->pixel_clk + * (mode->h.active + mode->h.front_porch + mode->h.sync + mode->h.back_porch) + * (mode->v.active + mode->v.front_porch + mode->v.sync + mode->v.back_porch); + + ticks = refresh_ticks - 1; + update_window(); + } + } template<class Crtc> display<Crtc>::~display() noexcept @@ -48,7 +66,54 @@ namespace taller::vga } template<class Crtc> - void display<Crtc>::tick(bool clk) noexcept + void display<Crtc>::tick() noexcept + { + if(++ticks == refresh_ticks) + { + ticks = 0; + if(!window) + { + update_window(); + } + + if(window) + { + ::SDL_UpdateWindowSurface(window); + } + } + } + + template<class Crtc> + bool display<Crtc>::read(std::uint32_t addr, std::uint32_t &data) noexcept + { + return true; + } + + template<class Crtc> + bool display<Crtc>::write(std::uint32_t addr, std::uint32_t data, unsigned byte_enable) noexcept + { + if(!window || !mode) + { + return true; + } + + auto *surface = ::SDL_GetWindowSurface(window); + if(!surface) + { + return true; + } + + auto *pixels = static_cast<std::uint32_t*>(surface->pixels); + if(addr < max_addr) + { + pixels[addr] = data; + } + + return true; + } + + template<class Crtc> + void display<Crtc>::signal_tick(bool clk) noexcept { if(!clk) { |
