FC2ブログ

[LM32]DE0 nanoでLEDチカチカしない原因解析 → 解決

XilinxのML501では動いていたソース(DWM200710のやつ)をもってきて、
コンパイラ等もDWM200710付属のデータを使い、DE0 nano上で
Lattice Mico32を動かそうとしてる。

メモリをXilinxからAlteraへ変えるだけで、確かこの前LEDチカチカ出来てたんだが、
また動かなくなった。ソースの取り違いの可能性大だが、こんな場合に、
どんな確認すれば良いのか考えてみる。
(単に動くソースを探して差し替えれば動くのかもしれないけど、そもそもCPUはどこがどうなると
 正常動作になるのか?というのを、ほんの触りだけでも探ってみる、という意味です)

■命令用SRAMから最初にどのデータが読まれるのか?
 main関数の前はスタートアップルーチンだ、くらいは知ってるけど、
 外部リセットを入れてから、どこからSRAMが読まれ、どんな値が出たらOKなのか?を確認したい。

 まずはobjdumpでelfを解析してみる。

$ lm32-elf-objdump.exe -d uart_int | more

uart_int: file format elf32-lm32

Disassembly of section .start:

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>
...
20: e0 00 00 6d bi 1d4 <__break_interrupt>
...
40: e0 00 00 61 bi 1c4 <__interrupt>
...
60: e0 00 00 59 bi 1c4 <__interrupt>
...
80: e0 00 00 51 bi 1c4 <__interrupt>
...
a0: e0 00 00 49 bi 1c4 <__interrupt>
...
c0: e0 00 00 41 bi 1c4 <__interrupt>
...
e0: e0 00 00 39 bi 1c4 <__interrupt>
...

00000100 <__startup>:
100: 78 1c 20 00 mvhi sp,0x2000
104: 3b 9c 1f fc ori sp,sp,0x1ffc
108: e0 00 01 41 bi 60c



0000010c :
10c: 37 9c ff c8 addi sp,sp,-56
110: 5b 81 00 04 sw (sp+4),r1
114: 5b 82 00 08 sw (sp+8),r2
118: 5b 83 00 0c sw (sp+12),r3
11c: 5b 84 00 10 sw (sp+16),r4
120: 5b 85 00 14 sw (sp+20),r5
124: 5b 86 00 18 sw (sp+24),r6
128: 5b 87 00 1c sw (sp+28),r7
12c: 5b 88 00 20 sw (sp+32),r8
130: 5b 89 00 24 sw (sp+36),r9
     :



 まずリセット直後に読まれるアドレスは0x00番地(のはず)。
 Webでぐぐっても0番地と書いてあるが、保有してるRTLの設定が本当にそうなってるのか?
 が確認出来てないから「はず」を付けた。

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>



 0番地から始まり、そこではbi命令で、_startupラベルの番地へ飛ぶ。
 __startupラベルは100番地を指していて、__startupの記述を見ると次のようになってた。

00000100 <__startup>:
100: 78 1c 20 00 mvhi sp,0x2000
104: 3b 9c 1f fc ori sp,sp,0x1ffc
108: e0 00 01 41 bi 60c



 mvhiって何だ?と思ったら以下を見る。ここにアセンブラの仕様がのってる。
 http://www.latticesemi.com/~/media/Documents/UserManuals/JL/LatticeMico32ProcessorReferenceManual34.pdf?document_id=50900

少なくとも0番地からスタートする事は正しそうだし、hexファイルを見ても、0番地に下の命令がある。

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>


ただし、シミュレーションしても、addr=0でrden=Hなのにデータ出力はAll 0のまま。なぜ?

命令メモリ単体でシミュレーションしても同じでwren=0、rden=1、addr=0、be=0xfにしても0番地が読まれない。
QuartusII 14.1でIP Catalog画面へD&DしてMegaWizardを起動し、パラメータを確認してみると・・・

目的と違って出力がレジスタ付になってる。詳細な論理は不明だが、単にレジスタ1段入ってたって、
ずっと出力が変わらないって事は無いだろう、とは思いつつも、ここを出力レジスタ無にした。
そうすると、リードデータが出力されるようになった。
ソースでいうと、以下の設定。UNREGISTEREDなので出力レジスタ無って事らしい。

