HDLCoder hdl.ram: Error System Object methods can only be called once

조회 수: 1 (최근 30일)
Hi, I'm a Senior Staff Engineer at Northrop Grumman:
I am putting together a Matched Filter for a Software Defined Radio. I setup two separate ram.hdl blocks, one for the PN code and another for the Rx Samples. Both blocks have separate address, dataIn and dataOut ports.
For reasons I don't understand, during HDL code generation, I get an error: system object methods can only be called once. This occurs in the if FSel == 2 code. I was hoping the separate address and data buses would let me call both of the RAM banks in ONE clock cycle. When I look at the VHDL code in Vivado, I see there is only one 'CLK_IO_Buf', and it goes to both of the RAM banks... if there's a workaround for this or some enlightenment on whether there is a way to gen separate clocks, I'd appreciate it.
Best,
Dr. W. Kurt Dobson
SLC, UT
%% ram_HDLTB Test Bench
%
clear all
close all
%
% Read PN
%
PN = ML13();
PN = PN(1:4095); % use half of ML13 code
PN = PN.*8191; % scale to in 13
%
Len = 4095;
PNLen = 4095;
%
%ramDataIn = fi(randi((2^16)-1,1,Len),0,16,0); % random data set
PNDataIn = fi(PN,0,13,0);
RAMDataIn = fi(PN,0,13,0); % ** next will be MFBuf
PadPNData = fi(0,0,13,0);
PadRx = fi(0,0,13,0);
PNAddr = fi([1:Len],0,12,0);
RAMWriteAddr = fi([1:Len],0,12,0);
PadAdr = fi(0,0,12,0);
%
%% Set and Test PN RAM
%
FSel = 0; % select PN RAM
for ii = 1:Len
[PNrdOut(ii),~, MF] = ram_HDL(FSel,PNDataIn(ii), PNAddr(ii),PadPNData,PadAdr,true); % write banks 1
end
% Read and test
for ii = 1:Len
[PNrdOut(ii),~, MF] = ram_HDL(FSel, PNDataIn(ii), PNAddr(ii),PadPNData, PadAdr,false); % read banks 1
end
%
% ** will need to adjust for clock -1
PNErr = sum(PNDataIn == PNrdOut);
fprintf('PN RAM Errors = %6.0f\n',PNErr)
%
%% Setup and Test Rx RAM
%
FSel = 1; % select PN RAM
for ii = 1:Len
[~,RAMrdOut(ii),MF] = ram_HDL(FSel,PadPNData, PadAdr, RAMDataIn(ii),RAMWriteAddr(ii),true); % write banks 1
end
% Read and test
for ii = 1:Len
[~,RAMrdOut(ii),MF] = ram_HDL(FSel,PadPNData, PadAdr, RAMDataIn(ii),RAMWriteAddr(ii),false); % read banks 1
end
%
RAMErr = sum(PNDataIn == PNrdOut); % ** Ne
fprintf('Rx RAM Errors = %6.0f\n',RAMErr);
%
%% Gen Matched filter Cycle
%
FSel = 2; % set hdl function to PN/MF cycle
rw = false; % set for read on both banks
for k = 1:PNLen
[PNrdOut(k), RAMrdOutMF(k),MF] = ram_HDL(FSel,PNDataIn(k), PNAddr(k), RAMDataIn(k), RAMWriteAddr(k),rw);
end
%%
function [PNrdOut,RAMrdOut, MF] = ram_HDL(FSel,PNDataIn, PNWriteAddr, RAMDataIn, RAMWriteAddr,rw)
%
% This code runs an HDL operation
% FSel determines operation
% 0 = r/w cycle to PN (ram_2p)
% 1 = r/w cycle to Rx (ram_Rx) |FSEL|PNData | PN Adr | RAM Data | RAM Adr | R/W|
%
persistent ram_2p ram_Rx
%
PNrdOut = fi(0,0,13,0); % avoid fall-through errors
RAMrdOut = fi(0,0,13,0);
PNSample = fi(0,0,13,0);
RxSample = fi(0,0,13,0);
MaxVal = fi(0,0,14,0);
MF = fi(0,0,15,0);
%
% Setup PN and RAM O
%
if isempty(ram_2p)
ram_2p = hdl.RAM('RAMType','Single port','WriteOutputValue','New data');
end
%
if isempty(ram_Rx)
ram_Rx = hdl.RAM('RAMType','Single port','WriteOutputValue','New data');
end
%
if FSel == 0 % rw to PN
PNrdOut = ram_2p(PNDataIn,PNWriteAddr-1,rw);
end
%
% RxQueue RAM Operations
%
if FSel == 1
[RAMrdOut] = ram_Rx(RAMDataIn,RAMWriteAddr-1,rw);
end
%
% PN/RxQueue Matched Filter Cycle
% ** Idea: Just one line call in TB??? May still not work
if FSel == 2 % single cycle read of both PN and RxQueue
PNSample = ram_2p(PNDataIn, PNWriteAddr-1,rw);
RxSample = ram_Rx(RAMDataIn,RAMWriteAddr-1,rw);
% MF = MaxVal - (PNSample - RxSample);
end
end
%%
function G = ML13() % Generate Maximal Length PN code
%
% Next, Generate ML of Length x^10
% Gold code N=10, G1 = 1+x^7+x^10, G2 = 1+x^2+x^7+x^8+x^10
%
S = [13 12 11 10 9 6 0];
n = S(1); n2 = S(2); n3 = S(3); n4 = S(4); n5 = S(5); n6 = S(6);
% S = [10 8 7 2 0]; n = S(1); n2 = S(2); n3 = S(3); n4 = S(4);
R = ones(1,n);
L = 2^n-1;
%
T = [10 7 0]; m2 = T(2);
Q = ones(1,n);
%
for i=1:L
G(i)=mod(R(n),2);
R=[mod(R(n)+R(n2)+R(n3)+R(n4)+R(n5)+R(n6),2) R(1:n-1)];
%Q=[mod(Q(n)+Q(m2),2) Q(1:n-1)];
end
end

