buid/sim: add vga framebuffer with SDL
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 4 May 2016 18:17:02 +0000 (20:17 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 4 May 2016 18:17:02 +0000 (20:17 +0200)
litex/boards/platforms/sim.py
litex/build/sim/dut_tb.cpp
litex/build/sim/verilator.py

index 6860fde07f1823f321ce84c6d8138e64e2b8ab67..ad969fce4332740c4870b4d757ab939b57b64b9f 100644 (file)
@@ -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)),
+    ),
 ]
 
 
index f2b4804685ccfb986d0a1de242195b576122905a..0fbf45b4eafab30a71629193330e9eb03944b58b 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/if.h>
 #include <linux/if_tun.h>
 
+#include <SDL/SDL.h>
+
 /* ios */
 
 #ifdef SERIAL_SOURCE_VALID
 #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);
 }
index 19dcc83c1429a31af10df8ebee0c191be403674d..5335d987b02d84bab4560c0c64bd87f0ab2259ba 100644 (file)
@@ -1,4 +1,4 @@
-# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
+# This file is Copyright (c) 2015-2016 Florent Kermarrec <florent@enjoy-digital.fr>
 # 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)