Home記事一覧フォーラム

SynthesijerでのVGA出力ライブラリの実装例

【更新履歴】
2016/09/25 カウンタのバグを修正
2015/06/28 vsync待ちの方法を修正
2015/05/16 ターゲットボードをTerasic DE0-CVに変更。クロックドメインを跨ぐ部分に同期化回路を追加
2015/04/27 公式セットアップ方法に合わせてMakefileを修正
2015/04/15 VRAMのRead addressをレジスタ化。未接続ピンのデフォルト設定をINPUT TRI-STATED WITH WEAK PULL-UPに変更
2015/04/01 VGA出力モジュールのパラメーターの与え方をシンプルにするために修正
2015/03/29 プロジェクトのMakefileを修正しました。以前にダウンロードされた方は再度ダウンロードしなおしてください。
2015/03/21 新規公開

SynthesijerにはHDLで書かれたモジュールをクラスライブラリ化してJava側から簡単に使えるようにする仕組みがあります。
今回はVerilog HDLで書いたVGA出力モジュールをクラスライブラリ化してJavaで書いたライフゲームの画面出力に使用してみます。

ターゲットボードについて

このプロジェクトはFPGA開発ボード「Terasic DE0-CV」用です。

プロジェクトのダウンロード、ビルド

Synthesijerはあらかじめ「高位合成ツール「Synthesijer」を使う」の方法でインストールしているものとします。

wget -O sjr_vga_example_de0_cv.tar.gz https://cellspe.matrix.jp/zerofpga/files/sjr_vga_example_de0_cv.tar.gz

tar xzf sjr_vga_example_de0_cv.tar.gz

sjr_vga_example_de0_cv ディレクトリ以下にファイルが展開されます。sjr_vga_example_de0_cv/synthesijer ディレクトリに移動してmakeします。

cd sjr_vga_example_de0_cv/synthesijer

make

これでVerilog HDLファイルが生成され、一つ上のディレクトリにコピーされます。synthesijerのライブラリファイル $SYNTHESIJER_LIB/verilog/singleportram.v もコピーされます。

Quartus II Ver.15.0以上 でプロジェクトファイルsjr_vga_example_de0_cv.qpfを開いて「Start Compilation」、「Programmer」で転送して実行します。

ソースコード

これらのソースコードはBSD 2-Clauseライセンスで公開します。

