RiscV / / 2022. 4. 15. 10:46

Chisel Modules trial

*참고 

Tilelink의 경우 valid = true후 ready가 오지 않더라도 valid를 false로 바꾸고 끝낼 수 있도록 설계되어있다. 이 때문에 아래 나오게될 "Decoupled" 를 기반으로 한 readyValid IO를 사용한다. 

 

AXI protocol의 경우 valid = true후 ready가 올때까지 대기해야만한다. 따라서 valid = false가 되지 않도록 해야하므로 

"Irrevocable"를 기반으로 한 readyValid IO를 사용한다. 

 

 

 

Valid

- valid

- bits

 

 

Decoupled

- valid

- bits

- ready

- fire - Bool that is true if and only if ready & valid

- enq(data) - Sends data and sets valid to true (doesn't check ready)

- noenq - Sets valid to false

- deq/nodeq - Like enq/noenq for receiver

Decoupled 선언시 아래와 같이 ready/valid/bits 3개가 port 선언됨

 

 

 

<> : biconnection 에 대한 동작

 

 

Flipped : input output의 상태를 바꿔줌

위와 같이 연결한다면

특정 대상에 대한 in/output 상태를 flipped로 감싸면 정확히 반대가 된 상태이므로 <>를 사용하여 위와 같이 쉽게 연결할 수 있음

 

위와 같이 연결하면,

 

 

 

위와 같이 한번에 연결 가능함

 

 

Like Wire Assign : Manual Assign wire of bit Width

 

class Reducer(n: Int, m: Int) extends Module {
  class BundleIO extends Bundle{
    val in: Vec[UInt] = Input(Vec(n, UInt(m.W)))
    val out: UInt = Output(UInt((m + 1).W))
  }

  val io: BundleIO = IO(new BundleIO())
  require(n > 0)
//  val totalSoFar = Seq.fill(n - 1)(Wire(UInt((m + 1).W)))
//  var totalSoFar: UInt = io.in(0)
//  totalSoFar.pad(5)
  var totalSoFar2: UInt = Wire(UInt(3.W))
  totalSoFar2 := io.in(0)
//  totalSoFar2.pad(5)

  for (i <- 1 until n)
    totalSoFar2 = io.in(i) + totalSoFar2
  io.out := totalSoFar2
}

 

 

Decoupled 선언시,

val decup = Decoupled(UInt())

 output인 bits, valid를 반드시 정의해주어야한다

ready는 선택사항

 

Flipped(Decoupled)면 ready를 반드시 지정해주어야함

 

가능예제

 

Decoupled

val io = IO(new Bundle {
  val decup = Decoupled(UInt())
})
 io.decup.bits := 5.U
 io.decup.valid := true.B

Flipped(Decoupled)

val io = IO(new Bundle {
  val decup = Flipped(Decoupled(UInt(5.W)))
})
 io.decup.ready := true.B

 

Vec 를 IO로 썼을때, 예제1,

Vec는 IO의 for문 같은 존재임

class ArbiterTest(n: Int, m: Int) extends Module {
  val io = IO(new Bundle {
    val req = Flipped(Vec(5, Decoupled(UInt(10.W))))
  })

  io.req(0).ready := true.B
  io.req(1).ready := true.B
  io.req(2).ready := true.B
  io.req(3).ready := true.B
  io.req(4).ready := true.B

//  val arb = Module(new Arbiter(UInt(n.W), 10))

}
module ArbiterTest(
  input        clock,
  input        reset,
  output       io_req_0_ready,
  input        io_req_0_valid,
  input  [9:0] io_req_0_bits,
  output       io_req_1_ready,
  input        io_req_1_valid,
  input  [9:0] io_req_1_bits,
  output       io_req_2_ready,
  input        io_req_2_valid,
  input  [9:0] io_req_2_bits,
  output       io_req_3_ready,
  input        io_req_3_valid,
  input  [9:0] io_req_3_bits,
  output       io_req_4_ready,
  input        io_req_4_valid,
  input  [9:0] io_req_4_bits
);
  assign io_req_0_ready = 1'h1; // @[ArbiterTest.scala 16:19]
  assign io_req_1_ready = 1'h1; // @[ArbiterTest.scala 17:19]
  assign io_req_2_ready = 1'h1; // @[ArbiterTest.scala 18:19]
  assign io_req_3_ready = 1'h1; // @[ArbiterTest.scala 19:19]
  assign io_req_4_ready = 1'h1; // @[ArbiterTest.scala 20:19]
endmodule

Vec 를 IO로 썼을때, 예제2

class ArbiterTest(n: Int, m: Int) extends Module {
  val io = IO(new Bundle {
    val req = Vec(5, Decoupled(UInt(10.W)))
  })

  io.req(0).bits := 10.U
  io.req(1).bits := 10.U
  io.req(2).bits := 10.U
  io.req(3).bits := 10.U
  io.req(4).bits := 10.U

  io.req(0).valid := true.B
  io.req(1).valid := true.B
  io.req(2).valid := true.B
  io.req(3).valid := true.B
  io.req(4).valid := true.B

}
module ArbiterTest(
  input        clock,
  input        reset,
  input        io_req_0_ready,
  output       io_req_0_valid,
  output [9:0] io_req_0_bits,
  input        io_req_1_ready,
  output       io_req_1_valid,
  output [9:0] io_req_1_bits,
  input        io_req_2_ready,
  output       io_req_2_valid,
  output [9:0] io_req_2_bits,
  input        io_req_3_ready,
  output       io_req_3_valid,
  output [9:0] io_req_3_bits,
  input        io_req_4_ready,
  output       io_req_4_valid,
  output [9:0] io_req_4_bits
);
  assign io_req_0_valid = 1'h1; // @[ArbiterTest.scala 19:19]
  assign io_req_0_bits = 10'ha; // @[ArbiterTest.scala 13:18]
  assign io_req_1_valid = 1'h1; // @[ArbiterTest.scala 20:19]
  assign io_req_1_bits = 10'ha; // @[ArbiterTest.scala 14:18]
  assign io_req_2_valid = 1'h1; // @[ArbiterTest.scala 21:19]
  assign io_req_2_bits = 10'ha; // @[ArbiterTest.scala 15:18]
  assign io_req_3_valid = 1'h1; // @[ArbiterTest.scala 22:19]
  assign io_req_3_bits = 10'ha; // @[ArbiterTest.scala 16:18]
  assign io_req_4_valid = 1'h1; // @[ArbiterTest.scala 23:19]
  assign io_req_4_bits = 10'ha; // @[ArbiterTest.scala 17:18]
endmodule

 

<> biconnect 연결 예제 1

class InnerModule extends Module(){
  val io = IO(new Bundle {
    val intermediateDecoupled = Flipped(Decoupled(UInt(5.W)))
    val intermediateDecoupledOut = Decoupled(UInt())
  })
  io.intermediateDecoupled.ready := true.B
  io.intermediateDecoupledOut.valid := io.intermediateDecoupled.ready
  io.intermediateDecoupledOut.bits := io.intermediateDecoupled.bits
}

class ArbiterTest(n: Int, m: Int) extends Module {
  val io = IO(new Bundle {
    val in = Flipped(Decoupled(UInt(n.W)))
    val out = Decoupled(UInt(n.W))
  })

  val innerModuler = Module(new InnerModule)
  innerModuler.io.intermediateDecoupled <> io.in
  io.out <> innerModuler.io.intermediateDecoupledOut

}

 

Flipped는 Flipped와 <> 되고 

unFlipped 는 unFlipped와 <> 됨

 

 

 

<> biconnect 연결 예제 2

 

class InnerModule extends Module(){
  val io = IO(new Bundle {
    val in11 = Input(UInt(5.W))
    val out11 = Output(UInt(5.W))
    val out12 = Output(UInt(5.W))
  })

  val w = Wire(UInt(5.W))
  io.in11 <> io.out11
  w <> io.in11
  io.out12 <> (w +& 10.U)
}

class ArbiterTest(n: Int, m: Int) extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(n.W))
    val enable = Input(Bool())
    val out = Output(UInt(n.W))
    val out2 = Output(UInt(n.W))
    val out3 = Flipped(Decoupled(UInt(m.W)))
    val vecin = Input(Vec(6, UInt(5.W)))
    val vecout = Flipped(Input(Vec(6, UInt(5.W))))
  })

  private val inner = Module(new InnerModule())

  inner.io.in11 <> io.in
  io.out <> inner.io.out11
  io.out2 <> inner.io.out12
  io.out3.ready <> io.enable

  val mediator = Wire(Vec(6, UInt(5.W)))
  mediator <> io.vecin
  io.vecout <> mediator

}


