Is it possible to connect an accelerator with several memory mapped inputs/outputs? - chisel

Again I have some questions that are mainly due to my inexperience.
I am designing a memory mapped accelerator, the idea is that the accelerator will have 1 Data input, 1 Data output, and a control input.
And I want all this connections to be memory mapped and connected via FIFOs.
I have already design a memory mapped accelerator before, but it just had 1 input and 1 output as the example given (GenericFIR).
If we check the example of the GenericFIR example we can see how to connect 1 Input and 1 Output:
// DOC include start: GenericFIRBlock chisel
abstract class GenericFIRBlock[D, U, EO, EI, B<:Data, T<:Data:Ring]
(
genIn: T,
genOut: T,
coeffs: Seq[T]
)(implicit p: Parameters) extends DspBlock[D, U, EO, EI, B] {
val streamNode = AXI4StreamIdentityNode()
val mem = None
lazy val module = new LazyModuleImp(this) {
require(streamNode.in.length == 1)
require(streamNode.out.length == 1)
val in = streamNode.in.head._1
val out = streamNode.out.head._1
// instantiate generic fir
val fir = Module(new GenericFIR(genIn, genOut, coeffs))
// Attach ready and valid to outside interface
in.ready := fir.io.in.ready
fir.io.in.valid := in.valid
fir.io.out.ready := out.ready
out.valid := fir.io.out.valid
// cast UInt to T
fir.io.in.bits := in.bits.data.asTypeOf(GenericFIRBundle(genIn))
// cast T to UInt
out.bits.data := fir.io.out.bits.asUInt
}
}
// DOC include end: GenericFIRBlock chisel
But how do we modify this for the case in which the GenericFIR has two InputBundles and two OutputBundles? Lets say in1, in2, out1, out2 and all of them with their Ready/Valid signals (Decoupled).
Also how do we connect the StreamNodes after?
Thanks!

Related

Add a memory to regmap()

