DE0(Cyclone III) + DEOCM

DEOCM (でおしむ) という MSX のスロットが付いたボードを家電のケンちゃんで買いました。DE0 と DE0-CV で使用可能のボードです。今回は古い DE0 に頑張ってもらうということで OneChipMSX на Altera DE0 – Development and Education Board のロシア語サイトのファームウエアを書き込んで使うことにしました。一応、DE0 というか Cyclone III は古いのでボードが余っている人向けの記事です。

今からやってみたい方は DE-CV(Cyclone V) + DEOCM-PLD-CV(仮称)計画 のファームウエアを使うといいでしょう。今回こちらの方法は記載していません。

ダウンロードするファイル

OneChipMSX на Altera DE0 の 2018年リリースのファイルをダウンロードします。

  • source は 1chipMSX の DE0 版ソースです。コンパイルしてみたい人はダウンロード
  • POF-file は DE0 のコンフィグレーションROM に書き込むコンパイル済みのファイルです。これは必要
  • SOF-file は DE0 の FPGA に直接ダウンロードするアイルです。今回は使いません。
  • BIOS MSXDOS2 SDHCカードに対応したMSX DOS2のROMファイル。MSXDOS2 の場合はこの .zip ファイル内の biossdhc.sys を使う。今回は使いません。
  • BIOS NEXTOR SDカードに書き込むためのNextorシステム搭載のROMファイル。この .zip ファイル内の biosnext.sys は必要

OneChipMSX на Altera DE0 の 2017年リリースファイルのリンク

  • NEXTOR メモリカードに書き込むシステムファイルのアーカイブ。アーカイブファイル これは必要
  • OCM_NEXT.ROM – は、ディスクに書き込む最初のファイルでなければなりません。カードはFAT16形式でフォーマットされている必要があります。4Gバイト以上のSDHCカードをIBMカードフォーマットFAT32でフォーマットし、Nextor Basicに内蔵されているFDISKユーティリティで4Gバイトのパーティションに分割することをお勧めします。BASICからfdiskを呼び出す。これは不要

、NEXTOR という言葉が出てきました。DE0 版 MSX の DOS は Konamiman’s MSX page の DOS がターゲットです。

また、Intel FPGA サイトから Quartus II 13.1 もダウンロードしてインストールする。

.pof ファイルの書き込み

DE0 を PC と USB ケーブルで接続します。DE0 のスライドスイッチを PROG 側にしておきます。Quartus II 13.1 を起動して 「Tools」「Programmer」を選択してプログラマを起動します。

Hardware Setup で USB Blaster を選択。Mode は Active Serial Programming を選択する。

Add File ボタンを押してダウンロードした .pof ファイルを選択して Open ボタンを押す。

チェックボックスにチェックが付いた状態で Start ボタンを押す。

書き込みエラーになる場合は、スライドスイッチが PROG 側であること、また電源を入れ直して再度 Start ボタンを押せば故障でもない限り書き込み始まると思います。書き込みが終了したら、電源を切ってスライドスイッチを RUN に戻してください。

MSXDOS の SD(microSD)カード作成

NEXTOR DOS を microSDカードに書き込みします。コマンドプロンプトを起動して、DISKPART コマンドを起動します。管理者モードの確認ダイアログが出たら OK で続行。そうすると、もう一枚コマンドプロントのウィンドウが表示され DISKPART> のプロンプトが表示されます。

まず、microSD カード内の不要パーティションを削除します。下記は Raspberry Pi で使用した microSD カードでしたので、boot のパーティションと ext4 のパーティション2つあるやつでした。下記実行例のようにパーティション削除を行います。

DISKPART> LIST DISK

  ディスク      状態           サイズ   空き   ダイナ GPT
  ###                                          ミック
  ------------  -------------  -------  -------  ---  ---
  ディスク 0    オンライン           931 GB  2048 KB        *
  ディスク 1    オンライン           931 GB      0 B        *
  ディスク 2    オンライン          1863 GB      0 B
  ディスク 3    メディアなし             0 B      0 B
  ディスク 4    オンライン            14 GB  3072 KB

DISKPART> SELECT DISK 4

ディスク 4 が選択されました。

DISKPART> LIST PARTITION

  Partition ###  Type                Size     Offset
  -------------  ------------------  -------  -------
  Partition 1    プライマリ               41 MB  4096 KB
  Partition 2    プライマリ               14 GB    46 MB


DISKPART> SELECT PARTITION 2

パーティション 2 が選択されました。

DISKPART> DELETE PARTITION

DiskPart は選択されたパーティションを正常に削除しました。

DISKPART> SELECT PARTITION 1

パーティション 1 が選択されました。

DISKPART> DELETE PARTITION

DiskPart は選択されたパーティションを正常に削除しました。

DISKPART> LIST PARTITION

このディスクには表示するパーティションがありません。

DISKPART>

これで、microSD にパーティションが無い状態になりました。また、SELECT DISK をした後に CLEAN コマンド一発でパーティションをすべて削除できます。SELECT DISK を間違えると大変なことになるので、好きな方法で microSD カードの中身を削除してください。

DISKPART> help clean

     フォーカスされたディスクからすべてのパーティション フォーマットまたは
     ボリューム フォーマットを削除します。