object ArbiterTest extends App{
  (new ChiselStage).emitVerilog(new ArbiterTest(8,15))
  //(new ChiselStage).emitVerilog(f.asInstanceOf[RawModule])
  val targetDir = "test_run_dir/gcd"
  (new ElkStage).execute(
    Array("-td", targetDir),
    Seq(ChiselGeneratorAnnotation(() => new ArbiterTest(8,15)))
  )
}

<>로 input과 output을 연결할 수 있고, input/input도 연결할 수 있고, output/output도 연결할 수 있고 wire/input, wire/output도 가능하다.

module InnerModule(
  input  [4:0] io_in11,
  output [4:0] io_out11,
  output [4:0] io_out12
);
  wire [5:0] _io_out12_T = io_in11 + 5'ha; // @[ArbiterTest.scala 21:18]
  assign io_out11 = io_in11; // @[ArbiterTest.scala 19:11]
  assign io_out12 = _io_out12_T[4:0]; // @[ArbiterTest.scala 21:12]
endmodule
module ArbiterTest(
  input         clock,
  input         reset,
  input  [7:0]  io_in,
  input         io_enable,
  output [7:0]  io_out,
  output [7:0]  io_out2,
  output        io_out3_ready,
  input         io_out3_valid,
  input  [14:0] io_out3_bits,
  input  [4:0]  io_vecin_0,
  input  [4:0]  io_vecin_1,
  input  [4:0]  io_vecin_2,
  input  [4:0]  io_vecin_3,
  input  [4:0]  io_vecin_4,
  input  [4:0]  io_vecin_5,
  output [4:0]  io_vecout_0,
  output [4:0]  io_vecout_1,
  output [4:0]  io_vecout_2,
  output [4:0]  io_vecout_3,
  output [4:0]  io_vecout_4,
  output [4:0]  io_vecout_5
);
  wire [4:0] inner_io_in11; // @[ArbiterTest.scala 35:29]
  wire [4:0] inner_io_out11; // @[ArbiterTest.scala 35:29]
  wire [4:0] inner_io_out12; // @[ArbiterTest.scala 35:29]
  InnerModule inner ( // @[ArbiterTest.scala 35:29]
    .io_in11(inner_io_in11),
    .io_out11(inner_io_out11),
    .io_out12(inner_io_out12)
  );
  assign io_out = {{3'd0}, inner_io_out11}; // @[ArbiterTest.scala 38:10]
  assign io_out2 = {{3'd0}, inner_io_out12}; // @[ArbiterTest.scala 39:11]
  assign io_out3_ready = io_enable; // @[ArbiterTest.scala 40:17]
  assign io_vecout_0 = io_vecin_0; // @[ArbiterTest.scala 42:22 43:12]
  assign io_vecout_1 = io_vecin_1; // @[ArbiterTest.scala 42:22 43:12]
  assign io_vecout_2 = io_vecin_2; // @[ArbiterTest.scala 42:22 43:12]
  assign io_vecout_3 = io_vecin_3; // @[ArbiterTest.scala 42:22 43:12]
  assign io_vecout_4 = io_vecin_4; // @[ArbiterTest.scala 42:22 43:12]
  assign io_vecout_5 = io_vecin_5; // @[ArbiterTest.scala 42:22 43:12]
  assign inner_io_in11 = io_in[4:0]; // @[ArbiterTest.scala 37:17]
endmodule

 

Flipped, <> Wiring, Reg 응용 예제

 


class InnerModule extends Module(){
  val io = IO(new Bundle {
    val in11 = Input(UInt(5.W))
    val out11 = Output(UInt(5.W))
    val out12 = Output(UInt(5.W))
  })

  val w = Wire(UInt(5.W))
  io.in11 <> io.out11
  w <> io.in11
  io.out12 <> (w +& 10.U)
}

class ArbiterTest(n: Int, m: Int) extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(n.W))
    val enable = Input(Bool())
    val out = Output(UInt(n.W))
    val out2 = Output(UInt(n.W))
    val out3 = Flipped(Decoupled(UInt(m.W)))
    val vecin = Input(Vec(6, UInt(5.W)))
    val vecout = Flipped(Input(Vec(6, UInt(5.W))))
//    val req = Flipped(Vec(n, Decoupled(UInt(n.W))))
  })

  private val inner = Module(new InnerModule())

  inner.io.in11 <> io.in
  io.out <> inner.io.out11
  io.out2 <> inner.io.out12
  io.out3.ready <> io.enable

  val mediator = Wire(Vec(6, UInt(5.W)))
  mediator <> io.vecin
//  io.vecout <> mediator

  val regs = Mem(6, UInt(64.W))

//  regs <> mediator
  for (p <- 0 until 6) {
     regs(p) := mediator(p)
  }

  for (p <- 0 until 6) {
    when(regs(p) > 5.U){
      io.vecout(p) := regs(p)
    }.otherwise{
      if(p != 0)
      {
        io.vecout(p) := regs(p-1)
      }
      else{
        io.vecout(p) := regs(p)
      }
    }
  }
}

 

generating된 모델 일부

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유