vga_vram_8.v : VGA出力モジュール本体
/*
  Copyright (c) 2015, miya
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


module vga_vram_8
  (
   input                    clk,
   input                    reset,
   output signed [32-1 : 0] data_length,
   input signed [32-1 : 0]  data_address,
   input signed [8-1 : 0]   data_din,
   output signed [8-1 : 0]  data_dout,
   input                    data_we,
   input                    data_oe,
   output                   vsync,
   input signed [32-1 : 0]  offset_h,
   input signed [32-1 : 0]  offset_v,
   input                    ext_clkv,
   input                    ext_resetv,
   output                   ext_vga_hs,
   output                   ext_vga_vs,
   output                   ext_vga_de,
   output signed [8-1 : 0]  ext_vga_r,
   output signed [8-1 : 0]  ext_vga_g,
   output signed [8-1 : 0]  ext_vga_b
   );

  localparam VGA_MAX_H = 799; // 800-1
  localparam VGA_MAX_V = 524; // 525-1
  localparam VGA_WIDTH = 640;
  localparam VGA_HEIGHT = 480;
  localparam VGA_SYNC_H_START = 656;
  localparam VGA_SYNC_V_START = 490;
  localparam VGA_SYNC_H_END = 752;
  localparam VGA_SYNC_V_END = 492;
  localparam OFFSET_WIDTH = 10;

  reg [9:0]                 count_h;
  reg [9:0]                 count_v;
  reg [9:0]                 count_hp;
  reg [9:0]                 count_vp;
  wire                      vga_hs;
  wire                      vga_vs;
  wire                      pixel_valid;
  reg [1:0]                 vga_hs_delay;
  reg [1:0]                 vga_vs_delay;
  reg [1:0]                 pixel_valid_delay;
  wire [OFFSET_WIDTH-1:0]   offset_h_sync;
  wire [OFFSET_WIDTH-1:0]   offset_v_sync;

  // H counter
  always @(posedge ext_clkv)
    begin
      if (ext_resetv == 1'b1)
        begin
          count_h <= 1'd0;
        end
      else
        begin
          if (count_h == VGA_MAX_H)
            begin
              count_h <= 1'd0;
            end
          else
            begin
              count_h <= count_h + 1'd1;
            end
        end
    end

  // V counter
  always @(posedge ext_clkv)
    begin
      if (ext_resetv == 1'b1)
        begin
          count_v <= 1'd0;
        end
      else
        begin
          if (count_h == VGA_MAX_H)
            begin
              if (count_v == VGA_MAX_V)
                begin
                  count_v <= 1'd0;
                end
              else
                begin
                  count_v <= count_v + 1'd1;
                end
            end
        end
    end

  // viewport
  always @(posedge ext_clkv)
    begin
      if (ext_resetv == 1'b1)
        begin
          count_hp <= 1'd0;
          count_vp <= 1'd0;
        end
      else
        begin
          count_hp <= count_h + offset_h_sync;
          count_vp <= count_v + offset_v_sync;
        end
    end

  // H sync
  assign vga_hs = ((count_h >= VGA_SYNC_H_START) && (count_h < VGA_SYNC_H_END)) ? 1'b0 : 1'b1;
  // V sync
  assign vga_vs = ((count_v >= VGA_SYNC_V_START) && (count_v < VGA_SYNC_V_END)) ? 1'b0 : 1'b1;
  // Pixel valid
  assign pixel_valid = ((count_h < VGA_WIDTH) && (count_v < VGA_HEIGHT)) ? 1'b1 : 1'b0;
  // delay (1 cycle)
  always @(posedge ext_clkv)
    begin
      vga_hs_delay <= {vga_hs_delay[0], vga_hs};
      vga_vs_delay <= {vga_vs_delay[0], vga_vs};
      pixel_valid_delay <= {pixel_valid_delay[0], pixel_valid};
    end

  // ext out
  assign ext_vga_r = pixel_valid_delay[1] ? {vram_odata[7:5], 1'b0} : 4'd0;
  assign ext_vga_g = pixel_valid_delay[1] ? {vram_odata[4:2], 1'b0} : 4'd0;
  assign ext_vga_b = pixel_valid_delay[1] ? {vram_odata[1:0], 2'b0} : 4'd0;
  assign ext_vga_hs = vga_hs_delay[1];
  assign ext_vga_vs = vga_vs_delay[1];
  assign ext_vga_de = pixel_valid_delay[1];

  // VRAM
  wire [7:0]  vram_idata;
  wire [7:0]  vram_odata;
  wire [11:0] vram_raddr;
  wire [11:0] vram_waddr;
  wire        vram_we;
  wire        vram_rclock;
  wire        vram_wclock;
  assign vram_rclock = ext_clkv;
  assign vram_wclock = clk;
  assign vram_raddr = {count_vp[9:4], count_hp[9:4]};
  assign data_length = 4096;
  assign vram_waddr = data_address;
  assign vram_idata = data_din;
  assign data_dout = 1'd0;
  assign vram_we = data_we;

  dual_port_ram
    #(
      .DATA_WIDTH (8),
      .ADDR_WIDTH (12)
      )
  vram0
    (
     .data_in (vram_idata),
     .read_addr (vram_raddr),
     .write_addr (vram_waddr),
     .we (vram_we),
     .read_clock (vram_rclock),
     .write_clock (vram_wclock),
     .data_out (vram_odata)
     );

  cdc_synchronizer
    #(
      .DATA_WIDTH (OFFSET_WIDTH)
      )
  sync_offset_h
    (
     .clk_in (clk),
     .clk_out (ext_clkv),
     .data_in (offset_h[OFFSET_WIDTH-1:0]),
     .data_out (offset_h_sync),
     .reset_in (reset)
     );

  cdc_synchronizer
    #(
      .DATA_WIDTH (OFFSET_WIDTH)
      )
  sync_offset_v
    (
     .clk_in (clk),
     .clk_out (ext_clkv),
     .data_in (offset_v[OFFSET_WIDTH-1:0]),
     .data_out (offset_v_sync),
     .reset_in (reset)
     );

  cdc_synchronizer
    #(
      .DATA_WIDTH (1)
      )
  sync_vsync
    (
     .clk_in (ext_clkv),
     .clk_out (clk),
     .data_in (ext_vga_vs),
     .data_out (vsync),
     .reset_in (ext_resetv)
     );

endmodule

cdc_synchronizer.v : 同期化回路
/*
  Copyright (c) 2015-2016, miya
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


// latency: 2 clk_in cycles + 3 clk_out cycles
// data_in value must be held for 4 clk_out cycles
module cdc_synchronizer
  #(
    parameter DATA_WIDTH=8
    )
  (
   input                     clk_in,
   input                     clk_out,
   input [(DATA_WIDTH-1):0]  data_in,
   output [(DATA_WIDTH-1):0] data_out,
   input                     reset_in
   );

  reg [(DATA_WIDTH-1):0]     data_in_reg;
  reg [(DATA_WIDTH-1):0]     data_out_reg[2:0];
  reg                        change_flag_in;
  reg [2:0]                  change_flag_out;

  always @(posedge clk_in)
    begin
      if (reset_in == 1'b1)
        begin
          change_flag_in <= 1'b0;
        end
      else if (data_in_reg != data_in)
        begin
          change_flag_in <= ~change_flag_in;
        end
      data_in_reg <= data_in;
    end

  always @(posedge clk_out)
    begin
      if (change_flag_out[2] == change_flag_out[1])
        begin
          data_out_reg[2] <= data_out_reg[1];
        end
    end

  always @(posedge clk_out)
    begin
      change_flag_out <= {change_flag_out[1:0], change_flag_in};
      data_out_reg[1] <= data_out_reg[0];
      data_out_reg[0] <= data_in_reg;
    end

  assign data_out = data_out_reg[2];
endmodule

VgaVram8.java : VGA出力モジュールのSynthesijer用ラッパークラス
/*
  Copyright (c) 2015, miya
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


import java.util.EnumSet;

import synthesijer.hdl.HDLModule;
import synthesijer.hdl.HDLPort;
import synthesijer.hdl.HDLPort.DIR;
import synthesijer.hdl.HDLPrimitiveType;

public class VgaVram8 extends HDLModule
{
  // フィールド定義。下のポート仕様で同じ名前のポートを記述するとJava側から読み書きできるレジスタになる。
  byte[] data;
  boolean vsync;
  int offset_h;
  int offset_v;

  public VgaVram8(String... args)
  {
    // "vga_vram_8"は実体のHDLのモジュール名
    super("vga_vram_8", "clk", "reset");

    // 配列のポート仕様記述には以下のようなポートが必要
    // length: 配列のサイズ取得用
    newPort("data_length", DIR.OUT, HDLPrimitiveType.genSignedType(32));
    // address: アドレス(配列の添字)
    newPort("data_address",DIR.IN, HDLPrimitiveType.genSignedType(32));
    // din: 入力データ。byte配列なのでサイズが8。int配列なら32にする。
    newPort("data_din",    DIR.IN, HDLPrimitiveType.genSignedType(8));
    // dout: 出力データ
    newPort("data_dout",   DIR.OUT, HDLPrimitiveType.genSignedType(8));
    // we, oe: 読み書き時に使われるフラグ
    newPort("data_we",     DIR.IN, HDLPrimitiveType.genBitType());
    newPort("data_oe",     DIR.IN, HDLPrimitiveType.genBitType());

    newPort("vsync", DIR.OUT, HDLPrimitiveType.genBitType());
    newPort("offset_h", DIR.IN, HDLPrimitiveType.genSignedType(32));
    newPort("offset_v", DIR.IN, HDLPrimitiveType.genSignedType(32));

    // HDLPort.OPTION.EXPORT を指定したポートはトップモジュールまで遡って接続される。ピンに接続したい時などに使う。
    newPort("ext_clkv", DIR.IN, HDLPrimitiveType.genBitType(), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_resetv", DIR.IN, HDLPrimitiveType.genBitType(), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_vga_hs", DIR.OUT, HDLPrimitiveType.genBitType(), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_vga_vs", DIR.OUT, HDLPrimitiveType.genBitType(), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_vga_de", DIR.OUT, HDLPrimitiveType.genBitType(), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_vga_r", DIR.OUT, HDLPrimitiveType.genSignedType(8), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_vga_g", DIR.OUT, HDLPrimitiveType.genSignedType(8), EnumSet.of(HDLPort.OPTION.EXPORT));
    newPort("ext_vga_b", DIR.OUT, HDLPrimitiveType.genSignedType(8), EnumSet.of(HDLPort.OPTION.EXPORT));
  }
}

Sjr_VGA_Test.java : サンプルプログラム(ライフゲームの描画)
/*
  Copyright (c) 2015, miya
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


public class Sjr_VGA_Test extends Thread
{
  private final VgaVram8 vram = new VgaVram8();

  private int calc_page;
  private int draw_page;
  private int color;

  private byte cell[] = new byte[8192 /*all_page_size*/];

  private void pset(int x, int y, int color)
  {
    vram.data[(y << 6) + x] = (byte)color;
  }

  public void init()
  {
    for (int i = 0; i < 8192 /*all_page_size*/; i++)
    {
      cell[i] = (byte)0;
    }
    set_cell(34, 29, 0, (byte)1);
    set_cell(32, 30, 0, (byte)1);
    set_cell(34, 30, 0, (byte)1);
    set_cell(35, 30, 0, (byte)1);
    set_cell(32, 31, 0, (byte)1);
    set_cell(34, 31, 0, (byte)1);
    set_cell(32, 32, 0, (byte)1);
    set_cell(30, 33, 0, (byte)1);
    set_cell(28, 34, 0, (byte)1);
    set_cell(30, 34, 0, (byte)1);
    calc_page = 1;
    draw_page = 0;
    clear_screen();
    draw_cells();
    calc_page = 0;
    draw_page = 1;
  }

  private int get_index(int x, int y, int page)
  {
    return (x & 63 /*cell_size_minus_1*/) + ((y & 63 /*cell_size_minus_1*/) << 6 /*cell_size_bits*/) + (page << 12 /*page_bits*/);
  }

  private byte get_cell(int x, int y, int page)
  {
    return cell[get_index(x, y, page)];
  }

  private void set_cell(int x, int y, int page, byte value)
  {
    cell[get_index(x, y, page)] = value;
  }

  private int get_neighbor(int x, int y, int p)
  {
    int neighbor =
      get_cell(x-1,y-1,p)+get_cell(x,y-1,p)+get_cell(x+1,y-1,p)+
      get_cell(x-1,y,p)+                    get_cell(x+1,y,p)+
      get_cell(x-1,y+1,p)+get_cell(x,y+1,p)+get_cell(x+1,y+1,p);
    return neighbor;
  }

  private void calc_cells()
  {
    for (int y = 0; y < 64 /*cell_size*/; y++)
    {
      for (int x = 0; x < 64 /*cell_size*/; x++)
      {
        byte me = get_cell(x, y, calc_page);
        set_cell(x, y, draw_page, me);
        int neighbor = get_neighbor(x, y , calc_page);
        if (me == (byte)0)
        {
          if (neighbor == 3)
          {
            set_cell(x, y, draw_page, (byte)1);
          }
        }
        else
        {
          if ((neighbor < 2) || (neighbor > 3))
          {
            set_cell(x, y, draw_page, (byte)0);
          }
        }
      }
    }
  }

  private void clear_screen()
  {
    for (int i = 0; i < 4096; i++)
    {
      vram.data[i] = (byte)0;
    }
  }

  private void draw_cells()
  {
    for (int y = 0; y < 30 /*screen_height*/; y++)
    {
      for (int x = 0; x < 40 /*screen_width*/; x++)
      {
        int col;
        if (get_cell(x + 12, y + 16, draw_page) == (byte)1)
        {
          col = color;
        }
        else
        {
          col = 0;
        }
        pset(x, y, col);
      }
    }
  }

  public void run()
  {
    init();
    for (int i = 0; i < 512; i++)
    {
      // scroll
      vram.offset_h = i - 256;
      vram.offset_v = i - 256;
      // color shift
      color = i;
      calc_cells();
      // vsync wait
      while (vram.vsync == true)
      {
        yield();
      }
      while (vram.vsync == false)
      {
        yield();
      }
      draw_cells();
      int p = calc_page;
      calc_page = draw_page;
      draw_page = p;
    }
  }
}

