• Showing Page History #73181
  • Showing Page History #66371

Show page source of PicoBlazeBankedMemory #73181

= !PicoBlazeBankedMemory =

r203 で、Spartan3E Starter Kitを使用した動作確認ができるようになりました。

PicoBlaze3(KCPSM3)の命令アドレスは10bitなので、命令数は1024が限界です。
Virtex6やSpartan6向けにはもっと広い命令空間を持つPicoBlaze6があるのですが、Spartan3系では使用できません。

命令数が1024を超えた場合、複数のサブルーチンの共通処理をくくりだしてJUMPで繋いだり、レジスタsXが0,1,2のどれかの判定をCOMPARE sX, 1だけでやったり(0ならC、1ならZ、2ならNCかつNZ)と、1命令単位でカリカリに削る努力をしなければなりません。

そんな努力をしなくても救われるために、バンクメモリ方式を適用してみることにしました。

= どう切り替えるか =
まず、PicoBlazeは、レジスタの値を命令アドレスとみなしてJUMPあるいはCALLするということができません。命令アドレスは10bit、データ幅は8bitなので、原理的に無理です。よって、s4にバンク番号、s5にサブルーチンのアドレスを入れて、トランポリンルーチンでs4の値にバンク切り替えしたあとにs5の値をアドレスとしてCALL、なんていうのは不可能です。

Banked Memoryの普通の方式は、メモリ空間を4ブロックぐらいに分割し、そのうち何ブロックかを窓として、窓の先に見える実メモリをとっかえひっかえするものです。

バンク切り替えは、切り替えの対象でないブロックにバンク切り替えルーチン(仮に、トランポリンルーチンと表記します)をおいて、トランポリンルーチンに「バンクを切り替え、目的のルーチンをCALLし、戻ってきたら切り替え前のバンクに戻してリターン」という仕事をさせるのがセオリーです。

トランポリンルーチンに頼らずに、切り替えの対象であるブロックを実行中にバンク切り替えをしてしまうと、自分の足場がなくなってしまうので普通はやりません。

普通はやらないのですが、PicoBlazeだと一番合理的な実装になる予感がしたので、やってみることにしました。

また、命令メモリ空間を分割するとただでさえ狭い空間がさらに狭くなるし、pBlazIDEでシミュレーションするのも困難になるので、
命令メモリ空間の分割はせずにメモリを丸ごと入れ替えてしまうことにしました。それでもデータメモリ(ScratchPad)は同一なので困らないはずです。

※以下の記述でnopと書いてある部分は、PicoBlazeにはnopが無いので実際にはload s0, s0です。


bankA, bankB共通
{{{ code asm
BANKA_OP      DSOUT $80
BANKB_OP      DSOUT $81
BANKPREV_OP   DSOUT $43
}}}
bankA用
{{{ code asm
                  適当なプログラム
                  CALL init_lcd
                  ...
                  CALL write_lcdram
                  ...
    isr:          割り込みサービスルーチン
                  ...
                  RET
                  ORG $3F9
3F9 init_lcd:     OUT s0, BANKB_OP
3FA               RET
3FB write_lcdram: OUT s0, BANKB_OP
3FC               RET
3FD               nop
3FE               RET
3FF isv:          JUMP isr
}}}

bankB用
{{{ code asm
    init_lcd:     LCD初期化処理
                  ...
                  RET
    write_lcdram: LCDに文字を出す処理
                  ...
                  RET
                  ORG $3F9
3F9 init_lcd_:    nop
3FA               CALL init_lcd
3FB write_lcdram_:OUT  s0, BANKPREV_OP
3FC               CALL write_lcdram
3FD               OUT  s0, BANKPREV_OP
3FE               nop
3FF               nop
}}}

上記のようなプログラムと、「ポートアドレス$80または$81に書き込みがあったら、現在の選択バンクをスタック構造へpushし、$80ならbankAへ、$81ならbankBにバンク切り替えする」かつ「ポートアドレス$43に書き込みがあったら、スタック構造からpopした値にバンク切り替えする」モジュールをハードウェアとしてPicoBlazeに接続します。

※ちなみに、上記のモジュールはPicoBlazeのOUT_PORTを無視するので、s0の値は動作に影響しません。

bankA上のプログラムから、bankB上のLCD_initを呼び出す場合、その流れは以下のようになります。

||  || 実行される命令            || 命令の場所||
|| 1|| {{{CALL init_lcd}}}       || bankA||
|| 2|| {{{OUT  s0,  BANKA_OP}}}  || bankA 3F9||
|| 3|| {{{CALL init_lcd}}}       || bankB 3FA(この時点でbankBが選択されている)||
|| 4|| {{{init_lcdの処理が行われる}}}||bankB||
|| 5|| {{{RET}}}                 || bankB    ||
|| 6|| {{{OUT  s0, BANKPREV_OP}}}|| bankB 3FB||
|| 7|| {{{RET}}}                 || bankA 3FC(この時点でbankAが選択されている)||
|| 8|| {{{bankAの、CALL init_lcdの次の命令}}}|| bankA ||

割り込みに関しては、PBLAZBLOCK.vhdにて、「INTERRUPT_ACKがHighになったら強制的にBankAを選択し、RETI命令が検知されたら強制的にもとのバンクに戻す」という処理をしているため、オーバヘッドはありません。

...PicoBlazeで開発していると、こうやってソフトとハードを両方設計して、連係動作させて問題を解決するということできるのでとても楽しいです。
新人にSpartan3A Starter Kit(!DigiKeyで2万ぐらいで購入できます)を渡して、「PicoBlazeを使ってナイトライダーを作れ」とかいう課題を与えれば短期間で両刀使いが育成できるかもしれませんね。