かずの不定期便ブログ

備忘録代わりに書きます

onedriveの自動バックアップを切るお話

onedriveの自動バックアップを切るお話

自動バックアップをオフにしても、再起動後、ONに戻る

最近、winodows11へアップデートしたのですが、デスクトップとドキュメントフォルダがonedriveの自動バックアップ対象になってしまいました。
もしかしたら直近のwinodwsアップデート(2024/1/12)が原因かも。win11へアップデート直後は大丈夫だった気がします。
そのせいで、OneDrive上のドキュメントフォルダとCドライブにあったドキュメントフォルダがマージされて、くちゃくちゃになってしまいました。。。(ひどいよマイクロソフトさん)

検索すると、windows11はデフォルトでそのような動作になってしまうとの事。
自動バックアップ対象になると何が困るかというと、

CドライブはSSDにしていて、"デスクトップ"とか"ドキュメント"フォルダはCドライブにあります。onedriveはサブスクリプション契約で1TBで契約しているため、低容量のSSDではなくっ大容量のHDDのフォルダへ移動させています。該当フォルダがonedriveの自動バックアップ対象になってしまうと、OneDriveのフォルダ配下に"デスクトップ"とか"ドキュメント"フォルダが移動してしまいます。
そのため、"デスクトップ"とか"ドキュメント"が低速なHDDになってしまうことが問題です。

既存アプリがデータの格納場所として、元々の場所を見ている場合、動作しないこともありそうです(適当書いちゃいましたが、こちらは不明。ハードリンクで解決している感じがします)

また、これらのフォルダは、さして重要でないファイルを気軽に置いてきたため、サイズも肥大化してきており、かつイマイチ整理する気力が今更ないという事もあり、そのようなくだらないデータでOneDriveの様な高コストなストレージを使うのがもったいない

あと、僕の場合は、1TBと割と余裕があるのでいいですが、無料の場合には5GBしかないので、そもそもこれらのフォルダがOneDriveへ収容できない(容量不足でアップロードできないので同期エラーが起きる)という問題もありそうです。

という事で、 同期を止めたいと思いました。

onedriveの設定→"同期とバックアップ"→"バックアップを管理"

で自動バックアップをオフにしました。
以下の様な画面で警告が出ているうちはスイッチをスライドできません。おそらく、ドキュメントフォルダのデータをOneDriveへ移動の最中は本警告は消えないようです。サイズが大きいと時間がかかりますので気長に待ちます。

自動バックアップ設定画面

オフに出来たら、OneDrive配下に移動してしまったドキュメント配下のファイルを、元の場所へ移動します。(c:\ユーザー\xxxx\ドキュメント)
この際に、"ドキュメント へのショートカット (OneDrive - 個人用)"というショートカットが生成されていますが、削除します。(ショートカット先は意図せず出来たOneDriveのドキュメントになります)

これで作業は終了だと思ったのは、間違いで、再起動すると、またもドキュメントがOneDrive配下へ移動するという事態が発生。ひどいよマイクロソフトさん。
そして、自動バックアップ対象のスイッチもONに戻ってしまっています。
検索しても、そのような事例は見つからず。バグなのか、仕様なのか、分かりません。事例がないので、前者だと信じたい。

しかし、この状態は好ましくない。。。
色々調査すると、PCの再起動さえ行わなければ、自動バックアップはオフのままです。
OneDriveアプリを再起動しても自動バックアップの設定はキープされています。

暫定対処

という事で、次のような暫定対策で暫く様子を見る事にしました。

  • OneDriveの自動起動をオフ
  • PC再起動後に手動でOneDriveを起動

一応、今のところ、ドキュメントフォルダが移動することなく、OneDriveが使えてます。

はやく修正されることを祈ってます。

自動起動オフのやりかた
タスクマネージャを起動して、
スタートアップアプリを選択。OneDrive.exeを右クリック"無効化"を押します。

OneDrive自動起動のオフ

PicoRV32のプログラムをSDRAM上で動かす(TangNano20K)

はじめに

