FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

量子プログラミング言語Q#の勉強 (3. Bell状態から量子の状態を測定するサンプルプログラム)

量子プログラミングの何たるかについて、MicrosoftのQ#プログラミング言語チュートリアルを読みながら進めている。 量子プログラミングについて少しわかってみたので、一番最初のサンプルプログラムを読み解いていきたい。

参考にしているのは、これまでと同様にQ#のチュートリアルサイトだ。今回は "Writing a Quantum Program" を読みながら、量子プログラミングの一番最初のプログラムを学んでいく。

docs.microsoft.com

ベル状態とは

これは正直まだ理解しきっていない。しかしベルといくらいだし、量子ビットの状態がまだ確定していない状態、つまり0でも1でもない状態であると考えることができるだろう。

Q#では、量子ビットを定義して、最初にそれを初期化する処理が入っている。下記のプログラムでは、量子ビットqubits[0]を値initialで初期化し、M()操作を使って量子ビットの値を測定している。

using (qubits = Qubit[1])
{
   for (test in 1..count)
   {
       Set (initial, qubits[0]);    // 量子ビットqubits[0]を、値 initialで初期化する

       let res = M (qubits[0]);   // Mは、量子ビットqubits[0]を測定する。これにより量子ビットqubits[0]の値は0 or 1に確定される。

当然、initial=0ならば測定される値は0になるはずだし、initial=1ならば測定される値は1になるはずだ。これは簡単。

Hadamard ゲートを使って量子もつれ状態を作る

次に、量子ビットにHadamardゲートを適用して、量子のもつれ状態を作る。これにより、量子ビット01かわからない状態になってしまう。 ちなみに、Hadamardゲートというのは、行列の形式で記述すると、

$$ H=\dfrac{1}{\sqrt{2}}\begin{bmatrix}1&&1\\1&&-1\end{bmatrix} $$

量子ビットの0/1の状態から、0/1の等しい重みへの写像となるので、これで量子ビットは 0/1のどちらかわからなくなる。 さて、どっちなんだろう?次に、この量子ビットともう一つの量子ビットをCNOTで制御してみる。

Set (initial, qubits[0]);
Set (Zero, qubits[1]);

H(qubits[0]);
CNOT(qubits[0],qubits[1]);
let res = M (qubits[0]);

qubits[0]は現在もつれ状態。qubits[1]=0で初期化されている。 CNOTは前回説明したとおりだ。"qubits[0]が1ならば、qubits[1]を反転する、qubits[0]が0ならば、qubits[0]はそのまま"というゲートのため、

  • qubits[0]=1 ならば、 qubits[1]=NOT(0)=1
  • qubits[0]=0 ならば、 qubits[1]=0

となり、必ずqubits[0]=qubits[1]となることが確認できる。

これがサンプルプログラムの最後の出力に反映されている。

using (qubits = Qubit[2])
{
    for (test in 1..count)
    {
        Set (initial, qubits[0]);
        Set (Zero, qubits[1]);

        H(qubits[0]);
        CNOT(qubits[0],qubits[1]);
        let res = M (qubits[0]);

        if (M (qubits[1]) == res) 
        {
            set agree = agree + 1;
        }

        // Count the number of ones we saw:
        if (res == One)
        {
            set numOnes = numOnes + 1;
        }
    }

出力結果は以下だ。注目すべきなのは以下の2点。

  • qubits[0]の状態は、Hゲートの作用により確率1/2で0か1のどちらかに転んでいる。
  • ただし、qubits[1]の状態は、CNOTの作用により必ずqubits[0]と同じ値に転がっている。つまり、agreeは常に真となっている。
Init:Zero 0s=499  1s=501  agree=1000
Init:One  0s=490  1s=510  agree=1000

なるほど、ここまでは理解できた。次に、Teleportのプログラム解読に取り組みたい。

関連記事

TileLinkの仕様まとめ (TL-UL)

TileLinkの3つのレベル

  • TL-UL (TileLink Uncached-Lightweight)
    • 簡易的なTileLink。Get/Putのアクセスのみをサポート。
  • TL-UH (TileLink Uncached-Heavyweight)
    • Uncachedだが、TL-ULよりは高性能。Multibeat operations/atomic accesses, Hint operationをサポート。
  • TL-C (TileLink Cached)
    • Cacheラインの転送をサポート。Channel-B/C/Eをサポート。
TL-UL TL-UH TL-C
Cache line transfers
Channels B+C+E
Multibeat operations
Atomic accesses
Hint operations
Get/Put accesses

TileLinkの5つのチャネル

TileLinkは以下の5つのチャネルを持っている。

  • Channel-A : Master → Slave。 特定アドレスへのリクエスト送信。
  • Channel-B : Slave → Master。 特定アドレスへのキャッシュブロック送信
  • Channel-C : Master → Slave。 キャッシュブロックからのレスポンス
  • Channel-D : Slave → Master。 特定アドレスからのレスポンス
  • Channel-E : Master → Slave。 キャッシュブロック転送での最終ハンドシェーク。

各チャネルでの信号説明の際に登場するTypeについてここで紹介しておく。

Type Direction Description
X クロック入力・リセット信号 TileLink Agentへの入力信号
C 制御信号 転送制御中には変化しない制御信号群
D データ信号 転送毎に変化する
F Final信号 最終転送の時のみ変化する信号
V Valid信号 C/D/Fに有効な信号が含まれているときのみ駆動する
R Ready信号 V信号が受け入れられた時に駆動する信号

TileLink Uncached Lightweight (TL-UL)

TileLinkの最小構成。以下の2つのオペレーションしか実行することが出来ない。

  • Get操作 : メモリからデータを読み込む。
  • Put操作 : メモリに対してデータを書き込む。書込み操作については、バイト単位での細粒度書き込みが許される。

  • Channel-A での転送できるメッセージ (()内は実際のOpcode)

    • Get(4)
    • PutFullData(0)
    • PutPartialData(1)
  • Channel-D で転送できるメッセージ (()内は実際のOpcode)
    • AccessAckData(1)
    • AccessAck(0)

Get操作 (Read)

  • Master : Getコマンドを発行する
  • Slave : Getコマンドを受け取ると、AccessAckDataを返す。

PutFullData操作 / PullPartialData操作 (Write)

  • Master : PutFullData / PullPartialData を発行する
  • Slave : PutFullData / PullPartialDataコマンドを受け取ると、AccessAckを返す。
f:id:msyksphinz:20180215231604p:plain
図. TL-ULのトランザクションの例。Get/Putのどちらでも、A-Channelでのリクエストに対して、D-ChannelでのAcknowledgeを返す必要がある。

関連記事

SiFiveのFreedom E300 Platformを単体でカスタマイズできるようにする (4. TileLinkの解析とコンフィグレーション設定)

RISC-Vの実装であるRocket-Chipは、RISC-Vの最新使用に追従しているため最初に見るべきデザインとしてはよくできているが、

  • Chiselで記述されており(初心者には)可読性が低い。
  • 外部のSoCプラットフォームについて情報がない

ことから、なかなかオリジナルのSoCをくみ上げるためのデザインとしてポーティングしにくい。

とはいえ、TileLinkは単なるバスのはずだし、クロックとリセットさえ突っ込めばとりあえずフェッチリクエストが上がってくるはずだ。 そのあたりを解析して、Rocket-Chipを利用したオリジナルSoCプラットフォーム構築のための情報収集を行っていこう。

f:id:msyksphinz:20180211025506p:plain
図. とりあえず実現したいRISC-V SoCブロック。まずはQSPIを取り除いて、だれでもアクセスできるTestRAMを接続したい。

関連記事

TileLink のコンフィグレーション設定

やっと気が付いたのだが、Freedom SoC (しいてはRocket-Core)を生成するときにメモリマップが表示されるのだが、これをよく見てみると ターゲットとしている0x2000_0000 にはReadの許可しか入っていなかった。

Generated Address Map
               0 -     1000 ARWX  debug-controller@0
           10000 -    12000  R XC rom@10000
         2000000 -  2010000 ARW   clint@2000000
         c000000 - 10000000 ARW   interrupt-controller@c000000
        10000000 - 10001000 ARW   aon@10000000
        10012000 - 10013000 ARW   gpio@10012000
        10013000 - 10014000 ARW   serial@10013000
        10015000 - 10016000 ARW   pwm@10015000
        10016000 - 10017000 ARW   i2c@10016000
        10023000 - 10024000 ARW   serial@10023000
        10024000 - 10025000 ARW   spi@10024000
        10025000 - 10026000 ARW   pwm@10025000
        10034000 - 10035000 ARW   spi@10034000
        10035000 - 10036000 ARW   pwm@10035000
        20000000 - 20002000  R    ram@20000000   <-- ここにRWしたいのだが、Readのフラグしか立っていない。
        80000000 - 80004000 ARWX  dtim@80000000

これをどうやって立てるのかずっと調査していたのだが、どうやら各モジュールのインタフェースとなっているTileLinkのコンフィグレーションで、Read/Write/Executableの権限を制御できるようになっているらしい。

こんなの、資料が無いと分からんわ...

diff --git a/src/main/scala/devices/tilelink/SimpleRAM.scala b/src/main/scala/devices/tilelink/SimpleRAM.scala
index d7c5d74..5b7552e 100644
--- a/src/main/scala/devices/tilelink/SimpleRAM.scala
+++ b/src/main/scala/devices/tilelink/SimpleRAM.scala
@@ -32,6 +32,8 @@ class TLSimpleRAM(c: SimpleRAMParams)(implicit p: Parameters) extends LazyModule
       regionType         = RegionType.UNCACHED,
       executable         = true,
       supportsGet        = TransferSizes(1, beatBytes),
+      supportsPutPartial = TransferSizes(1, beatBytes),
+      supportsPutFull    = TransferSizes(1, beatBytes),
       fifoId             = Some(0))), // requests are handled in order
     beatBytes = beatBytes)))

