-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
add version of histogram-array using SMI
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Array Histogram Example - using SMI protocol | ||
|
||
In this example some random sample data is sent to the FPGA, it is then sorted into bins to create a histogram. The process of sorting the data has been parallelized to work efficiently on the FPGA – the sample data is held in an array, and while the FPGA reads the sample data in from the array it concurrently sorts the data and writes it back into a new channel. | ||
|
||
## Structure | ||
|
||
This directory contains code for an FPGA located at `main.go`. It also has a | ||
command, `test-histogram` located at `cmd/test-histogram/main.go` | ||
|
||
## Testing | ||
|
||
To run this example in a simulator, execute the following: | ||
|
||
``` | ||
reco test test-histogram | ||
``` | ||
|
||
This will simulate the code running on an FPGA using a hardware simulator, and test it | ||
using the `test-histogram` command. | ||
|
||
## Building | ||
|
||
``` | ||
reco build | ||
``` | ||
|
||
This will build your commands and FPGA code for execution on hardware. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"github.com/ReconfigureIO/sdaccel/xcl" | ||
"log" | ||
"math/rand" | ||
"reflect" | ||
) | ||
|
||
// Define constants to be used in func main | ||
const ( | ||
// The maximum bit width we allow values to have | ||
MAX_BIT_WIDTH = 16 | ||
// The bit width we will compress to | ||
HISTOGRAM_BIT_WIDTH = 9 | ||
// The resulting number of elements of the histogram | ||
HISTOGRAM_WIDTH = 1 << 9 | ||
) | ||
|
||
func main() { | ||
// Allocate a 'world' for interacting with the FPGA | ||
world := xcl.NewWorld() | ||
defer world.Release() | ||
|
||
// Import the compiled code that will be loaded onto the FPGA (referred to here as a kernel) | ||
// Right now these two identifiers are hard coded as an output from the build process | ||
krnl := world.Import("kernel_test").GetKernel("reconfigure_io_sdaccel_builder_stub_0_1") | ||
defer krnl.Release() | ||
|
||
// Define a new array for the data we'll send to the FPGA for processing | ||
input := make([]uint32, 20) | ||
|
||
// Seed it with 20 random values, bound to 0 - 2**16 | ||
for i, _ := range input { | ||
input[i] = uint32(uint16(rand.Uint32())) | ||
} | ||
|
||
// Allocate a space in the shared memory to store the data you're sending to the FPGA | ||
buff := world.Malloc(xcl.ReadOnly, uint(binary.Size(input))) | ||
defer buff.Free() | ||
|
||
// Construct an array to hold the output data from the FPGA | ||
var output [HISTOGRAM_WIDTH]uint32 | ||
|
||
// Allocate a space in the shared memory to store the output data from the FPGA | ||
outputBuff := world.Malloc(xcl.ReadWrite, uint(binary.Size(output))) | ||
defer outputBuff.Free() | ||
|
||
// Write our input data to shared memory at the address we previously allocated | ||
binary.Write(buff.Writer(), binary.LittleEndian, &input) | ||
|
||
// Zero out the space in shared memory for the result from the FPGA | ||
binary.Write(outputBuff.Writer(), binary.LittleEndian, &output) | ||
|
||
// Pass the pointer to the input data in shared memory as the first argument | ||
krnl.SetMemoryArg(0, buff) | ||
// Pass the pointer to the memory location reserved for the result as the second argument | ||
krnl.SetMemoryArg(1, outputBuff) | ||
// Pass the total length of the input as the third argument | ||
krnl.SetArg(2, uint32(len(input))) | ||
|
||
// Run the FPGA with the supplied arguments. This is the same for all projects. | ||
// The arguments ``(1, 1, 1)`` relate to x, y, z co-ordinates and correspond to our current | ||
// underlying technology. | ||
krnl.Run(1, 1, 1) | ||
|
||
// Read the result from shared memory. If it is zero return an error | ||
err := binary.Read(outputBuff.Reader(), binary.LittleEndian, &output) | ||
if err != nil { | ||
log.Fatal("binary.Read failed:", err) | ||
} | ||
|
||
// Calculate the same values locally to check the FPGA got it right | ||
var expected [HISTOGRAM_WIDTH]uint32 | ||
for _, val := range input { | ||
expected[val>>(MAX_BIT_WIDTH-HISTOGRAM_BIT_WIDTH)] += 1 | ||
} | ||
|
||
// Return an error if the local and FPGA calculations do not give the same result | ||
if !reflect.DeepEqual(expected, output) { | ||
log.Fatalf("%v != %v\n", output, expected) | ||
} | ||
|
||
// Print out each bin and coresponding value | ||
for i, val := range output { | ||
fmt.Printf("%d: %d\n", i<<(MAX_BIT_WIDTH-HISTOGRAM_BIT_WIDTH), val) | ||
} | ||
|
||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package: . | ||
import: | ||
- package: github.com/ReconfigureIO/sdaccel | ||
subpakages: | ||
- smi | ||
- xcl |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package main | ||
|
||
import ( | ||
// import the entire framework (including bundled verilog) | ||
_ "github.com/ReconfigureIO/sdaccel" | ||
|
||
// Use the new SMI protocol package | ||
"github.com/ReconfigureIO/sdaccel/smi" | ||
) | ||
|
||
// function to calculate the bin for each sample | ||
func CalculateIndex(sample uint32) uint16 { | ||
return uint16(sample) >> (16 - 9) | ||
} | ||
|
||
// magic identifier for exporting | ||
func Top( | ||
// Three operands from the host. Pointers to the input data and the space for the result in shared | ||
// memory and the length of the input data so the FPGA knows what to expect. | ||
inputData uintptr, | ||
outputData uintptr, | ||
length uint32, | ||
|
||
// Set up channels for interacting with the shared memory | ||
readReq chan<- smi.Flit64, | ||
readResp <-chan smi.Flit64, | ||
|
||
writeReq chan<- smi.Flit64, | ||
writeResp <-chan smi.Flit64) { | ||
|
||
// Create an array to hold the histogram data as it is sorted | ||
histogram := [512]uint32{} | ||
|
||
// Read all of the input data into a channel | ||
inputChan := make(chan uint32) | ||
go smi.ReadBurstUInt32(readReq, readResp, inputData, smi.DefaultOptions, length, inputChan) | ||
|
||
// The host needs to provide the length we should read | ||
for ; length > 0; length-- { | ||
// First we'll pull of each sample from the channel | ||
sample := <-inputChan | ||
|
||
// And increment the value in the correct bin using the calculation function | ||
histogram[CalculateIndex(sample)] += 1 | ||
} | ||
|
||
// Write the results to a new channel | ||
data := make(chan uint32) | ||
go func() { | ||
for i := 0; i < 512; i++ { | ||
data <- histogram[i] | ||
} | ||
}() | ||
|
||
// Write the results to shared memory | ||
smi.WriteBurstUInt32( | ||
writeReq, writeResp, outputData, smi.DefaultOptions, 512, data) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
"testing/quick" | ||
) | ||
|
||
func TestCalculateIndexDoesNotOutOfBounds(t *testing.T) { | ||
// Check that we never generate an index out of bounds | ||
f := func(x uint32) bool { | ||
index := CalculateIndex(x) | ||
return index < 512 | ||
} | ||
if err := quick.Check(f, nil); err != nil { | ||
t.Error(err) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
memory_interface: smi | ||
ports: 2 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.