채택된 답변

Ryan Baird
Ryan Baird 2023년 1월 8일
The problem here isn't that you're using both ram_2p and ram_rx (that is allowed), but that HDL Coder doesn't know this access pattern will only be a single access to ram_2p:
if FSel == 0
PNrdOut = ram_2p(PNDataIn,PNWriteAddr-1,rw);
end
% ...
if FSel == 2
PNSample = ram_2p(PNDataIn, PNWriteAddr-1,rw);
% ...
end
If you write this so that there is a single call to ram_2p:
if FSel == 0 || FSel == 2
ram2pout = ram_2p(PNDataIn,PNWriteAddr-1,rw);
if(FSel == 0)
PNrdOut = ram2pout;
else
PNSample = ram2pout;
end
end
And you do the same for ram_Rx, HDL coder should not throw the error about system objects being called more than once.

추가 답변 (1개)

Kiran Kintali
Kiran Kintali 2023년 1월 8일
편집: Kiran Kintali 2023년 1월 8일
can you please share the design.m, testbench.m and matched_filter.prj files associated with the matched filter design with the codegen settings?
The current limitation for hdl.RAM or any other system object with state is that you instantate them once in the design and not call them in the conditional regions.
You can compute the read, write address and data variables inside the conditional regions and use them in the hdl.RAM instance.
% you can compute input variables in control logic (if/switch conditions)
ramWriteAddr = ...;
ramWriteData = ...;
ramWriteEnable = ...;
ramReadAddr = ...;
% execute single step of RAM
% this call to the step function needs to be outside the conditionals
% this call will be inferred as a RAM instantiation in RTL (VHDL/Verilog)
[~, ramRdDout] = step(hRam, ramWriteData, ramWriteAddr, ramWriteEnable, ramReadAddr);
% you can use the output variables in control logic (if/switch conditions)
someConditionalVar = ramRdDout;
This limitation will be relaxed in future.

제품


릴리스

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by