ChiselはScalaをベースにしたハードウェア記述言語で、より高位な記法を使ってハードウェアを設計しようという考え方を持っている。
しかし、どうしてもVerilogを使いたい場合、あるいはある部品は既存のVerilogで記述されたものを使いたいと思うときがある。例えば、Chiselを使えばメモリも記述することができるが、実際にはSRAMに置き換えたい場合であったり、FPGAで推論しやすくするためにVerilogで書いたモジュールに置き換えたい場合がある。このような場合に、どのようにChiselを記述するのかについて調査した。
ChiselにVerilogを埋め込むための方法は2つ存在する。

どちらの方法を使うかは、その状況下で使い分ければいいと思う。例えば、今回は以下のようなメモリモジュールをVerilogで置き換えるためにはどのようにしたらよいのか考えた。
class Memory [Conf <: RVConfig](conf: Conf)extends Module {val io =new MemoryIo(conf)...
Memoryモジュールを置き換えるために、内部にインラインでVerilogを記述するためにはBlackBoxモジュールを継承し、HasBlackBoxInlineトレイトを追加する。
class MemoryBlackBox [Conf <: RVConfig](conf: Conf)extends BlackBoxwith HasBlackBoxInline {val io = IO(new Bundle {val clock = Input(Clock())val mem =new MemoryIo(conf) })
ここで、I/Oにクロックを追加している。理由は、このブラックボックスのモジュールは明示的にクロックとリセットを追加しないと自動的に挿入されないためだ。つまり、明示的にポートを追加しないと内部でクロックを使用できない。
BlackBoxes · freechipsproject/chisel3 Wiki · GitHub
Unlike Module,BlackBox has no implicit clock and reset.Ports declared in the IO Bundle will be generated with the requested name (ie. no preceding io_).
そして、内部にVerilogコードをそのまま埋め込んでいく。これにはsetInlineを使用する。
setInline("MemoryBlackBox.v", s"""|module MemoryBlackBox| (| input logic clock,| input logic mem_inst_bus_req,...||endmodule // MemoryBlackBox """.stripMargin)}
これで完了だ。クロックポートを追加したので、メモリのインタフェースはmemという変数でラップされてしまった。オリジナル(Chiselで記述した)Memoryモジュールとのポート互換性を合わせたければ、Memoryモジュール側も同じようにI/Oポートをラップさせるのが良いと思う。
class Memory [Conf <: RVConfig](conf: Conf)extends Module {val io = IO(new Bundle {val mem =new MemoryIo(conf) })
これでVerilogを生成すると、CpuTop.vというCPU本体のモジュールと、MemoryBlackBox.vという別にファイルが生成される。さらに、ブラックボックスのファイル一覧を示すblack_box_verilog_files.fというファイルも生成される。
ls-ltMemoryBlackBox.vblack_box_verilog_files.fCpuTop.v
module MemoryBlackBox(input logic clock,input logic mem_inst_bus_req,input logic[15:0] mem_inst_bus_addr,output logic mem_inst_bus_ack,output logic[31:0] mem_inst_bus_rddata,input logic mem_data_bus_req,input logic[1:0] mem_data_bus_cmd,input logic[15:0] mem_data_bus_addr,...
こちらの方がリソースを再利用する方法としては優れていると思う。
インラインする方法とは異なるトレイト(HasBlackBoxResource)を使用する。Verilogファイルは、setResourceで場所を指定する。こちらもクロックは明示的に追加しないとポートとして現れないので、IOバンドルとしてラップする。
このsetResourceで指定されるVerilogファイルは、プロジェクトのルートディレクトリからsrc/{main,test}/resources/に配置されている必要がある。今回は、src/main/resources/memory_real.vにVerilogファイルを配置した。
class MemoryResourceBox [Conf <: RVConfig](conf: Conf)extends BlackBoxwith HasBlackBoxResource {val io = IO(new Bundle {val clock = Input(Clock())val mem =new MemoryIo(conf) }) setResource ("/memory_real.v")}
module MemoryResourceBox ( input logic clock, input logic mem_inst_bus_req, input logic [15:0] mem_inst_bus_addr,...
同様にVerilogファイルを生成すると、CpuTop.vというCPU本体のモジュールと一緒に、プロジェクトのルートディレクトリにもmemory_real.vが生成され、さらにブラックボックスのファイルリストを含んでいるblack_box_verilog_files.fも生成された。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。