data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v
1: b'%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:17: Cannot find include file: ../driver.v\n`include "../driver.v" \n         ^~~~~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/524532083/verilog/dv/system_10dot_test,data/full_repos/permissive/524532083/../driver.v\n             data/full_repos/permissive/524532083/verilog/dv/system_10dot_test,data/full_repos/permissive/524532083/../driver.v.v\n             data/full_repos/permissive/524532083/verilog/dv/system_10dot_test,data/full_repos/permissive/524532083/../driver.v.sv\n             ../driver.v\n             ../driver.v.v\n             ../driver.v.sv\n             obj_dir/../driver.v\n             obj_dir/../driver.v.v\n             obj_dir/../driver.v.sv\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:114: syntax error, unexpected (-for-strength, expecting \'(\'\n pulldown (weak0,strong1) p (gpio);\n           ^~~~~\n%Warning-STMTDLY: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:117: Unsupported: Ignoring delay on this delayed statement.\n always #40 clock <= (clock === 1\'b0);\n        ^\n                  ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message.\n%Warning-STMTDLY: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:119: Unsupported: Ignoring delay on this delayed statement.\n always #150 spi_clock <= (spi_clock === 1\'b0);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:161: syntax error, unexpected \'@\'\n         @(posedge clock);\n         ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:172: syntax error, unexpected \'@\'\n   @(negedge spi_clock);\n   ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:176: syntax error, unexpected \'@\'\n   @(posedge spi_clock)\n   ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:181: syntax error, unexpected \'@\'\n  @(posedge clock);\n  ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:262: syntax error, unexpected \'@\'\n      @(posedge clock);\n      ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:268: syntax error, unexpected \'@\'\n      @(posedge update_cycle_complete);\n      ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:278: syntax error, unexpected \'@\'\n      @(posedge update_cycle_complete);\n      ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:302: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:304: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:306: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:325: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:337: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:339: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:352: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:354: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:356: syntax error, unexpected \'@\'\n        @(posedge clock);\n        ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:387: syntax error, unexpected \'@\'\n      @(posedge clock);\n      ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:435: syntax error, unexpected \'@\'\n          @(posedge clock);\n          ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:444: syntax error, unexpected \'@\'\n          @(posedge clock);\n          ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:461: syntax error, unexpected \'@\'\n    @(posedge clock);\n    ^\n%Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:500: Unsupported: Seeding $random doesn\'t map to C++, use $c("srand")\n  seed = $random(seed);\n         ^~~~~~~\n%Error: Internal Error: data/full_repos/permissive/524532083/verilog/dv/system_10dot_test/system_10dot_test_tb.v:500: ../V3Ast.cpp:358: Null item passed to setOp1p\n  seed = $random(seed);\n       ^\n'
module system_10dot_test_tb;

  	localparam NUM_OF_DRIVERS =10;
  	localparam NUM_OF_ROWS =5;
  	localparam NUM_OF_COLS =5;
  	localparam CCR0 =32;
  	localparam CCR1 =128;
	localparam DRIVER_MEM_LEN = 48;
  	localparam NUM_OF_UPDATE_CYCLES = NUM_OF_ROWS*NUM_OF_COLS;  
  localparam MEM_LENGTH           =48;
  localparam MEM_ADDRESS_LENGTH   =6;
  localparam MEM_BOUND            =3;
  localparam NUM_OF_DOTS_PER_MEM    = 3;
  localparam ACTIVE_MEM_LOWER_BOUND = 0;
  localparam ACTIVE_MEM_UPPER_BOUND = ACTIVE_MEM_LOWER_BOUND + NUM_OF_DOTS_PER_MEM * MEM_LENGTH - 1 ;
  localparam SELECT_MEM_LOWER_BOUND = ACTIVE_MEM_UPPER_BOUND + 1 ;
  localparam SELECT_MEM_UPPER_BOUND = SELECT_MEM_LOWER_BOUND + MEM_LENGTH -1 ;
  localparam DOT_MEM_LOWER_BOUND    = SELECT_MEM_UPPER_BOUND + 1 ;
  localparam DOT_MEM_UPPER_BOUND    = DOT_MEM_LOWER_BOUND + NUM_OF_DOTS_PER_MEM - 1 ;
  localparam SYS_MEM_BOUND          = DOT_MEM_UPPER_BOUND;
  localparam SYS_MEM_ADDRESS_LENGTH = 2*MEM_ADDRESS_LENGTH;
	integer seed=0;
	



	reg 		clock;
	reg 		spi_clock;
    	reg 		RSTB;
	reg 		CSB;

	reg 		power1, power2;

	wire 		gpio;
	wire [37:0] 	mprj_io;



  	reg           reset_n;
  	reg           latch_data;
  	reg           control_trigger;
  	wire           sclk;
	reg           mosi;
	reg           ss_n;
	wire          miso;
	wire [NUM_OF_DRIVERS*2-1:0]   driver_io;
	wire          update_cycle_complete;

	wire  		output_state [0:NUM_OF_ROWS-1][NUM_OF_COLS-1:0];
	reg 		dot_2d_array [0:NUM_OF_ROWS-1][NUM_OF_COLS-1:0];
	wire [NUM_OF_DRIVERS*2-1:0]   driver_cell_output;


	assign mprj_io[37]   =	reset_n;     	
	assign mprj_io[36]   =	control_trigger; 	  
	assign mprj_io[35]   = 	latch_data;	
	assign miso          = 	mprj_io[34];
	assign mprj_io[33]   =  mosi; 	   	
	assign mprj_io[32]   = 	ss_n; 	   	
	assign mprj_io[31]   = 	sclk; 	   	
	assign update_cycle_complete = mprj_io[30];
	assign driver_io[0]  = 	mprj_io[29];
	assign driver_io[1]  = 	mprj_io[28];
	assign driver_io[2]  = 	mprj_io[27];
	assign driver_io[3]  = 	mprj_io[26];
	assign driver_io[4]  = 	mprj_io[25];
	assign driver_io[5]  = 	mprj_io[24];
	assign driver_io[6]  = 	mprj_io[23];
	assign driver_io[7]  = 	mprj_io[22];
	assign driver_io[8]  = 	mprj_io[21]; 	   	
	assign driver_io[9]  = 	mprj_io[20]; 	   	
	assign mprj_io[19]   = 	0; 	   	
	assign mprj_io[18]   = 	0; 	   	
	assign driver_io[10] = 	mprj_io[17]; 	   	
	assign driver_io[11] = 	mprj_io[16]; 	   	
	assign driver_io[12] = 	mprj_io[15];
	assign driver_io[13] = 	mprj_io[14];
	assign driver_io[14] = 	mprj_io[13];
	assign driver_io[15] = 	mprj_io[12];
	assign driver_io[16] = 	mprj_io[11];
	assign driver_io[17] = 	mprj_io[10];
	assign driver_io[18] = 	mprj_io[9];
	assign driver_io[19] = 	mprj_io[8];
	assign mprj_io[7]   = 	0; 	   	
	assign mprj_io[6]   = 	0; 	   	
	assign mprj_io[5]   = 	0; 	   	
	assign mprj_io[4]   = 	0; 	   	
	assign mprj_io[3]   = 	0; 	   	
	assign mprj_io[2]   = 	0; 	   	
	assign mprj_io[1]   = 	0; 	   	
	assign mprj_io[0]   = 	0; 	   	


	pulldown (weak0,strong1) p (gpio);


	always #40 clock <= (clock === 1'b0);

	always #150 spi_clock <= (spi_clock === 1'b0);
  	assign sclk = ~ss_n & spi_clock;


	

	initial begin
		clock 		= 0;
      		spi_clock     	= 1;
	end


	task init_signals;
      	begin
        	reset_n 	= 0;
        	control_trigger	= 0;
        	latch_data	= 0;
        	mosi 		= 0;
        	ss_n		= 1;
		wait_n_clocks(50);
    	end
  	endtask

	task enable_chip;
	begin
	      	reset_n      = 1; 
	end
	endtask


	task disable_chip;
	begin
	      	reset_n      = 0; 
	end
	endtask
	

  	task wait_n_clocks;
    	input integer i;
    	integer j;
    	begin
      		for(j=0;j<i;j=j+1)
        	@(posedge clock);
    	end
  	endtask

	task spi_shift;
	input [31:0] data_in;
	output [31:0] data_out;
	integer ii;
	begin
		for(ii=0;ii<32;ii=ii+1)
		begin
			@(negedge spi_clock);
			ss_n = 1'b0;
			mosi = data_in[31];
			data_in = data_in << 1;
			@(posedge spi_clock)
			data_out = {data_out[31:0],miso};
		end
		@(negedge spi_clock);
		ss_n = 1'b1;
		@(posedge clock);
		@(posedge clock);
	end
	endtask

	task spi_write;
	input [31:0] spi_data;
	reg   [31:0] pass;
	begin
		wait_n_clocks(50); 
		latch_data=0;
		wait_n_clocks(50); 
		spi_shift(spi_data,pass);
		wait_n_clocks(50); 
		latch_data=1;
		wait_n_clocks(100); 
		latch_data=0;
		wait_n_clocks(50); 
	end
	endtask

  task write_mem_data_cmd;
    input [3:0]  driver_select;
    input [9:0]  address;
    input [15:0] data;
    reg [31:0] cmd; 
    begin
      cmd[15:0] = data;
      cmd[25:16] = address;
      cmd[29:26] = driver_select;
      cmd[31:30] = 2'b00;
      wait_n_clocks(10);
      wait_n_clocks(10);
      spi_write(cmd);
      wait_n_clocks(10);
    end
  endtask


  task clear_mem;
    input [3:0] device_select;
    integer ii;
    begin
      for(ii=0;ii<SYS_MEM_BOUND+1;ii=ii+1) begin
        write_mem_data_cmd(device_select,ii,16'b0);
      end
    end
  endtask


  task write_to_select_mem;
    input [3:0]  driver_select;
    input [31:0] idx;
    input [31:0] data;
    begin
      write_mem_data_cmd(driver_select,idx+SELECT_MEM_LOWER_BOUND,data); 
    end
  endtask

  task write_to_active_mem;
    input [3:0]  driver_select;
    input [31:0] idx;
    input [31:0] data;
    begin
      write_mem_data_cmd(driver_select,idx+ACTIVE_MEM_LOWER_BOUND,data); 
    end
  endtask

  task write_to_dot_data_mem;
    input [3:0]  driver_select;
    input [31:0] idx;
    input [31:0] data;
    begin
      write_mem_data_cmd(driver_select,idx+DOT_MEM_LOWER_BOUND,data); 
    end
  endtask



  task oneshot_exe;
    begin
      @(posedge clock);
      spi_write({2'b11,4'b1101,26'b0});
      wait_n_clocks(100);
      control_trigger = 1'b1;
      wait_n_clocks(100);
      control_trigger = 1'b0;
      @(posedge update_cycle_complete);
      wait_n_clocks(10);
    end
  endtask

  task refresh_display;
  begin
      control_trigger = 1'b1;
      wait_n_clocks(100);
      control_trigger = 1'b0;
      @(posedge update_cycle_complete);
  end
  endtask

  task update_select;
    input [31:0] driver_select;
    integer ii;
    begin
      for(ii=0;ii<48;ii=ii+1)
      begin
        write_to_select_mem(driver_select,ii,ii);
      end
    end
  endtask

  task update_active_mem_row;
    input [3:0]   driver_select;
    input [6:0]   address;
    input [47:0] data;
    integer ii;
    reg [15:0] d;
    begin
      for(ii=0;ii<3;ii=ii+1)
      begin
        @(posedge clock);
        d = data>>(16*ii);
        @(posedge clock);
        write_to_active_mem(driver_select,address*3,d);
        @(posedge clock);
      end
    end
  endtask

  task update_active_mem_col;
    input [3:0]   driver_select;
    input [9:0]   address;
    input [47:0] data;
    integer ii;
    reg d; 
    reg [15:0] insert_data;
    reg [2:0] mask_offset ;
    reg [9:0] address_offset;
    reg [9:0] row_address;
    begin
      for(ii=0;ii<48;ii=ii+1)
      begin
        insert_data = data[ii];
        @(posedge clock);
        if(address < 16) begin
          address_offset = 0;
          insert_data = insert_data << address;
        end else if(address < 32) begin
          address_offset = 1;
          insert_data = insert_data << (address - 16);
        end else begin
          address_offset = 2;
          insert_data = insert_data << (address - 32);
        end
        row_address = address_offset+3*ii;
        @(posedge clock);
        write_to_active_mem(driver_select,row_address,insert_data);
        @(posedge clock);
      end
    end
  endtask

  task update_dot_data;
    input [3:0]   driver_select;
    input [47:0] data;
    integer ii;
    reg [15:0] d;
    begin
      for(ii=0;ii<3;ii=ii+1)
      begin
        @(posedge clock);
        d = data>>(16*ii);
        @(posedge clock);
        write_to_dot_data_mem(driver_select,ii,d);
        @(posedge clock);
      end
    end
  endtask

  task write_config_cmd;
    input [9:0]  address;
    input [15:0] data;
    reg [31:0] cmd; 
    begin
      cmd[15:0] = data;
      cmd[25:16] = address;
      cmd[29:26] = 4'b0;
      cmd[31:30] = 2'b10;
      wait_n_clocks(10);
      wait_n_clocks(10);
      spi_write(cmd);
      wait_n_clocks(10);
    end
  endtask


  task config_backend;
    input [31:0] _ccr0;
    input [31:0] _ccr1;
    input [31:0] _ordering_complete;
    input [31:0] _row_limit;
    input [31:0] _col_limit;
    input [31:0] _inverter_select;
    input [31:0] _row_col_select;
    begin
      @(posedge clock);
      write_config_cmd(0,_ccr0[15:0]);
      write_config_cmd(1,_ccr0[31:16]);
      write_config_cmd(2,_ccr1[15:0]);
      write_config_cmd(3,_ccr1[31:16]);
      write_config_cmd(4,_ordering_complete[15:0]);
      write_config_cmd(5,_ordering_complete[31:16]);
      write_config_cmd(6,_row_limit);
      write_config_cmd(7,_col_limit);
      write_config_cmd(8,_inverter_select);
      write_config_cmd(9,_row_col_select);
    end
  endtask

  task set_config_5x5;
    integer ii, jj;
    reg [31:0] device;
    begin
      config_backend(CCR0,CCR1,NUM_OF_UPDATE_CYCLES,NUM_OF_ROWS-1,NUM_OF_COLS-1,16'b0000_0011_1110_0000,16'b0000_0000_0001_1111);
      for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
      begin
        device = ii;
        update_active_mem_row(device,device,~(48'b0));
        update_select(device);
      end
      for(ii=0;ii<NUM_OF_COLS;ii=ii+1)
      begin
        device = ii;
        update_active_mem_col(device+NUM_OF_ROWS,device,~(48'b0));
        update_select(device+NUM_OF_ROWS);
      end
    end
  endtask

  task write_5x5_data;

    integer ii,jj;
    reg [47:0] row;
    reg [47:0] col;
    begin

      row=0;
      col=0;
      for(jj=0;jj<NUM_OF_ROWS;jj=jj+1)
      begin
        for(ii=0;ii<NUM_OF_COLS;ii=ii+1)
        begin
          row[ii] = dot_2d_array[jj][ii];
          @(posedge clock);
        end
        update_dot_data(jj,row);
      end
      for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
      begin
        for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
        begin
          col[ii] = dot_2d_array[ii][jj];
          @(posedge clock);
        end
        update_dot_data(jj+NUM_OF_ROWS,col);
      end
    end
  endtask

	task check_output;
	input [31:0] test_case;
	integer ii,jj;
	reg pass;
	begin
		pass=1;
		for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
		begin
			for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
			begin
				@(posedge clock);
				if(dot_2d_array[ii][jj] === output_state[ii][jj])
				begin
					pass=pass&1;
				end
				else
				begin
					pass=pass&0;

				end
			end
		end
		if(pass === 0)
		begin
			$display("Test [%d] FAILED",test_case);
			for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
			begin
				for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
				begin
					if(!(dot_2d_array[ii][jj] === output_state[ii][jj]))
					begin
						$display("testcase[%d] failed : orig[%d][%d]: %d != %d",test_case,ii,jj,dot_2d_array[ii][jj],output_state[ii][jj]);
					end
				end
			end
		end
		else
		begin
		  $display("Test Case [%d] Passed",test_case);
		end
	end
 	endtask

	task test_output_5x5;
	input [31:0] test_case;
	reg [NUM_OF_ROWS*NUM_OF_COLS-1:0] dot_array;
	integer ii,jj;
	begin
		ii=0;
		seed = $random(seed);
		dot_array = seed ^ ($random(seed) ^ $random(ii));
		set_config_5x5();
		for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
		begin
			for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
			begin
				dot_2d_array[ii][jj] = dot_array[ii*NUM_OF_COLS+jj];
			end
		end
		$display("writing 2d array to asic");
		write_5x5_data();
		$display("staring onshot execute asic");
		oneshot_exe();
		check_output(test_case);
	end
	endtask


	initial
	begin
                init_signals();
		#200;
		@(posedge gpio);
		$display("staring test");
		wait_n_clocks(10);
		disable_chip();
		wait_n_clocks(100);
		enable_chip();
		wait_n_clocks(100);
		test_output_5x5(0);
		test_output_5x5(1);
		wait_n_clocks(100);
		$finish();
	  

	end

	initial begin
		$dumpfile("system_10dot_test.vcd");
		$dumpvars(0, system_10dot_test_tb);


		repeat (400) @(posedge clock);
		@(posedge gpio)
		repeat (10000) begin
			repeat (100) @(posedge clock);

		end
		$display("%c[1;31m",27);
		`ifdef GL
			$display ("Monitor: Timeout, Test LA (GL) Failed");
		`else
			$display ("Monitor: Timeout, Test LA (RTL) Failed");
		`endif
		$display("%c[0m",27);
		$finish;
	end
	
	initial begin
		RSTB <= 1'b0;
		CSB  <= 1'b1;
		#2000;
		RSTB <= 1'b1;
		#170000;
		CSB = 1'b0;
	end

	initial begin
		power1 <= 1'b0;
		power2 <= 1'b0;
		#200;
		power1 <= 1'b1;
		#200;
		power2 <= 1'b1;
	end

	wire flash_csb;
	wire flash_clk;
	wire flash_io0;
	wire flash_io1;

	wire VDD1V8;
	wire VDD3V3;
	wire VSS;
    
	assign VDD3V3 = power1;
	assign VDD1V8 = power2;
	assign VSS = 1'b0;




	caravel uut (
		.vddio	  (VDD3V3),
		.vddio_2  (VDD3V3),
		.vssio	  (VSS),
		.vssio_2  (VSS),
		.vdda	  (VDD3V3),
		.vssa	  (VSS),
		.vccd	  (VDD1V8),
		.vssd	  (VSS),
		.vdda1    (VDD3V3),
		.vdda1_2  (VDD3V3),
		.vdda2    (VDD3V3),
		.vssa1	  (VSS),
		.vssa1_2  (VSS),
		.vssa2	  (VSS),
		.vccd1	  (VDD1V8),
		.vccd2	  (VDD1V8),
		.vssd1	  (VSS),
		.vssd2	  (VSS),
		.clock    (clock),
		.gpio     (gpio),
		.mprj_io  (mprj_io),
		.flash_csb(flash_csb),
		.flash_clk(flash_clk),
		.flash_io0(flash_io0),
		.flash_io1(flash_io1),
		.resetb	  (RSTB)
	);

	spiflash #(
		.FILENAME("system_10dot_test.hex")
	) spiflash (
		.csb(flash_csb),
		.clk(flash_clk),
		.io0(flash_io0),
		.io1(flash_io1),
		.io2(),
		.io3()
	);

	genvar I,J;
	generate
		for(I=0;I<NUM_OF_DRIVERS;I=I+1)
		begin
			HBCell u5(
				.p_in                 (driver_io[I*2+1]),
				.n_in                 (driver_io[I*2]),
				.line                 (driver_cell_output[I])
			);
		end                       
		for(I=0;I<NUM_OF_ROWS;I=I+1)
		begin
			for(J=0;J<NUM_OF_COLS;J=J+1)
			begin
				cell_converter u7(
					.in                 ({driver_cell_output[I],driver_cell_output[J+NUM_OF_ROWS]}),
					.state              (output_state[I][J])
				);
			end
		end
	endgenerate                 
		`ifdef ENABLE_SDF
	        
		initial begin

			$sdf_annotate("../../../sdf/controller_unit.sdf", uut.mprj.controller_unit_mod) ;












		end
	`endif
endmodule
module system_10dot_test_tb;


  	localparam NUM_OF_DRIVERS =10;
  	localparam NUM_OF_ROWS =5;
  	localparam NUM_OF_COLS =5;
  	localparam CCR0 =32;
  	localparam CCR1 =128;
	localparam DRIVER_MEM_LEN = 48;
  	localparam NUM_OF_UPDATE_CYCLES = NUM_OF_ROWS*NUM_OF_COLS;  
  localparam MEM_LENGTH           =48;
  localparam MEM_ADDRESS_LENGTH   =6;
  localparam MEM_BOUND            =3;
  localparam NUM_OF_DOTS_PER_MEM    = 3;
  localparam ACTIVE_MEM_LOWER_BOUND = 0;
  localparam ACTIVE_MEM_UPPER_BOUND = ACTIVE_MEM_LOWER_BOUND + NUM_OF_DOTS_PER_MEM * MEM_LENGTH - 1 ;
  localparam SELECT_MEM_LOWER_BOUND = ACTIVE_MEM_UPPER_BOUND + 1 ;
  localparam SELECT_MEM_UPPER_BOUND = SELECT_MEM_LOWER_BOUND + MEM_LENGTH -1 ;
  localparam DOT_MEM_LOWER_BOUND    = SELECT_MEM_UPPER_BOUND + 1 ;
  localparam DOT_MEM_UPPER_BOUND    = DOT_MEM_LOWER_BOUND + NUM_OF_DOTS_PER_MEM - 1 ;
  localparam SYS_MEM_BOUND          = DOT_MEM_UPPER_BOUND;
  localparam SYS_MEM_ADDRESS_LENGTH = 2*MEM_ADDRESS_LENGTH;
	integer seed=0;
	



	reg 		clock;
	reg 		spi_clock;
    	reg 		RSTB;
	reg 		CSB;

	reg 		power1, power2;

	wire 		gpio;
	wire [37:0] 	mprj_io;



  	reg           reset_n;
  	reg           latch_data;
  	reg           control_trigger;
  	wire           sclk;
	reg           mosi;
	reg           ss_n;
	wire          miso;
	wire [NUM_OF_DRIVERS*2-1:0]   driver_io;
	wire          update_cycle_complete;

	wire  		output_state [0:NUM_OF_ROWS-1][NUM_OF_COLS-1:0];
	reg 		dot_2d_array [0:NUM_OF_ROWS-1][NUM_OF_COLS-1:0];
	wire [NUM_OF_DRIVERS*2-1:0]   driver_cell_output;


	assign mprj_io[37]   =	reset_n;     	
	assign mprj_io[36]   =	control_trigger; 	  
	assign mprj_io[35]   = 	latch_data;	
	assign miso          = 	mprj_io[34];
	assign mprj_io[33]   =  mosi; 	   	
	assign mprj_io[32]   = 	ss_n; 	   	
	assign mprj_io[31]   = 	sclk; 	   	
	assign update_cycle_complete = mprj_io[30];
	assign driver_io[0]  = 	mprj_io[29];
	assign driver_io[1]  = 	mprj_io[28];
	assign driver_io[2]  = 	mprj_io[27];
	assign driver_io[3]  = 	mprj_io[26];
	assign driver_io[4]  = 	mprj_io[25];
	assign driver_io[5]  = 	mprj_io[24];
	assign driver_io[6]  = 	mprj_io[23];
	assign driver_io[7]  = 	mprj_io[22];
	assign driver_io[8]  = 	mprj_io[21]; 	   	
	assign driver_io[9]  = 	mprj_io[20]; 	   	
	assign mprj_io[19]   = 	0; 	   	
	assign mprj_io[18]   = 	0; 	   	
	assign driver_io[10] = 	mprj_io[17]; 	   	
	assign driver_io[11] = 	mprj_io[16]; 	   	
	assign driver_io[12] = 	mprj_io[15];
	assign driver_io[13] = 	mprj_io[14];
	assign driver_io[14] = 	mprj_io[13];
	assign driver_io[15] = 	mprj_io[12];
	assign driver_io[16] = 	mprj_io[11];
	assign driver_io[17] = 	mprj_io[10];
	assign driver_io[18] = 	mprj_io[9];
	assign driver_io[19] = 	mprj_io[8];
	assign mprj_io[7]   = 	0; 	   	
	assign mprj_io[6]   = 	0; 	   	
	assign mprj_io[5]   = 	0; 	   	
	assign mprj_io[4]   = 	0; 	   	
	assign mprj_io[3]   = 	0; 	   	
	assign mprj_io[2]   = 	0; 	   	
	assign mprj_io[1]   = 	0; 	   	
	assign mprj_io[0]   = 	0; 	   	


	pulldown (weak0,strong1) p (gpio);


	always #40 clock <= (clock === 1'b0);

	always #150 spi_clock <= (spi_clock === 1'b0);
  	assign sclk = ~ss_n & spi_clock;


	

	initial begin
		clock 		= 0;
      		spi_clock     	= 1;
	end


	task init_signals;
      	begin
        	reset_n 	= 0;
        	control_trigger	= 0;
        	latch_data	= 0;
        	mosi 		= 0;
        	ss_n		= 1;
		wait_n_clocks(50);
    	end
  	endtask

	task enable_chip;
	begin
	      	reset_n      = 1; 
	end
	endtask


	task disable_chip;
	begin
	      	reset_n      = 0; 
	end
	endtask
	

  	task wait_n_clocks;
    	input integer i;
    	integer j;
    	begin
      		for(j=0;j<i;j=j+1)
        	@(posedge clock);
    	end
  	endtask

	task spi_shift;
	input [31:0] data_in;
	output [31:0] data_out;
	integer ii;
	begin
		for(ii=0;ii<32;ii=ii+1)
		begin
			@(negedge spi_clock);
			ss_n = 1'b0;
			mosi = data_in[31];
			data_in = data_in << 1;
			@(posedge spi_clock)
			data_out = {data_out[31:0],miso};
		end
		@(negedge spi_clock);
		ss_n = 1'b1;
		@(posedge clock);
		@(posedge clock);
	end
	endtask

	task spi_write;
	input [31:0] spi_data;
	reg   [31:0] pass;
	begin
		wait_n_clocks(50); 
		latch_data=0;
		wait_n_clocks(50); 
		spi_shift(spi_data,pass);
		wait_n_clocks(50); 
		latch_data=1;
		wait_n_clocks(100); 
		latch_data=0;
		wait_n_clocks(50); 
	end
	endtask

  task write_mem_data_cmd;
    input [3:0]  driver_select;
    input [9:0]  address;
    input [15:0] data;
    reg [31:0] cmd; 
    begin
      cmd[15:0] = data;
      cmd[25:16] = address;
      cmd[29:26] = driver_select;
      cmd[31:30] = 2'b00;
      wait_n_clocks(10);
      wait_n_clocks(10);
      spi_write(cmd);
      wait_n_clocks(10);
    end
  endtask


  task clear_mem;
    input [3:0] device_select;
    integer ii;
    begin
      for(ii=0;ii<SYS_MEM_BOUND+1;ii=ii+1) begin
        write_mem_data_cmd(device_select,ii,16'b0);
      end
    end
  endtask


  task write_to_select_mem;
    input [3:0]  driver_select;
    input [31:0] idx;
    input [31:0] data;
    begin
      write_mem_data_cmd(driver_select,idx+SELECT_MEM_LOWER_BOUND,data); 
    end
  endtask

  task write_to_active_mem;
    input [3:0]  driver_select;
    input [31:0] idx;
    input [31:0] data;
    begin
      write_mem_data_cmd(driver_select,idx+ACTIVE_MEM_LOWER_BOUND,data); 
    end
  endtask

  task write_to_dot_data_mem;
    input [3:0]  driver_select;
    input [31:0] idx;
    input [31:0] data;
    begin
      write_mem_data_cmd(driver_select,idx+DOT_MEM_LOWER_BOUND,data); 
    end
  endtask



  task oneshot_exe;
    begin
      @(posedge clock);
      spi_write({2'b11,4'b1101,26'b0});
      wait_n_clocks(100);
      control_trigger = 1'b1;
      wait_n_clocks(100);
      control_trigger = 1'b0;
      @(posedge update_cycle_complete);
      wait_n_clocks(10);
    end
  endtask

  task refresh_display;
  begin
      control_trigger = 1'b1;
      wait_n_clocks(100);
      control_trigger = 1'b0;
      @(posedge update_cycle_complete);
  end
  endtask

  task update_select;
    input [31:0] driver_select;
    integer ii;
    begin
      for(ii=0;ii<48;ii=ii+1)
      begin
        write_to_select_mem(driver_select,ii,ii);
      end
    end
  endtask

  task update_active_mem_row;
    input [3:0]   driver_select;
    input [6:0]   address;
    input [47:0] data;
    integer ii;
    reg [15:0] d;
    begin
      for(ii=0;ii<3;ii=ii+1)
      begin
        @(posedge clock);
        d = data>>(16*ii);
        @(posedge clock);
        write_to_active_mem(driver_select,address*3,d);
        @(posedge clock);
      end
    end
  endtask

  task update_active_mem_col;
    input [3:0]   driver_select;
    input [9:0]   address;
    input [47:0] data;
    integer ii;
    reg d; 
    reg [15:0] insert_data;
    reg [2:0] mask_offset ;
    reg [9:0] address_offset;
    reg [9:0] row_address;
    begin
      for(ii=0;ii<48;ii=ii+1)
      begin
        insert_data = data[ii];
        @(posedge clock);
        if(address < 16) begin
          address_offset = 0;
          insert_data = insert_data << address;
        end else if(address < 32) begin
          address_offset = 1;
          insert_data = insert_data << (address - 16);
        end else begin
          address_offset = 2;
          insert_data = insert_data << (address - 32);
        end
        row_address = address_offset+3*ii;
        @(posedge clock);
        write_to_active_mem(driver_select,row_address,insert_data);
        @(posedge clock);
      end
    end
  endtask

  task update_dot_data;
    input [3:0]   driver_select;
    input [47:0] data;
    integer ii;
    reg [15:0] d;
    begin
      for(ii=0;ii<3;ii=ii+1)
      begin
        @(posedge clock);
        d = data>>(16*ii);
        @(posedge clock);
        write_to_dot_data_mem(driver_select,ii,d);
        @(posedge clock);
      end
    end
  endtask

  task write_config_cmd;
    input [9:0]  address;
    input [15:0] data;
    reg [31:0] cmd; 
    begin
      cmd[15:0] = data;
      cmd[25:16] = address;
      cmd[29:26] = 4'b0;
      cmd[31:30] = 2'b10;
      wait_n_clocks(10);
      wait_n_clocks(10);
      spi_write(cmd);
      wait_n_clocks(10);
    end
  endtask


  task config_backend;
    input [31:0] _ccr0;
    input [31:0] _ccr1;
    input [31:0] _ordering_complete;
    input [31:0] _row_limit;
    input [31:0] _col_limit;
    input [31:0] _inverter_select;
    input [31:0] _row_col_select;
    begin
      @(posedge clock);
      write_config_cmd(0,_ccr0[15:0]);
      write_config_cmd(1,_ccr0[31:16]);
      write_config_cmd(2,_ccr1[15:0]);
      write_config_cmd(3,_ccr1[31:16]);
      write_config_cmd(4,_ordering_complete[15:0]);
      write_config_cmd(5,_ordering_complete[31:16]);
      write_config_cmd(6,_row_limit);
      write_config_cmd(7,_col_limit);
      write_config_cmd(8,_inverter_select);
      write_config_cmd(9,_row_col_select);
    end
  endtask

  task set_config_5x5;
    integer ii, jj;
    reg [31:0] device;
    begin
      config_backend(CCR0,CCR1,NUM_OF_UPDATE_CYCLES,NUM_OF_ROWS-1,NUM_OF_COLS-1,16'b0000_0011_1110_0000,16'b0000_0000_0001_1111);
      for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
      begin
        device = ii;
        update_active_mem_row(device,device,~(48'b0));
        update_select(device);
      end
      for(ii=0;ii<NUM_OF_COLS;ii=ii+1)
      begin
        device = ii;
        update_active_mem_col(device+NUM_OF_ROWS,device,~(48'b0));
        update_select(device+NUM_OF_ROWS);
      end
    end
  endtask

  task write_5x5_data;

    integer ii,jj;
    reg [47:0] row;
    reg [47:0] col;
    begin

      row=0;
      col=0;
      for(jj=0;jj<NUM_OF_ROWS;jj=jj+1)
      begin
        for(ii=0;ii<NUM_OF_COLS;ii=ii+1)
        begin
          row[ii] = dot_2d_array[jj][ii];
          @(posedge clock);
        end
        update_dot_data(jj,row);
      end
      for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
      begin
        for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
        begin
          col[ii] = dot_2d_array[ii][jj];
          @(posedge clock);
        end
        update_dot_data(jj+NUM_OF_ROWS,col);
      end
    end
  endtask

	task check_output;
	input [31:0] test_case;
	integer ii,jj;
	reg pass;
	begin
		pass=1;
		for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
		begin
			for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
			begin
				@(posedge clock);
				if(dot_2d_array[ii][jj] === output_state[ii][jj])
				begin
					pass=pass&1;
				end
				else
				begin
					pass=pass&0;

				end
			end
		end
		if(pass === 0)
		begin
			$display("Test [%d] FAILED",test_case);
			for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
			begin
				for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
				begin
					if(!(dot_2d_array[ii][jj] === output_state[ii][jj]))
					begin
						$display("testcase[%d] failed : orig[%d][%d]: %d != %d",test_case,ii,jj,dot_2d_array[ii][jj],output_state[ii][jj]);
					end
				end
			end
		end
		else
		begin
		  $display("Test Case [%d] Passed",test_case);
		end
	end
 	endtask

	task test_output_5x5;
	input [31:0] test_case;
	reg [NUM_OF_ROWS*NUM_OF_COLS-1:0] dot_array;
	integer ii,jj;
	begin
		ii=0;
		seed = $random(seed);
		dot_array = seed ^ ($random(seed) ^ $random(ii));
		set_config_5x5();
		for(ii=0;ii<NUM_OF_ROWS;ii=ii+1)
		begin
			for(jj=0;jj<NUM_OF_COLS;jj=jj+1)
			begin
				dot_2d_array[ii][jj] = dot_array[ii*NUM_OF_COLS+jj];
			end
		end
		$display("writing 2d array to asic");
		write_5x5_data();
		$display("staring onshot execute asic");
		oneshot_exe();
		check_output(test_case);
	end
	endtask


	initial
	begin
                init_signals();
		#200;
		@(posedge gpio);
		$display("staring test");
		wait_n_clocks(10);
		disable_chip();
		wait_n_clocks(100);
		enable_chip();
		wait_n_clocks(100);
		test_output_5x5(0);
		test_output_5x5(1);
		wait_n_clocks(100);
		$finish();
	  

	end

	initial begin
		$dumpfile("system_10dot_test.vcd");
		$dumpvars(0, system_10dot_test_tb);


		repeat (400) @(posedge clock);
		@(posedge gpio)
		repeat (10000) begin
			repeat (100) @(posedge clock);

		end
		$display("%c[1;31m",27);
		`ifdef GL
			$display ("Monitor: Timeout, Test LA (GL) Failed");
		`else
			$display ("Monitor: Timeout, Test LA (RTL) Failed");
		`endif
		$display("%c[0m",27);
		$finish;
	end
	
	initial begin
		RSTB <= 1'b0;
		CSB  <= 1'b1;
		#2000;
		RSTB <= 1'b1;
		#170000;
		CSB = 1'b0;
	end

	initial begin
		power1 <= 1'b0;
		power2 <= 1'b0;
		#200;
		power1 <= 1'b1;
		#200;
		power2 <= 1'b1;
	end

	wire flash_csb;
	wire flash_clk;
	wire flash_io0;
	wire flash_io1;

	wire VDD1V8;
	wire VDD3V3;
	wire VSS;
    
	assign VDD3V3 = power1;
	assign VDD1V8 = power2;
	assign VSS = 1'b0;




	caravel uut (
		.vddio	  (VDD3V3),
		.vddio_2  (VDD3V3),
		.vssio	  (VSS),
		.vssio_2  (VSS),
		.vdda	  (VDD3V3),
		.vssa	  (VSS),
		.vccd	  (VDD1V8),
		.vssd	  (VSS),
		.vdda1    (VDD3V3),
		.vdda1_2  (VDD3V3),
		.vdda2    (VDD3V3),
		.vssa1	  (VSS),
		.vssa1_2  (VSS),
		.vssa2	  (VSS),
		.vccd1	  (VDD1V8),
		.vccd2	  (VDD1V8),
		.vssd1	  (VSS),
		.vssd2	  (VSS),
		.clock    (clock),
		.gpio     (gpio),
		.mprj_io  (mprj_io),
		.flash_csb(flash_csb),
		.flash_clk(flash_clk),
		.flash_io0(flash_io0),
		.flash_io1(flash_io1),
		.resetb	  (RSTB)
	);

	spiflash #(
		.FILENAME("system_10dot_test.hex")
	) spiflash (
		.csb(flash_csb),
		.clk(flash_clk),
		.io0(flash_io0),
		.io1(flash_io1),
		.io2(),
		.io3()
	);

	genvar I,J;
	generate
		for(I=0;I<NUM_OF_DRIVERS;I=I+1)
		begin
			HBCell u5(
				.p_in                 (driver_io[I*2+1]),
				.n_in                 (driver_io[I*2]),
				.line                 (driver_cell_output[I])
			);
		end                       
		for(I=0;I<NUM_OF_ROWS;I=I+1)
		begin
			for(J=0;J<NUM_OF_COLS;J=J+1)
			begin
				cell_converter u7(
					.in                 ({driver_cell_output[I],driver_cell_output[J+NUM_OF_ROWS]}),
					.state              (output_state[I][J])
				);
			end
		end
	endgenerate                 
		`ifdef ENABLE_SDF
	        
		initial begin

			$sdf_annotate("../../../sdf/controller_unit.sdf", uut.mprj.controller_unit_mod) ;












		end
	`endif
endmodule