testbench.cpp (6448B)
1 /* Copyright 2014 Brian Swetland <swetland@frotz.net> 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 /* reusable verilator testbench driver 17 * - expects the top module to be testbench(clk); 18 * - provides clk to module 19 * - handles vcd tracing if compiled with TRACE 20 * - allows tracefilename to be specified via -o 21 */ 22 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/types.h> 27 #include <unistd.h> 28 #include <fcntl.h> 29 30 #include "Vtestbench.h" 31 #include "verilated.h" 32 #include <verilated_vcd_c.h> 33 34 #ifdef SDRAM 35 #include "sim-sdram.h" 36 #endif 37 38 static unsigned memory[65536]; 39 40 void dpi_mem_write(int addr, int data) { 41 //fprintf(stdout,"WR %08x = %08x\n", addr, data); 42 memory[addr & 0xFFFF] = data; 43 } 44 45 void dpi_mem_read(int addr, int *data) { 46 //fprintf(stdout,"RD %08x = %08x\n", addr, memory[addr & 0xFFFF]); 47 *data = (int) memory[addr & 0xFFFF]; 48 } 49 50 int dpi_mem_read2(int addr) { 51 //fprintf(stdout,"Rd %08x = %08x\n", addr, memory[addr & 0xFFFF]); 52 return (int) memory[addr & 0xFFFF]; 53 } 54 55 void loadmem(const char *fn) { 56 unsigned a = 0; 57 FILE *fp = fopen(fn, "r"); 58 char buf[128]; 59 memset(memory, 0xaa, sizeof(memory)); 60 if (fp == NULL) { 61 fprintf(stderr, "warning: cannot load memory from '%s'\n", fn); 62 return; 63 } 64 while (fgets(buf, 128, fp) != NULL) { 65 unsigned n; 66 char *x = buf; 67 while (isspace(*x)) x++; 68 if (*x == '#') continue; 69 if ((x[0] == '/') && (x[1] == '/')) continue; 70 n = 0; 71 if (x[0] == '.') { 72 x++; 73 while (isdigit(*x)) { 74 n <<= 1; 75 if (*x == '1') { 76 n |= 1; 77 } 78 x++; 79 } 80 } else { 81 sscanf(x, "%x", &n); 82 } 83 //fprintf(stderr,"mem[%08x] = %08x\n",a,n); 84 memory[a++] = n; 85 if (a == 4096) break; 86 } 87 } 88 89 #ifdef VGA 90 #define FRAME_W 800 91 #define FRAME_H 524 92 #define FRAME_TICKS (FRAME_W * FRAME_H) 93 #define FRAME_BYTES (FRAME_W * FRAME_H * 3) 94 95 static unsigned vga_ticks = 0; 96 static unsigned vga_frames = 0; 97 static unsigned char vga_data[2][FRAME_BYTES]; 98 static unsigned vga_active; 99 100 static int vga_tick(int hs, int vs, int fr, int red, int grn, int blu) { 101 if (fr) { 102 //fprintf(stderr, "VGA: frame=%u active=%u ticks=%u\n", 103 // vga_frames, vga_active, vga_ticks); 104 if (vga_ticks < FRAME_TICKS) { 105 fprintf(stderr, "VGA: frame too small: %u ticks\n", vga_ticks); 106 } else if (vga_ticks > FRAME_TICKS) { 107 fprintf(stderr, "VGA: frame too large: %u ticks\n", vga_ticks); 108 } else if (memcmp(vga_data[vga_active], vga_data[!vga_active], FRAME_BYTES)) { 109 char tmp[256]; 110 sprintf(tmp, "frame%04d.ppm", vga_frames); 111 int fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644); 112 if (fd < 0) { 113 fprintf(stderr, "VGA: cannot write '%s'\n", tmp); 114 } else { 115 sprintf(tmp, "P6\n%u %u 15\n", FRAME_W, FRAME_H); 116 write(fd, tmp, strlen(tmp)); 117 write(fd, vga_data[vga_active], FRAME_BYTES); 118 close(fd); 119 } 120 vga_active = !vga_active; 121 } else { 122 //fprintf(stderr, "VGA: frame %u did not change\n", vga_frames); 123 } 124 memset(vga_data[vga_active], 0xff, FRAME_BYTES); 125 vga_ticks = 0; 126 vga_frames++; 127 if (vga_frames == 5) { 128 return -1; 129 } 130 } 131 if (vga_ticks < FRAME_TICKS) { 132 unsigned char* pixel = vga_data[vga_active] + vga_ticks * 3; 133 if (hs == 0) { 134 pixel[0] = 0xf; 135 pixel[1] = 0x8; 136 pixel[2] = 0x0; 137 } else if (vs == 0) { 138 pixel[0] = 0xf; 139 pixel[1] = 0x0; 140 pixel[2] = 0xf; 141 } else { 142 pixel[0] = red; 143 pixel[1] = grn; 144 pixel[2] = blu; 145 } 146 } 147 vga_ticks++; 148 return 0; 149 } 150 #endif 151 152 #ifdef TRACE 153 static vluint64_t now = 0; 154 155 double sc_time_stamp() { 156 return now; 157 } 158 #endif 159 160 int main(int argc, char **argv) { 161 const char *vcdname = "trace.vcd"; 162 const char *memname = NULL; 163 int fd; 164 165 while (argc > 1) { 166 if (!strcmp(argv[1], "-trace")) { 167 #ifdef TRACE 168 if (argc < 3) { 169 fprintf(stderr,"error: -trace requires argument\n"); 170 return -1; 171 } 172 vcdname = argv[2]; 173 argv += 2; 174 argc -= 2; 175 continue; 176 #else 177 fprintf(stderr,"error: no trace support\n"); 178 return -1; 179 #endif 180 } else if (!strcmp(argv[1], "-dump")) { 181 if (argc < 3) { 182 fprintf(stderr, "error: -dump requires argument\n"); 183 return -1; 184 } 185 memname = argv[2]; 186 argv += 2; 187 argc -= 2; 188 } else if (!strcmp(argv[1], "-load")) { 189 if (argc < 3) { 190 fprintf(stderr, "error: -load requires argument\n"); 191 return -1; 192 } 193 loadmem(argv[2]); 194 argv += 2; 195 argc -= 2; 196 } else { 197 break; 198 } 199 } 200 201 #ifdef SDRAM 202 sim_sdram_init(); 203 #endif 204 205 Verilated::commandArgs(argc, argv); 206 Verilated::debug(0); 207 Verilated::randReset(2); 208 209 Vtestbench *testbench = new Vtestbench; 210 testbench->clk = 1; 211 212 // first tick, line up with gtk's vert lines 213 testbench->eval(); 214 215 #ifdef TRACE 216 Verilated::traceEverOn(true); 217 VerilatedVcdC* tfp = new VerilatedVcdC; 218 testbench->trace(tfp, 99); 219 tfp->open(vcdname); 220 tfp->dump(now); 221 #define SAVETRACE() tfp->dump(now) 222 #else 223 #define SAVETRACE() do {} while (0) 224 #endif 225 226 int oops = 0; 227 while (!(testbench->done | testbench->error | oops)) { //Verilated::gotFinish()) { 228 now += 5; 229 testbench->clk = 0; 230 testbench->eval(); 231 SAVETRACE(); 232 233 now += 5; 234 testbench->clk = 1; 235 #ifdef SDRAM 236 unsigned ctl = 237 (testbench->sdram_ras_n << 2) | 238 (testbench->sdram_cas_n << 1) | 239 (testbench->sdram_we_n << 0); 240 unsigned out = 0; 241 oops = sim_sdram(ctl, testbench->sdram_addr, testbench->sdram_data_o, &out); 242 testbench->sdram_data_i = out; 243 #endif 244 testbench->eval(); 245 SAVETRACE(); 246 #ifdef VGA 247 if (vga_tick(testbench->vga_hsync, testbench->vga_vsync, 248 testbench->vga_frame, testbench->vga_red, 249 testbench->vga_grn, testbench->vga_blu)) { 250 break; 251 } 252 #endif 253 } 254 255 int status = testbench->error ? -1 : 0; 256 fprintf(stderr, "%s: %s\n", argv[0], testbench->error ? "FAIL" : "PASS"); 257 258 #ifdef TRACE 259 tfp->close(); 260 #endif 261 testbench->final(); 262 delete testbench; 263 264 if (memname != NULL) { 265 fd = open(memname, O_WRONLY | O_CREAT | O_TRUNC, 0640); 266 if (fd < 0) { 267 fprintf(stderr, "cannot open '%s' for writing\n", memname); 268 return -1; 269 } 270 write(fd, memory, sizeof(memory)); 271 close(fd); 272 } 273 return status; 274 } 275