FPGA開発日記

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

Chisel事始め(2)

Chiselのチュートリアルの続き。

github.com

chisel-tutorial/examples/BasicALU.scala を見てみよう。

package TutorialExamples

import Chisel._

class BasicALU extends Module {
  val io = new Bundle {
    val a = UInt(INPUT, 4)
    val b = UInt(INPUT, 4)
    val opcode = UInt(INPUT, 4)
    val output = UInt(OUTPUT, 4)
  }
  io.output := UInt(0) //THIS SEEMS LIKE A HACK/BUG
  when (io.opcode === UInt(0)) {
    io.output := io.a //pass A
  } .elsewhen (io.opcode === UInt(1)) {
    io.output := io.b //pass B
  } .elsewhen (io.opcode === UInt(2)) {
    io.output := io.a + UInt(1) //increment A by 1
  } .elsewhen (io.opcode === UInt(3)) {
    io.output := io.a - UInt(1) //increment B by 1
  } .elsewhen (io.opcode === UInt(4)) {
    io.output := io.a + UInt(4) //increment A by 4
  } .elsewhen (io.opcode === UInt(5)) {
    io.output := io.a - UInt(4) //decrement A by 4
  } .elsewhen (io.opcode === UInt(6)) {
    io.output := io.a + io.b //add A and B
  } .elsewhen (io.opcode === UInt(7)) {
    io.output := io.a - io.b //subtract B from A
  } .elsewhen (io.opcode === UInt(8)) {
    io.output := io.a < io.b //set on A less than B
  } .otherwise {
    io.output :=  (io.a === io.b).toUInt() //set on A equal to B
  }
}

class SimpleALU extends Module {
  val io = new Bundle {
    val a      = UInt(INPUT,  4)
    val b      = UInt(INPUT,  4)
    val opcode = UInt(INPUT,  2)
    val output = UInt(OUTPUT, 4)
  }
  io.output := UInt(0)
  when (io.opcode === UInt(0)) {
    io.output := io.a + io.b //ADD
  } .elsewhen (io.opcode === UInt(1)) {
    io.output := io.a - io.b //SUB
  } .elsewhen (io.opcode === UInt(2)) {
    io.output := io.a        //PASS A
  } .otherwise {
    io.output := io.b        //PASS B
  }
}

うーん、単純なデコーダに見えるね。全てif + elseifのように見えるけど、どのようなハードウェアが生成されるのかな?

make BasicALU.v

あれ、BasicALU.vが生成されずにSimpleALU.vが生成された。何でだろう。

module SimpleALU(
    input [3:0] io_a,
    input [3:0] io_b,
    input [1:0] io_opcode,
    output[3:0] io_output
);

  wire[3:0] T0;
  wire[3:0] T1;
  wire[3:0] T2;
  wire[3:0] T3;
  wire[3:0] T4;
  wire T5;
  wire[3:0] T6;
  wire T7;
  wire T8;
  wire T9;
  wire T10;
  wire T11;
  wire T12;
  wire T13;
  wire T14;
  wire T15;


  assign io_output = T0;
  assign T0 = T14 ? io_b : T1;
  assign T1 = T10 ? io_a : T2;
  assign T2 = T7 ? T6 : T3;
  assign T3 = T5 ? T4 : 4'h0;
  assign T4 = io_a + io_b;
  assign T5 = io_opcode == 2'h0;
  assign T6 = io_a - io_b;
  assign T7 = T9 & T8;
  assign T8 = io_opcode == 2'h1;
  assign T9 = T5 ^ 1'h1;
  assign T10 = T12 & T11;
  assign T11 = io_opcode == 2'h2;
  assign T12 = T13 ^ 1'h1;
  assign T13 = T5 | T8;
  assign T14 = T15 ^ 1'h1;
  assign T15 = T13 | T11;
endmodule

うわ、読み辛い....

次はRouter.scalaだ。

class ReadCmd extends Bundle {
  val addr = UInt(width = 32);
}

class WriteCmd extends ReadCmd {
  val data = UInt(width = 32)
}

class Packet extends Bundle {
  val header = UInt(width = 8)
  val body   = Bits(width = 64)
}

class RouterIO(n: Int) extends Bundle {
  override def clone = new RouterIO(n).asInstanceOf[this.type]
  val reads   = new DeqIO(new ReadCmd())
  val replies = new EnqIO(UInt(width = 8))
  val writes  = new DeqIO(new WriteCmd())
  val in      = new DeqIO(new Packet())
  val outs    = Vec.fill(n){ new EnqIO(new Packet()) }
}

class Router extends Module {
  val depth = 32
  val n     = 4
  val io    = new RouterIO(n)
  val tbl   = Mem(UInt(width = sizeof(n)), depth)
  when(io.reads.valid && io.replies.ready) {
    val cmd = io.reads.deq();  io.replies.enq(tbl(cmd.addr))
  } .elsewhen(io.writes.valid) {
    val cmd = io.writes.deq(); tbl(cmd.addr) := cmd.data
  } .elsewhen(io.in.valid) {
    val pkt = io.in.bits
    val idx = tbl(pkt.header(0))
    when (io.outs(idx).ready) {
      io.in.deq(); io.outs(idx).enq(pkt)
    }
  }
}

生成されたRouter.vは、

module Router(input clk,
    output io_reads_ready,
    input  io_reads_valid,
    input [31:0] io_reads_bits_addr,
    input  io_replies_ready,
    output io_replies_valid,
    output[7:0] io_replies_bits,
    output io_writes_ready,
    input  io_writes_valid,
    input [31:0] io_writes_bits_addr,
    input [31:0] io_writes_bits_data,
    output io_in_ready,
    input  io_in_valid,
    input [7:0] io_in_bits_header,
    input [63:0] io_in_bits_body,
    input  io_outs_3_ready,
    output io_outs_3_valid,
    output[7:0] io_outs_3_bits_header,
    output[63:0] io_outs_3_bits_body,
    input  io_outs_2_ready,
    output io_outs_2_valid,
    output[7:0] io_outs_2_bits_header,
    output[63:0] io_outs_2_bits_body,
    input  io_outs_1_ready,
    output io_outs_1_valid,
    output[7:0] io_outs_1_bits_header,
    output[63:0] io_outs_1_bits_body,
    input  io_outs_0_ready,
    output io_outs_0_valid,
    output[7:0] io_outs_0_bits_header,
    output[63:0] io_outs_0_bits_body
);

  wire[63:0] T0;
  wire T1;
  wire T2;
  wire[3:0] T3;
  wire[1:0] T4;
  wire[1:0] T44;
  wire[2:0] T5;
  reg [2:0] tbl [31:0];
  wire[2:0] T6;
  wire[2:0] T45;
  wire T7;
  wire T8;
  wire T9;
  wire[4:0] T46;
  wire[4:0] T47;
  wire T10;
  wire T11;
  wire T12;
  wire T13;
  wire T14;
  wire T15;
  wire T16;
  wire T17;
  wire T18;
  wire T19;
...

うぎゃ、こりゃデバッグは出来無いな...