altsyncram_component.outdata_reg_a = "UNREGISTERED",



MegaWizardの画面で見る限り、単に1クロック遅れて出力させるための出力レジスタだと思ってたが、
このレジスタ動作には他の論理が絡んでるって事かな?
LUTでなく、BLOCK RAMを使われると物理LAYOUTにおいて、BLOCK RAMからその後段の論理が遠くなり、
セットアップ違反になるケースを回避するための役目程度にしか考えてなかった。今後注意しよう。


とりあえずhexはちゃんとかどうか不明だが、見る限り先頭の100アドレスくらいは初期値として読まれている。
そして、SRAMからデータも出力されるようになった。
SRAM単体のシミュレーションからMico32のシミュレーションに戻ってみると、命令アドレスは、
0x000、0x004、0x008、0x100、0x104、0x108・・・
と進んで行く。

リセット解除後に、0x000に進むのは納得。ここがスタートアップルーチンの開始ポイントだから。

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>
...
20: e0 00 00 6d bi 1d4 <__break_interrupt>
...
40: e0 00 00 61 bi 1c4 <__interrupt>
...


次の0x004、0x008に行くのはなぜ?と思ったが、
よくよく考えると以下が理由だよね。納得。

  ・32bit CPUなので、データは4バイト毎読まれる。だから0、4、8と進む。
  ・今シミュレーションで見ているのはSRAMへのアドレス入力。
   つまりパイプライン内の命令フェッチステージの動作。
   さらに0x000にbi命令(Unconditional branch)があるため、無条件分岐するのだが、
   パイプライン上の命令フェッチステージでは次から次への先取りしてアドレスを進める。
  ・0x000のbi命令が、IF、DECODE、EXEとパイプラインを進むうちに分岐命令が実行され、
   0x008の次にbi命令で指定した0x100へジャンプした。



アドレスは想定通りに進んでいるが、0x100へ飛んだ後、そこでもまたメモリ出力がおかしく、
hexファイル上では

:10010000781c20003b9c1ffce0000141379cffc88D


「781c2000」が0x100の命令なのに、シミュレーションではALL 0出力。
またどこかおかしいらしい。次はこの解析。

っと思ったら、.hexのパスが間違ってた。DWM200710付属のmemcvt.exeで.hex生成してから、
hex内のアドレスをRubyで修正していて、修正版の.hexを使ってなかった事が原因でした。

■.hexのアドレス数間違ってる?
Veritakでこんなエラーが。

readmemb(h) ./inst_ram_data.ver Access Error accessing address=800 min_address=7ff max_address=0
In module:tb_mico32_neek.uut.mico32.inst_rom32_core.inst_ram.altsyncram_component.m_non_arria10.altsyncram_inst;
C:\user\onedrive\vm_share\de0_nano\mico32\rtlsim\rtl\altera_mf.v(48133)::
readmemb(h) ./data_ram_data.ver Access Error accessing address=800 min_address=7ff max_address=0
In module:tb_mico32_neek.uut.mico32.data_ram32_core.data_ram.altsyncram_component.m_non_arria10.altsyncram_inst;
C:\user\onedrive\vm_share\de0_nano\mico32\rtlsim\rtl\altera_mf.v(48133)::



Mico32命令メモリとして使ってるアルテラメモリIPの初期値ファイルを試しにQuartusで作ってみる。

Quartus II 14.1 > File > New > Memory Initialization File
 > Number of Word=2047, Word size=32
 > メモリアレイ内で右クリック > Custom Fill Cell...
 > Starting Address=0、Ending Address=2048、Starting Value=0、Increment by=1
 > OKを押して値がセットされた。保存するとmifファイルが生成される。

.hexしか使えないと思ってたが、.mifが使えるなら、その方が記述簡単そうだ。

.mifを使う方向で再度、おさらい。
・DWM200710付属memcvt.exeでelfから.mifを生成。
・そこで生成された.mifは以下のフォーマットだった。