Gowin_PicoRV32の命令の実行方法は下記の3択になっております。

  1. フラッシュメモリ上でプログラムを実行
  2. フラッシュメモリでブートするが、その後ITCMでプログラムを動かす
  3. ITCM上でプログラムを実行する

実行速度は3.が最も早く、1.が最も大きなプログラムが動かせます。
TangNano20KのITCMのデフォルトサイズは32KBで(実際にサイズの大きなプログラムを作る機会があるか?というのは置いておいて)、ちょっと込み入ったものを作るとすぐに枯渇してしまいます。
TangNano20KのBSRAMは32KB使った状態でもまだ余っているので、サイズを大きくできる余地があるとはいえ、そんなに大きくできるわけではありません。
じゃーフラッシュメモリを使えばよいのではないか?という話になるのですが、読み出し速度がとてつもなく遅く、実行速度がガタ落ちになってしまいます。

というわけで、SDRAM上に命令コードを置いて、かつキャッシュメモリを挟めば、そこそこの速度を出しつつ大容量(8MB)の命令空間を確保できるのはないか?というのが発想です。 ただ今にして思えば、フラッシュメモリキャッシュメモリを挟むだけでよかったのでは?とも思います。

課題

フラッシュメモリからSDRAMへ命令コードを転送して、かつSDRAMへPC(プログラムカウンタ)を移動させる必要があります。メモリ配置でリンカをうまく使う必要がありそうで、その知識がないため難しそうです。

という慣れた人には、なんら課題でもない気がしますが、自分には大きな課題でした。
今回、IP版のPicoRV32には"フラッシュメモリ→ITCM"へ命令を移すという事が簡単に出来てしまうので、ITCM部分をSDRAMへ変更すれば実現できるのはないか?と思ったからです。

ソースコードの解析とか色々やってますが、SDRAM上で動かすための方法だけを知りたい方は、
ITCM実行部分をSDRAM領域へ差し替えを行う(ソフト面) へ飛んでください。

フラッシュからITCMへ命令実行を遷移する方法の解析

どのように実現しているかを前回使ったリファレンスデザインのソフトを解析してみました。 ブート方法をFLASH→ITCMとした場合には、loader.cのboot() から実行されます。
(config.hで BUILD_MODE == BUILD_BURN としている場合) なぜboot()だと特定したかは後ほど記載します。

_lma_ldsec_startなどの変数はexternで参照されています。
本変数はリンカファイルsections.lds にて定義されています。 本変数がアドレスであることは、想像がつくかと思いますが、実アドレスの特定は難しいので一旦置いておいて、boot()で何を行っているかを見てみます。
おそらく_lma_ldsec_startから配置されているコードを_vsloaderの示すアドレスへコピーしていることは分かります。またそのコピーサイズは(&lma_ldsec_end - &lma_ldsec_start)byteです。
また、

    src_ptr += 0x4100000;
    src_ptr_end += 0x4100000;

コピー元アドレスの算出のため、lma_ldsec_startに対し0x4100000を加算しています。
この値は4byte単位である(unsigned intでsrc_ptr変数を作っている)ので、0x4100000をbyte単位に変換すると、0x1040_0000になります。このアドレスはFLASHメモリのアドレスになります。
リンカファイルで定義されたアドレス情報を命令コードが置かれているFLASHメモリのアドレスへ変換しているのだと思います。
つまり、FLASHメモリに書き込まれた命令コードを、リンカファイルで定義されたアドレス**
vsloader**へコピーしているのだろうと思います。
おそらく、リンカファイルで定義されたアドレスとはITCMのアドレスを示しているのだろうと大方予想が付きます。

読み進めると

    __asm__ __volatile__("la t3, _vsloader");
    __asm__ __volatile__("jr t3");

という記述が現れるので、_vsloaderのアドレスへbranchしていることが分かります。
つまりここでコピーしたコードの先へbranchしています。

ここでリンカファイルの方へ戻って、_lma_ldsec_end の定義を見てみます。 _lma_ldsec_end = _lma_ldsec_start + SIZEOF(.ldsec);
と書いてあります。コピーサイズは.ldsecのサイズ分だという事が分かります。
.ldsecのサイズはリンカファイルから