@@ -71,4 +73,3 @@ class TLSimpleRAM(c: SimpleRAMParams)(implicit p: Parameters) extends LazyModule
     in.e.ready := Bool(true)
   }
 }

というわけで、TileLink側でアクセス許可を渡してやると、プログラムからRead/Writeできるようになった。

生成されるメモリマップ表は以下のように変わり、0x2000_0000 - 0x20002000にRead/Write/Executableが与えられるようになった (CはCachableか?Uncachedの構成にしてほしいのだが...)

Generated Address Map
               0 -     1000 ARWX  debug-controller@0
           10000 -    12000  R XC rom@10000
         2000000 -  2010000 ARW   clint@2000000
         c000000 - 10000000 ARW   interrupt-controller@c000000
        10000000 - 10001000 ARW   aon@10000000
        10012000 - 10013000 ARW   gpio@10012000
        10013000 - 10014000 ARW   serial@10013000
        10015000 - 10016000 ARW   pwm@10015000
        10016000 - 10017000 ARW   i2c@10016000
        10023000 - 10024000 ARW   serial@10023000
        10024000 - 10025000 ARW   spi@10024000
        10025000 - 10026000 ARW   pwm@10025000
        10034000 - 10035000 ARW   spi@10034000
        10035000 - 10036000 ARW   pwm@10035000
        20000000 - 20002000 ARWXC ram@20000000
        80000000 - 80004000 ARWX  dtim@80000000

