aboutsummaryrefslogtreecommitdiff
`default_nettype none
`timescale 1ns/1ns

`include "messages.vh"

`ifndef SIMULATION
 `error_SIMULATION_not_defined
; /* Cause syntax error */
`endif

`define MAX_WORD_IDX 1280

/*
 * Using model from models/master.v would require an operations file over 1280
 * lines long, so we'll write a custom master instead.
 */
module simple_master
  (
   input wire 	      ACK_I,
   input wire 	      CLK_I,
   output wire [19:0] ADR_O,
   input wire [15:0]  DAT_I,
   output wire [15:0] DAT_O,
   input wire 	      RST_I,
   output wire 	      STB_O,
   output wire 	      CYC_O,
   output wire 	      WE_O,
   input wire 	      STALL_I,

   /* Non-wishbone */
   output wire 	      finished
   );

   integer 	      commands_sent;
   integer 	      commands_acknowledged;

   wire 	      sent;
   wire 	      acknowledged;
   assign sent = !STALL_I && STB_O;
   assign acknowledged
     = ((commands_acknowledged == commands_sent && STB_O && !STALL_I) ||
	commands_acknowledged < commands_sent) && ACK_I;

   wire 	      sent_all;
   wire 	      acknowledged_all;
   assign sent_all = commands_sent == `MAX_WORD_IDX + 1 ||
		     (commands_sent == `MAX_WORD_IDX && sent);
   assign acknowledged_all = commands_acknowledged == `MAX_WORD_IDX + 1 ||
			     (commands_acknowledged == `MAX_WORD_IDX &&
			      acknowledged);

   assign finished = acknowledged_all;

   reg 		      sending;

   assign STB_O = sending;
   assign WE_O = sending;
   assign CYC_O = !acknowledged_all && !RST_I;
   assign ADR_O = commands_sent;
   assign DAT_O = commands_sent == `MAX_WORD_IDX ? 1 :
		  {commands_sent[6:0], 1'b1, commands_sent[6:0], 1'b0};

   initial begin
      commands_sent <= 0;
      commands_acknowledged <= 0;
   end

   always @ (posedge CLK_I) begin
      if (RST_I) begin
	 sending <= 0;
	 commands_sent <= 0;
	 commands_acknowledged <= 0;
      end else begin
	 if (sent)
	   commands_sent <= commands_sent + 1;

	 if (acknowledged)
	   commands_acknowledged <= commands_acknowledged + 1;

	 if (sent_all)
	   sending <= 0;
	 else
	   sending <= 1;
      end // else: !if(RST_I)
   end // always @ (posedge CLK_I)
endmodule // simple_master

module vga_test
  #(
    /* wishbone clock isn't in any special way related to clock_25mhz */
    parameter WISHBONE_CLOCK_PERIOD = 14 /* ns */
    ) ();
   wire        M_ACK_I;
   wire        M_CLK_I;
   wire [19:0] M_ADR_O;
   wire [15:0] M_DAT_I;
   wire [15:0] M_DAT_O;
   wire        M_RST_I;
   wire        M_STB_O;
   wire        M_CYC_O;
   wire        M_WE_O;
   wire        M_STALL_I;

   wire        S_ACK_O;
   wire        S_CLK_I;
   wire [10:0] S_ADR_I;
   wire [15:0] S_DAT_I;
   wire [15:0] S_DAT_O;
   wire        S_RST_I;
   wire        S_STB_I;
   wire        S_WE_I;
   wire        S_STALL_O;

   /* Non-wishbone */
   wire        M_finished;

   reg 	       clock_25mhz;
   wire        vga_h_sync;
   wire        vga_v_sync;
   wire [2:0]  vga_red;
   wire [2:0]  vga_green;
   wire [2:0]  vga_blue;

   wire [9:0]  image_writes;

   simple_master master
     (
      .ACK_I(M_ACK_I),
      .CLK_I(M_CLK_I),
      .ADR_O(M_ADR_O),
      .DAT_I(M_DAT_I),
      .DAT_O(M_DAT_O),
      .RST_I(M_RST_I),
      .STB_O(M_STB_O),
      .CYC_O(M_CYC_O),
      .WE_O(M_WE_O),
      .STALL_I(M_STALL_I),

      .finished(M_finished)
      );

   vga
     #(
       .FONT_FILE("../../design/font.mem")
       ) vga_controller
       (
	.ACK_O(S_ACK_O),
	.CLK_I(S_CLK_I),
	.ADR_I(S_ADR_I),
	.DAT_I(S_DAT_I),
	.DAT_O(S_DAT_O),
	.RST_I(S_RST_I),
	.STB_I(S_STB_I),
	.WE_I(S_WE_I),
	.STALL_O(S_STALL_O),

	/* Non-wishbone */
	.clock_25mhz(clock_25mhz),
	.h_sync(vga_h_sync),
	.v_sync(vga_v_sync),
	.red(vga_red),
	.green(vga_green),
	.blue(vga_blue)
	);

   VGA_640_480_60Hz vga_display
     (
      .horizontal_sync(vga_h_sync),
      .vertical_sync(vga_v_sync),

      .red(vga_red),
      .green(vga_green),
      .blue(vga_blue),

      .image_writes(image_writes)
      );

   reg 	       CLK;
   reg 	       RST;

   assign M_ACK_I = S_ACK_O;
   assign M_CLK_I = CLK;
   assign M_DAT_I = S_DAT_O;
   assign M_RST_I = RST;
   assign M_STALL_I = S_STALL_O;

   assign S_CLK_I = CLK;
   assign S_ADR_I = M_ADR_O[10:0]; /* Ignore 9 topmost bits */
   assign S_DAT_I = M_DAT_O;
   assign S_RST_I = RST;
   assign S_STB_I = M_STB_O && M_CYC_O;
   assign S_WE_I = M_WE_O;

   initial begin
      CLK <= 0;
      RST <= 1;

      while (1) begin
	 #(WISHBONE_CLOCK_PERIOD / 2);

	 CLK <= ~CLK;

	 if (CLK)
	   RST <= 0;
      end
   end // initial begin

   initial begin
      clock_25mhz <= 0;

      while (1) begin
	 #20;

	 clock_25mhz <= ~clock_25mhz;
      end
   end

   always @ (image_writes) begin
      if (image_writes > 0) begin
	 if (!M_finished)
	   $display("error: master hasn't finished its operations");

	 $finish;
      end
   end

   parameter SCREEN_DISPLAY_TIME = 10 ** 9 / 60; /* 60 screens per second */
   parameter MAX_SIM_TIME = `MAX_WORD_IDX * WISHBONE_CLOCK_PERIOD +
			    SCREEN_DISPLAY_TIME + 1000; /* Some safety margin */

   initial begin
      #MAX_SIM_TIME;

      if (!M_finished) begin
	 $display("error: master hasn't finished its operations in %0d ns",
		  MAX_SIM_TIME);
      end

      if (image_writes == 0)
	$display("error: no VGA image displayed in %0d ns", MAX_SIM_TIME);

      $finish;
   end // initial begin
endmodule // vga_test