%% Verify Viterbi Decoder Using MATLAB System Object and HDL Simulator
% This example shows you how to use MATLAB(R) System objects and Mentor
% Graphics(R) ModelSim(R)/QuestaSim(R) or Cadence(R) Incisive(R)/Xcelium(R)
% to cosimulate a Viterbi decoder implemented in VHDL.

%   Copyright 2011-2018 The MathWorks, Inc.

%% Set Simulation Parameters and Instantiate Communication System Objects
%
% If you are using Incisive/Xcelium, set simulator variable to 'Incisive'
Simulator = 'Incisive';
%%
% or if you are using ModelSim/QuestaSim, set simulator variable to
% 'ModelSim'
%%
%   Simulator = 'ModelSim';
%%
% The following code sets up the simulation parameters and instantiates the
% system objects that represent the channel encoder, BPSK modulator, AWGN
% channel, BPSK demodulator, and error rate calculator. Those objects
% comprise the system around the Viterbi decoder and can be thought of as
% the test bed for the Viterbi HDL implementation.
%%
EsNo = 0;	% Energy per symbol to noise power spectrum density ratio in dB
FrameSize = 1024;  % Number of bits in each frame
%%
% Convolution Encoder
hConEnc = comm.ConvolutionalEncoder; 
%%
% BPSK Modulator
hMod    = comm.BPSKModulator;        
%%
% AWGN channel
hChan   = comm.AWGNChannel('NoiseMethod', ...
                           'Signal to noise ratio (Es/No)',...
                           'SamplesPerSymbol',1,...
                           'EsNo',EsNo);
%%
% BPSK demodulator                       
hDemod  = comm.BPSKDemodulator('DecisionMethod','Log-likelihood ratio',...
                               'Variance',0.5*10^(-EsNo/10));
%%                           
% Error Rate Calculator                           
hError  = comm.ErrorRate('ComputationDelay',100,'ReceiveDelay', 58);

%% Instantiate the Cosimulation System Object
% The hdlcosim function returns an HDL cosimulation System object, which
% represents the HDL implementation of the Viterbi decoder in this
% simulation system.  The object's interface is common for all simulators.
% As a convenience to avoid writing some HDL testbench code, we generate 
% waveforms for the clocks and resets using simulator-specific Tcl code.
%%
hDec = hdlcosim('InputSignals', {'/viterbi_block/In1','/viterbi_block/In2'}, ...
                'OutputSignals', {'/viterbi_block/Out1'}, ...
                'OutputSigned', false, ...
                'OutputFractionLengths', 0, ...                   
                'TCLPostSimulationCommand', 'echo "done";', ...
                'PreRunTime', {10,'ns'}, ...
                'Connection', {'Shared'}, ... 
                'SampleTime', {10,'ns'});
switch Simulator
    case 'ModelSim'
        hDec.TCLPreSimulationCommand = ...
            'force /viterbi_block/clk_enable 1 0; force /viterbi_block/clk 0 0 ns, 1 5 ns -repeat 10 ns; force /viterbi_block/reset 1 0 ns, 0 8 ns; ';
    case 'Incisive'
        hDec.TCLPreSimulationCommand = ...
            'force :clk B"0" -after 0ns B"1" -after 5ns -repeat 10ns; force reset B"1" -after 0ns B"0" -after 8ns; force :clk_enable B"1" -after 0ns';
end
        

%% Launch HDL Simulator
% The vsim and nclaunch command launches HDL simulator. The launched HDL
% simulator session compiles the HDL design and loads the HDL simulation.
% You are ready to perform cosimulation when the HDL simulation is fully
% loaded in simulator.
%%
disp('Launching HDL simulator...');
switch Simulator
    case 'ModelSim'
        vsim('tclstart',viterbi_cosimulation_tclcmds('vsimmatlabsysobj'));
    case 'Incisive'
        nclaunch('tclstart',viterbi_cosimulation_tclcmds('hdlsimmatlabsysobj'));
end
Timeout=30;
processid = pingHdlSim(Timeout);
% Check if HDL simulator is ready for Cosimulation.
assert(ischar(processid),['Timeout: HDL simulator took more than ', num2str(Timeout),' seconds to setup,please increase the timeout in ''pingHdlSim''']);
disp('...Simulator is ready for cosimulation.');

              
%% Run Cosimulation
% This example simulates the BPSK communication system in MATLAB
% incorporating the Viterbi decoder HDL implementation via the cosimulation
% System object. This section of the code calls the processing loop to
% process the data frame-by-frame with 1024 bits in each data frame.
%%
for counter = 1:20480/FrameSize
    data            = randi([0 1],FrameSize,1);
    encodedData     = step(hConEnc, data);
    modSignal       = step(hMod, encodedData);
    receivedSignal  = step(hChan, modSignal);
    demodSignalSD   = step(hDemod, receivedSignal);
    quantizedValue  = fi(4-demodSignalSD,0,3,0);
    input1          = quantizedValue(1:2:2*FrameSize);
    input2          = quantizedValue(2:2:2*FrameSize);
    receivedBits    = step(hDec,input1, input2);
    errors          = step(hError, data, double(receivedBits));
end

%% Display the Bit-Error Rate
% The Bit-Error Rate is displayed for the Viterbi decoder.
sprintf('Bit Error Rate is %d\n',errors(1))

%% Destroy Cosimulation System Object to Release HDL Simulator
% The HDL simulator is unblocked when the HDL cosimulation system object is
% destroyed in MATLAB. Close the HDL simulator session manually.
clear hDec;

%%
% This concludes the "Verify Viterbi Decoder Using MATLAB System Object and
% HDL Simulator".
