Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tapasco
tapasco
Commits
52108c3e
Commit
52108c3e
authored
Aug 27, 2016
by
Jens Korinth
Browse files
Merge commit '9a26aa5c3479f3bc887be835aa73a078d7584fac' as 'miscutils'
parents
b3c0eff4
e23188d9
Changes
9
Hide whitespace changes
Inline
Side-by-side
miscutils/.gitignore
0 → 100644
View file @
52108c3e
*.log
*.jou
.Xil
/target/
/project/
/test/
/ip/
miscutils/build.sbt
0 → 100644
View file @
52108c3e
scalaVersion
:=
"2.11.7"
libraryDependencies
+=
"edu.berkeley.cs"
%%
"chisel"
%
"latest.release"
libraryDependencies
+=
"com.novocode"
%
"junit-interface"
%
"0.11"
%
"test"
libraryDependencies
+=
"org.scalatest"
%%
"scalatest"
%
"2.2.6"
%
"test"
libraryDependencies
+=
"com.typesafe.play"
%%
"play-json"
%
"2.5.4"
parallelExecution
in
Test
:=
false
testForkedParallel
in
Test
:=
false
miscutils/src/main/scala/DataWidthConverter.scala
0 → 100644
View file @
52108c3e
package
chisel.miscutils
import
Chisel._
/**
* DataWidthConverter converts the data width of a Queue.
* Output is provided via a Queue, with increased or decreased
* data rate, depending on the direction of the conversion.
* Note: This would be much more useful, if the two Queues
* could use different clocks, but multi-clock support
* in Chisel is currently unstable.
* @param inWidth Data width of input Decoupled (bits).
* @param outWidth Data width of output Decoupled (bits); must
* be integer multiples of each other.
* @param littleEndian if inWidth > outWidth, determines
* the order of the nibbles (low to high)
**/
class
DataWidthConverter
(
val
inWidth
:
Int
,
val
outWidth
:
Int
,
val
littleEndian
:
Boolean
=
true
)
extends
Module
{
require
(
inWidth
>
0
,
"inWidth must be > 0"
)
require
(
outWidth
>
0
,
"inWidth must be > 0"
)
require
(
inWidth
!=
outWidth
,
"inWidth (%d) must be different from outWidth (%d)"
.
format
(
inWidth
,
outWidth
))
require
(
inWidth
%
outWidth
==
0
||
outWidth
%
inWidth
==
0
,
"inWidth (%d) and outWidth (%d) must be integer multiples of each other"
.
format
(
inWidth
,
outWidth
))
val
io
=
new
Bundle
{
val
inq
=
Decoupled
(
UInt
(
width
=
inWidth
)).
flip
()
val
deq
=
Decoupled
(
UInt
(
width
=
outWidth
))
}
val
ratio
:
Int
=
if
(
inWidth
>
outWidth
)
inWidth
/
outWidth
else
outWidth
/
inWidth
val
d_w
=
if
(
inWidth
>
outWidth
)
inWidth
else
outWidth
// data register width
if
(
inWidth
>
outWidth
)
downsize
()
else
upsize
()
private
def
upsize
()
=
{
val
i
=
Reg
(
UInt
(
width
=
log2Up
(
ratio
+
1
)))
val
d
=
Reg
(
UInt
(
width
=
outWidth
))
io
.
inq
.
ready
:=
!
reset
&&
(
i
=/=
UInt
(
0
)
||
(
io
.
inq
.
valid
&&
io
.
deq
.
ready
))
io
.
deq
.
bits
:=
d
io
.
deq
.
valid
:=
!
reset
&&
i
===
UInt
(
0
)
when
(
reset
)
{
i
:=
UInt
(
ratio
)
d
:=
UInt
(
0
)
}
.
otherwise
{
when
(
io
.
inq
.
ready
&&
io
.
inq
.
valid
)
{
if
(
littleEndian
)
d
:=
Cat
(
io
.
inq
.
bits
,
d
)
>>
UInt
(
inWidth
)
else
d
:=
(
d
<<
UInt
(
inWidth
))
|
io
.
inq
.
bits
i
:=
i
-
UInt
(
1
)
}
when
(
io
.
deq
.
valid
&&
io
.
deq
.
ready
)
{
i
:=
Mux
(
io
.
inq
.
valid
,
UInt
(
ratio
-
1
),
UInt
(
ratio
))
}
}
}
private
def
downsize
()
=
{
val
i
=
Reg
(
UInt
(
width
=
log2Up
(
ratio
+
1
)))
val
d
=
Reg
(
UInt
(
width
=
inWidth
))
io
.
inq
.
ready
:=
!
reset
&&
(
i
===
UInt
(
0
)
||
(
i
===
UInt
(
1
)
&&
io
.
deq
.
ready
))
if
(
littleEndian
)
io
.
deq
.
bits
:=
d
(
outWidth
-
1
,
0
)
else
io
.
deq
.
bits
:=
d
(
inWidth
-
1
,
inWidth
-
outWidth
)
io
.
deq
.
valid
:=
!
reset
&&
i
>
UInt
(
0
)
when
(
reset
)
{
i
:=
UInt
(
0
)
d
:=
UInt
(
0
)
}
.
otherwise
{
when
(
i
>
UInt
(
0
)
&&
io
.
deq
.
ready
)
{
if
(
littleEndian
)
d
:=
d
>>
UInt
(
outWidth
)
else
d
:=
d
<<
UInt
(
outWidth
)
i
:=
i
-
UInt
(
1
)
}
when
(
io
.
inq
.
ready
&&
io
.
inq
.
valid
)
{
d
:=
io
.
inq
.
bits
i
:=
UInt
(
ratio
)
}
}
}
}
miscutils/src/main/scala/DecoupledDataSource.scala
0 → 100644
View file @
52108c3e
package
chisel.miscutils
import
Chisel._
/**
* Interface for DecoupledDataSource.
**/
class
DecoupledDataSourceIO
[
T
<:
Data
](
gen
:
T
)
extends
Bundle
{
val
out
=
Decoupled
(
gen
.
cloneType
)
}
/**
* Data source providing fixed data via Decoupled interface.
* Provides the data given via Decoupled handshakes; if repeat
* is true, data is wrapped around.
* @param gen Type.
* @param size Total number of elements.
* @param data Function providing data for each index
* @param repeat If true, will always have data via wrap-around,
otherwise valid will go low after data was
consumed.
**/
class
DecoupledDataSource
[
T
<:
Data
](
gen
:
T
,
val
size
:
Int
,
data
:
(
Int
)
=>
T
,
val
repeat
:
Boolean
=
true
)
extends
Module
{
println
(
"DecoupledDataSource: size = %d, repeat = %s"
.
format
(
size
,
if
(
repeat
)
"true"
else
"false"
))
println
(
" width = %d"
.
format
(
log2Up
(
if
(
repeat
)
size
else
size
+
1
)))
val
ds
=
for
(
i
<-
0
until
size
)
yield
data
(
i
)
// evaluate data to array
val
io
=
new
DecoupledDataSourceIO
(
gen
)
// interface
val
i
=
Reg
(
UInt
(
width
=
log2Up
(
if
(
repeat
)
size
else
size
+
1
)))
// index
val
rom
=
Vec
.
tabulate
(
size
)(
n
=>
ds
(
n
))
// ROM with data
io
.
out
.
bits
:=
rom
(
i
)
// current index data
io
.
out
.
valid
:=
!
reset
&&
i
<
UInt
(
size
)
// valid until exceeded
when
(
reset
)
{
i
:=
UInt
(
0
)
}
.
otherwise
{
if
(
repeat
)
when
(
io
.
out
.
ready
&&
io
.
out
.
valid
)
{
i
:=
i
+
UInt
(
1
)
}
else
when
(
io
.
out
.
ready
&&
io
.
out
.
valid
&&
i
<
UInt
(
size
))
{
i
:=
i
+
UInt
(
1
)
}
}
}
miscutils/src/main/scala/SignalGenerator.scala
0 → 100644
View file @
52108c3e
package
chisel.miscutils
import
Chisel._
sealed
case
class
Signal
(
value
:
Boolean
,
periods
:
Int
=
1
)
extends
Ordered
[
Signal
]
{
import
scala.math.Ordered.orderingToOrdered
def
compare
(
that
:
Signal
)
:
Int
=
periods
compare
that
.
periods
}
object
SignalGenerator
{
type
Waveform
=
List
[
Signal
]
implicit
def
makeSignal
(
sd
:
(
Boolean
,
Int
))
:
Signal
=
Signal
(
sd
.
_1
,
sd
.
_2
)
implicit
def
makeWaveform
(
ls
:
List
[(
Boolean
,
Int
)])
:
Waveform
=
ls
map
makeSignal
}
class
SignalGenerator
(
signals
:
SignalGenerator.Waveform
,
useInputAsClock
:
Boolean
=
false
)
extends
Module
{
require
(
signals
.
length
>
0
,
"Waveform must not be empty."
)
require
(
signals
map
(
_
.
periods
>
1
)
reduce
(
_
&&
_
),
"All signals must have at least two clock cycles length."
)
val
io
=
new
Bundle
{
val
v
=
Bool
(
OUTPUT
);
val
in
=
Bool
(
INPUT
)
}
val
cnts_rom
=
Vec
(
signals
map
(
n
=>
UInt
(
n
.
periods
-
1
)))
val
vals_rom
=
Vec
(
signals
map
(
n
=>
Bool
(
n
.
value
)))
val
cnt
=
Reg
(
UInt
(
width
=
log2Up
(
signals
.
max
.
periods
)))
val
curr_idx
=
Reg
(
UInt
(
width
=
log2Up
(
signals
.
length
)))
val
vreg
=
Reg
(
Bool
())
io
.
v
:=
vreg
when
(
reset
)
{
curr_idx
:=
UInt
(
0
)
cnt
:=
cnts_rom
(
0
)
vreg
:=
UInt
(
0
)
}
.
otherwise
{
vreg
:=
vals_rom
(
curr_idx
)
// trigger on either clock or pos input edge
when
(
if
(
useInputAsClock
)
io
.
in
&&
!
RegNext
(
io
.
in
)
else
Bool
(
true
))
{
when
(
cnt
===
UInt
(
0
))
{
val
next_idx
=
Mux
(
curr_idx
<
UInt
(
signals
.
length
-
1
),
curr_idx
+
UInt
(
1
),
UInt
(
0
))
curr_idx
:=
next_idx
cnt
:=
cnts_rom
(
next_idx
)
}
.
otherwise
{
cnt
:=
cnt
-
UInt
(
1
)
}
}
}
}
miscutils/src/test/scala/DataWidthConverterSuiteCorrectness.scala
0 → 100644
View file @
52108c3e
package
chisel.miscutils
import
Chisel._
import
org.scalatest.junit.JUnitSuite
import
org.junit.Test
import
org.junit.Assert._
import
scala.math._
import
java.nio.file.Paths
class
SlowQueue
(
width
:
Int
,
val
delay
:
Int
=
10
)
extends
Module
{
val
io
=
new
Bundle
{
val
enq
=
Decoupled
(
UInt
(
width
=
width
)).
flip
val
deq
=
Decoupled
(
UInt
(
width
=
width
))
val
dly
=
UInt
(
INPUT
,
width
=
log2Up
(
delay
))
}
val
waiting
::
ready
::
Nil
=
Enum
(
UInt
(),
2
)
val
state
=
Reg
(
init
=
ready
)
val
wr
=
Reg
(
UInt
(
width
=
log2Up
(
delay
)))
io
.
deq
.
bits
:=
io
.
enq
.
bits
io
.
enq
.
ready
:=
io
.
deq
.
ready
&&
state
===
ready
io
.
deq
.
valid
:=
io
.
enq
.
valid
&&
state
===
ready
when
(
reset
)
{
state
:=
ready
}
.
otherwise
{
when
(
state
===
ready
&&
io
.
enq
.
ready
&&
io
.
deq
.
valid
)
{
state
:=
waiting
wr
:=
io
.
dly
}
when
(
state
===
waiting
)
{
wr
:=
wr
-
UInt
(
1
)
when
(
wr
===
UInt
(
0
))
{
state
:=
ready
}
}
}
}
/**
* DataWidthConverterHarness: Correctness test harness.
* A DecoupledDataSource with random data is connected to a pair
* of data width converters with inverted params. This circuit
* must behave exactly like a delay on the input stream (where
* the length of the delay is 2 * in/out-width-ratio).
* There's a slow queue in-between to simulate receivers with
* varying speed of consumption.
**/
class
DataWidthConverterHarness
(
inWidth
:
Int
,
outWidth
:
Int
,
littleEndian
:
Boolean
,
delay
:
Int
=
10
)
extends
Module
{
val
io
=
new
Bundle
{
val
dly
=
UInt
(
INPUT
,
width
=
log2Up
(
delay
))
}
val
dwc
=
Module
(
new
DataWidthConverter
(
inWidth
,
outWidth
,
littleEndian
))
val
dsrc
=
Module
(
new
DecoupledDataSource
(
UInt
(
width
=
inWidth
),
Seq
(
Seq
(
pow
(
2
,
inWidth
).
toLong
,
dwc
.
ratio
).
max
,
10000.
toLong
).
min
.
toInt
,
//n => UInt(n % pow(2, inWidth).toInt + 1, width = inWidth),
n
=>
UInt
((
scala
.
math
.
random
*
pow
(
2
,
inWidth
)).
toLong
,
width
=
inWidth
),
repeat
=
false
))
val
dwc2
=
Module
(
new
DataWidthConverter
(
outWidth
,
inWidth
,
littleEndian
))
val
slq
=
Module
(
new
SlowQueue
(
outWidth
,
delay
))
dwc
.
io
.
inq
<>
dsrc
.
io
.
out
slq
.
io
.
enq
<>
dwc
.
io
.
deq
slq
.
io
.
dly
:=
io
.
dly
dwc2
.
io
.
inq
<>
slq
.
io
.
deq
dwc2
.
io
.
deq
.
ready
:=
Bool
(
true
)
}
/**
* Generic tester for DataWidthConverterHarness:
* Uses DataWidthConverterHarness class to check output correctness.
* Tracks incoming data from the data source in expecteds list.
* Whenever output is valid, it is compared to the expecteds,
* mismatches are reported accordingly.
* Does NOT check timing, only correctness of the output values.
**/
class
DataWidthConverterCorrectnessTester
[
T
<:
UInt
](
m
:
DataWidthConverterHarness
)
extends
Tester
(
m
,
false
)
{
import
scala.util.Properties.
{
lineSeparator
=>
NL
}
// returns binary string for Int, e.g., 0011 for 3, width 4
private
def
toBinaryString
(
n
:
BigInt
,
width
:
Int
)
=
"%%%ds"
.
format
(
width
).
format
(
n
.
toString
(
2
)).
replace
(
' '
,
'0'
)
/** Performs data correctness check. **/
def
check
()
=
{
var
i
=
0
var
delay
=
m
.
slq
.
delay
-
1
poke
(
m
.
slq
.
io
.
dly
,
delay
)
var
expecteds
:
List
[
BigInt
]
=
List
()
def
running
=
peek
(
m
.
dsrc
.
io
.
out
.
valid
)
>
0
||
peek
(
m
.
dwc
.
io
.
inq
.
valid
)
>
0
||
peek
(
m
.
dwc
.
io
.
deq
.
valid
)
>
0
||
peek
(
m
.
dwc2
.
io
.
inq
.
valid
)
>
0
||
peek
(
m
.
dwc2
.
io
.
deq
.
valid
)
>
0
while
(
running
)
{
// scan output element and add to end of expected list
if
(
peek
(
m
.
dsrc
.
io
.
out
.
valid
)
>
0
&&
peek
(
m
.
dwc
.
io
.
inq
.
ready
)
>
0
)
{
val
e
=
peek
(
m
.
dsrc
.
io
.
out
.
bits
)
expecteds
=
expecteds
:+
e
println
(
"adding expected value: %d (%s)"
.
format
(
e
,
toBinaryString
(
e
,
m
.
dwc
.
inWidth
)))
}
// check output element: must match head of expecteds
if
(
peek
(
m
.
dwc2
.
io
.
deq
.
valid
)
>
0
&&
peek
(
m
.
dwc2
.
io
.
deq
.
ready
)
>
0
)
{
// update delay (decreasing with each output)
delay
=
if
(
delay
==
0
)
m
.
slq
.
delay
-
1
else
delay
-
1
poke
(
m
.
io
.
dly
,
delay
)
// check output
val
v
=
peek
(
m
.
dwc2
.
io
.
deq
.
bits
)
if
(
expecteds
.
isEmpty
)
{
val
errmsg
=
"received value output value %d (%s), but none expected yet"
.
format
(
v
,
toBinaryString
(
v
,
m
.
dwc
.
inWidth
))
println
(
errmsg
)
expect
(
false
,
errmsg
)
}
else
{
if
(
v
==
expecteds
.
head
)
{
println
(
"element #%d ok!"
.
format
(
i
))
}
else
{
val
errmsg
=
"element #%d wrong: expected %d (%s), found %d (%s)"
.
format
(
i
,
expecteds
.
head
,
toBinaryString
(
expecteds
.
head
,
m
.
dwc
.
inWidth
),
v
,
toBinaryString
(
v
,
m
.
dwc
.
inWidth
))
println
(
errmsg
)
expect
(
v
==
expecteds
.
head
,
errmsg
)
}
expecteds
=
expecteds
.
tail
}
i
+=
1
}
// advance sim
step
(
1
)
}
}
reset
(
10
)
// reset for 10 cycles
check
()
step
(
20
)
// settle output
}
/** Unit test for DataWidthConverter hardware. **/
class
DataWidthConverterSuite
extends
JUnitSuite
{
def
resize
(
inWidth
:
Int
,
outWidth
:
Int
,
littleEndian
:
Boolean
=
true
)
=
{
println
(
"testing conversion of %d bit to %d bit, %s ..."
.
format
(
inWidth
,
outWidth
,
if
(
littleEndian
)
"little-endian"
else
"big-endian"
))
val
dir
=
Paths
.
get
(
"test"
)
.
resolve
(
"DataWidthConverterSuite"
)
.
resolve
(
"%dto%d%s"
.
format
(
inWidth
,
outWidth
,
if
(
littleEndian
)
"le"
else
"be"
))
.
toString
chiselMainTest
(
Array
(
"--genHarness"
,
"--backend"
,
"c"
,
"--vcd"
,
"--targetDir"
,
dir
,
"--compile"
,
"--test"
),
()
=>
Module
(
new
DataWidthConverterHarness
(
inWidth
,
outWidth
,
littleEndian
)))
{
m
=>
new
DataWidthConverterCorrectnessTester
(
m
)
}
}
// simple test group, can be used for waveform analysis
/*@Test def check16to4le { resize(16, 4, true) }
@Test def check4to16le { resize(4, 16, true) }
@Test def check16to4be { resize(16, 4, false) }
@Test def check4to16be { resize(4, 16, false) }
@Test def check64to32be { resize(64, 32, false) }*/
// downsizing tests
@Test
def
check2to1le
{
resize
(
2
,
1
,
true
)
}
@Test
def
check2to1be
{
resize
(
2
,
1
,
false
)
}
@Test
def
check8to1le
{
resize
(
8
,
1
,
true
)
}
@Test
def
check8to1be
{
resize
(
8
,
1
,
false
)
}
@Test
def
check16to4le
{
resize
(
16
,
4
,
true
)
}
@Test
def
check16to4be
{
resize
(
16
,
4
,
false
)
}
@Test
def
check16to8le
{
resize
(
16
,
8
,
true
)
}
@Test
def
check16to8be
{
resize
(
16
,
8
,
false
)
}
@Test
def
check32to8le
{
resize
(
32
,
8
,
true
)
}
@Test
def
check32to8be
{
resize
(
32
,
8
,
false
)
}
@Test
def
check64ot8le
{
resize
(
64
,
8
,
true
)
}
@Test
def
check64to8be
{
resize
(
64
,
8
,
false
)
}
@Test
def
check64ot32le
{
resize
(
64
,
32
,
true
)
}
@Test
def
check64to32be
{
resize
(
64
,
32
,
false
)
}
// upsizing tests
@Test
def
check1to2le
{
resize
(
1
,
2
,
true
)
}
@Test
def
check1to2be
{
resize
(
1
,
2
,
false
)
}
@Test
def
check1to8le
{
resize
(
1
,
8
,
true
)
}
@Test
def
check1to8be
{
resize
(
1
,
8
,
false
)
}
@Test
def
check4to16le
{
resize
(
4
,
16
,
true
)
}
@Test
def
check4to16be
{
resize
(
4
,
16
,
false
)
}
@Test
def
check8to16le
{
resize
(
8
,
16
,
true
)
}
@Test
def
check8to16be
{
resize
(
8
,
16
,
false
)
}
@Test
def
check8to32le
{
resize
(
8
,
32
,
true
)
}
@Test
def
check8to32be
{
resize
(
8
,
32
,
false
)
}
@Test
def
check8ot64le
{
resize
(
8
,
64
,
true
)
}
@Test
def
check8to64be
{
resize
(
8
,
64
,
false
)
}
@Test
def
check32ot64le
{
resize
(
32
,
64
,
true
)
}
@Test
def
check32to64be
{
resize
(
32
,
64
,
false
)
}
}
miscutils/src/test/scala/DataWidthConverterSuiteFullSpeed.scala
0 → 100644
View file @
52108c3e
package
chisel.miscutils
import
Chisel._
import
org.scalatest.junit.JUnitSuite
import
org.junit.Test
import
org.junit.Assert._
import
scala.math._
import
java.nio.file.Paths
/**
* DataWidthConverterHarness: Correctness test harness.
* A DecoupledDataSource with random data is connected to a pair
* of data width converters with inverted params. This circuit
* must behave exactly like a delay on the input stream (where
* the length of the delay is 2 * in/out-width-ratio).
**/
class
DataWidthConverterHarnessFullSpeed
(
val
inWidth
:
Int
,
val
outWidth
:
Int
,
val
littleEndian
:
Boolean
)
extends
Module
{
val
io
=
new
Bundle
val
dwc
=
Module
(
new
DataWidthConverter
(
inWidth
,
outWidth
,
littleEndian
))
val
dsrc
=
Module
(
new
DecoupledDataSource
(
UInt
(
width
=
inWidth
),
Seq
(
Seq
(
pow
(
2
,
inWidth
).
toLong
,
dwc
.
ratio
).
max
,
10000.
toLong
).
min
.
toInt
,
//n => UInt(n % pow(2, inWidth).toInt + 1, width = inWidth),
n
=>
UInt
((
scala
.
math
.
random
*
pow
(
2
,
inWidth
)).
toLong
,
width
=
inWidth
),
repeat
=
false
))
val
dwc2
=
Module
(
new
DataWidthConverter
(
outWidth
,
inWidth
,
littleEndian
))
dwc
.
io
.
inq
<>
dsrc
.
io
.
out
dwc2
.
io
.
inq
<>
dwc
.
io
.
deq
dwc2
.
io
.
deq
.
ready
:=
!
reset
}
/**
* Generic tester for DataWidthConverterHarness:
* Uses DataWidthConverterHarness class to check output correctness.
* Tracks incoming data from the data source in expecteds list.
* Whenever output is valid, it is compared to the expecteds,
* mismatches are reported accordingly.
* Does NOT check timing, only correctness of the output values.
**/
class
DataWidthConverterFullSpeed
[
T
<:
UInt
](
m
:
DataWidthConverterHarnessFullSpeed
)
extends
Tester
(
m
,
false
)
{
import
scala.util.Properties.
{
lineSeparator
=>
NL
}
// returns binary string for Int, e.g., 0011 for 3, width 4
private
def
toBinaryString
(
n
:
BigInt
,
width
:
Int
)
=
"%%%ds"
.
format
(
width
).
format
(
n
.
toString
(
2
)).
replace
(
' '
,
'0'
)
/** Performs data correctness at full speed check. **/
def
check
()
=
{
var
i
=
0
var
firstOutputReceived
=
false
var
expecteds
:
List
[
BigInt
]
=
List
()
def
running
=
peek
(
m
.
dsrc
.
io
.
out
.
valid
)
>
0
||
peek
(
m
.
dwc
.
io
.
inq
.
valid
)
>
0
||
peek
(
m
.
dwc
.
io
.
deq
.
valid
)
>
0
||
peek
(
m
.
dwc2
.
io
.
inq
.
valid
)
>
0
||
peek
(
m
.
dwc2
.
io
.
deq
.
valid
)
>
0
while
(
running
)
{
// scan output element and add to end of expected list
if
(
peek
(
m
.
dsrc
.
io
.
out
.
valid
)
>
0
&&
peek
(
m
.
dwc
.
io
.
inq
.
ready
)
>
0
)
{
val
e
=
peek
(
m
.
dsrc
.
io
.
out
.
bits
)
expecteds
=
expecteds
:+
e
println
(
"adding expected value: %d (%s)"
.
format
(
e
,
toBinaryString
(
e
,
m
.
dwc
.
inWidth
)))
}
// check output element: must match head of expecteds
if
(
peek
(
m
.
dwc2
.
io
.
deq
.
valid
)
>
0
&&
peek
(
m
.
dwc2
.
io
.
deq
.
ready
)
>
0
)
{
firstOutputReceived
=
true
val
v
=
peek
(
m
.
dwc2
.
io
.
deq
.
bits
)
if
(
expecteds
.
isEmpty
)
{
val
errmsg
=
"received value output value %d (%s), but none expected yet"
.
format
(
v
,
toBinaryString
(
v
,
m
.
dwc
.
inWidth
))
println
(
errmsg
)
expect
(
false
,
errmsg
)
}
else
{
if
(
v
==
expecteds
.
head
)
{
println
(
"element #%d ok!"
.
format
(
i
))
}
else
{
val
errmsg
=
"element #%d wrong: expected %d (%s), found %d (%s)"
.
format
(
i
,
expecteds
.
head
,
toBinaryString
(
expecteds
.
head
,
m
.
dwc
.
inWidth
),
v
,
toBinaryString
(
v
,
m
.
dwc
.
inWidth
))
println
(
errmsg
)
expect
(
v
==
expecteds
.
head
,
errmsg
)
}
expecteds
=
expecteds
.
tail
}
i
+=
1
}
// check: if upsizing, inq may never block
if
(
m
.
inWidth
<
m
.
outWidth
)
{
val
error
=
peek
(
m
.
dwc
.
io
.
inq
.
ready
)
==
0
&&
peek
(
m
.
dwc
.
io
.
inq
.
valid
)
!=
0
if
(
error
)
println
(
"ERROR: input queue may never block while input is available"
)
expect
(!
error
,
"upsizing: input queue may not block while input is available"
)
}
// check: if downsizing, deq must remain valid until end
if
(
firstOutputReceived
&&
!
expecteds
.
isEmpty
&&
m
.
inWidth
>
m
.
outWidth
)
{
if
(
peek
(
m
.
dwc
.
io
.
deq
.
valid
)
==
0
)
println
(
"ERROR: output queue must remain valid after first element"
)
if
(
peek
(
m
.
dwc
.
io
.
deq
.
ready
)
==
0
)
println
(
"ERROR: output queue must remain ready after first element"
)
expect
(
peek
(
m
.
dwc
.
io
.
deq
.
ready
)
!=
0
,
"downsizing: output queue must remain ready after first"
)
expect
(
peek
(
m
.
dwc
.
io
.
deq
.
valid
)
!=
0
,
"downsizing: output queue must remain valid after first"
)
}
// advance sim
step
(
1
)
}
}
reset
(
10
)
// reset for 10 cycles
check
()
step
(
20
)
// settle output
}
/** Unit test for DataWidthConverter hardware. **/
class
DataWidthConverterSuiteFullSpeed
extends
JUnitSuite
{
def
resize
(
inWidth
:
Int
,
outWidth
:
Int
,
littleEndian
:
Boolean
=
true
)
=
{
println
(
"testing conversion of %d bit to %d bit, %s ..."
.
format
(
inWidth
,
outWidth
,
if
(
littleEndian
)
"little-endian"
else
"big-endian"
))
val
dir
=
Paths
.
get
(
"test"
)
.
resolve
(
"dwc_fullspeed"
)
.
resolve
(
"%dto%d%s"
.
format
(
inWidth
,
outWidth
,
if
(
littleEndian
)
"le"
else
"be"
))
.
toString
chiselMainTest
(
Array
(
"--genHarness"
,
"--backend"
,
"c"
,
"--vcd"
,
"--targetDir"
,
dir
,
"--compile"
,
"--test"
),
()
=>
Module
(
new
DataWidthConverterHarnessFullSpeed
(
inWidth
,
outWidth
,
littleEndian
)))
{
m
=>
new
DataWidthConverterFullSpeed
(
m
)
}
}
// simple test group, can be used for waveform analysis
/*@Test def check16to4le { resize(16, 4, true) }
@Test def check4to16le { resize(4, 16, true) }
@Test def check16to4be { resize(16, 4, false) }
@Test def check4to16be { resize(4, 16, false) }
@Test def check64to32be { resize(64, 32, false) }
@Test def check32to64be { resize(32, 64, false) }*/
// downsizing tests
@Test
def
check2to1le
{
resize
(
2
,
1
,
true
)
}
@Test
def
check2to1be
{
resize
(
2
,
1
,
false
)
}
@Test
def
check8to1le
{
resize
(
8
,
1
,
true
)
}
@Test
def
check8to1be
{
resize
(
8
,
1
,
false
)
}
@Test
def
check16to4le
{
resize
(
16
,
4
,
true
)
}
@Test
def
check16to4be
{
resize
(
16
,
4
,
false
)
}
@Test
def
check16to8le
{
resize
(
16
,
8
,
true
)
}
@Test
def
check16to8be
{
resize
(
16
,
8
,
false
)
}
@Test
def
check32to8le
{
resize
(
32
,
8
,
true
)
}
@Test
def
check32to8be
{
resize
(
32
,
8
,
false
)
}
@Test
def
check64ot8le
{
resize
(
64
,
8
,
true
)
}
@Test
def
check64to8be
{
resize
(
64
,
8
,
false
)
}
@Test
def
check64ot32le
{
resize
(
64
,
32
,
true
)
}
@Test
def
check64to32be
{
resize
(
64
,
32
,
false
)
}
// upsizing tests
@Test
def
check1to2le
{
resize
(
1
,
2
,
true
)
}
@Test
def
check1to2be
{
resize
(
1
,
2
,
false
)
}
@Test
def
check1to8le
{
resize
(
1
,
8
,
true
)
}