.ldsec : AT (_lma_ldsec_start)
    {
        _vsloader = .;
~
 } >SMEM

の部分であることが想像は付きますが、具体的にどこのコード部分かが分かりません。
また、本sectionに_vsloaderと記載があるので、先ほどのコピー先がこの位置であることが想像できます。 このセクションの最後のSMEMというキーワードですが、リンカファイルの先頭で SMEM (rxai!w) : ORIGIN = 0x02000000, LENGTH = 32K /* LENGTH based on hardware configuration of ITCM size */ と記載があります。 SMEMとはITCMの領域で先頭アドレスが0x02000000だったのですね。
とはいえ、セクション.ldsecのスタートがITCMの先頭ではなく、SMEM領域の定義はこの部分より前に.textのセクションが存在しています。この.textセクションがITCMの先頭に配置されます。
そしてITCMが0x0200_0000から配置されています。
(本来はハード情報から、このmakefileを作る流れになりますが、私はmakefileが分からないので本来とは逆の順序で見ています)

_vsloader のアドレスの特定

make時に、ディスアセンブルリストが生成されます。生成場所は以下になります。
Gowin_PicoRV32_V1.3\ref_design\MCU_RefDesign\picorv32_demo\Debug\picorv32_demo.lst
このリストで、_vsloader のアドレスを特定することにします。
本ファイル中のvsloaderを検索すると私のディスアセンブルリストでは以下の様になっていました。
02001c34 g .ldsec 00000000 _vsloader
アドレス0x02001c34
vsloderの先頭なので、disアセンブルリストから02001c34を検索します。

