Skip to content

Commit

Permalink
Merge pull request custom-computing-ic#1 from James-Arram/master
Browse files Browse the repository at this point in the history
added multi-channel LMem test design
  • Loading branch information
paul-g committed Jan 27, 2016
2 parents fe47179 + 29912c9 commit aa23e66
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 0 deletions.
12 changes: 12 additions & 0 deletions test/Tests/LMemMultiChannel/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Multi-Channel LMem design

This is a simple pass-through kernel built to test the multiple memory
channel feature in MaxCompiler 2015.2

##Notes
1. You can vary the number of kernes and memory channels by setting
the **n_kernel** parameter in the manager. This value must be in the
range [1, 6]
2. This design works on Maia, but not for max3 (possible bug in API)
3. Any questions please email me (jma11_at_ic.ac.uk)

45 changes: 45 additions & 0 deletions test/Tests/LMemMultiChannel/src/LMemMultiChannelCpuCode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/***
This is a simple demo project that you can copy to get started.
Comments blocks starting with '***' and subsequent non-empty lines
are automatically added to this project's wiki page.
*/

#include <stdio.h>
#include <cstdlib>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <vector>
#include "Maxfiles.h"
#include "MaxSLiCInterface.h"

int main(void)
{

const uint32_t inSize = 384;

std::vector<uint32_t> in(inSize), out0(inSize, 0), out1(inSize, 0);

for(uint32_t i = 0; i < inSize; ++i) {
in[i] = i;
}

std::cout << "Writing data to LMem." << std::endl;
LMemMultiChannel_Write(inSize, &in[0]);

std::cout << "Running DFE." << std::endl;
LMemMultiChannel_Exec(inSize, &out0[0], &out1[0]);

/***
Note that you should always test the output of your DFE
design against a CPU version to ensure correctness.
*/
for (uint32_t i = 0; i < inSize; i++)
if (in[i] != out0[i] && in[i] != out1[i]) {
printf("Output from DFE did not match CPU\n");
return 1;
}

std::cout << "Test passed!" << std::endl;
return 0;
}
20 changes: 20 additions & 0 deletions test/Tests/LMemMultiChannel/src/LMemMultiChannelKernel.maxj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/***
A simple pass-through Kernel

A single stream of data is read from LMem and directly output to host CPU
*/

import com.maxeler.maxcompiler.v2.kernelcompiler.Kernel;
import com.maxeler.maxcompiler.v2.kernelcompiler.KernelParameters;
import com.maxeler.maxcompiler.v2.kernelcompiler.types.base.DFEVar;

class LMemMultiChannelKernel extends Kernel {

protected LMemMultiChannelKernel(KernelParameters parameters) {
super(parameters);

DFEVar a = io.input("k_in", dfeInt(32));
io.output("k_out", a, dfeInt(32));
}

}
112 changes: 112 additions & 0 deletions test/Tests/LMemMultiChannel/src/LMemMultiChannelManager.maxj
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/***
n_kernel pass through Kernels are instantiated on the DFE
Each Kernel has its own independent LMem channel
A fanout is used to send the same input data to each active LMem module
*/

import com.maxeler.maxcompiler.v2.build.EngineParameters;
import com.maxeler.maxcompiler.v2.managers.custom.CustomManager;
import com.maxeler.maxcompiler.v2.managers.custom.DFELink;
import com.maxeler.maxcompiler.v2.managers.custom.blocks.KernelBlock;
import com.maxeler.maxcompiler.v2.managers.custom.stdlib.LMemCommandGroup;
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.CPUTypes;
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.EngineInterface;
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.EngineInterface.Direction;
import com.maxeler.maxcompiler.v2.managers.engine_interfaces.InterfaceParam;
import com.maxeler.maxcompiler.v2.managers.custom.blocks.Fanout;
import com.maxeler.maxcompiler.v2.managers.custom.stdlib.LMemInterface;

public class LMemMultiChannelManager extends CustomManager{

private static final String s_kernelName = "LMemMultiChannelKernel";

private static final int n_kernel = 2;

LMemMultiChannelManager(EngineParameters ep)
{
super(ep);

// instantiate memory channels
LMemInterface[] iface = new LMemInterface[n_kernel];
for (int i = 0; i < n_kernel; i++) {
iface[i] = addLMemInterface("ctrl" + i, 1);
}

// instantiate kernels
for (int i = 0; i < n_kernel; i++) {
KernelBlock k = addKernel(new LMemMultiChannelKernel(makeKernelParameters(s_kernelName + i)));

DFELink lmemToKernel = iface[i].addStreamFromLMem("k_in" + i, LMemCommandGroup.MemoryAccessPattern.LINEAR_1D);
k.getInput("k_in") <== lmemToKernel;

DFELink kernelToHost = addStreamToCPU("k_out" + i);
kernelToHost <== k.getOutput("k_out");
}

// data to LMem
DFELink hostToMger = addStreamFromCPU("hostToMger");
Fanout fan = fanout("fan");
fan.getInput() <== hostToMger;
for (int i = 0; i < n_kernel; i++) {
DFELink fanOut = fan.addOutput("fanOut" + i);
DFELink mgerToLMem = iface[i].addStreamToLMem("mgerToLMem" + i, LMemCommandGroup.MemoryAccessPattern.LINEAR_1D);
mgerToLMem <== fanOut;
}
}

// write data to LMem
private static EngineInterface interfaceWrite(String name) {
EngineInterface engine_interface = new EngineInterface(name);
CPUTypes type = CPUTypes.UINT32;
int size = type.sizeInBytes();

String routeString = "";
InterfaceParam N = engine_interface.addParam("N", type);
InterfaceParam sizeBytes = N * size;
InterfaceParam zero = engine_interface.addConstant(0l);

engine_interface.setStream("hostToMger", type, sizeBytes);
for (int i = 0; i < n_kernel; i++) {
engine_interface.setLMemLinear("ctrl" + i, "mgerToLMem" + i, zero, sizeBytes);
String tmp;
if (i < n_kernel-1)
tmp = String.format("fan -> fanOut%d, ", i);
else
tmp = String.format("fan -> fanOut%d", i);
routeString += tmp;
}

engine_interface.route(routeString);
engine_interface.ignoreAll(Direction.IN_OUT);

return engine_interface;
}

// run pass through kernel
private static EngineInterface interfaceExec(String name) {
EngineInterface engine_interface = new EngineInterface(name);
CPUTypes type = CPUTypes.UINT32;
int size = type.sizeInBytes();

InterfaceParam N = engine_interface.addParam("N", CPUTypes.INT);
InterfaceParam sizeBytes = N * size;
InterfaceParam zero = engine_interface.addConstant(0l);

for (int i = 0; i < n_kernel; i++) {
engine_interface.setTicks(s_kernelName + i, N);
engine_interface.setStream("k_out" + i, type, sizeBytes);
engine_interface.setLMemLinear("ctrl" + i, "k_in" + i, zero, sizeBytes);
}
engine_interface.ignoreAll(Direction.IN_OUT);
return engine_interface;
}


public static void main(String[] args) {
LMemMultiChannelManager manager = new LMemMultiChannelManager(new EngineParameters(args));
manager.createSLiCinterface(interfaceWrite("Write"));
manager.createSLiCinterface(interfaceExec("Exec"));
manager.suppressDefaultInterface();
manager.build();
}
}

0 comments on commit aa23e66

Please sign in to comment.