しかし、まだ疑問点がある。1回目のWriteだけで止まってしまったぞ? TileLinkはAcknowledgeを出す必要があるのか?解析は続く...

    li  a0, 0x20000000
    lw  t0, 0x20(a0)
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    li   t0, 0xdeadbeef
    sw  t0, 0x00(a0)
    sw  t0, 0x04(a0)
    sw  t0, 0x08(a0)
f:id:msyksphinz:20180214010449p:plain
図. SimpleRAMモジュールに対してWriteコマンドが発行され、データ0xdeadbeefが伝えられた波形。

2018/02/15追記。結局、TileLinkのアービトレーションが必要らしい。 in.d.bits および in.d.bits.opcode を制御するような論理を追加した。これらは、SRAM.scalaを参考にした。 この辺、資料がちゃんと用意されていないと、分かりようがないよ...

     // Flow control
-    when (in.d.fire())         { d_full := Bool(false) }
-    when (in.a.fire() && read) { d_full := Bool(true)  }
+    when (in.d.fire()) { d_full := Bool(false) }
+    when (in.a.fire()) { d_full := Bool(true)  }
     in.d.valid := d_full
     in.a.ready := in.d.ready || !d_full

+    in.d.bits := edge.AccessAck(d_source, d_size, !d_legal)
+    // avoid data-bus Mux
+    in.d.bits.data := d_data
+    in.d.bits.opcode := Mux(d_read, TLMessages.AccessAckData, TLMessages.AccessAck)
+
+    val read = in.a.bits.opcode === TLMessages.Get
+    val rdata = Wire(Vec(beatBytes, Bits(width = 8)))
+    val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) }

