2011年12月22日木曜日

独自のCPUを創ってみる(9) - まとめ


独自のCPUを創ってみる(8) - DMMファイルの続き


未完成のTD32のプロジェクトファイル

拾い物のDDR SDRAMコントローラを試す

で試したSDRAMコントローラとTD32を繋ぎたいと、やってみたがうまく行かない。
原因は2点考えられ、一つはもともとこのコントローラはちょっと変、
ということと、もう一つはSDRAMコントローラは100MHz用で、
一方CPUのTD32はそんなに高速に動作しないので25MHzで
動かしていて、ちょうど4倍のクロックなのを利用してなんとか
接続する回路にしたはずなのだが、まだどこかにバグがあるかも知れない、
ということ。

コントローラが変なのは、もともとこれを作った人がコメントで
以下のようなことを書いてて、つまりうまくタイミングが合ってないのだ。

/***************************************************
 * De-duplex of the data path
 * For some reason, for read, the output is CL=2.5, not CL=2
 * Thus, catching of the data is 1/2 a cycle late.
 * Flip the main_clk and main_clk_n, 1/2 cycle delay catched
 * on data_mux_latch
 ***************************************************/

がんばれば、いつかはバグが取れるかも知れないが、
だれてきたので、ここで一旦締めて、別のテーマに移ることにする。
でも「独自CPUにDRAMを接続する」というのは諦めてないので、
いつかまた戻ってくるだろう。

もともと、以下の目的があった。


自分でCPUを設計して実装する技量を身につけたい。
Spartan starter kit に搭載されているDRAMを使いたい。
wishbone の使い方を学びたい。
DRAM以外は、まぁまぁ達成できた。

反省として、TD32はアーキテクチャというものを考慮しておらず、
そのため動作周波数が遅い上にリソース消費が大きいことだ。
単純に以下のようなレジスタを定義しているが、この部分で
512個のフリップフロップを使ってしまっている。

reg [31:0] gr[0:15];

また、以下のような32bitのMUXを多用していて、
このような記述でかなりリソースを使ってしまっている。

wire [31:0] alu2 = (cycrd | cycrd2) ? indata1 : 
(oprr | opar) ? grim8 : gr[opregj];

また、インタフェース仕様としてwishboneを使うこと自体は
よかったが、CPUが1クロックで命令を実行するというのに、
その1クロックの忙しい間にwishboneでI/OやRAMにアクセス
するのはぜんぜん無理だった。
次に作るときは、wishboneはI/O用とDRAM用で別にするか、
もしくはI/Oだけwishboneで接続して、DRAMは別途専用配線と
するのがいい。
今回はメインメモリもwishbone接続だったが、メインメモリは
BLOCK RAMをうまく使ってCPU内部の専用配線にしないと
タイミング的に間に合わない。また、レジスタファイルも
BLOCK RAMを活用しないとリソース的にも問題だ。

これらの反省を生かして、次は100MHz動作の16bit CPUを創ってみたい。

さて、最後に備忘録として各種ファイルの説明をしておく。
半年もすると絶対忘れてしまって自分でも分からなくなると思うので。

asm.cmd
TD32用のアセンブラを使ってアセンブルしてHEXファイルを生成する。
次にram1.bmm の記述に従って top.bit 内のBLOCK RAMを書き換え、
top_rp.bitを生成する。
data2mem -bm ram1.bmm -bd %MEM% -bt top.bit -p xc3s500e
次に、impactを使ってボードに書きこむ。
call wbit top_rp.bit

bus.v
wishboneバスを使ってCPU, RAM, I/O などを接続する。

Chattering.v
チャタリング除去用の簡単な回路

clkgen2.v
ddr_sdram.v で使われているDRAM用のクロック生成回路

dcm1.v
入力クロックを n/m 倍して任意のクロックを生成する

dcm2.v
90度ずつずれた4つのクロックを生成する

dcm4ddr.v
dcm1とdcm2を足したような回路

ddr_sdram.v
SDRAMコントローラ

hexconv.py
tool.py hex2hx2 に統合した

inport.v
汎用入力ポート

outport.v
汎用出力ポート

output.bmm
以下の出力例
data2mem -bm ram1.bmm -bd p2.mem -o p output

output.v
以下の出力例
data2mem -bm ram1.bmm -bd p2.mem -o v output

p1_led.txt
LEDを光らせるテストプログラム。ハンドアセンブルした。

p2.asm
p1_led.txt をアセンブラで置き換えた。

p3.asm
DRAMとの接続テスト用。結局、ちゃんと動作してない。

param.h
以下の定義を含むヘッダファイル。
シミュレーションのときは定義し、ボードに書きこむときはコメントアウトする。
`define DEBUG_SIM

paramconv.py
tool.py fmthex に統合した

paramlist_cpucyc.h
paramlist_opaddr.h
paramlist_opalu.h
paramlist_opcond.h
veritakでenum表示を使うための定義ファイル。
これらのファイルをincludeして、信号と紐付ける。
veritakでenum表示を選択すると、信号の値が数値ではなく
ラベルで表示される。

Prescaler.v
分周回路

prog.hex
prog.txtから、tool.py fmthex で整形した結果

prog.txt
ハンドアセンブルしてた頃のテストプログラム。
テストベンチt_top.v で使われ、多くの命令をひと通りテストする。

progconv.cmd
paramconv.py を起動するバッチファイル

ram.v
block ramを使用した512 word x 32 bit メモリ
wishbone 仕様

ram1.bmm
asm.cmd参照

rom.v
テストプログラムを含むROM。

td32.v
TD32 本体

td32asm.txt
TD32用のマクロ定義ファイル。汎用アセンブラAASMに適用する。
使用例はasm.cmd参照。
AASMのおかげで、簡単にアセンブラを利用できた。
ハンドアセンブルでずいぶん苦労したが、AASMがこんなに役に立つと
分かってたらもっと早くマクロ定義をしたのだが。

tool.py
各種のツールをまとめたもの。含まれるツールは下記。

tool.py fmthex [-h] [-f fillstring] [-s size] <in-file> [<out-file>]
    fmthex - format for $readmem(). "00_ab/*..*/cd" => "00abcd"

tool.py hex2hx2 [-h] [-f fillstring] [-s size] <in-file> [<out-file>]
    hex2hx2 - format for $readmem(). intel HEX (output of AASM) => HX2 (suitable for readmem())

tool.py hx22mem [-h] <in-file> [<out-file>]
    hx22mem - hx2 => xilinx mem file for data2mem command (to replace memory part of a bit file


top.ucf
UCFファイル

top.v
topファイル。クロック生成、リセット回路など。

top.vtakprj
top2.vtakprj
top3.vtakprj
veritak用プロジェクトファイル

t_top.v
t_top2.v
t_top3.v
テストベンチ

v13.gise
v13.xise
ISE用プロジェクトファイル

wbit.bat
IMPACTでボードに書きこむバッチファイル。
bitファイル名を省略すると、top.bitとなる。
wbit <bitファイル>

wishbone_wait.v
wishboneのslave側で、ACKの応答を固定クロック遅らせるための回路

以上

0 件のコメント:

コメントを投稿