I am having a device added to the rocket chip, it has its control & status registers and also an internal ram. To have the ability to access it with software I have added it into the regmap() in the next way :
val mem = Module(new SinglePortMemory(32,128, 7))
// init //
mem.io.re := false.B
mem.io.we := false.B
mem.io.addr := 0.U
mem.io.din := 0.S
val dout = RegNext(mem.io.dout)
regmap((
Seq(
0x0 -> Seq(RegField(1,enable,RegFieldDesc("enable","This bit enable my device")))
++ Seq.tabulate(128) {j =>
(0x50 + (j*4)) -> Seq(RegField(32,
RegReadFn(ready => {
when(ready) {
mem.io.addr := j.asUInt
mem.io.re := true.B
}
(true.B,dout.asUInt)
}),
RegWriteFn((valid,data) => {
when(valid) {
mem.io.addr := j.asUInt
mem.io.we := true.B
mem.io.din := data.asSInt
}
true.B
}),
RegFieldDesc(s"mem_${j}","")
))}
):_*)
Now this works , but I'm not sure if that is the best way to do that (I mean adding the memory to regmap). Can someone advise on a different / better way to do that ?
rocketchip has some built in memories for TileLink and AXI (AHB/APB I don't recall, but can use the others as an example and/or add converters)
https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tilelink/SRAM.scala
You can then connect the new TLRAM to a Xbar in addition to your normal memory mapped registers.

Constructor of derived types

I am trying to write a constructor for a derived type of an abstract one to solve this other question, but it seems that it's not working, or better, it isn't called at all.
The aim is to have a runtime polymorphism setting the correct number of legs of an animal.
These are the two modules:
animal
module animal_module
implicit none
type, abstract :: animal
private
integer, public :: nlegs = -1
contains
procedure :: legs
end type animal
contains
function legs(this) result(n)
class(animal), intent(in) :: this
integer :: n
n = this%nlegs
end function legs
cat
module cat_module
use animal_module, only : animal
implicit none
type, extends(animal) :: cat
private
contains
procedure :: setlegs => setlegs
end type cat
interface cat
module procedure init_cat
end interface cat
contains
type(cat) function init_cat(this)
class(cat), intent(inout) :: this
print *, "Cat!"
this%nlegs = -4
end function init_cat
main program
program oo
use animal_module
use cat_module
implicit none
type(cat) :: c
type(bee) :: b
character(len = 3) :: what = "cat"
class(animal), allocatable :: q
select case(what)
case("cat")
print *, "you will see a cat"
allocate(cat :: q)
q = cat() ! <----- this line does not change anything
case default
print *, "ohnoes, nothing is prepared!"
stop 1
end select
print *, "this animal has ", q%legs(), " legs."
print *, "cat animal has ", c%legs(), " legs."
end program
The constructor isn't called at all, and the number of legs still remains to -1.
The available non-default constructor for the cat type is given by the module procedure init_cat. This function you have defined like
type(cat) function init_cat(this)
class(cat), intent(inout) :: this
end function init_cat
It is a function with one argument, of class(cat). In your later reference
q = cat()
There is no specific function under the generic cat which matches that reference: the function init_cat does not accept a no-argument reference. The default structure constructor is instead used.
You must reference the generic cat in a way matching your init_cat interface to have that specific function called.
You want to change your init_cat function to look like
type(cat) function init_cat()
! print*, "Making a cat"
init_cat%nlegs = -4
end function init_cat
Then you can reference q=cat() as desired.
Note that in the original, you are attempting to "construct" a cat instance, but you aren't returning this constructed entity as the function result. Instead, you are modifying an argument (already constructed). Structure constructors are intended to be used returning such useful things.
Note also that you don't need to
allocate (cat :: q)
q = cat()
The intrinsic assignment to q already handles q's allocation.
FWIW, here is some sample code comparing three approaches (method = 1: sourced allocation, 2: polymorphic assignment, 3: mixed approach).
module animal_module
implicit none
type, abstract :: animal_t
integer :: nlegs = -1
contains
procedure :: legs !! defines a binding to some procedure
endtype
contains
function legs(this) result(n)
class(animal_t), intent(in) :: this
!! The passed variable needs to be declared as "class"
!! to use this routine as a type-bound procedure (TBP).
integer :: n
n = this % nlegs
end
end
module cat_module
use animal_module, only : animal_t
implicit none
type, extends(animal_t) :: cat_t
endtype
interface cat_t !! overloads the definition of cat_t() (as a procedure)
module procedure make_cat
end interface
contains
function make_cat() result( ret ) !! a usual function
type(cat_t) :: ret !<-- returns a concrete-type object
ret % nlegs = -4
end
end
program main
use cat_module, only: cat_t, animal_t
implicit none
integer :: method
type(cat_t) :: c
class(animal_t), allocatable :: q
print *, "How to create a cat? [method = 1,2,3]"
read *, method
select case ( method )
case ( 1 )
print *, "1: sourced allocation"
allocate( q, source = cat_t() )
!! An object created by a function "cat_t()" is used to
!! allocate "q" with the type and value taken from source=.
!! (Empirically most stable for different compilers/versions.)
case ( 2 )
print *, "2: polymorphic assignment"
q = cat_t()
!! Similar to sourced allocation. "q" is automatically allocated.
!! (Note: Old compilers may have bugs, so tests are recommended...)
case ( 3 )
print *, "3: mixed approach"
allocate( cat_t :: q )
q = cat_t()
!! First allocate "q" with a concrete type "cat_t"
!! and then assign a value obtained from cat_t().
case default ; stop "unknown method"
endselect
c = cat_t()
!! "c" is just a concrete-type variable (not "allocatable")
!! and assigned with a value obtained from cat_t().
print *, "c % legs() = ", c % legs()
print *, "q % legs() = ", q % legs()
end
--------------------------------------------------
Test
$ gfortran test.f90 # using version 8 or 9
$ echo 1 | ./a.out
How to create a cat? [method = 1,2,3]
1: sourced allocation
c % legs() = -4
q % legs() = -4
$ echo 2 | ./a.out
How to create a cat? [method = 1,2,3]
2: polymorphic assignment
c % legs() = -4
q % legs() = -4
$ echo 3 | ./a.out
How to create a cat? [method = 1,2,3]
3: mixed approach
c % legs() = -4
q % legs() = -4
--------------------------------------------------
Side notes
* It is also OK to directly use make_cat() to generate a value of cat_t:
e.g., allocate( q, source = make_cat() ) or q = make_cat().
In this case, we do not need to overload cat_t() via interface.
* Another approach is to write an "initializer" as a type-bound procedure,
and call it explicitly as q % init() (after allocating it via
allocate( cat_t :: q )). If the type contains pointer components,
this approach may be more straightforward by avoiding copy of
components (which can be problematic for pointer components).

Add registers of sub-module to the regmap() of a module that new/instantiate it

I am trying to add the registers of of a sub module to the module where it is being instantiated. My usecase is a periphery in the rocket-chip with a few hw engines in it, for example crypto periphery with sha1 engine.
I've Implemented the sha1 as a sub-module with its own set of control registers
class sha1 extends Module {
....
def sha1RegMap(offset: Int): Seq[(Int, Seq[RegField])] = {
val regs = Seq(
(offset) -> Seq(Regfield(32,reg1,RegFileDesc("r1",""))),
(offset + 4) -> Seq(Regfield(32,reg2,RegFileDesc("r2",""))),
(offset + 8) -> Seq(Regfield(32,reg3,RegFileDesc("r3",""))),
)
regs
}
....
}
Then I tried to add it to the containing periphery module:
lazy val module = new LazyModuleImp(this) {
...
val sha1_engine = Module(new sha1)
...
regmap(
0x0 -> Seq(Regfield(32,creg1,RegFileDesc("cr1",""))),
0x4 -> Seq(Regfield(32,creg2,RegFileDesc("cr2",""))),
0x8 -> Seq(Regfield(32,creg3,RegFileDesc("cr3",""))),
++ sha1_engine.sha1RegMap(0xC):_*
)
}
That didn't compile. How can I add the registers of the sub-module ?
Also what about when I need to add more sub-modules after the first one or even some local registers of the periphery itself ?
Can you try the following. I think you need the add the two Seqs together first then
convert them into a an argument list with the :_* operator. I might have more parens than necessary.
lazy val module = new LazyModuleImp(this) {
...
val sha1_engine = Module(new sha1)
...
regmap(
(
Seq(
0x0 -> Seq(Regfield(32,creg1,RegFileDesc("cr1",""))),
0x4 -> Seq(Regfield(32,creg2,RegFileDesc("cr2",""))),
0x8 -> Seq(Regfield(32,creg3,RegFileDesc("cr3","")))
)
++ sha1_engine.sha1RegMap(0xC)
):_*
)
}

How to use "javax.sound.midi.MidiSystem.getSequence" in Octave

I have been using Matlab for some time, but have just started using Octave. I am trying to read a midi file using the following code on my Windows machine:
javaaddpath('C:/Program Files/Java/jdk1.8.0_45/jre/lib/rt.jar');
midiFile = javaObject('java.io.File', file_name);
if ~midiFile.exists
error('Unable to find file %s',file_name);
end
seq = javaObject('javax.sound.midi.MidiSystem.getSequence', midiFile);
But I am getting the following error:
error: [java] java.lang.ClassNotFoundException: javax.sound.midi.MidiSystem.getSequence
What am I doing wrong?
Thanks!
The function javaObject() is used to call a class constructor. However, getSequence() is a "normal" method of the javax.sound.midi.MidiSystem class.
octave> help javaObject
-- Built-in Function: JOBJ = javaObject (CLASSNAME)
-- Built-in Function: JOBJ = javaObject (CLASSNAME, ARG1, ...)
Create a Java object of class CLASSSNAME, by calling the class
constructor with the arguments ARG1, ...
octave> man javaMethod
-- Built-in Function: RET = javaMethod (METHODNAME, OBJ)
-- Built-in Function: RET = javaMethod (METHODNAME, OBJ, ARG1, ...)
Invoke the method METHODNAME on the Java object OBJ with the
arguments ARG1, ....
For static methods, OBJ can be a string representing the fully
qualified name of the corresponding class.
Note that typically, the second argument to javaMethod is an object, but can also be a string with the class name. Therefore, you need to do:
octave> midiFile = javaObject ("java.io.File", "Downloads/MIDI_sample.mid");
octave> seq = javaMethod ("getSequence", "javax.sound.midi.MidiSystem", midiFile )
seq =
<Java object: javax.sound.midi.Sequence>

How can I implement a Fisher-Yates shuffle in Scala without side effects?

I want to implement the Fisher-Yates algorithm (an in-place array shuffle) without side effects by using an STArray for the local mutation effects, and a functional random number generator
type RNG[A] = State[Seed,A]
to produce the random integers needed by the algorithm.
I have a method def intInRange(max: Int): RNG[Int] which I can use to produce a random Int in [0,max).
From Wikipedia:
To shuffle an array a of n elements (indices 0..n-1):
for i from n − 1 downto 1 do
j ← random integer such that 0 ≤ j ≤ i
exchange a[j] and a[i]
I suppose I need to stack State with ST somehow, but this is confusing to me. Do I need a [S]StateT[ST[S,?],Seed,A]? Do I have to rewrite RNG to use StateT as well?
(Edit) I don't want to involve IO, and I don't want to substitute Vector for STArray because the shuffle wouldn't be performed in-place.
I know there is a Haskell implementation here, but I'm not currently capable of understanding and porting this to Scalaz. But maybe you can? :)
Thanks in advance.
You have lots of options. One simple (but not very principled) one would be just to lift both the Rng and ST operations into IO and then work with them together there. Another would be to use both an STRef[Long] and an STArray in the same ST. Another would be to use a State[(Long, Vector[A]), ?].
You could also use a StateT[State[Long, ?], Vector[A], ?] but that would be kind of pointless. You could probably use a StateT (for the RNG state) over an ST (for the array), but again, I don't really see the point.
It's possible to do this pretty cleanly without side effects with just Rng, though. For example, using NICTA's RNG library:
import com.nicta.rng._, scalaz._, Scalaz._
def shuffle[A](xs: Vector[A]): Rng[Vector[A]] =
(xs.size - 1 to 1 by -1).toVector.traverseU(
i => Rng.chooseint(0, i).map((i, _))
).map {
_.foldLeft(xs) {
case ((i, j), v) =>
val tmp = v(i)
v.updated(i, v(j)).updated(j, tmp)
}
}
Here you just pick all your swap operations in the Rng monad, and then fold over them with your collection as the accumulator, swapping as you go.
Here is a more or less direct translation from the Haskell version you linked that uses a mutable STArray. The Scalaz STArray doesn't have an exact equivalent of the listArray function, so I've made one up. Otherwise, it's a straightforward transliteration:
import scalaz._
import scalaz.effect.{ST, STArray}
import ST._
import State._
import syntax.traverse._
import std.list._
def shuffle[A:Manifest](xs: List[A]): RNG[List[A]] = {
def newArray[S](n: Int, as: List[A]): ST[S, STArray[S, A]] =
if (n <= 0) newArr(0, null.asInstanceOf[A])
else for {
r <- newArr[S,A](n, as.head)
_ <- r.fill((_, a: A) => a, as.zipWithIndex.map(_.swap))
} yield r
for {
seed <- get[Seed]
n = xs.length
r <- runST(new Forall[({type λ[σ] = ST[σ, RNG[List[A]]]})#λ] {
def apply[S] = for {
g <- newVar[S](seed)
randomRST = (lo: Int, hi: Int) => for {
p <- g.read.map(intInRange(hi - lo).apply)
(a, sp) = p
_ <- g.write(sp)
} yield a + lo
ar <- newArray[S](n, xs)
xsp <- Range(0, n).toList.traverseU { i => for {
j <- randomRST(i, n)
vi <- ar read i
vj <- ar read j
_ <- ar.write(j, vi)
} yield vj }
genp <- g.read
} yield put(genp).map(_ => xsp)
})
} yield r
}
Although the asymptotics of using a mutable array might be good, do note that the constant factors of the ST monad in Scala are quite large. You may be better off just doing this in a monolithic block using regular mutable arrays. The overall shuffle function remains pure because all of your mutable state is local.
This is amost the same as Travis solution only difference is that it uses the State monad. I wanted to find a minimal set of imports but I finally gave up:
import com.nicta.rng.Rng
import scalaz._
import Scalaz._
object FisherYatesShuffle {
def randomJ(i: Int): Rng[Int] = Rng.chooseint(0,i)
type Exchange = (Int,Int)
def applyExchange[A](exchange: Exchange)(l: Vector[A]): Vector[A] = {
val (i,j) = exchange
val vi = l(i)
l.updated(i,l(j)).updated(j,vi)
}
def stApplyExchange[A](exchange: Exchange): State[Vector[A], Unit] = State.modify(applyExchange(exchange))
def shuffle[A](l: Vector[A]): Rng[Vector[A]] = {
val rngExchanges: Rng[Vector[Exchange]] = (l.length - 1 to 1 by -1).toVector.traverseU { i =>
for {
j <- randomJ(i)
} yield (i, j)
}
for {
exchanges <- rngExchanges
} yield exchanges.traverseU(stApplyExchange[A]).exec(l)
}
}