Dチャネルに正しくAcknowledge を挟むことによりTileLinkが動作するようになった。ただし、まだ不明な点がある。

  • d.bits.error が立ち上がっているがこれは問題無いのか。
  • d.bits.source はそもそもどういう意味があるのか。
f:id:msyksphinz:20180215001207p:plain
図. TileLink において連続Read/Writeを実行した様子。上側がA-Channel, 下側がD-Channel

CARRV 2018: Computer Architecture Research with RISC-V

f:id:msyksphinz:20170628010131p:plain

Second Workshop on Computer Architecture Research with RISC-V (CARRV 2018) | carrv.github.io

2018年の研究者向けRISC-V Workshopのウェブサイトが公開されました。今年はISCAとの共催らしい。

CARRVはRISC-V Workshopとは違い、より研究者向けのワークショップとなっています。

RISC-Vを使ったコンピュータアーキテクチャ半導体の研究テーマなど、興味のある方は投稿してみてはどうでしょう?

関連記事

SiFiveのFreedom E300 Platformを単体でカスタマイズできるようにする (3. SRAMモジュールを作成して接続、テストパタンで動作を確認する)

RISC-Vの実装であるRocket-Chipは、RISC-Vの最新使用に追従しているため最初に見るべきデザインとしてはよくできているが、

  • Chiselで記述されており(初心者には)可読性が低い。
  • 外部のSoCプラットフォームについて情報がない

ことから、なかなかオリジナルのSoCをくみ上げるためのデザインとしてポーティングしにくい。

とはいえ、TileLinkは単なるバスのはずだし、クロックとリセットさえ突っ込めばとりあえずフェッチリクエストが上がってくるはずだ。 そのあたりを解析して、Rocket-Chipを利用したオリジナルSoCプラットフォーム構築のための情報収集を行っていこう。

f:id:msyksphinz:20180211025506p:plain
図. とりあえず実現したいRISC-V SoCブロック。まずはQSPIを取り除いて、だれでもアクセスできるTestRAMを接続したい。

関連記事

Freedmo-SoC に独自のRAMモジュールを配置する

Rocket-Chipには、P-Busに接続できるモジュールとしてはマスクROMやPLICなどが定義されている。 この中にTestRAMというモジュールがあるが、これはシミュレーション用で、論理合成はできない仕組みだ。

rocket-chip/src/main/scala/devices/tilelink$ tree
.
├── BootROM.scala
├── BusBlocker.scala
├── BusBypass.scala
├── Clint.scala
├── Error.scala
├── MaskROM.scala
├── Plic.scala
├── TestRAM.scala
└── Zero.scala
  • rocket-chip/src/main/scala/devices/tilelink/TestRAM.scala
// Do not use this for synthesis! Only for simulation.
class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4, errors: Seq[AddressSet] = Nil)(implicit p: Parameters) extends LazyModule

そこで、SimpleなRAMを作成して接続してみる。

  • rocket-chip/src/main/scala/devices/tilelink/SimpleRAM.scala