Sjr_Top.java : Java側トップモジュール
/*
  Copyright (c) 2015, miya
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


import synthesijer.rt.*;

@synthesijerhdl
public class Sjr_Top
{
  private final Sjr_VGA_Test obj = new Sjr_VGA_Test();

  @auto
  public void main()
  {
    obj.run();
  }
}

sjr_vga_example_de0_cv.v : HDL側トップモジュール
/*
  Copyright (c) 2015, miya
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


module sjr_vga_example_de0_cv
  (
   input        CLOCK_50,
   input [3:0]  KEY,
   output       VGA_HS,
   output       VGA_VS,
   output [3:0] VGA_R,
   output [3:0] VGA_G,
   output [3:0] VGA_B
   );

  wire          clk_video;
  wire          clk_audio;

  // main
  wire          main_busy;
  wire          main_req;
  assign main_req = 1'b1;

  // synchronize reset
  reg           areset;
  reg           aresetv;
  reg           areset1;
  reg           aresetv1;

  always @(posedge CLOCK_50)
    begin
      areset1 <= ~KEY[0];
      areset <= areset1;
    end

  always @(posedge clk_video)
    begin
      aresetv1 <= ~KEY[0];
      aresetv <= aresetv1;
    end


  av_pll av_pll_0
    (
     .refclk (CLOCK_50),
     .rst (areset),
     .outclk_0 (clk_video),
     .outclk_1 (clk_audio)
     );


  Sjr_Top sjr_top0
    (
     .clk (CLOCK_50),
     .reset (areset),
     .obj_vram_ext_clkv_exp (clk_video),
     .obj_vram_ext_resetv_exp (aresetv),
     .obj_vram_ext_vga_hs_exp (VGA_HS),
     .obj_vram_ext_vga_vs_exp (VGA_VS),
     .obj_vram_ext_vga_de_exp (),
     .obj_vram_ext_vga_r_exp (VGA_R),
     .obj_vram_ext_vga_g_exp (VGA_G),
     .obj_vram_ext_vga_b_exp (VGA_B)
     );

endmodule

このVGA出力モジュールの現時点での仕様

まとめ

このようにHDLモジュールをクラスライブラリ化しておくと、Java側からはインスタンス化するだけで利用でき、HDL側の配列やレジスタにもフィールドとしてアクセスできます。

また、Javaによる記述だけでは実装の難しい、厳密なタイミングを必要とする回路や、ぎりぎりまで高速化したい回路などをHDLで記述して、Javaで記述した回路から利用することが可能です。

一旦ライブラリ化しておけば、モジュールどうしのポート接続はSynthesijerが自動的に記述してくれるので効率的に再利用できます。(トップモジュールの配線だけは少しだけ手作業が必要ですが)

参考文献

Synthesijerサンプルプログラム

CQ出版社 FPGAマガジン No.5 「画面表示コントローラを実装してディスプレイ表示!」(VGAのタイミング表)