diff --git a/litex/boards/platforms/sim.py b/litex/boards/platforms/sim.py index 6860fde07..ad969fce4 100644 --- a/litex/boards/platforms/sim.py +++ b/litex/boards/platforms/sim.py @@ -30,6 +30,14 @@ _io = [ Subsignal("sink_ready", SimPins(1)), Subsignal("sink_data", SimPins(8)), ), + ("vga", 0, + Subsignal("de", SimPins(1)), + Subsignal("hsync", SimPins(1)), + Subsignal("vsync", SimPins(1)), + Subsignal("r", SimPins(8)), + Subsignal("g", SimPins(8)), + Subsignal("b", SimPins(8)), + ), ] diff --git a/litex/build/sim/dut_tb.cpp b/litex/build/sim/dut_tb.cpp index f2b480468..0fbf45b4e 100644 --- a/litex/build/sim/dut_tb.cpp +++ b/litex/build/sim/dut_tb.cpp @@ -17,6 +17,8 @@ #include #include +#include + /* ios */ #ifdef SERIAL_SOURCE_VALID @@ -27,6 +29,10 @@ #define WITH_ETH #endif +#ifdef VGA_DE +#define WITH_VGA +#endif + #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -38,6 +44,9 @@ double sc_time_stamp() return main_time; } +Vdut* dut; +VerilatedVcdC* tfp; + /* Sim struct */ struct sim { bool run; @@ -180,8 +189,78 @@ int eth_read(struct sim *s, unsigned char *buf) } #endif -Vdut* dut; -VerilatedVcdC* tfp; +/* VGA functions */ +#ifdef WITH_VGA + +SDL_Surface *screen; +SDL_Event event; + +void vga_set_pixel(SDL_Surface *screen, int x, int y, char r, char g, char b) +{ + unsigned int *pixmem32; + unsigned int color; + + color = SDL_MapRGB(screen->format, r, g, b); + pixmem32 = (unsigned int*) screen->pixels + y*640 + x; + *pixmem32 = color; +} + +int vga_init(struct sim *s) { + if(SDL_Init(SDL_INIT_VIDEO) < 0) return 1; + if(!(screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE))) { + SDL_Quit(); + return 1; + } + return 0; +} + +int x; +int y; +int hsync_needs_de = 1; +int vsync_needs_de = 1; + +void vga_service(struct sim *s) { + if(VGA_HSYNC == 1 && hsync_needs_de == 0) { + x = 0; + y++; + hsync_needs_de = 1; + } + if(VGA_VSYNC == 1 && vsync_needs_de == 0) { + y = 0; + vsync_needs_de = 1; + if(SDL_MUSTLOCK(screen)) + SDL_UnlockSurface(screen); + SDL_Flip(screen); + if(SDL_MUSTLOCK(screen)) + SDL_LockSurface(screen); + } + if(VGA_DE == 1) { + hsync_needs_de = 0; + vsync_needs_de = 0; + vga_set_pixel(screen, x, y, VGA_R, VGA_G, VGA_B); + x++; + } + + if(s->tick%1000 == 0) { + while(SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + s->run = false; + break; + case SDL_KEYDOWN: + s->run = false; + break; + } + } + } +} + +int vga_close(struct sim *s) { + SDL_Quit(); +} + +#endif + #ifndef WITH_SERIAL_PTY int console_service(struct sim *s) @@ -366,6 +445,10 @@ int main(int argc, char **argv, char **env) eth_open(&s); #endif +#ifdef WITH_VGA + if(vga_init(&s)) return 1; +#endif + s.run = true; while(s.run) { sim_tick(&s); @@ -376,6 +459,9 @@ int main(int argc, char **argv, char **env) #endif #ifdef WITH_ETH ethernet_service(&s); +#endif +#ifdef WITH_VGA + vga_service(&s); #endif } } @@ -387,13 +473,15 @@ int main(int argc, char **argv, char **env) tfp->close(); - #ifdef WITH_SERIAL_PTY console_close(&s); #endif #ifdef WITH_ETH eth_close(&s); #endif +#ifdef WITH_VGA + vga_close(&s); +#endif exit(0); } diff --git a/litex/build/sim/verilator.py b/litex/build/sim/verilator.py index 19dcc83c1..5335d987b 100644 --- a/litex/build/sim/verilator.py +++ b/litex/build/sim/verilator.py @@ -1,4 +1,4 @@ -# This file is Copyright (c) 2015 Florent Kermarrec +# This file is Copyright (c) 2015-2016 Florent Kermarrec # License: BSD import os @@ -71,6 +71,25 @@ def _build_tb(platform, vns, serial, template): except: pass + try: + ios += """ +#define VGA_DE dut->{vga_de} +#define VGA_HSYNC dut->{vga_hsync} +#define VGA_VSYNC dut->{vga_vsync} +#define VGA_R dut->{vga_r} +#define VGA_G dut->{vga_g} +#define VGA_B dut->{vga_b} +""".format( + vga_de=io_name("vga", "de"), + vga_hsync=io_name("vga", "hsync"), + vga_vsync=io_name("vga", "vsync"), + vga_r=io_name("vga", "r"), + vga_g=io_name("vga", "g"), + vga_b=io_name("vga", "b"), + ) + except: + pass + content = "" f = open(template, "r") done = False @@ -91,7 +110,7 @@ def _build_sim(platform, vns, build_name, include_paths, serial, verbose): build_script_contents = """# Autogenerated by LiteX rm -rf obj_dir/ -verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp -LDFLAGS "-lpthread" -trace {include} +verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp -LDFLAGS "-lpthread -lSDL" -trace {include} make -j -C obj_dir/ -f Vdut.mk Vdut """.format( @@ -126,7 +145,7 @@ def _run_sim(build_name): class SimVerilatorToolchain: def build(self, platform, fragment, build_dir="build", build_name="top", - toolchain_path=None, serial="console", run=True, verbose=False): + toolchain_path=None, serial="console", run=True, verbose=True): tools.mkdir_noerror(build_dir) os.chdir(build_dir)