複数のConfigを組み合わせる
前回のパラメータは、いくつかのコンフィグレーションを組み合わせて新しいコンフィグレーションを作り上げることができる。例えば以下の2つのConfig
を組み合わせて新しいConfig
を作り上げることができる。
class Bus32BitConfig extends Config((site, here, up) => { case BusWidthBytes => 32 / 8 }) class IfuConnectConfig extends Config((site, here, up) => { case ConnectIfu => true })
class Default1Config extends Config( new Bus32BitConfig ++ new IfuConnectConfig )
新たに作成したConnectIfu
を使って、モジュールをインスタンスするかどうかを指定することができる。パラメータを取得するためにはp()
を使用する。
val xbar = LazyModule(new TLXbar) val memory = LazyModule(new TLRAM(AddressSet(0x02000, p(AddrSize)-1), beatBytes = p(BusWidthBytes))) xbar.node := pusher1.node if (p(ConnectIfu)) { val ifu = LazyModule(new ifu("ifu")) xbar.node := ifu.node } memory.node := xbar.node
この新しく作ったDefault1Config
を使用してパラメータを設定できる。
object Generator { final def main(args: Array[String]) { val p = (new Default1Config).toInstance val verilog = Driver.emitVerilog( new TestHarness()(p) ) } }
here()
, site()
, up()
などの使い方
Config
で使用しているパラメータを計算するにあたり、さらに別のパラメータの値を使用したい場合どうするか。Verilogでいう以下のようなことを実現したい。
localparam param1 = 100; localparam param2 = param1 * 100;
これをChiselで実現しようしようとすると以下のようになるだろう。BusWidthBytes
パラメータを使用してアドレスサイズの計算をしているが、実はこれはコンパイルできない。
class Bus128BitConfig extends Config((site, here, up) => { case BusWidthBytes => 128 / 8 case AddrSize => 0x100 * BusWidthBytes }) class Bus64BitConfig extends Config((site, here, up) => { case BusWidthBytes => 64 / 8 case AddrSize => 0x200 * BusWidthBytes })
[error] /home/msyksphinz/work/riscv/chisel-development/minimal-diplomacy/src/main/scala/core_complex/Configs.scala:11:26: overloaded method value * with alternatives: [error] (x: Double)Double <and> [error] (x: Float)Float <and> [error] (x: Long)Long <and> [error] (x: Int)Int <and> [error] (x: Char)Int <and> [error] (x: Short)Int <and> [error] (x: Byte)Int [error] cannot be applied to (core_complex.BusWidthBytes.type) [error] case AddrSize => 0x100 * BusWidthBytes [error] ^
ようするにBusWidthBytes
自体がcase classなので、値として直接使用することができないのだ。そこで、同じConfig
内の値を参照するためのhere()
を利用する。
class Bus128BitConfig extends Config((site, here, up) => { case BusWidthBytes => 128 / 8 case AddrSize => 0x100 * here(BusWidthBytes) }) class Bus64BitConfig extends Config((site, here, up) => { case BusWidthBytes => 64 / 8 case AddrSize => 0x200 * here(BusWidthBytes) })
// Bus128BitConfigで構成したTLRAM, 12ビットのバス幅で構成される module TLRAM( input clock, input reset, input auto_in_a_valid, input [2:0] auto_in_a_bits_opcode, input [11:0] auto_in_a_bits_address, input [31:0] auto_in_a_bits_data, output auto_in_d_valid, output [2:0] auto_in_d_bits_opcode, output [31:0] auto_in_d_bits_data );
一方で、site()
を使用するとより上位のConfigを使用するようになる。例えばDefault2Config
では以下のように構成している。Bus128BitConfig
でsite()
を使用するとBaseConfig
を参照する。つまりAddrSize
は0x100 * (256/8)
になるはずだ。
class Default2Config extends Config( new BaseConfig ++ new Bus128BitConfig ++ new IfuNotConnectConfig )
class BaseConfig extends Config((site, here, up) => { case BusWidthBytes => 256 / 8 }) class Bus128BitConfig extends Config((site, here, up) => { case BusWidthBytes => 128 / 8 case AddrSize => 0x100 * here(BusWidthBytes) })
// BaseConfigで構成したTLRAM, 13ビットのバス幅で構成される module TLRAM( input clock, input reset, input auto_in_a_valid, input [2:0] auto_in_a_bits_opcode, input [12:0] auto_in_a_bits_address, input [255:0] auto_in_a_bits_data, output auto_in_d_valid, output [2:0] auto_in_d_bits_opcode, output [255:0] auto_in_d_bits_data );