構文:  CLEAN [ALL]

    ALL         ディスク上のすべてのバイトおよびセクターをゼロに設定するように指定します。
                これにより、そのディスクに格納されているすべてのデータが完全に削除されます。

    マスター ブート レコード (MBR) ディスクでは、MBR パーティション情報と
    隠しセクター情報だけが上書きされます。GUID パーティション テーブル
    (GPT) ディスクでは、プロテクティブ MBR を含む GPT パーティション情報が
    上書きされます。ALL パラメーターを使用しない場合、最初の 1 MB と最後の
    1 MB がゼロに設定されます。これにより、以前にディスクに適用された
    フォーマットは消去されます。ディスクの消去の後、ディスクの状態は
    未初期化になります。

例:

    CLEAN

パーティションを作成する。

DISKPART> CREATE PARTITION PRIMARY SIZE=2000

DiskPart は指定したパーティションの作成に成功しました。

DISKPART> ACTIVE

DiskPart は現在のパーティションをアクティブとしてマークしました。

DISKPART> FORMAT FS=FAT QUICK

  100% 完了しました

DiskPart は、ボリュームのフォーマットを完了しました。

DISKPART> SET ID=06

DiskPart は、パーティション ID を設定しました。

DISKPART> DETAIL PARTITION

パーティション 1
種類         : 06
隠し属性     : いいえ
アクティブ   : はい
オフセット (バイト): 1048576

  Volume ###  Ltr Label        Fs    Type        Size     Status     Info
  ----------  --- -----------  ----  ----------  -------  ---------  --------
* Volume 8     I                FAT    リムーバブル      2000 MB  正常

DISKPART>

Ltr は ドライブレターなので、パソコンによって変化します。DISKPART のコマンドプロンプトウィンドウを閉じます。

microSD カードに、NEXTOR DOS のファイルをコピーします。ロシア語サイトからダウンロードした biosnext.zip と nextor.zip を解凍しておきます。そして、biosnext.zip ファイル内の biosnext.sys を最初に microSD にコピーします。nextor.zip は NEXTOR.SYS と *.COM ファイルをコピーします。これで microSD カードから起動できます。

MSXDOS 起動

microSDカードを取り外して、DE0の SDカードスロットに装着します。大きさ変換のアダプタを使用して差し込みます。また、VGA 液晶、PS/2 キーボードも接続します。10個並んだスライドスイッチは全部 OFF で電源を入れます。

Initial Program Loader のメッセージやロゴが表示された後、MSXDOS のプロンプトが表示されれば成功です。

NEXTOR.SYS verstion 2.01 と表示されて konamiman dos が起動しています。

https://github.com/Konamiman/Nextor/releases

の最新リリースにある NEXTOR.SYS.japanese をNEXTOR.SYS にリネームし、microSDカードに上書きしてところ version 2.12 と表示され起動しましたので、その他コマンド類もリポジトリの最新版を build して置き換えてもいいと思われます。

あとは、Louthrax’s MSX game room から、sofarun をダウンロードして microSD にいれておけば、 .dsk のディスクイメージもファイルを選んでボタンクリックするだけで起動してくれる便利なソフトなので導入しておきましょう。

Terasic DE0-Nano 購入しました。

2014-07-20 16.30.26

日曜日、ふと思い付きで京都方面へお出かけ。目的は、↓の写真にある

2014-07-20 09.18.24

2014-07-20 10.50.17

電電宮という電気の神さんと、京都御苑内にある技芸上達の白雲神社にお参りでした。私の場合は朝早めに出て午後になったら早々に撤収するのがパターンなのですが、この日にかぎって帰りにわざわざ日本橋に寄って最初の写真にある FPGA ボードを買って帰った次第。

最初の写真左側 10年いきませんが Xilinx Spartan-3 (Spartan-3Eではない)のボード。右の小さなボードが DE0-Nano 。40ピンの GPIO コネクタのピン数はちょっと少なくなりますが、基板サイズはちっちゃくなってコンパクトです。搭載されている石は DE0 の Cyclone III と違い Cyclone IV です。Altera の Quartus II Web エディションで楽しめます。残念なのは、Xilinx の Spartan-6 が ISE 14.7 以降はサポートしないのと同じような感じで DE0-Nano の Cyclone-IV も Quartus II 14.0 以降はおそらくサポートされなさそう。ということろでしょうか。まぁ、書籍執筆される方は、開発ソフトのバージョン固定出来るので入門本書きやすいでしょう。

2014-07-21 08.40.06

今日は、HDL だけの LED チカチカを組んで書き込む練習だけしました。FPGA 使ってややこしいことする予定は無く自己学習でございます。

Digilent NEXYS3 で HDMI 出力

2014-07-06 11.17.46

この土日は散歩しに行こうと思いつつも、土曜日の朝、「積み基板で遊ぼう」と思いついたのが優先事項になってしまいまして NEXYS3 SPARTAN-6 LX16 ボードをひっぱり出す。Xilinx のサイトにある、XAPP495(Implementing a TMDS Video Interface in the Spartan-6 FPGA) をダウンロードして作業開始。

この XAPP495 の対象ボードは Digilent の ATLYS という SPARTAN-6 LX45 搭載のボードが対象です。私の積み基板のより規模の大きいのが載ってまして HDMI コネクタもオンボードで付いてます。私のには HDMI コネクタが付いていないので、この NEXYS 3 基板買ったときに追加の小さいボードも買いました。これにマイクロなHDMI コネクタが4つとpmodコネクタ3つ付いてます。