DEPTH=1024;
WIDTH=32;
ADDRESS_RADIX = HEX;
DATA_RADIX = HEX;
CONTENT
BEGIN
00000000:e0000040;
00000001:00000000;
00000002:00000000;
00000003:00000000;
00000004:00000000;
00000005:00000000;
00000006:00000000;
00000007:00000000;
00000008:e000006d;
00000009:00000000;
  :
000003fd:00000000;
000003fe:00000000;
000003ff:00000000;
END;


・Word=1024になってるが、実際に今使ってるQuartusのRAM IPは2048にしてた。
 RAM IPをWord=1024に変更して、生成した.mifがそのまま読み込めるようにした。
・Veritakで確認してみても、シミュレーション開始時エラー無く.mifが読めてる。
・先のVeritakでのエラー(inst_ram_data.ver Access Error accessing address=800・・・)
 の原因は初期値ファイルのアドレスサイズと実際のRAM定義が違っていた模様。

■0x60c配置mainプログラムはどこにある?
・Mico32用にビルドしたelfのobjdump -d .elf結果では、以下だった。

uart_int: file format elf32-lm32

Disassembly of section .start:

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>
...
20: e0 00 00 6d bi 1d4 <__break_interrupt>
  :
00000100 <__startup>:
100: 78 1c 20 00 mvhi sp,0x2000
104: 3b 9c 1f fc ori sp,sp,0x1ffc
108: e0 00 01 41 bi 60c


  :
0000060c <main>:
60c: 37 9c ff ec addi sp,sp,-20
610: 5b 9b 00 08 sw (sp+8),fp
614: 5b 9d 00 04 sw (sp+4),ra
618: 34 1b 00 14 mvi fp,20
 ※ mainのかっこは全角<>にしてます。
   半角だとHTML記述?に関係して表示されなかったため。


・リセット解除後、0x000 > 0x100(__startup) > 0x60c(main)と進む。
・mainが配置されるべき0x60c=dec1548なので、生成したRAMのword=1024をこえてる。
・.mifの中身を追うと、以下を発見出来る。

00000183:379cffec;
00000184:5b9b0008;
00000185:5b9d0004;
00000186:341b0014;
00000187:b77cd800;
00000188:78012000;
00000189:38210000;
0000018a:28210000;
0000018b:5b61fffc;
0000018c:78012000;
0000018d:38210004;
0000018e:34020000;


これはobjdumpして確認出来るmain関数の最初と命令コードが全て一致。

0000060c <main>:
60c: 37 9c ff ec addi sp,sp,-20
610: 5b 9b 00 08 sw (sp+8),fp
614: 5b 9d 00 04 sw (sp+4),ra
618: 34 1b 00 14 mvi fp,20
61c: b7 7c d8 00 add fp,fp,sp
620: 78 01 20 00 mvhi r1,0x2000
624: 38 21 00 00 ori r1,r1,0x0
628: 28 21 00 00 lw r1,(r1+0)
62c: 5b 61 ff fc sw (fp+-4),r1
630: 78 01 20 00 mvhi r1,0x2000
634: 38 21 00 04 ori r1,r1,0x4
638: 34 02 00 00 mvi r2,0


・.mifにおけるmain開始位置は0x183=dec387と分かった。
 387*4=1548であり、0x60c=dec1548と一致。
・そういえばDWM200710付属のRTLは命令メモリアドレスは下位2bitを抜かしてRAMへ接続していた。
 そういう事か。
 下位2bitを抜かす事で、実際の命令アドレス信号の1/4サイズのRAMで対応させてると。

■これでLEDチカチカが動いた!
 以上の事を踏まえ、system_top.v(Mico32のトップmodule)の以下を修正し、LEDチカチカ出来た。

inst_ram_altera inst_rom32_core (
// .addr(inst_sram_addr[9:0]), // 2015.2.1
.addr(inst_sram_addr[11:2]), // 2015.2.1

スポンサーサイト



コメントの投稿

非公開コメント

カレンダー
07 | 2021/08 | 09
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
累積訪問者
現在の訪問者
現在の閲覧者数:
最新記事
最新トラックバック
最新コメント
月別アーカイブ
カテゴリ
プロフィール

bobgosso

Author:bobgosso
FPGAのブログへようこそ!

検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード