Video in testbench
authorlekernel <sebastien.bourdeauducq@lekernel.net>
Mon, 28 Jun 2010 21:22:38 +0000 (23:22 +0200)
committerlekernel <sebastien.bourdeauducq@lekernel.net>
Mon, 28 Jun 2010 21:22:38 +0000 (23:22 +0200)
cores/bt656cap/rtl/bt656cap.v
cores/bt656cap/rtl/bt656cap_colorspace.v
cores/bt656cap/rtl/bt656cap_ctlif.v
cores/bt656cap/rtl/bt656cap_decoder.v
cores/bt656cap/rtl/bt656cap_dma.v
cores/bt656cap/test/Makefile [new file with mode: 0644]
cores/bt656cap/test/tb_bt656cap.v [new file with mode: 0644]
cores/bt656cap/test/vpi_imageout.c [new file with mode: 0644]

index 5aee21a..a485311 100644 (file)
@@ -30,9 +30,9 @@ module bt656cap #(
        output irq,
 
        output [fml_depth-1:0] fml_adr,
-       output reg fml_stb,
+       output fml_stb,
        input fml_ack,
-       output [63:0] fml_do
+       output [63:0] fml_do,
 
        input vid_clk,
        input [7:0] p,
index fc5fd59..18d3a25 100644 (file)
@@ -48,7 +48,7 @@ always @(*) begin
 end
 
 reg [16:0] mult_result;
-reg [8:0] mult_result_t = mult_result[16:8];
+wire [8:0] mult_result_t = mult_result[16:8];
 always @(posedge vid_clk) mult_result <= mult_opa*mult_opb;
 
 reg [8:0] int_r0;
@@ -64,24 +64,24 @@ reg sub_g;
 reg add_b;
 always @(posedge vid_clk) begin
        if(load_y) begin
-               r0 <= y0;
-               g0 <= y0;
-               b0 <= y0;
-               r1 <= y1;
-               g1 <= y1;
-               b1 <= y1;
+               int_r0 <= y0;
+               int_g0 <= y0;
+               int_b0 <= y0;
+               int_r1 <= y1;
+               int_g1 <= y1;
+               int_b1 <= y1;
        end
        if(add_r) begin
-               r0 <= r0 + mult_result_t;
-               r1 <= r1 + mult_result_t;
+               int_r0 <= int_r0 + mult_result_t;
+               int_r1 <= int_r1 + mult_result_t;
        end
        if(sub_g) begin
-               g0 <= g0 - mult_result_t;
-               g1 <= g1 - mult_result_t;
+               int_g0 <= int_g0 - mult_result_t;
+               int_g1 <= int_g1 - mult_result_t;
        end
        if(add_b) begin
-               b0 <= b0 + mult_result_t;
-               b1 <= b1 + mult_result_t;
+               int_b0 <= int_b0 + mult_result_t;
+               int_b1 <= int_b1 + mult_result_t;
        end
 end
 
@@ -176,14 +176,14 @@ always @(*) begin
                        next_state = S5;
                end
                S5: begin
-                       fml_stb = 1'b1;
+                       fsm_stb = 1'b1;
                        load_y = 1'b1;
                        mult_sela = 1'b1; // 1.402*Cr
                        mult_selb = 2'd0;
                        if(stb_i)
                                next_state = S2;
                        else
-                               next_state = S0;
+                               next_state = S1;
                end
        endcase
 end
index ae2f4f3..bc36878 100644 (file)
@@ -37,7 +37,7 @@ module bt656cap_ctlif #(
        output reg last_burst,
 
        inout sda,
-       output sdc
+       output reg sdc
 );
 
 /* I2C */
@@ -64,8 +64,13 @@ always @(posedge sys_clk) begin
        if(sys_rst) begin
                csr_do <= 32'd0;
 