今回はカラーバー出れば満足なので、Planahead 14.7 で新規プロジェクトを作成しサンプルのソースから vtc_demo.v をトップモジュールにして ucf ファイル書き換えてシンセサイズとインプリして、書き込みしたら OK なはずでした。
が、ioclock が配線出来ませんと言われ土曜日の午前中はあきらめて一旦終了。

こういうときは UCF ファイルが悪いのが相場なので、オリジナル ATLYS 基板用の UCF でビルドしてワーニングとかは出るもののインプリメント出来るのを確認。結局のところ 100MHz のクロック入力が、 ATLYS は BANK1 のポート、NEXYS3 は BANK2 のポートですが、この UCF のピン番号を替えたらエラーの山でした。

モジュールの内部は 50MHz で動いているので、100MHz のクロックを50MHz にしているところがあります。ここらへんを書き換えたら動くのではないかと修正開始。

  IBUF sysclk_buf (.I(SYS_CLK), .O(sysclk));
  BUFIO2 #(.DIVIDE_BYPASS("FALSE"), .DIVIDE(2))
  sysclk_div (.DIVCLK(clk50m), .IOCLK(), .SERDESSTROBE(), .I(sysclk));
 BUFG clk50m_bufgbufg (.I(clk50m), .O(clk50m_bufg));

もとのソースは クロック入力ピンを IBUF で受けて、それを BUFIO2 で分周。50MHz 出力を BUFG でグローバルなクロック配線に載せるいうことをやっています。これの入力のピン位置がかわるだけで、インプリ出来んのはバグちゃう?と思いたくなりますが、仕方ありません。

  • DCM で 50MHZ を作ってそれを使うように修正してみたところ、「タイミング守れません」でアウト。FPGA EDITOR でDCM変更でなとかなるかもしれませんが、なんとかするスキルはありません(笑)
  • 仕方ないので always で分周する方法を。遅延なしにちゃんと分周出来る保証はありませんが簡単なのでやってみたら動きだした

という次第。居間にあるハーフパネルの液晶テレビ(家に HDMI 入力あるのはこれだけで PC は DVI なので変換が必要)に接続してみて、表示されるか確認。「信号がありません」とは言われませんでした。表示サイズがあわないかしておかしい表示になっていますが一つ進んだかな。

DIGILENT NEXYS3 で Hello World

nexys3_201304202350

DIGILENT NEXYS3 で、HDL の復習ですが、今日は WebPack で開発出来るはずの Microblaze MCS を入れてみて動くか実験。結果動いたので良しです。XILINX DS865 の手順。

  • WebPack 新規プロジェクト
  • Coregen から Microblaze MCS を追加(今回は UART だけ有効にした)
  • トップモジュール記述
  • Synthesize
  • TCL コンソールから source ipcore_dir/microblaze_mcs_setup.tcl を実行
  • Implement Design
  • SDK を起動
  • ISE プロジェクトフォルダの下の workspace を SDK のプロジェクトディレクトリ
  • Xilinx Hardware Platform Specification 作成
  • Xilinx Board Support Package 作成
  • 新規 application ウィザードから Hello プロジェクトの雛形を選択して C 言語プロジェクト作成 → 自動でサンプルが Build される
  • ISE に戻り、UCF 作成
  • TCL コンソールから microblaze_mcs_data2mem workspace/アプリプロジェクト/Debug/xxxxxx.elf
  • Synthesize から Generate Programming File までの中で再実行必要なものを行なう
  • DIGILENT ADPT 経由で bit ファイルを書く

まぁ、ちゃんと Tera Term に、Hello World が出たので良しとしましょう。久しぶりにやると時間かかります。まだ SDK で C のソース修正してビルド仕直したときの ISE の手順やっていないので、手順は改めてまとめましょう。

SDK の Microblaze MCS の gcc の説明とかどこか探さないとプログラム書けませんね。これも探さなきゃ

とりあえず、FPGA版 Hello, World

普段 DWMとか読まないんで、CPLDやFPGAの事情はさっぱりわかりません。昔のページに XILINX XC9500シリーズの
CPLD使った記事も書きましたが2002年6月のことで、当然ここのサイトには掲載してません。
今更という感じはあるのですが、久しぶりにやってみたくなったので入門キットを買ってボチボチ遊びたいと思います。

FPGAの「Hello, World」は、はやり LEDピコピコですが、今回は飛ばして VGA 出力の練習です。
Verilog HDL入門本見ながら書いてみました。以下ソースとUCFです。
Webpack 10.1で作成してとりあえず成功っと


モニタはPCデポ店頭に積んであったセリング KW-M80C というとこのSVGAモニタでアナログRGBとコンポッジト入力だけの
シンプル構成です。1万4千円くらいだったと思います。まぁちょっと使う程度なら使えるモニタです。

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:    12:46:33 06/22/2008
// Design Name:
// Module Name:    vga
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
//
// -- 水平タイミング --
// 表示期間:   640ドット
// フロントポーチ:  16ドット
// 水平同期:    96ドット(656)
// バックポーチ:   48ドット(752)
//
// -- 垂直タイミング --
// 表示期間:   480ライン
// フロントポーチ:  10ライン
// 垂直同期:     2ライン(490)
// バックポーチ:   29ライン(492)