class TLSimpleRAM(c: SimpleRAMParams)(implicit p: Parameters) extends LazyModule {
  val beatBytes = c.width/8
  val node = TLManagerNode(Seq(TLManagerPortParameters(
    Seq(TLManagerParameters(
      address            = AddressSet.misaligned(c.address, c.depth*beatBytes),
      resources          = new SimpleDevice("ram", Seq("msyksphinz,simpleRAM")).reg("mem"),
...
  lazy val module = new LazyModuleImp(this) {
    val memory = Mem(1024, UInt(width = c.width))

    val (in, edge) = node.in(0)
    val mem_address = edge.addr_hi(in.a.bits.address - UInt(c.address))(log2Ceil(c.depth)-1, 0)

    val read = (in.a.bits.opcode === TLMessages.Get)
    when (in.a.fire() && !read) {
      memory(mem_address) := in.a.bits.data
      // memory(mem_address) := 0.U
    }
...

これをP-Busのマップ上に定義して、FIRRTLでVerilogファイルを生成する。 - freedom/src/main/scala/everywhere/e300artydevkit/Config.scala

// Freedom E300 Arty Dev Kit Peripherals
class E300DevKitPeripherals extends Config((site, here, up) => {
  case PeripheryGPIOKey => List(
    GPIOParams(address = 0x10012000, width = 32, includeIOF = true))
  case PeripheryPWMKey => List(
    PWMParams(address = 0x10015000, cmpWidth = 8),
    PWMParams(address = 0x10025000, cmpWidth = 16),
    PWMParams(address = 0x10035000, cmpWidth = 16))
  case PeripherySPIKey => List(
    SPIParams(csWidth = 4, rAddress = 0x10024000, sampleDelay = 3),
    SPIParams(csWidth = 1, rAddress = 0x10034000, sampleDelay = 3))
  // case PeripherySPIFlashKey => List(
  //   SPIFlashParams(
  //     fAddress = 0x20000000,
  //     rAddress = 0x10014000,
  //     sampleDelay = 3))
  case PeripheryUARTKey => List(
    UARTParams(address = 0x10013000),
    UARTParams(address = 0x10023000))
  case PeripheryI2CKey => List(
    I2CParams(address = 0x10016000))
  case PeripheryMockAONKey =>
    MockAONParams(address = 0x10000000)
  case PeripheryMaskROMKey => List(
    MaskROMParams(address = 0x10000,    name = "BootROM")
  )
  case PeripherySimpleRAMKey => List(
    SimpleRAMParams(address = 0x20000000, name = "TestRAM")
  )
})

以下のように入力して、Verilogファイルを生成する。

make -f Makefile.e300artydevkit clean && make -f Makefile.e300artydevkit verilog && make -f Makefile.e300artydevkit romgen

VerilogシミュレーションでSimpleRAMへのアクセスを確認する

次に、アセンブリコードを書いてSimpleSRAMモジュールへアクセスが入ることを確認しよう。 このCoreplex E31のメモリマップでは、Uncached / Cachedをどう使い分ければよいのかわからないが、デフォルトでは必ずMissになるはずなのでReadは上手くできるはずだ。

    .section .text.init
    .option norvc
    .globl _start
_start:
        csrr a0, mhartid

    li  a0, 0x20000000
    li  a1, 0xdeadbeef
        lw      t0, 0x00(a0)
        lw      t1, 0x04(a0)
        lw      t2, 0x08(a0)
        lw      t3, 0x0c(a0)
        lw      t4, 0x10(a0)
        lw      t5, 0x14(a0)
        lw      t6, 0x18(a0)
        lw      a1, 0x1c(a0)

        la a1, dtb
        li t0, XIP_TARGET_ADDR
        jr t0

    .section .rodata
dtb:
    .incbin DEVICE_TREE

波形を確認すると、以下のようにリクエストがSimpleSRAMに到達しているのが確認できた。

f:id:msyksphinz:20180212195639p:plain
図. SimpleSRAMのアドレスへRead Requestを発行して、データの応答が帰っている様子が確認できた。

しかし、Store命令を発行しても、SimpleSRAMモジュールにリクエストが到達しない。考えられるのは、 - キャッシュに入ったままFlushされない - そもそも発行する命令とアドレスが間違っている

だが、どちらも納得できない。DCacheにリクエストが入った後TLBへの参照が入っているようだが、その辺りでコケていないだろうか?慎重にデバッグする必要がありそうだ。

SiFiveのFreedom E300 Platformを単体でカスタマイズできるようにする (2. バスのマップと新しいモジュールの追加)

RISC-Vの実装であるRocket-Chipは、RISC-Vの最新使用に追従しているため最初に見るべきデザインとしてはよくできているが、

  • Chiselで記述されており(初心者には)可読性が低い。
  • 外部のSoCプラットフォームについて情報がない

ことから、なかなかオリジナルのSoCをくみ上げるためのデザインとしてポーティングしにくい。

とはいえ、TileLinkは単なるバスのはずだし、クロックとリセットさえ突っ込めばとりあえずフェッチリクエストが上がってくるはずだ。 そのあたりを解析して、Rocket-Chipを利用したオリジナルSoCプラットフォーム構築のための情報収集を行っていこう。

関連記事

Freedmo-SoC の「Instruction & Data Cache」の領域に向けてメモリのフェッチを発行する

前回紹介したとおり、Freedom SoC E300 Platform のメモリマップには "Instruction & Data RAM" という項目があるため、ここにメモリアクセスを発行すると外部からデータをフェッチしてキャッシュに配置してくれるのだろう、と思い、 0x8000_0000に向けてメモリ読み込み (実際には0x8000_0000に向けてプログラムをジャンプさせる)コードを書いてシミュレーションしてみたが、途中でフェッチが止まってしまいうまく動かなかった。

そこでダンプデータを使ってアクセスの行方を探っていたのだが、

  • ICache からメモリフェッチが Rocket CoreのIFに向けて発行される (0x8000_0000)
  • Rocket CoreのIFからRocketTileに向けてリクエストが発行される (0x8000_0000)
  • Peripheral-Busを通じて、RocketTileの逆方向のバスを通じてリクエストがRocket-Coreに戻ってくる。
  • DCache/ICache にリクエストが入って消えた。

というわけで、"Instruction & Data RAM"という場所にアクセスしても意味がないらしい。

f:id:msyksphinz:20180211021741p:plain
図. リクエストの解析の様子。Rocket-Coreから出てきたリクエストは、Rocket-Tileの外へ出ていき、そして戻って来て、ICache/DCacheのアクセスとなっていた

というか、Freedom E300のマニュアル的には、外部からこれらのキャッシュにアクセスするためのメモリアドレスであって、Rocket-Coreがメモリアクセスを行うためには、0x8000_0000ではなくて、普通にE31 Coreplex のメモリマップの場所を使わなければならない。

f:id:msyksphinz:20180209230017p:plain
表. Freedom E300 Platform のメモリマップ
f:id:msyksphinz:20180209230407p:plain
表. Coreplex E31 のメモリマップ

つまり、Coreplex E31のマニュアルにのっとると、システムバスとかペリフェラルバスからのアクセスを発生させるためには、0x2000_0000 もしくは 0x4000_0000 へアクセスを行わなければならない。

で、0x2000_0000にアクセスするとPeripheral-Bus なのでとりあえず外部に出るのだが、そこにはFreedom E300 PlatformではQSPIにつながっており、QSPIのプロトコルに変換されて外に出ていくわけだ。

実現したいことは、Freedom E300 Platformに適当にSRAMを接続してそこから命令とデータをフェッチできる環境を作りたい。 とりあえず、QSPIを取り除いて、そこにROMでもRAMでも接続してみたい。

f:id:msyksphinz:20180211025506p:plain
図. とりあえず実現したいRISC-V SoCブロック。まずはQSPIを取り除いて、だれでもアクセスできるTestRAMを接続したい。

Freedom E300 Platformの改造

Scalaについてはよくわからないのだが、QSPIの接続されている0x2000_0000のアドレスマップに張り付いているモジュールを取り除き、MaskROMを0x2000_0000に接続する。 なぜRAMではなくROMなのかというと、その場で接続できるRAMモジュールが見当たらなかったためだ(笑)。

diff --git a/src/main/scala/everywhere/e300artydevkit/Config.scala b/src/main/scala/everywhere/e300artydevkit/Config.scala
index a85d1e6..3dd9f90 100644
--- a/src/main/scala/everywhere/e300artydevkit/Config.scala
+++ b/src/main/scala/everywhere/e300artydevkit/Config.scala
@@ -35,11 +35,11 @@ class E300DevKitPeripherals extends Config((site, here, up) => {
   case PeripherySPIKey => List(
     SPIParams(csWidth = 4, rAddress = 0x10024000, sampleDelay = 3),
     SPIParams(csWidth = 1, rAddress = 0x10034000, sampleDelay = 3))
-  case PeripherySPIFlashKey => List(
-    SPIFlashParams(
-      fAddress = 0x20000000,
-      rAddress = 0x10014000,
-      sampleDelay = 3))
+  // case PeripherySPIFlashKey => List(
+  //   SPIFlashParams(
+  //     fAddress = 0x20000000,
+  //     rAddress = 0x10014000,
+  //     sampleDelay = 3))
   case PeripheryUARTKey => List(
     UARTParams(address = 0x10013000),
     UARTParams(address = 0x10023000))
@@ -48,7 +48,9 @@ class E300DevKitPeripherals extends Config((site, here, up) => {
   case PeripheryMockAONKey =>
     MockAONParams(address = 0x10000000)
   case PeripheryMaskROMKey => List(
-    MaskROMParams(address = 0x10000, name = "BootROM"))
+    MaskROMParams(address = 0x10000,    name = "BootROM"),
+    MaskROMParams(address = 0x20000000, name = "TestROM")
+  )
 })

 // Freedom E300 Arty Dev Kit Peripherals
diff --git a/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala b/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala
index e0b0634..ea3edb8 100644
--- a/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala
+++ b/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala
@@ -44,13 +44,13 @@ class E300ArtyDevKitFPGAChip(implicit override val p: Parameters) extends ArtySh
     // SPI flash IOBUFs
     //---------------------------------------------------------------------

-    IOBUF(qspi_sck, dut.io.pins.qspi.sck)
-    IOBUF(qspi_cs,  dut.io.pins.qspi.cs(0))
-
-    IOBUF(qspi_dq(0), dut.io.pins.qspi.dq(0))
-    IOBUF(qspi_dq(1), dut.io.pins.qspi.dq(1))
-    IOBUF(qspi_dq(2), dut.io.pins.qspi.dq(2))
-    IOBUF(qspi_dq(3), dut.io.pins.qspi.dq(3))
+    // IOBUF(qspi_sck, dut.io.pins.qspi.sck)
+    // IOBUF(qspi_cs,  dut.io.pins.qspi.cs(0))
+    //
+    // IOBUF(qspi_dq(0), dut.io.pins.qspi.dq(0))
+    // IOBUF(qspi_dq(1), dut.io.pins.qspi.dq(1))
+    // IOBUF(qspi_dq(2), dut.io.pins.qspi.dq(2))
+    // IOBUF(qspi_dq(3), dut.io.pins.qspi.dq(3))

     //---------------------------------------------------------------------
     // JTAG IOBUFs

diff --git a/src/main/scala/everywhere/e300artydevkit/Platform.scala b/src/main/scala/everywhere/e300artydevkit/Platform.scala
index be1789a..289f97e 100644
--- a/src/main/scala/everywhere/e300artydevkit/Platform.scala
+++ b/src/main/scala/everywhere/e300artydevkit/Platform.scala
@@ -39,7 +39,7 @@ class E300ArtyDevKitPlatformIO(implicit val p: Parameters) extends Bundle {
   val pins = new Bundle {
     val jtag = new JTAGPins(() => PinGen(), false)
     val gpio = new GPIOPins(() => PinGen(), p(PeripheryGPIOKey)(0))
-    val qspi = new SPIPins(() => PinGen(), p(PeripherySPIFlashKey)(0))
+    /* val qspi = new SPIPins(() => PinGen(), p(PeripherySPIFlashKey)(0)) */
     val aon = new MockAONWrapperPins()
   }
   val jtag_reset = Bool(INPUT)
@@ -159,8 +159,8 @@ class E300ArtyDevKitPlatform(implicit val p: Parameters) extends Module {
   // Result of Pin Mux
   GPIOPinsFromPort(io.pins.gpio, sys.gpio(0))

-  // Dedicated SPI Pads
-  SPIPinsFromPort(io.pins.qspi, sys.qspi(0), clock = sys.clock, reset = sys.reset, syncStages = 3)
+  // // Dedicated SPI Pads
+  // SPIPinsFromPort(io.pins.qspi, sys.qspi(0), clock = sys.clock, reset = sys.reset, syncStages = 3)

   // JTAG Debug Interface
   val sjtag = sys.debug.systemjtag.get
diff --git a/src/main/scala/everywhere/e300artydevkit/System.scala b/src/main/scala/everywhere/e300artydevkit/System.scala
index c3fbd96..8ef51e9 100644
--- a/src/main/scala/everywhere/e300artydevkit/System.scala
+++ b/src/main/scala/everywhere/e300artydevkit/System.scala
@@ -26,7 +26,7 @@ class E300ArtyDevKitSystem(implicit p: Parameters) extends RocketCoreplex
     with HasPeripheryDebug
     with HasPeripheryMockAON
     with HasPeripheryUART
-    with HasPeripherySPIFlash
+    /* with HasPeripherySPIFlash */
     with HasPeripherySPI
     with HasPeripheryGPIO
     with HasPeripheryPWM
@@ -40,7 +40,7 @@ class E300ArtyDevKitSystemModule[+L <: E300ArtyDevKitSystem](_outer: L)
     with HasPeripheryUARTModuleImp
     with HasPeripherySPIModuleImp
     with HasPeripheryGPIOModuleImp
-    with HasPeripherySPIFlashModuleImp
+    /* with HasPeripherySPIFlashModuleImp */
     with HasPeripheryMockAONModuleImp
     with HasPeripheryPWMModuleImp
     with HasPeripheryI2CModuleImp {

これで再生成を行う。

make -f Makefile.e300artydevkit clean && make -f Makefile.e300artydevkit verilog
make -f Makefile.e300artydevkit romgen

これで、MaskROMが2種類作られる。ただし、とりあえず初期値は1つしか指定できないようだ。

make -f Makefile.e300artydevkit romgen
make -C /home/msyksphinz/work/freedom/bootrom/xip romgen
make[1]: ディレクトリ '/home/msyksphinz/work/freedom/bootrom/xip' に入ります
/home/msyksphinz/work/freedom/rocket-chip/scripts/vlsi_rom_gen /home/msyksphinz/work/freedom/builds/e300artydevkit/sifive.freedom.everywhere.e300artydevkit.E300ArtyDevKitConfig.rom.conf /home/msyksphinz/work/freedom/builds/e300artydevkit/xip.hex > /home/msyksphinz/work/freedom/builds/e300artydevkit/rom.v
/home/msyksphinz/work/freedom/rocket-chip/scripts/vlsi_rom_gen:131: UserWarning: vlsi_rom_gen detected multiple ROMs. ROM contents will be duplicated.
  warnings.warn('vlsi_rom_gen detected multiple ROMs. ROM contents will be duplicated.')
...

このVerilogファイルを使って再度RTLシミュレーションを行ってみた。 まだROMの状態ではあるが、TestROMに対して正常なメモリアクセスを発行させることができたようだ。 次は、テスト用のRAMを作って、接続作業を行ってみる。

f:id:msyksphinz:20180211025016p:plain

調べ物をしたりまとめたりする場合には Vivaldi ウェブブラウザが超絶便利だと言う話

ブラウザといえば、Internet Explorer(Edge?)か、Chromeである。

しかし、Chromeはどんどん遅くなっていき不便、ほかにいろいろ無いかなと探した結果、今はVivaldiに落ち着いている。

Vivaldi Community – Free webmail, blogging platform and tech forum.

このVivaldiChromeには無いいろんな便利な機能がある。特に、ブラウザで資料を読みながらブログにまとめ上げる私のようなスタイルでは、「資料とノートを同時に表示する」という要望がある。この要望に対して、Vivaldiはピッタリなのだ。

そもそもWebパネルが便利

これはVivaldiユーザなら全員使っていると思う。ブラウザの再度の領域に別の情報を表示することができる。

これはおそらくモバイル表示モードに設定されているので、

  • Twitterのアカウントなどを表示させておき、常時表示させておく。
  • Inboxのメール一覧を常に表示させておく

などの活用方法がある。

f:id:msyksphinz:20180210184716p:plain

タブのタイリング

例えばネットで英語の資料を読んでいるとき、その資料を読みながら翻訳したり、メモを取っていく必要がある。 メモを手書きで書けばよいのだが、やはり後に残すためにMarkdownなりノートにとっておきたい。 このとき、ブラウザとノートを行ったり来たりするのはあまりにも不便だ。

また、自分はメモを共有したりどこでも読めるようにするために、Jupyter Notebookを使ってウェブ上にメモを残すようにしている。 つまり、やりたいことはJupyterのノート画面と、今読んでいる資料のページを同時に表示したいのだ。

このときに超絶便利なのがVivaldiの「タブのタイリング」という機能だ。

f:id:msyksphinz:20180210184916p:plain

2つのタブを選択して、「タブのタイリング」をクリックすると、

f:id:msyksphinz:20180210185151p:plain

2つのタブを並んで表示させることができる。

これにより、左側のタブに読みたい文章、右側のタブでJupyter Notebookを表示させてまとめを記入していく、ということが可能になる。

2枚だけのタイリングだけではない

このタイリング、2枚だけでなく、それ以上のタブもまとめてタイリングすることができる。

f:id:msyksphinz:20180210185357p:plain

このタイリングのスタイルについては、右下のページの並べ方で制御することができる。

f:id:msyksphinz:20180210185442p:plain

4枚縦にタブを並べた例。あまり便利じゃないけど。

f:id:msyksphinz:20180210185513p:plain

という訳で、まるで勉強の時のスタイル。

  • 読みたい内容
  • まとめるためのノート

を同時にタイリングして表示できる点が非常に重宝している。

それ以外にも、2つのウェブページを比較したり、いろんな活用法がある。どんどん活用していきたい。