High-Level Synthesis Code Generation for Data Packetization
This example shows how to generate High-Level Synthesis (HLS) code from a MATLAB® design that packetizes a transmit sequence.
Introduction
In wireless communication, systems receive data that is oversampled at the radio frequency (RF) front end. This data serves several purposes, including providing sufficient sampling rates for receive filtering.
One of the most important functions is to provide multiple sampling points on the received waveform such that data can be sampled near the maximum amplitude point in the received waveform. This example illustrates a basic lead-lag time offset estimation core, operating recursively.
The generated hardware core for this design operates at 1/os_rate, where os_rate is the oversampled rate. That is, for 8 oversampled clock cycles, this core iterates once. The output is at the symbol rate.
design_name = 'mlhdlc_comms_data_packet'; testbench_name = 'mlhdlc_comms_data_packet_tb';
Review the MATLAB design.
type(design_name);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLAB design: Data packetization
%
% Introduction:
%
% This core is meant to illustrate packetization of a transmit sequence.
% There is a "pad" data section, which allows for the transmit amplifier to
% settle. This is then followed by a 65-bit training sequence. This is
% followed by the number of symbols beginning encoded into two bytes or
% 16-bits. This is then followed by a variable length data sequence and a
% CRC. All bits can optionally be differentially encoded.
%
% Key design pattern covered in this example:
% (1) Design illustrates the us of binary operands, such as bitxor
% (2) Shows how to properly segment persistent variables for register an
% BRAM access
% (3) Illustrates the use of fi math
% (4) Shows how to properly format and store ROM data, e.g., padData
% Copyright 2011-2015 The MathWorks, Inc.
%#codegen
function [symbolOut, reByte] = ...
mlhdlc_comms_data_packet(emptyFlag, byteValue, numberSymbols, diffOn, Nts, Npad)
persistent trainBits1 padData
persistent valueCRC crcVector bitPrev
persistent inPacketFlag bitOfByteIndex symbolCount
fm = hdlfimath;
if isempty(symbolCount)
symbolCount = 1;
inPacketFlag = 0;
valueCRC = fi(1, 0,16,0, fm);
bitOfByteIndex = 1;
bitPrev = fi(1, 0,1,0, fm);
crcVector = zeros(1,16);
end
if isempty(trainBits1)
% data-set already exists
trainBits1 = TRAIN_DATA;
padData = PAD_DATA;
end
%genPoly = 69665;
genPoly = fi(65535, 0,16,0, fm);
byteUint8 = uint8(byteValue);
reByte = 0;
symbolOut = fi(0, 0,1,0, fm);
%the first condition is whether or not we're currently processing a packet
if inPacketFlag == 1
bitOut = fi(0, 0,1,0, fm);
if symbolCount <= Npad
bitOut(:) = padData(symbolCount);
elseif symbolCount <= Npad+Nts
bitOut(:) = trainBits1(symbolCount-Npad);
elseif symbolCount <= Npad+Nts+numberSymbols
bitOut(:) = bitget(byteUint8,9-bitOfByteIndex);
bitOfByteIndex = bitOfByteIndex + 1;
if bitOfByteIndex == 9 && symbolCount < Npad+Nts+numberSymbols
bitOfByteIndex = 1;
reByte = 1; % we've exhausted this one so pop new one off
end
elseif symbolCount <= Npad+Nts+numberSymbols+16
bitOut(:) = 0;
elseif symbolCount <= Npad+Nts+numberSymbols+32
bitOut(:) = crcVector(symbolCount-(Npad+Nts+numberSymbols+16));
else
inPacketFlag = 0; %we're done
end
%leadValue = 0;
% here we have the bit going out so if past Nts+Npad then form CRC.
% Note that we throw 16 zeros on the end in order to flush the CRC
if symbolCount > Npad+Nts && symbolCount <= Npad+Nts+numberSymbols+16
valueCRCsh1 = bitsll(valueCRC, 1);
valueCRCadd1 = bitor(valueCRCsh1, fi(bitOut, 0,16,0, fm));
leadValue = bitget(valueCRCadd1,16);
if leadValue == 1
valueCRCxor = bitxor(valueCRCadd1, genPoly);
else
valueCRCxor = valueCRCadd1;
end
valueCRC = valueCRCxor;
if symbolCount == Npad+Nts+numberSymbols+16
crcVector(:) = bitget( valueCRC, 16:-1:1);
end
end
if diffOn == 0 || symbolCount <= Npad+Nts
symbolOut(:) = bitOut;
else
if bitPrev == bitOut
symbolOut(:) = 1;
else
symbolOut(:) = 0;
end
end
bitPrev(:) = symbolOut;
symbolCount = symbolCount + 1; %total number of symbols transmitted
else
% we're not processing a packet and waiting for a new packet to arrive
if emptyFlag == 0
% reset everything
inPacketFlag = 1;
% toggle re to grab data
reByte = 1;
symbolCount = 1;
bitOfByteIndex = 1;
valueCRC(:) = 65535;
bitPrev(:) = 0;
end
end
end
type(testbench_name);
function mlhdlc_comms_data_packet_tb
%
% Copyright 2011-2015 The MathWorks, Inc.
% generate transmit data, note the first two bytes are the data length
numberBytes = 8; % this is total number of symbols
numberSymbols = numberBytes*8;
rng(1); % always default to known state
data = [floor(numberBytes/2^8) mod(numberBytes,2^8) ...
round(rand(1,numberBytes-2)*255)];
% generate training data helper function
make_train_data('TRAIN_DATA');
% make sure training data is generated
pause(2)
[~] = which('TRAIN_DATA');
trainBits1 = TRAIN_DATA;
Nts = length(trainBits1);
make_pad_data('PAD_DATA');
pause(2)
[~] = which('PAD_DATA');
Npad = 2^9;
% Give number of samples, where the start of the sequence flag will be
% (indicated by a zero), as well as an output buffer for generated symbols
Nsamp = 1000;
Noffset = 20;
emptyFlagHold = ones(1,Nsamp); emptyFlagHold(Noffset) = 0;
symbolOutHold = zeros(1,Nsamp);
dataIndex = 1;
byteValue = 0;
diffOn = 1; % 0 - regular encoding, 1 - differential encoding
for i1 = 1:Nsamp
emptyFlag = emptyFlagHold(i1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Call to the design
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[symbolOut, reByte] = ...
mlhdlc_comms_data_packet(emptyFlag, byteValue, numberSymbols, diffOn, Nts, Npad);
% This set of code emulates the external FIFO interface
if reByte == 1 % when high, pop a value off the input FIFO
byteValue = data(dataIndex);
dataIndex = dataIndex + 1;
end
symbolOutHold(i1) = symbolOut;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This is all code to verify we did the encoding properly
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% grad training data - not differentially encoded
symbolTrain = symbolOutHold(1+Noffset+Npad:Noffset+Npad+Nts);
% grab user data and decode if necessary
symbolEst = zeros(1,numberSymbols);
symbolPrev = trainBits1(end);
if diffOn == 0
symbolData = ...
symbolOutHold(1+Noffset+Npad+Nts:Noffset+Npad+Nts+numberSymbols); %#ok<NASGU>
else
% decoding is simply comparing adjacent received symbols
symbolTemp = ...
symbolOutHold(1+Noffset+Npad+Nts:Noffset+Npad+Nts+numberSymbols+32);
for i1 = 1:length(symbolTemp)
if symbolTemp(i1) == symbolPrev
symbolEst(i1) = 1;
else
symbolEst(i1) = 0;
end
symbolPrev = symbolTemp(i1);
end
end
% training data
trainDataEst = symbolTrain(1:Nts);
trainDiff = abs(trainDataEst-trainBits1');
% user data
userDataEst = symbolEst(1:numberSymbols);
dataEst = zeros(1,numberBytes);
for i1 = 1:numberBytes
y = userDataEst((i1-1)*8+1:i1*8);
dataEst(i1) = bin2dec(char(y+48));
end
userDiff = abs(dataEst-data);
disp(['Training Difference: ',num2str(sum(trainDiff)), ...
' User Data Difference: ',num2str(sum(userDiff))]);
% run it through and check CRC
genPoly = 69665;
c = symbolEst;
cEst = c(1,:);
cEst2 = [cEst(1:end-32) cEst(end-15:end)];
cEst = cEst2;
valueCRCc = 65535;
for i1 = 1:length(cEst)
valueCRCsh1 = bitsll(uint16(valueCRCc), 1);
valueCRCadd1 = bitor(uint16(valueCRCsh1), cEst(i1));
leadValue = bitget( valueCRCadd1, 16);
if (leadValue == 1)
valueCRCxor = bitxor(uint16(valueCRCadd1), uint16(genPoly));
else
valueCRCxor = bitxor(uint16(valueCRCadd1), 0);
end
valueCRCc = valueCRCxor;
end
if valueCRCc == 0
disp('CRC decoded correctly');
else
disp('CRC check failed');
end
function make_train_data(filename)
x = load('mlhdlc_dpack_train_data.txt');
fid = fopen([filename,'.m'],'w+');
fprintf(fid,['function y = ' filename '\n']);
fprintf(fid,'%%#codegen\n');
fprintf(fid,'y = [\n');
fprintf(fid,'%1.0e\n',x);
fprintf(fid,'];\n');
fclose(fid);
function make_pad_data(filename)
rng(1);
x = round(rand(1,2^9));
fid = fopen([filename,'.m'],'w+');
fprintf(fid,['function y = ' filename '\n']);
fprintf(fid,'%%#codegen\n');
fprintf(fid,'y = [\n');
fprintf(fid,'%1.0e\n',x);
fprintf(fid,'];\n');
fclose(fid);
Simulate the Design
Before code generation, simulate the design by using the test bench to make sure that there are no run-time errors.
mlhdlc_comms_data_packet_tb
Training Difference: 0 User Data Difference: 0 CRC decoded correctly
Create HDL Coder™ Project
coder -hdlcoder -new mlhdlc_dpack
Add the file mlhdlc_comms_data_packet.m to the project as the MATLAB Function and mlhdlc_comms_data_packet_tb.m as the MATLAB Test Bench.
For more information, see Get Started with MATLAB to High-Level Synthesis Workflow Using the Command Line Interface or Get Started with MATLAB to High-Level Synthesis Workflow Using HDL Coder App.
Run Fixed-Point Conversion and HLS Code Generation
To generate HLS code from a MATLAB design:
1. At the MATLAB command line, setup the path for HLS code generation by using the function hdlsetuphlstoolpath.
2. Start the Workflow Advisor by clicking the Workflow Advisor button.
3. In the HDL Workflow Advisor, select Code Generation Workflow as MATLAB to HLS.
4. Select Cadence Stratus HLS as the Synthesis tool for Select Code Generation Target.
5. Right-click the HLS Code Generation and choose the option Run to selected task to run all the steps from the beginning through the HLS code generation.
Examine the generated HLS code by clicking the hyperlinks in the Code Generation Log window.