초장부터 좀 빡세보였다.
val io = IO(new Bundle {
val in = DeqIO(new RealGCDInput())
val out = Output(Valid(UInt(16.W)))
})
도대체 이게 뭐야;
유클리드 호제법은 나눗셈으로도 구현할 수 있고,
뺄셈으로도 구현할 수 있다.(속도는 나눗셈이 훨씬 빠르다)
모듈러 연산시 문제가 발생할 수 있으니, 우선 뺄셈으로 하자.
원리는 대동소이하다.
int gcd(int a, int b){
int t;
while(a!=0){
if(b > a){
`swap(a,b)
}
a = a-b;
}
return b;
}
// See LICENSE.txt for license details.
package problems
import chisel3.iotesters.PeekPokeTester
class RealGCDTests(c: RealGCD) extends PeekPokeTester(c) {
val inputs = List( (48, 32), (7, 3), (100, 10) )
val outputs = List( 16, 1, 10)
var i = 0
do {
var transfer = false
do {
poke(c.io.in.bits.a, inputs(i)._1)
poke(c.io.in.bits.b, inputs(i)._2)
poke(c.io.in.valid, 1)
transfer = peek(c.io.in.ready) == BigInt(1)
step(1)
} while (t < 100 && !transfer)
do {
poke(c.io.in.valid, 0)
step(1)
} while (t < 100 && (peek(c.io.out.valid) == BigInt(0)))
expect(c.io.out.bits, outputs(i))
i += 1
} while (t < 100 && i < 3)
if (t >= 100) fail
}
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util.{Valid, DeqIO}
// Problem:
// Implement a GCD circuit (the greatest common divisor of two numbers).
// Input numbers are bundled as 'RealGCDInput' and communicated using the Decoupled handshake protocol
//
class RealGCDInput extends Bundle {
val a = UInt(16.W)
val b = UInt(16.W)
}
class RealGCD extends Module {
val io = IO(new Bundle {
val in = DeqIO(new RealGCDInput())
val out = Output(Valid(UInt(16.W)))
})
// Implement below ----------
def EuclidGCD(a:Int, b:Int):Int = {
if(b == 0) {
return a
}
else {
return EuclidGCD(b, a%b)
}
}
val aa = io.in.bits.a
val bb = io.in.bits.b
io.out := EuclidGCD(aa, bb).asUInt
// Implement above ----------
}
엄...
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util.{Valid, DeqIO}
// Problem:
// Implement a GCD circuit (the greatest common divisor of two numbers).
// Input numbers are bundled as 'RealGCDInput' and communicated using the Decoupled handshake protocol
//
class RealGCDInput extends Bundle {
val a = UInt(16.W)
val b = UInt(16.W)
}
class RealGCD extends Module {
val io = IO(new Bundle {
val in = DeqIO(new RealGCDInput())
val out = Output(Valid(UInt(16.W)))
})
// Implement below ----------
val a_reg = RegInit(0.U(16.W))
val b_reg = RegInit(0.U(16.W))
io.in.ready := true.B
when (io.in.valid){
a_reg := io.in.bits.a
b_reg := io.in.bits.b
} .elsewhen(a_reg === 0.U){ // return
a_reg := a_reg
b_reg := b_reg
}.elsewhen(a_reg < b_reg) {
a_reg := b_reg - a_reg
b_reg := a_reg
} .otherwise{
a_reg := a_reg - b_reg
b_reg := b_reg
}
io.out.bits := a_reg
when(a_reg === 0.U){
io.out.valid := true.B
}.otherwise{
io.out.valid := false.B
}
// Implement above ----------
}
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util.{Valid, DeqIO}
// Problem:
// Implement a GCD circuit (the greatest common divisor of two numbers).
// Input numbers are bundled as 'RealGCDInput' and communicated using the Decoupled handshake protocol
//
class RealGCDInput extends Bundle {
val a = UInt(16.W)
val b = UInt(16.W)
}
class RealGCD extends Module {
val io = IO(new Bundle {
val in = DeqIO(new RealGCDInput())
val out = Output(Valid(UInt(16.W)))
})
// Implement below ----------
val a_reg = RegInit(0.U(16.W))
val b_reg = RegInit(0.U(16.W))
io.in.ready := true.B
when (io.in.valid){
a_reg := io.in.bits.a
b_reg := io.in.bits.b
} .elsewhen(a_reg === 0.U){ // return
a_reg := a_reg
b_reg := b_reg
}.elsewhen(a_reg < b_reg) {
a_reg := b_reg - a_reg
b_reg := a_reg
} .otherwise{
a_reg := a_reg - b_reg
b_reg := b_reg
}
io.out.bits := b_reg
when(a_reg === 0.U){
io.out.valid := true.B
}.otherwise{
io.out.valid := false.B
}
// Implement above ----------
}
좀 더 깔끔하다.
다만, Verilog를 짜던 사람 입장에서, 하나의 val을 두 개의 when 문에서 write 접근한다는 점이 영-불편하긴 하다.
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util.{Valid, DeqIO}
// Problem:
// Implement a GCD circuit (the greatest common divisor of two numbers).
// Input numbers are bundled as 'RealGCDInput' and communicated using the Decoupled handshake protocol
//
class RealGCDInput extends Bundle {
val a = UInt(16.W)
val b = UInt(16.W)
}
class RealGCD extends Module {
val io = IO(new Bundle {
val in = DeqIO(new RealGCDInput())
val out = Output(Valid(UInt(16.W)))
})
// Implement below ----------
val a_reg = RegInit(0.U(16.W))
val b_reg = RegInit(0.U(16.W))
// val a_reg = Reg(UInt())
// val b_reg = Reg(UInt())
val working_reg = RegInit(false.B)
io.in.ready := !working_reg
when (io.in.valid && !working_reg){
a_reg := io.in.bits.a
b_reg := io.in.bits.b
working_reg := true.B
}
when(working_reg){
when(a_reg > b_reg) {
a_reg := b_reg
b_reg := a_reg
} .otherwise{
b_reg := b_reg - a_reg
}
}
io.out.bits := a_reg
io.out.valid := b_reg === 0.U && working_reg
when(io.out.valid){
working_reg := false.B
}
// Implement above ----------
}
io.in.ready := !p
when (io.in.valid && !p) {
x := io.in.bits.a
y := io.in.bits.b
p := true.B
}
when (p) {
when (x > y) { x := y; y := x }
.otherwise { y := y - x }
}
.elsewhen(a_reg === 0.U){ // return
a_reg := a_reg
b_reg := b_reg
}
하면 .v에서 그렇게 된다.
val a_reg = RegInit(0.U(16.W))
val a_reg = Reg(UInt())
중 아무거나 선택해도 무방하다.
다만, 후자를 선택했을 때, BitWidth는 어떻게 설정되는지는 의문이 든다.
실제로는 둘 다 [15:0]의 width로 elaborate된다.
아, 차이가 있다!!!
보다시피, a_reg 레지스터가 reset 변수의 영향을 받지 않도록 elaborate 된 것을 알 수 있다.
보다시피, Synchronous Reset의 영향을 받아 초기화되게 elab되었음을 확인할 수 있다.