void loader(void)
{
 2001c34:   1101                    addi    sp,sp,-32
 2001c36:   ce22                    sw  s0,28(sp)
 2001c38:   1000                    addi    s0,sp,32
…

上記のところにヒットします。関数loaderの先頭だという事が分かります。
関数loaderもコピー処理になります。きちんとは見ていないですが、おそらくFLASHの内容を同様にITCMへコピーして、ITCMのアドレスへブランチしているものと思われます。

リセット解除後、最初に実行される関数は?

最初に実行される関数は何でしょうか?
リンカのファイルにはそれらしい記述は、なかったです。正しいアドレスへプログラムが配置されればよいだけなので、もしかするとリンカは理解していないかもしれません。
ソフト面から追うのではなく、ハード面から追うことにしました。とにかくpicorv32のリセットベクタさえ分かればよいので、IDEがインストールされているIPが格納されているフォルダをなんとなく見てみました。
C:\Gowin\Gowin_V1.9.8.11_Education\IDE\ipcore\GowinPicoRV32\Gowin_PicoRV32\picosoc.v
がGOWIN_PicoRV32のTOPモジュールのようで、ここを見てみると

    localparam         [31:0]  PROGADDR_RESET    =  `PROGADDR_RESET_DEF;

という記述があります。PROGADDR_RESET_DEFが定義されているところを探すと
同フォルダのpico_config.vhなるファイルにて定義されていました。 `define PROGADDR_RESET_DEF 32'h1040_0000
とあるのでリセットベクタはアドレス0x1040_0000らしい事が分かりました。
このあたりのハード情報が記載されているドキュメントを見つけることが出来ませんでした。
分かりやすいところに記載があると良いのですが。。。
ここで逆アセンブルリストでアドレス10400000を探すと、以下を見つけることが出来ました。

void boot(void)
{
10400000:   1101                    addi    sp,sp,-32
10400002:   ce22                    sw  s0,28(sp)
10400004:   1000                    addi    s0,sp,32
…

つまりリセット解除後、最初に実行される関数はboot()関数のようです。
リンカファイルsections.ldsでも
FLASH (rxw) : ORIGIN = 0x10400000, LENGTH = 1M
となっていてアドレスが同じですね。

リンカはどうやってアドレスを決めているか?

大体Cのソースコードの流れは把握しました。
リンカはどのようにしてアドレスを決めているのでしょうか? 改めて、 リンカファイルsections.ldsへ目を向けると ENTRY(start)
の後に

SECTIONS {
    _lma_btsec_start = 0;
    .btsec : AT (_lma_btsec_start)
    {
        _vsbtsec = .;
        KEEP(*.o(.btsec))
        . = ALIGN(4);
    } >FLASH
    _lma_btsec_end = _lma_btsec_start + SIZEOF(.btsec);

大きなSECTIONSの中に.btsecというセクションが切られています。
そして、アドレスは_lma_btsec_startであると記載され、_lma_btsec_start=0と書かれています。
また本セクションはFLASHに割り付けらています。 つまり0x10400000をベースとするアドレス0番地が.btsecでありFLASHメモリであると分かります。
そして.btsecはCソースコードのどこを指すかというとloader.cに以下の様な記述があります。

void boot(void) __attribute__((section(".btsec")));
void loader(void) __attribute__((section(".ldsec")));

ここでboot(void).btsecセクションであると定義されています。 また。loader(void)は、.ldsecセクションであると定義されています。 リンカファイルsections.ldsへ戻って続きを読むと 、.ldsecセクションは.textの後ろに定義されています。 また.ldesc, .text両セクションともSMEM領域であるとも記載されています。
.textセクションがSMEM領域の先頭と定義されているので、つまりココが、ITCMの先頭アドレスになります。
.textセクションはどのソースかというと、逆アセンブルリストによるとstart.Sになります。

02000000 <_vstext>:
reset_vec():
<ソース配置フォルダ>\Gowin_PicoRV32_V1.3\ref_design\MCU_RefDesign\picorv32_demo\Debug/../src/start.S:26
    .section .text
    .global irq

きちんとアドレスと関数の関係及び、実行するアドレス順序をまとめたい気がしますが、目的はプログラムをSDRAMで実行させることで、ここまでの理解で十分だと思うので、細かく追うのはここまでにします。

ITCM実行部分をSDRAM領域へ差し替えを行う(ソフト面)

boot()が実行されるアドレス(0x200_0000番地でした)をSDRAMのアドレスへ書き換えればよいと分かります。
より簡単に実現するために、単にITCM空間をSDRAM空間へ差し替えます。
よってリンカファイルsections.ldsを以下の様に書き換えます。
SMEM (rxai!w) : ORIGIN = 0x30000000, LENGTH = 1M /* LENGTH based on hardware configuration of ITCM size */
SDRAM領域は0x3000_0000から1Mbyte分用意することにしました。(後ほど、ハード情報を記載します)
ITCMは使わない設定にします。
但し、GOWIN_PicoRV32をインスタンスする際に気が付くと思いますが、ITCMのサイズは0に出来なくて、最小8KB作る必要があるようです。(今回はこの8KBは全く使わない、もったいないRAMになってしまいました)

スタックポインタの設定を行う(ソフト面)

サンプルデモではスタックを使わないのかスタックポインタの設定がされていませんでした。
loader.cloader(void)関数でスタックポインタを設定します。 __asm__ __volatile__("la t3, _vstext");の行の手前に以下を追記します。

    extern int _stack_start;
    __asm__ __volatile__("la sp, _stack_start-4");
    __asm__ __volatile__("la t3, _vstext");

_stack_start変数はリンカファイルsections.ldsで設定します。
.eh_frameセクションの下に以下のような.stackセクションを記述します。

    .stack ORIGIN(RAM) + LENGTH(RAM) - _stack_size :
    {
        . = ALIGN(16);
        PROVIDE(_stack_end = .);
        . = _stack_size;
        . = ALIGN(16);
        PROVIDE(_stack_start = .);
    } >RAM

ソフト面はリンカファイルの書き換え、追記とスタックポインタの設定を行うのみです。
アセンブルリストを追ったりしましたが、正直なところ不要でした。キーワード検索で本ブログを参考にした方々にも無駄な時間を使わせた気がします。

ITCM実行部分をSDRAM領域へ差し替えを行う(ハード面)

picorv32のリセットベクタは変わらずFLASHの0x1040_0000のままでよいです。
しかし、先ほどのpicorv32のリセットベクタを記述しているファイルpico_config.hには、もう一行defineがありました。

`elsif BUILD_BURN
    `define PROGADDR_RESET_DEF 32'h1040_0000
    `define PROGADDR_IRQ_DEF   32'h0200_0010  ←この行がITCMのアドレス

PROGADDR_IRQ_DEFというdefineです。ITCMのアドレス+0x0010が定義されています。
割込みベクタの定義でしょうか?このあたりの説明のドキュメントが見つけられなくて、勘になります。
SDRAM領域は0x3000_0000以降1Mbyteと決めているので、以下の様に書き換えてしまいます。
ただ、本ファイルはIDEインストールフォルダのIPが格納されているフォルダにあるファイルですので、書き換えてしまうと、オリジナルのGOWIN_picoRV32とは異なるものになってしまいます。オリジナルは取っておくなどして、十分注意して作業を行いましょう。

`elsif BUILD_BURN
    `define PROGADDR_RESET_DEF 32'h1040_0000
    //`define PROGADDR_IRQ_DEF   32'h0200_0010
    `define PROGADDR_IRQ_DEF   32'h3000_0010

書き換えた後、GOWIN_IDEでpicorv32を再度IP呼び出しを行ってください。
ITCMの設定はMCU boot from External flash and run in ITCMへチェックを入れます。またITCMのサイズは0が設定できないので最小の8KBに設定します。
 また、この際に生成フォルダ(Create In:のところ)をデフォルトから書き換えてgowin_picorv32_run_sdramと後から見て分かりやすい場所にしておくというのも良いかと思います。見やすい以外にも理由があって後述します。
 OKボタンを押すとPicoRV32の合成が始まります。
 PicoRV32の合成が終わってしまえば、pico_config.hはオリジナルに戻してしまってもよいです。全体の合成時に、PicoRV32単体の合成が再度かかる事はありません。
 以上、ハード面は1行を書き換えればよいです。

合成済みPicoRV32の再利用方法

 少し話は逸れまずが、オリジナルPicoRV32と今回修正したPicoRV32をデバッグなどの目的でちょくちょく切り替えることが想定されるような場合に時短できる小技を紹介します。
 GOWIN_IDEのDesignタブでRTLファイルを指定しますが、IPの場合にはIPを呼び出すとココに自動的に追加されます。ソースファイルを右クリックすると下のスクショの様にEnable,Disableが切り替えられます。

designのenable,disable切替え
 この機能を使って、Designペインのところにあらかじめ、合成済みのSDRAM実行版とITCM実行版の両方のpicorv32を用意しておきます(よってpicorv32の合成時は生成フォルダを別にしておかないといけません)。
 このDesignペインで使う側のpicorv32をEnable,使わない側をDisableとして全体合成を行うと、disableと指定した側は合成対象外になるので、都度picoRV32を作成しなくても、あらかじめ合成済みのものを呼び出して使うという事が可能になります。
 つまりは、構成の異なるPicoRV32(今回はSDRAMで動く版とITCMで動く版)をあらかじめ合成してDesignペインに追加しておけば、マウス右クリックで簡単に切り替えが出来ます。

SDRAMで命令を実行するためのその他のハード情報

アドレスマップ

アドレスマップ

全体ブロック図

ブロック図
 簡単ですが、今回作成した回路のブロックを示します。PicoRV32から発行されたアクセス(アドレス0x3000_0000から1MB分の領域のみ)をキャッシュコントローラ経由でSDRAMメモリへアクセスします。
 キャッシュメモリの構成は、(こんなショボい容量ではありますが)4wayセットアソシアティブです。容量は4KBです。BSRAMの構成上、おそらく容量は4倍まで増やしても利用BSRAM数は変わらないんじゃないかと思われます。
(BSRAMは1個あたり1Kx16bitの容量を持つので、今回32bit幅のRAMとして使っているので1wayあたり2個のBSRAMを消費してしまいます。つまり4wayで8個、容量にしてトータル16KBにもなります)。詳しくは過去記事参照↓ spend-carefree.hatenablog.com

キャッシュメモリコントローラの性能
PicoRV32のwishboneバスにぶら下げていて、以下のような性能になります。あまり速くありません。
  Read Hit時 : 4cycle
  Write Hit時: 2cycle

Readの時は、TAGメモリからアドレスを引き出してHit/Miss判定を行うため、時間がかかってしまいます。
Write動作は、キャッシュの判定を待たないで、一旦書き込む動作を行っているので早いです。
 また、SDRAMへのアクセスは、命令の読み出し動作がほとんどになるので、write動作がread動作より早いというのは全体の実行時間に対する割合は非常に小さいです。
 それでも4cycleは外部FLASHメモリで動作するよりずっと高速です。

回路の公開

SDRAMコントローラは前回の記事でgitで公開していますが、そこからバグ取りなど行い再度アップロードしています。以下になります。
SDRAMコントローラ
tangnano20k/sdramc at main · kazuokada/tangnano20k · GitHub

■キャッシュコントローラ(新規)
tangnano20k/picorv32_cachec/rtl at main · kazuokada/tangnano20k · GitHub

公開はしていますが、デバッグ中(後述)という事もあり、動作は不安定です。ひたすらにコードは汚いです。

SDRAMの動作速度について

 GOWINのドキュメントによると166MHzまで動作するはずですが、安定動作が確認できたのは95MHzでした。133MHzへ上げると、動いたり動かなかったりで不安定でした。
キャッシュコントローラに不具合があるのか、SDRAMへのアクセスがうまくいかないのか。どちらに原因があるのか突き止められませんでした。
 SDRAMから出力されるリードデータをキャプチャするタイミングはSDRAMコントローラとは独立したクロック(clk_capdq)で行っていて、何通りか振ってみたのですが、調整の結果、アクセスが可能になったはずなのに、次の日に試したら何も変更していないのに時折データが化けたりと安定しません。リードタイミングを振りましたが、ライトで失敗している可能性もあります(低速では動作しているのでライトはOKだと思いますが)。
 とりあえず95MHzでは安定動作しているので、95MHzで動かす事にします。(なのでキャッシュコントローラはうまく動けていると信じたい)
 なんとか、133MHzでも安定動作を目指したいですけど、安定化作業だけで既に3week程度使っているので、一旦原因突き止めは休憩です。

SDRAMコントローラインスタンス部のサンプル

リードタイミングに係わる部分でパラメータを変更するようにしているので、そのサンプルという事で、インスタンス部を置いておきます。
`define SDRAM95M のdefine定義がインスタンス前に行われているという前提です。(ifdef SDRAM95M が存在していないのですが、という指摘は合ってます。現状、何もセットしなくても意図通りのパラメータが引き渡されます)

sdramc  #(
`ifdef SDRAM166M
    .FREQ(166*1000000),     // 166MHz
    .PHASE_SHIFT_CLKIN(0)   // when clk_capdq != sdramclk
`else
`ifdef SDRAM150M
    .FREQ(150*1000000),     // 150MHz
    .PHASE_SHIFT_CLKIN(1)   // when clk_capdq != sdramclk
`else
`ifdef SDRAM132M
    .FREQ(132*1000000),     // 132MHz
    .PHASE_SHIFT_CLKIN(1)   // when clk_capdq != sdramclk
`else
    .FREQ(95*1000000),     // 94.5MHz
    .PHASE_SHIFT_CLKIN(1)   // when clk_capdq != sdramclk
`endif
`endif
`endif
) inst_sdramc (
    // SDRAM side interface
    .SDRAM_DQ(IO_sdram_dq),     // inout [31:0]
    .SDRAM_A(O_sdram_addr),     // out [10:0]
    .SDRAM_BA(O_sdram_ba),      // out [1:0]
    .SDRAM_nCS(O_sdram_cs_n),   // out / not strictly necessary(), always 0
    .SDRAM_nWE(O_sdram_wen_n),  // out
    .SDRAM_nRAS(O_sdram_ras_n), // out
    .SDRAM_nCAS(O_sdram_cas_n), // out
    .SDRAM_CLK(O_sdram_clk),    // out
    .SDRAM_CKE(O_sdram_cke),    // out / not strictly necessary(), always 1
    .SDRAM_DQM(O_sdram_dqm),    // out [3:0]
    
    // Logic side interface
    .clk(sdramclk),             // input
    .clk_sdram(sdramclk),   // input / phase shifted from clk (normally 180-degrees)
    //.clk_sdram(~sdramclk),   // input / phase shifted from clk (normally 180-degrees)
`ifdef SDRAM166M
    .clk_capdq(sdramclk),   // DQ capture clock
    //.clk_capdq(sdramclk_90d),   // DQ capture clock
`else
`ifdef SDRAM150M
    //.clk_capdq(sdramclk),   // DQ capture clock
    .clk_capdq(~sdramclk),   // DQ capture clock
`else
`ifdef SDRAM132M
    .clk_capdq(~sdramclk),   // DQ capture clock
    //.clk_capdq(sdramclk_90d),   // DQ capture clock
    //.clk_capdq(sdramclk),   // DQ capture clock
`else
    .clk_capdq(sdramclk_90d),   // DQ capture clock
    //.clk_capdq(~sdramclk),   // DQ capture clock
`endif
`endif
`endif
    .resetn(sys_resetn_sdramc), // input
    .addr(cmd_addr_sdram),      // input [22:0] byte address(), buffered at cmd_en time. 8MB
    .busy(),                    // output / 0: ready for next command

    .cmd(cmd_sdram),            // input 0:read(), 1:write
    .cmd_en(cmd_en_sdram),      // input
    .cmd_ack(cmd_ack_sdram),    // output
    .cmd_len(cmd_len_sdram),    // input [3:0] 0-15
    .rd_data(cmd_rdata_sdram),  // output [31:0]
    .rd_data_valid(cmd_rvalid_sdram),   // output 
    .wr_data(cmd_wdata_sdram),  // input [31:0]
    .wr_mask(cmd_wmask_sdram)   // input [3:0]
);

動作速度について

以前に、以下の記事でbmp画像をHDMI表示させる挑戦しましたが、この時の動作速度との比較をします。
spend-carefree.hatenablog.com

前回(FLASH上で命令実行) 今回(キャッシュを介してSDRAM上で実行
80秒 6.9秒

10倍以上高速化が出来ました。

Gowin_PicoRV32合成でリセットパスのセットアップエラーの修正

本記事とは関係ないのですが、、、 PicoRV32を37.125MHzで利用しています。
Place&Route工程でリセットの同期化と思われる部分でセットアップエラーが発生しました。
パスを確認すると、リセットをクロックの逆相で同期化していました。そのため、PicoRV32コアへのリセットパスが半サイクル分のセットアップ時間しかなくエラーになりました。
以下のファイルを修正すると直りますが、これまたIP部を触ることになりますので、重々承知の上、作業を行う必要があります。
IDEのverは1.9.8.11
<GOWIN IDEインストールdir>\IDE\ipcore\GowinPicoRV32\Gowin_PicoRV32\picosoc.v
316行目のalways文のnegedgeをposedgeへ変更

まとめ

  1. ソフト開発環境はすごく便利(MCU designer)。
  2. SDRAMを高速動作させるのは難しい。phy部のタイミングが未考慮で済むようにSDRAMデータが必ず取得できるクロックとかあるとありがたいのだが。(私の設計のロジックのバグの可能性がありますが)
  3. SDRAMのACタイミングが公開されていないのがつらい。(ドキュメント見つけられないだけかも)
    2、3部分で時間の大半を使ってるので。。
  4. IPになっているGOWIN_PicoRV32 取り扱いが簡単でよい。
    ただ、SIMが出来ないのは我慢するとして、ロジックアナライザ―で内蔵RAMとの接続部分が観測出来たらなぁとデバッグ時に思う事がありました。

参考資料

次回予定

TangPrimer20Kを触りたいと思います。ただネタはなし。実は一度破壊しました。再注文しました。

FPGA Sipeed Tang Nano 20KでIP Gowin_PicoRV32を動かす

FPGA Sipeed Tang Nano 20KでIP Gowin_PicoRV32を動かす

  • FPGA Sipeed Tang Nano 20KでIP Gowin_PicoRV32を動かす
    • はじめに
    • PicoRV32のインスタンス方法
    • リファレンスデザインの実装
      • picorv32_demo.vの修正内容
      • picorv32.cstの修正内容
      • PicoRV32のインスタンスのやりなおし
    • GOWIN MCU Designerの準備
    • GOWIN MCU Designerの使い方
    • プログラムをTangNano20K用に修正
      • picorv32.h
      • config.h
      • main.c
    • プログラムの書き込み
    • ビットストリームの書き込み
    • 参考資料
    • 次回予定

はじめに

GOWIN IDEのIP Core Generatorから呼び出せるソフトrisc-vコアGowin_PicoRV32を使いました。 使用方法を簡単に書きたいと思います。

PicoRV32 IPインスタンス

続きを読む

FPGA Sipeed Tang Nano 20KでSDRAMを動かす

FPGA Sipeed Tang Nano 20KでSDRAMを動かす

  • FPGA Sipeed Tang Nano 20KでSDRAMを動かす
    • はじめに
    • 設計方針
    • 改造内容
    • バースト転送対応とPrechargeコマンドの投入について
    • Logical side interface仕様
    • 複数の要求元(最大3)に対応
    • ブロック図
    • cmd i/f 端子一覧
    • cmd i/f タイミング図
    • SDRAMのACスペックについて
    • RTL
    • 動作波形(SDRAM I/F)
    • 参考資料
続きを読む

FPGA Sipeed Tang Nano 9Kでフォトビューワーになりそこなったものを作りました

FPGA Sipeed Tang Nano 9Kでbmp画像を表示させる

フォートビューワ

  • FPGA Sipeed Tang Nano 9Kでbmp画像を表示させる
    • はじめに
    • フォトビューワー(のようなもの)の要件
    • HDMI表示の流れ
    • ハード構成図(SDカード→PSRAM)
      • PSRAM書き込み側制御回路
    • ハード構成図(PSRAM→HDMI)
      • HDMI表示制御回路
    • 動作の様子
    • 回路規模
    • まとめ
    • 次回
    • 今回の参考資料
続きを読む

FPGA Sipeed Tang Nano 9KでDualPortメモリの作成方法

FPGA Sipeed Tang Nano 9KでDualPortメモリの作成方法

  • FPGA Sipeed Tang Nano 9KでDualPortメモリの作成方法
    • BSRAMとは
    • BSRAMの推論が上手くいかないRTL記述
    • BSRAMを直置きするとSIMが出来ない
    • RTLから合成でBSRAMが推論されない理由が判明
    • 結論。DualPortメモリでもHDLコードからBSRAMは推論可能です!!
    • DualPortメモリのデータ幅は16bitまでにとどめるか、もしくはBSRAM1個当たりの最大容量16Kbitを使うように心がける
    • まとめ
    • 次回
    • 今回の参考資料
続きを読む

FPGA Sipeed Tang Nano 9Kを使ってPSRAMへアクセス

リーズナブルFPGAシリーズのTang Nano 9Kを使ってPSRAMへアクセスしました

TERM表示

  • リーズナブルFPGAシリーズのTang Nano 9Kを使ってPSRAMへアクセスしました
    • 1. PSRAMについて
    • 2. コントローラの実装について
      • PSRAMメモリーインターフェースIPの選択
      • チャネルインターフェースの仕様の確認
        • 残念ポイント
      • PSRAM本体はどこに?
    • 3. FPGA DesignerでPSRAMメモリーインターフェースIPの呼び出し
    • 4. サンプル
      • 4.1 Wishboneバス → PSRAM インターフェース ブリッジモジュール”brd_wb2ps.v"
      • 4.2 picotiny.vの改造
      • 4.3 PSRAMのメモリクロックをPLLで作成
      • 4.4 PICORV32で実行させるファームウェアの作成
      • 4.5 実行結果(TERM出力のコピーペースト。HDMI画像としても表示されております)
    • 5. まとめ
    • 6. 次回
  • 参考にさせていただいたサイトと資料
続きを読む