module vga(CLK_50MHZ, VGA_R, VGA_G, VGA_B, VGA_HSYNC, VGA_VSYNC);

input CLK_50MHZ;
output [3:0] VGA_R;
output [3:0] VGA_G;
output [3:0] VGA_B;
output VGA_HSYNC;
output VGA_VSYNC;

reg [3:0] VGA_R;
reg [3:0] VGA_G;
reg [3:0] VGA_B;
reg VGA_HSYNC;
reg VGA_VSYNC;

wire clk_25mhz;
reg clk_25mhz_a;
assign clk_25mhz = clk_25mhz_a;

reg [9:0] hcount;
reg [9:0] vcount;

/* 25MHz のクロック作成 */
always @(posedge CLK_50MHZ)
begin
clk_25mhz_a <= ‾clk_25mhz_a;
end

/* 25Mhz のクロックで画面描画 */
always @(posedge clk_25mhz)
begin

// 水平タイミング
hcount <= hcount + 1;     // 水平カウント 800 で一周     if(hcount > 10'd799)
begin
hcount <= 0;
vcount <= vcount + 1;
end
// 水平同期出力
if(hcount == 10'd655)
begin
VGA_HSYNC <= 0;
VGA_R <= 4'b0000;
VGA_G <= 4'b0000;
VGA_B <= 4'b0000;
end
// 水平同期出力終了
if(hcount == 10'd751)
begin
VGA_HSYNC <= 1;     end     // 垂直タイミング     // 521 ラインで一周     if(vcount > 10'd520)
begin
vcount <= 0;
end
// 垂直同期開始
if(vcount == 10'd489)
begin
VGA_VSYNC <= 0;
end
// 垂直同期終了
if(vcount == 10'd491)
begin
VGA_VSYNC <= 1;
end

// カラーバーもどき → メモリインタフェースにする
if(hcount == 10'd0)
begin
VGA_R <= 4'b1111;
VGA_G <= 4'b1111;
VGA_B <= 4'b1111;
end
if(hcount == 10'd79)
begin
VGA_R <= 4'b0000;
VGA_G <= 4'b1111;
VGA_B <= 4'b1111;
end
if(hcount == 10'd159)
begin
VGA_R <= 4'b1111;
VGA_G <= 4'b0000;
VGA_B <= 4'b1111;
end
if(hcount == 10'd239)
begin
VGA_R <= 4'b1111;
VGA_G <= 4'b1111;
VGA_B <= 4'b0000;
end
if(hcount == 10'd319)
begin
VGA_R <= 4'b1111;
VGA_G <= 4'b0000;
VGA_B <= 4'b0000;
end
if(hcount == 10'd399)
begin
VGA_R <= 4'b0000;
VGA_G <= 4'b1111;
VGA_B <= 4'b0000;
end
if(hcount == 10'd479)
begin
VGA_R <= 4'b0000;
VGA_G <= 4'b0000;
VGA_B <= 4'b1111;
end
if(hcount == 10'd559)
begin
VGA_R <= 4'b0000;
VGA_G <= 4'b0000;
VGA_B <= 4'b0000;
end

end
endmodule

 
<pre><code>

NET "VGA_R&lt;3&gt;" LOC = "C8" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_R&lt;2&gt;" LOC = "B8" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_R&lt;1&gt;" LOC = "B3" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_R&lt;0&gt;" LOC = "A3" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_G&lt;3&gt;" LOC = "D6" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_G&lt;2&gt;" LOC = "C6" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_G&lt;1&gt;" LOC = "D5" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_G&lt;0&gt;" LOC = "C5" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_B&lt;3&gt;" LOC = "C9" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_B&lt;2&gt;" LOC = "B9" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_B&lt;1&gt;" LOC = "D7" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_B&lt;0&gt;" LOC = "C7" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_HSYNC" LOC = "C11" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "VGA_VSYNC" LOC = "B11" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;

NET "CLK_50MHZ" LOC = "E12"| IOSTANDARD = LVCMOS33 ;

# NET "CLK_AUX" LOC = "V12"| IOSTANDARD = LVCMOS33 ;

# NET "CLK_SMA" LOC = "U12"| IOSTANDARD = LVCMOS33 ;


 

Spartan-3A DCM を veritak で動作確認してみた。

Spartan-3A スターターキットの PDF の資料やアプリケーションノートなど見てますが
基本クロックは、50MHzの水晶が原発ですが、それ以外の
クロックが欲しいときは、DCM(Digital Clock Manager)を使用するようです。
ということで、DCM を使用する準備として veritak で確認してみました。

  • CORE Generator で DCM のコードを GUI で生成
  • テスト用の Verilog コードを書いてみる
  • veritak(シェアウェア版)でシミューレーションしてみる

CORE Generator を起動して DCM のコアを作成してみました。
今回は、 FPGA Features and Design -> Clocking -> Spartan-3E, Spartan-3A -> Single DCM_SP
とファンクションを選択して、DCM作成です。
今回は、CLK0以外に、90度づつ位相ずれた CLK90, CLK180, CLK270 なども
出力するようにしてみました。

また、PDF 文書にあった推奨リセット回路(シフトレジスタでワンショットパルスを出す)も追加しました。

生成された DCM モジュール

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1995-2008 Xilinx, Inc.  All rights reserved.
////////////////////////////////////////////////////////////////////////////////
//   ____  ____ 
//  /   /\/   / 
// /___/  \  /    Vendor: Xilinx 
// \   \   \/     Version : 10.1.03
//  \   \         Application : xaw2verilog
//  /   /         Filename : dcm_test01.v
// /___/   /\     Timestamp : 04/21/2009 13:34:03
// \   \  /  \ 
//  \___\/\___\ 
//
//Command: xaw2verilog -st C:\mkusunoki\\dcm_test01.xaw C:\mkusunoki\\dcm_test01
//Design Name: dcm_test01
//Device: xc3s700a-4fg484
//
// Module dcm_test01
// Generated by Xilinx Architecture Wizard
// Written for synthesis tool: XST
`timescale 1ns / 1ps

module dcm_test01(CLKFB_IN, 
                  CLKIN_IN, 
                  RST_IN, 
                  CLKIN_IBUFG_OUT, 
                  CLK0_OUT, 
                  CLK90_OUT, 
                  CLK180_OUT, 
                  CLK270_OUT, 
                  LOCKED_OUT);

    input CLKFB_IN;
    input CLKIN_IN;
    input RST_IN;
   output CLKIN_IBUFG_OUT;
   output CLK0_OUT;
   output CLK90_OUT;
   output CLK180_OUT;
   output CLK270_OUT;
   output LOCKED_OUT;
   
   wire CLKFB_IBUFG;
   wire CLKIN_IBUFG;
   wire CLK0_BUF;
   wire CLK90_BUF;
   wire CLK180_BUF;
   wire CLK270_BUF;
   wire GND_BIT;
   
   assign GND_BIT = 0;
   assign CLKIN_IBUFG_OUT = CLKIN_IBUFG;
   IBUFG CLKFB_IBUFG_INST (.I(CLKFB_IN), 
                           .O(CLKFB_IBUFG));
   IBUFG CLKIN_IBUFG_INST (.I(CLKIN_IN), 
                           .O(CLKIN_IBUFG));
   BUFG CLK0_BUFG_INST (.I(CLK0_BUF), 
                        .O(CLK0_OUT));
   BUFG CLK90_BUFG_INST (.I(CLK90_BUF), 
                         .O(CLK90_OUT));
   BUFG CLK180_BUFG_INST (.I(CLK180_BUF), 
                          .O(CLK180_OUT));
   BUFG CLK270_BUFG_INST (.I(CLK270_BUF), 
                          .O(CLK270_OUT));
   DCM_SP DCM_SP_INST (.CLKFB(CLKFB_IBUFG), 
                       .CLKIN(CLKIN_IBUFG), 
                       .DSSEN(GND_BIT), 
                       .PSCLK(GND_BIT), 
                       .PSEN(GND_BIT), 
                       .PSINCDEC(GND_BIT), 
                       .RST(RST_IN), 
                       .CLKDV(), 
                       .CLKFX(), 
                       .CLKFX180(), 
                       .CLK0(CLK0_BUF), 
                       .CLK2X(), 
                       .CLK2X180(), 
                       .CLK90(CLK90_BUF), 
                       .CLK180(CLK180_BUF), 
                       .CLK270(CLK270_BUF), 
                       .LOCKED(LOCKED_OUT), 
                       .PSDONE(), 
                       .STATUS());
   defparam DCM_SP_INST.CLK_FEEDBACK = "1X";
   defparam DCM_SP_INST.CLKDV_DIVIDE = 2.0;
   defparam DCM_SP_INST.CLKFX_DIVIDE = 1;
   defparam DCM_SP_INST.CLKFX_MULTIPLY = 4;
   defparam DCM_SP_INST.CLKIN_DIVIDE_BY_2 = "FALSE";
   defparam DCM_SP_INST.CLKIN_PERIOD = 20.000;
   defparam DCM_SP_INST.CLKOUT_PHASE_SHIFT = "NONE";
   defparam DCM_SP_INST.DESKEW_ADJUST = "SYSTEM_SYNCHRONOUS";
   defparam DCM_SP_INST.DFS_FREQUENCY_MODE = "LOW";
   defparam DCM_SP_INST.DLL_FREQUENCY_MODE = "LOW";
   defparam DCM_SP_INST.DUTY_CYCLE_CORRECTION = "TRUE";
   defparam DCM_SP_INST.FACTORY_JF = 16'hC080;
   defparam DCM_SP_INST.PHASE_SHIFT = 0;
   defparam DCM_SP_INST.STARTUP_WAIT = "FALSE";
endmodule

作成してみたテストベンチ

`default_nettype none
`timescale 1ns / 1ns

module dcm_test01_testbench;

reg CLK50MHz;
reg RST_IN;
wire CLKIN_IBUFG_OUT;
wire CLK0_OUT;
wire CLK90_OUT;
wire CLK180_OUT;
wire CLK270_OUT;
wire LOCKED_OUT;

dcm_test01 dcm01 (
	.CLKFB_IN(CLK0_OUT),
	.CLKIN_IN(CLK50MHz),
	.RST_IN(Q),
	.CLKIN_IBUFG_OUT(CLKIN_IBUFG_OUT),
	.CLK0_OUT(CLK0_OUT),
	.CLK90_OUT(CLK90_OUT),
	.CLK180_OUT(CLK180_OUT),
	.CLK270_OUT(CLK270_OUT),
	.LOCKED_OUT(LOCKED_OUT)
	);

wire Q;
//defparam U1.INIT = 16'h000F;
SRL16 #(16'h000F) U1 (
	.Q(Q),
	.A0(1),
	.A1(1),
	.A2(1),
	.A3(1),
	.CLK(CLK50MHz),
	.D(0)
);

// クロック
initial
begin
	CLK50MHz = 0;
	forever #10 CLK50MHz = ~CLK50MHz;
end

initial
begin
	#1600
	$finish;
end

always
	$monitor($time, "clkin=%b reset=%b clk0=%b clk90=%b clk180=%b clk270=%b locked=%b\n", CLK50MHz, RST_IN,CLK0_OUT,CLK90_OUT,CLK180_OUT,CLK270_OUT,LOCKED_OUT);
endmodule

で、veritakでシミューレーションしてみましたところ、各種クロックと、リセットに反応すること、と
クロックのロック状態も表示されたので実際にインプリする場合もちょっと安心ということで

にしても、ついでで DDR2 SDRAM も MIG で作成してみて veritak してみましたところ
これも動きそうな感じではあります。が、UG086 に書いてる使いかたが
まだよく理解出来ないのと、DDR/DDR2 な SDRAM の基本もわかってないので
これから余裕が出来れば、使ってみたいですね。
とりあえず、picoblaze を先に使用したいです。

PicoBlaze でキャラクタ液晶表示

今回は、Spartan-3A の PicoBlaze でキャラクタ液晶の表示を行ないました。
と言っても今回は、fpga ポートの入出力動作がうまくいかなかったので
BUSYチェックはしないで、時間待ちして表示させてます。

何のヒネリも無いので、そのままソース掲載でし。マイコンのアセンブラとVerilogです。

PicoBlaze のソース

CONSTANT        LCD_DATA,       01      ;
CONSTANT        LCD_CTRL_E,     02      ;
CONSTANT        LCD_CTRL_RS,    03      ; 0=Command, 1=Data
CONSTANT        LCD_CTRL_RW,    04      ; 0=write, 1=read
CONSTANT        LED,            05      ; LED port

                ADDRESS 000
INIT00:
                ENABLE  INTERRUPT
                CALL    LCD_INIT

MAIN00:         LOAD    s4, 50          ; P
                CALL    LCD_PUTCH
                LOAD    s4, 69          ; i
                CALL    LCD_PUTCH
                LOAD    s4, 63          ; c
                CALL    LCD_PUTCH
                LOAD    s4, 6F          ; o
                CALL    LCD_PUTCH
                LOAD    s4, 42          ; B
                CALL    LCD_PUTCH
                LOAD    s4, 6C          ; l
                CALL    LCD_PUTCH
                LOAD    s4, 61          ; a
                CALL    LCD_PUTCH
                LOAD    s4, 7A          ; z
                CALL    LCD_PUTCH
                LOAD    s4, 65          ; e
                CALL    LCD_PUTCH
                LOAD    s4, 21          ; !
                CALL    LCD_PUTCH
                LOAD    s4, 00
MAIN90:
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                CALL    DELAY20ms
                OUTPUT  s4, LED        ; LED チカチカ
                ADD     s4, 01
                JUMP    MAIN90


LCD_INIT:       CALL    DELAY20ms
                CALL    DELAY20ms
                LOAD    s4, 30
                CALL    LCD_PUTCMD
                CALL    DELAY20ms
                LOAD    s4, 30
                CALL    LCD_PUTCMD
                CALL    DELAY1ms
                LOAD    s4, 30
                CALL    LCD_PUTCMD
                CALL    DELAY1ms
                LOAD    s4, 38
                CALL    LCD_PUTCMD
                CALL    DELAY100us
                LOAD    s4, 0F
                CALL    LCD_PUTCMD
                CALL    DELAY100us
                LOAD    s4, 06
                CALL    LCD_PUTCMD
                CALL    DELAY100us
                LOAD    s4, 01
                CALL    LCD_PUTCMD
                CALL    DELAY100us
                RETURN

LCD_PUTCH:      CALL    LCD_RS_1
                CALL    LCD_RW_0
                OUTPUT  s4, LCD_DATA
                CALL    LCD_E
                RETURN

LCD_PUTCMD:     CALL    LCD_RS_0
                CALL    LCD_RW_0
                OUTPUT  s4, LCD_DATA
                CALL    LCD_E
                RETURN

LCD_RS_0:       LOAD    s0, 00
                JUMP    LCD_RS
LCD_RS_1:       LOAD    s0, 01
LCD_RS:         OUTPUT  s0, LCD_CTRL_RS
                RETURN

LCD_RW_0:       LOAD    s0, 00
                JUMP    LCD_RW
LCD_RW_1:       LOAD    s0, 01
LCD_RW:         OUTPUT  s0, LCD_CTRL_RW
                RETURN

LCD_E:          LOAD    s0, 01
                OUTPUT  s0, LCD_CTRL_E
                CALL    DELAY1us
                LOAD    s0, 00
                OUTPUT  s0, LCD_CTRL_E
                CALL    DELAY1ms
                RETURN

; ------------------------------------------------------------------------------
; -- 時間待ち
; -- 50Mhz = 20ns
; -- 1命令 2クロック = 40ns
; -- s0,s1,s2,s3 
; -- 
; ------------------------------------------------------------------------------
DELAY1us:       LOAD    s0, 16
DELAY1us00:     SUB     s0, 01
                JUMP    NZ, DELAY1us00
                RETURN

DELAY100us:     LOAD    s1, 64
DELAY100us00:   CALL    DELAY1us
                SUB     s1, 01
                JUMP    NZ, DELAY100us00
                RETURN

DELAY1ms:       LOAD     s2, 0A
DELAY1ms00:     CALL    DELAY100us
                SUB     s2, 01
                JUMP    NZ, DELAY1ms00
                RETURN

DELAY20ms:      LOAD    s3, 14
DELAY20ms00:    CALL    DELAY1ms
                SUB     s3, 01
                JUMP    NZ, DELAY20ms00
                RETURN

; ------------------------------------------------------------------------------
; -- 割り込みルーチン
; -- 
; ------------------------------------------------------------------------------
INTERRUPT:
;               &lt;<コード>>
                RETURNI ENABLE

; ------------------------------------------------------------------------------
; -- 割り込みベクタ
; -- 
; ------------------------------------------------------------------------------
                ADDRESS 3FF
                JUMP    INTERRUPT

verilog のソース

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    10:28:22 04/24/2009 
// Design Name: 
// Module Name:    picolcd 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
`default_nettype none

module picolcd (
    input   wire CLK_50MHZ,
    output  wire LCD_E,
    output  wire LCD_RS,
    output  wire LCD_RW,
    output  wire [7:0] LCD_DB,
    output  wire [7:0] LED
);

wire RESET;     // DCMのLOCKED_OUTをロジカルなリセットにするのがいい
wire DCM01_CLKIN_IBUF_OUT;
wire DCM01_CLK0_OUT;
wire DCM01_LOCKED_OUT;
wire [9:0]	CPU00_ADDRESS;
wire [17:0]	CPU00_INSTRUCTION;
wire [7:0]	CPU00_PORT_ID;
wire [7:0]	CPU00_IN_PORT;
wire [7:0]	CPU00_OUT_PORT;
wire CPU00_READ_STROBE;
wire CPU00_WRITE_STROBE;
wire CPU00_INTERRUPT;
wire CPU00_INTERRUPT_ACK;

generate_reset_pulse generate_reset_pulse (
    .clock(DCM01_CLKIN_IBUF_OUT),
    .reset_pulse(RESET)
);

dcm01 DCM01 (
	.CLKIN_IN(CLK_50MHZ), 
	.RST_IN(RESET), 
	.CLKIN_IBUFG_OUT(DCM01_CLKIN_IBUF_OUT), 
	.CLK0_OUT(DCM01_CLK0_OUT),
	.LOCKED_OUT(DCM01_LOCKED_OUT)
);

kcpsm3 CPU00 (
 	.address(CPU00_ADDRESS),
 	.instruction(CPU00_INSTRUCTION),
 	.port_id(CPU00_PORT_ID),
 	.write_strobe(CPU00_WRITE_STROBE),
 	.out_port(CPU00_OUT_PORT),
 	.read_strobe(CPU00_READ_STROBE),
 	.in_port(CPU00_IN_PORT),
 	.interrupt(CPU00_INTERRUPT),
 	.interrupt_ack(CPU00_INTERRUPT_ACK),
 	.reset(RESET),
 	.clk(DCM01_CLK0_OUT)
);

lcd CPU00ROM (
	.address(CPU00_ADDRESS),
	.instruction(CPU00_INSTRUCTION),
	.clk(DCM01_CLK0_OUT)
);

lcdport_out lcd_port_out (
    .we(CPU00_WRITE_STROBE),
    .port(CPU00_PORT_ID),
    .data(CPU00_OUT_PORT),
    .lcd_data(LCD_DB),
    .lcd_e(LCD_E),
    .lcd_rs(LCD_RS),
    .lcd_rw(LCD_RW),
    .led(LED)
);

endmodule

////////////////////////////////////////////////////////////////////////////////
//  Generate 1shot pulse 
////////////////////////////////////////////////////////////////////////////////
module generate_reset_pulse (
    input wire clock,
    output wire reset_pulse
);

SRL16 #(.INIT(16'h00FF)) SRL16_inst (
    .Q(reset_pulse),
    .A0(1'b1),
    .A1(1'b1),
    .A2(1'b1),
    .A3(1'b1),
    .CLK(clock),
    .D(1'b0)
);

endmodule

////////////////////////////////////////////////////////////////////////////////
//  CPU00(PicoBlaze)  ADDRESS DECODER
////////////////////////////////////////////////////////////////////////////////
module lcdport_out (
    input wire we,
    input wire [7:0] port,
    input wire [7:0] data,
    output reg [7:0] lcd_data,
    output reg lcd_e,
    output reg lcd_rs,
    output reg lcd_rw,
    output reg [7:0] led
);
always @(posedge we)
begin
    case(port)
        8'h01:	lcd_data = data;
        8'h02:	lcd_e  = data[0];
        8'h03:	lcd_rs = data[0];
        8'h04:	lcd_rw = data[0];
        8'h05:  led = data;
    endcase	
end

endmodule

PicoBlaze で LEDピコピコ

PicoBlaze で LEDピコピコです。

PicoBlaze については、 http://www.xilinx.com/picoblaze に関連する情報と
PicoBlaze のアセンブラなどのダウンロードがあります。

  • ロイヤリティフリーで使用可
  • 8ビットマイコン
  • 全ての命令は2クロックで実行される
  • 16個のレジスタ / SCRACH PAD RAM(64Byte) / ROM(1K x 18bit)

マイコンは、アセンブラのソース(.psm)を KCPSM3.EXE でアセンブルします。
エラーが無ければHDLのソース VHDL と Verilog のソースが出力されるので
これをトップモジュールに組み込めば動くという寸法です。

xilinx からダウンロード出来る KCPSM3.ZIP の中には資料含めて一式入ってるので
大丈夫でしょう。また ug129 のユーザーガイドには日本語版PDF(日付古いですが…)
があるので、これもダウンロードしておけばいいと思います。

アセンブラのソース

		ADDRESS	000

INIT00:
		ENABLE	INTERRUPT

MAIN00:		LOAD	s5, 00

MAIN90:
		OUTPUT	s5, 01    ; ポート1に出力する
		ADD	s5, 01
		CALL	DELAY1s
		JUMP	MAIN90


; ------------------------------------------------------------------------------
; -- 時間待ち
; -- 50Mhz = 20ns
; -- 1命令 2クロック = 40ns
; -- s0,s1,s2,s3 
; ------------------------------------------------------------------------------
DELAY1us:	LOAD	s0, 17
DELAY1us00:	SUB	s0, 01
		JUMP	NZ, DELAY1us00
		RETURN

DELAY100us:	LOAD	s1, 64
DELAY100us00:	CALL	DELAY1us
		SUB	s1, 01
		JUMP	NZ, DELAY100us00
		RETURN

DELAY1ms:	LOAD	s2, 0A
DELAY1ms00:	CALL	DELAY100us
		SUB	s2, 01
		JUMP	NZ, DELAY1ms00
		RETURN

DELAY20ms:	LOAD	s3, 14
DELAY20ms00:	CALL	DELAY1ms
		SUB	s3, 01
		JUMP	NZ, DELAY20ms00
		RETURN

DELAY1s:	LOAD	s4, 32
DELAY1s00:	CALL	DELAY20ms
		SUB	s4, 01
		JUMP	NZ, DELAY1s00
		RETURN

; ------------------------------------------------------------------------------
; -- 割り込みルーチン
; -- 
; ------------------------------------------------------------------------------
INTERRUPT:
;		&lt;<コード>>
		RETURNI ENABLE

; ------------------------------------------------------------------------------
; -- 割り込みベクタ
; -- 
; ------------------------------------------------------------------------------
		ADDRESS 3FF
		JUMP	INTERRUPT
</コード></code></pre>
<p>
Verilog のソース
</p>
<pre><code>
module main (
	input wire CLK_50MHZ,
	output wire [7:0] LED );

wire RESET;
wire CLKIN_IBUFG_OUT;
wire CLK0_OUT;
wire LOCKED_OUT;
wire 	[9:0]	address ;
wire 	[17:0]	instruction ;
wire 	[7:0]	port_id ;
wire 		write_strobe, read_strobe, interrupt_ack ;
wire 	[7:0]	out_port ;
wire 	[7:0]	in_port ;
wire		interrupt, reset, clk ;

user_reset reset00 (
	.CLOCK(),
	.RESET()
);

dcmsp00 dcmsp00 (
	.CLKIN_IN(CLK_50MHZ), 
	.RST_IN(RESET), 
	.CLKIN_IBUFG_OUT(CLKIN_IBUFG_OUT), 
	.CLK0_OUT(CLK0_OUT),
	.LOCKED_OUT(LOCKED_OUT)
);

kcpsm3 CPU00 (
 	.address(address),
 	.instruction(instruction),
 	.port_id(port_id),
 	.write_strobe(write_strobe),
 	.out_port(out_port),
 	.read_strobe(read_strobe),
 	.in_port(in_port),
 	.interrupt(interrupt),
 	.interrupt_ack(interrupt_ack),
 	.reset(RESET),
 	.clk(CLK0_OUT)
);

led CPU00LED (
	.address(address),
	.instruction(instruction),
	.clk(CLK0_OUT)
);

outp_sel outp_sel (
	.port_id(port_id),
	.write_strobe(write_strobe),
	.indata(out_port),
	.otdata(LED)
);

endmodule

//
// Generate RESET PULSE
//
module user_reset (
	input wire CLOCK,
	output wire RESET );

   
   SRL16 #(.INIT(16'h00FF))	// Initial Value of Shift Register
     SRL16_inst (
      .Q(RESET),			// SRL data output
      .A0(1'b1),			// Select[0] input
      .A1(1'b1),			// Select[1] input
      .A2(1'b1),			// Select[2] input
      .A3(1'b1),			// Select[3] input
      .CLK(CLOCK),		// Clock input
      .D(1'b0)				// SRL data input
   );

   // End of SRL16_inst instantiation
endmodule

module outp_sel (
	input wire port_id,
	input wire write_strobe,
	input wire [7:0] indata,
	output reg [7:0] otdata
);

	always @(posedge write_strobe)
		begin
			if(port_id == 1)
				otdata = indata;
		end		

endmodule