+               field_filter <= 2'd0;
+               fml_adr_base <= {fml_depth-5{1'b0}};
+               max_bursts <= 15'd13824;
+
                sda_oe <= 1'b0;
                sda_o <= 1'b0;
+               sdc <= 1'b0;
        end else begin
                csr_do <= 32'd0;
 
@@ -75,6 +80,7 @@ always @(posedge sys_clk) begin
                                        3'd0: begin
                                                sda_o <= csr_di[1];
                                                sda_oe <= csr_di[2];
+                                               sdc <= csr_di[3];
                                        end
                                        3'd1: field_filter <= csr_di[1:0];
                                        3'd2: fml_adr_base <= csr_di[fml_depth-1:5];
@@ -83,7 +89,7 @@ always @(posedge sys_clk) begin
                        end
 
                        case(csr_a[2:0])
-                               3'd0: csr_do <= {sda_oe, sda_o, sda_2};
+                               3'd0: csr_do <= {sdc, sda_oe, sda_o, sda_2};
                                3'd1: csr_do <= {in_frame, field_filter};
                                3'd2: csr_do <= {fml_adr_base, 5'd0};
                                3'd3: csr_do <= max_bursts;
index 994f484..f45ec83 100644 (file)
@@ -66,9 +66,9 @@ always @(posedge vid_clk) begin
                /* just transferred a new 32-bit word */
                if(inreg[31:8] == 24'hff0000) begin
                        /*┬átiming code */
-                       in_hblank <= in_reg[4];
-                       in_vblank <= in_reg[5];
-                       in_field <= in_reg[6];
+                       in_hblank <= inreg[4];
+                       in_vblank <= inreg[5];
+                       in_field <= inreg[6];
                end else begin
                        /*┬ádata */
                        if(~in_hblank && ~in_vblank) begin
index cc0ba8e..1cba90e 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 module bt656cap_dma #(
-       input fml_depth = 27
+       parameter fml_depth = 27
 ) (
        input sys_clk,
        input sys_rst,
@@ -35,7 +35,7 @@ module bt656cap_dma #(
        input v_field,
        input [31:0] v_rgb565,
 
-       /* FML interface. fml_we=1 is assumed. */
+       /* FML interface. fml_we=1 and fml_sel=ff are assumed. */
        output [fml_depth-1:0] fml_adr,
        output reg fml_stb,
        input fml_ack,
@@ -69,7 +69,7 @@ bt656cap_burstmem burstmem(
 );
 
 /* FML address generator */
-reg [fml_adr-1-5:0] fml_adr_b;
+reg [fml_depth-1-5:0] fml_adr_b;
 
 always @(posedge sys_clk) begin
        if(start_of_frame)
@@ -106,7 +106,7 @@ always @(posedge sys_clk) begin
        if(sys_rst)
                state <= WAIT_SOF;
        else
-               stats <= next_state;
+               state <= next_state;
 end
 
 always @(*) begin
diff --git a/cores/bt656cap/test/Makefile b/cores/bt656cap/test/Makefile
new file mode 100644 (file)
index 0000000..c05a92d
--- /dev/null
@@ -0,0 +1,17 @@
+SOURCES=$(wildcard ../rtl/*.v) $(wildcard ../../asfifo/rtl/*.v) tb_bt656cap.v
+
+all: sim
+
+sim: vpi_imageout.so
+       cver +loadvpi=./vpi_imageout.so:vpi_register $(SOURCES)
+
+vpi_imageout.so: vpi_imageout.o
+       $(LD) -G -shared -export-dynamic -o vpi_imageout.so vpi_imageout.o -lgd -lpng -lz -ljpeg -lfreetype -lm
+
+vpi_imageout.o: vpi_imageout.c
+       $(CC) -I/usr/include/cver -fPIC -Wall -O2 -c -o vpi_imageout.o vpi_imageout.c
+
+clean:
+       rm -f verilog.log vpi_imageout.o vpi_imageout.so out.png
+
+.PHONY: clean sim
diff --git a/cores/bt656cap/test/tb_bt656cap.v b/cores/bt656cap/test/tb_bt656cap.v
new file mode 100644 (file)
index 0000000..488be51
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Milkymist VJ SoC
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+module tb_bt656cap();
+
+parameter fml_depth = 26;
+
+reg sys_clk;
+reg sys_rst;
+
+reg [13:0] csr_a;
+reg csr_we;
+reg [31:0] csr_di;
+wire [31:0] csr_do;
+
+wire irq;
+
+wire [fml_depth-1:0] fml_adr;
+wire fml_stb;
+reg fml_ack;
+wire [63:0] fml_do;
+
+reg vid_clk;
+reg [7:0] p;
+
+/* 100MHz system clock */
+initial sys_clk = 1'b0;
+always #5 sys_clk = ~sys_clk;
+
+/* ~27MHz video clock */
+initial vid_clk = 1'b0;
+always #19 vid_clk = ~vid_clk;
+
+reg field;
+reg [19:0] inc;
+initial field = 1'b0;
+initial inc = 20'd0;
+always @(posedge vid_clk) begin
+       inc <= inc + 20'd1;
+       p <= inc[7:0];
+       if(inc == 20'd442368) begin
+               field <= ~field;
+               p <= 8'hff;
+       end
+       if(inc == 20'd442369) p <= 8'h00;
+       if(inc == 20'd442370) p <= 8'h00;
+       if(inc == 20'd442371) begin
+               p <= {1'b1, field, 6'b00_0000};
+               inc <= 20'd0;
+       end
+end
+
+bt656cap #(
+       .fml_depth(fml_depth)
+) dut (
+       .sys_clk(sys_clk),
+       .sys_rst(sys_rst),
+       
+       .csr_a(csr_a),
+       .csr_we(csr_we),
+       .csr_di(csr_di),
+       .csr_do(csr_do),
+       
+       .irq(irq),
+       
+       .fml_adr(fml_adr),
+       .fml_stb(fml_stb),
+       .fml_ack(fml_ack),
+       .fml_do(fml_do),
+
+       .vid_clk(vid_clk),
+       .p(p),
+       .sda(),
+       .sdc()
+);
+
+task waitclock;
+begin
+       @(posedge sys_clk);
+       #1;
+end
+endtask
+
+task csrwrite;
+input [31:0] address;
+input [31:0] data;
+begin
+       csr_a = address[16:2];
+       csr_di = data;
+       csr_we = 1'b1;
+       waitclock;
+       $display("CSR write: %x=%x", address, data);
+       csr_we = 1'b0;
+end
+endtask
+
+task csrread;
+input [31:0] address;
+begin
+       csr_a = address[16:2];
+       waitclock;
+       $display("CSR read : %x=%x", address, csr_do);
+end
+endtask
+
+/* Handle FML master for pixel writes */
+integer write_burstcount;
+integer write_addr;
+
+task handle_write;
+integer write_addr2;
+integer x;
+integer y;
+begin
+       write_addr2 = write_addr[20:0]/2;
+       x = write_addr2 % 512;
+       y = write_addr2 / 512;
+       $image_set(1, x + 0, y, fml_do[63:48]);
+       $image_set(1, x + 1, y, fml_do[47:32]);
+       $image_set(1, x + 2, y, fml_do[31:16]);
+       $image_set(1, x + 3, y, fml_do[15:0]);
+end
+endtask
+
+initial write_burstcount = 0;
+always @(posedge sys_clk) begin
+       fml_ack = 1'b0;
+       if(write_burstcount == 0) begin
+               if(fml_stb & (($random % 5) == 0)) begin
+                       write_burstcount = 1;
+                       write_addr = fml_adr;
+                       
+                       $display("Starting   FML burst WRITE at address %x data=%x", write_addr, fml_do);
+                       handle_write;
+                       
+                       fml_ack = 1'b1;
+               end
+       end else begin
+               write_addr = write_addr + 8;
+               write_burstcount = write_burstcount + 1;
+               
+               $display("Continuing FML burst WRITE at address %x data=%x", write_addr, fml_do);
+               handle_write;
+               
+               if(write_burstcount == 4)
+                       write_burstcount = 0;
+       end
+end
+
+always begin
+       $image_open;
+       
+       /* Reset / Initialize our logic */
+       sys_rst = 1'b1;
+       
+       csr_a = 14'd0;
+       csr_di = 32'd0;
+       csr_we = 1'b0;
+
+       fml_ack = 1'b0;
+       
+       waitclock;
+       
+       sys_rst = 1'b0;
+       
+       waitclock;
+
+       /* Setup */
+       $display("Configuring DUT...");
+       csrwrite(32'h04, 32'h03);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       csrread(32'h04);
+       @(posedge irq);
+
+       $image_close;
+       $finish;
+end
+
+endmodule
diff --git a/cores/bt656cap/test/vpi_imageout.c b/cores/bt656cap/test/vpi_imageout.c
new file mode 100644 (file)
index 0000000..7a5ca53
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Milkymist VJ SoC
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <vpi_user.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gd.h>
+
+static gdImagePtr dst;
+
+/*
+ * Open output images.
+ *
+ * Use from Verilog:
+ * call $image_open at the beginning of the testbench.
+ */
+static int open_calltf(char *user_data)
+{
+       dst = gdImageCreateTrueColor(720, 288);
+       if(dst == NULL) {
+               fprintf(stderr, "Unable to create output picture\n");
+               exit(1);
+       }
+       return 0;
+}
+
+/*
+ * Set a RGB565 pixel.
+ *
+ * Use from Verilog:
+ * $image_set(img, x, y, color);
+ * img = 0/1 (source/dest)
+ * Parameters are not modified.
+ */
+static int set_calltf(char *user_data)
+{
+       vpiHandle sys;
+       vpiHandle argv;
+       vpiHandle item;
+       s_vpi_value value;
+       unsigned int x, y;
+       unsigned int c;
+       unsigned int red, green, blue;
+       
+       sys = vpi_handle(vpiSysTfCall, 0);
+       argv = vpi_iterate(vpiArgument, sys);
+       
+       /* get x */
+       item = vpi_scan(argv);
+       value.format = vpiIntVal;
+       vpi_get_value(item, &value);
+       x = value.value.integer;
+
+       /* get y */
+       item = vpi_scan(argv);
+       value.format = vpiIntVal;
+       vpi_get_value(item, &value);
+       y = value.value.integer;
+
+       /* get color */
+       item = vpi_scan(argv);
+       value.format = vpiIntVal;
+       vpi_get_value(item, &value);
+       c = value.value.integer;
+
+       vpi_free_object(argv);
+
+       /* do the job */
+       /* extract raw 5, 6 and 5-bit components */
+       red = (c & 0xf800) >> 11;
+       green = (c & 0x07e0) >> 5;
+       blue = c & 0x001f;
+       
+       /* shift right and complete with MSBs */
+       red = (red << 3) | ((red & 0x1c) >> 2);
+       green = (green << 2) | ((green & 0x30) >> 4);
+       blue = (blue << 3) | ((blue & 0x1c) >> 2);
+       
+       //printf("Set Pixel (%d,%d), %02x%02x%02x\n", x, y, red, green, blue);
+       
+       gdImageSetPixel(dst, x, y,
+               gdImageColorAllocate(dst, red, green, blue));
+       
+       return 0;
+}
+
+/*
+ * Close output image.
+ *
+ * Use from Verilog:
+ * call $image_close at the end of the testbench.
+ * Don't forget it, or the destination file will
+ * not be written !
+ */
+static int close_calltf(char *user_data)
+{
+       FILE *fd;
+       
+       fd = fopen("out.png", "wb");
+       gdImagePng(dst, fd);
+       fclose(fd);
+       gdImageDestroy(dst);
+       return 0;
+}
+
+void vpi_register()
+{
+       s_vpi_systf_data tf_data;
+       
+       tf_data.type      = vpiSysTask;
+       tf_data.tfname    = "$image_open";
+       tf_data.calltf    = open_calltf;
+       tf_data.compiletf = 0;
+       tf_data.sizetf    = 0;
+       tf_data.user_data = 0;
+       vpi_register_systf(&tf_data);
+
+       tf_data.type      = vpiSysTask;
+       tf_data.tfname    = "$image_set";
+       tf_data.calltf    = set_calltf;
+       tf_data.compiletf = 0;
+       tf_data.sizetf    = 0;
+       tf_data.user_data = 0;
+       vpi_register_systf(&tf_data);
+       
+       tf_data.type      = vpiSysTask;
+       tf_data.tfname    = "$image_close";
+       tf_data.calltf    = close_calltf;
+       tf_data.compiletf = 0;
+       tf_data.sizetf    = 0;
+       tf_data.user_data = 0;
+       vpi_register_systf(&tf_data);
+       
+       printf("PLI Image output functions registered\n");
+}
+
+void (*vlog_startup_routines[])() = {
+       vpi_register,
+       0
+};