A
alb
Hi all,
this thread is intended for testbench only, no RTL needed.
I've just finished to read JB's 'Writing Testbenches' 2nd edition and I
must say that I found it quite enlightening.
The model he proposes to write testbenches is essentially to wrap away
the physical interface of the DUT and provide a level of abstraction to
the testcases so that interface implementation changes do not affect the
rewrite of the testcases.
The book covers well the fact that a package is not a 'structural
element' in VHDL, therefore you cannot abstract away the interface by
means of a package (you always need to pass all the signals in your
procedure call) and a bus functional model entity is proposed in place
(for details see pag. 325 - VHDL TEST HARNESS).
His proposal, as I think I have understood, is to use an entity with a
'server' process which is implementing the bus functional model while
serving 'abstract' requests from the client process which does not know
the details of the physical interface. Abstract signals to handle
handshake between client and server are also needed, but the great
advantage of the proposed method is that test cases are now at a much
higher level and have no details referred to the DUT (a test case for a
read/modify/write operation can be completely independent on the DUT and
the test case may be reused for very many projects where read/write
operations are meaningful).
I started out writing like hell the various elements of my bus
functional model, the test harness and some of the test cases, but now
my problem is the following: my 'server' has to perform abstract actions
(read_data, write_data, setup_interface, generate_input_pattern, ...)
which are essentially mapped to an 'address'. To be more specific, my
test case would call a procedure like this:
procedure exec( type: in bool; -- read/write
addr: in natural; -- what to do
data: inout natural; -- data provided or returned
signal: to_server: out to_srv_control; --handshake
signal: from_server: in frm_srv_control
; --handshake
while the test case will look like:
-- RD/WR are type defined as true/false
exec(RD, reg0, data, to_srv, frm_srv);
exec(WR, reg1, data, to_srv, frm_srv);
exec(WR, reg2, data, to_srv, frm_srv);
....
by changing the address (reg[0,1,2]) we may want to either send a pulse
to the interface or have a write cycle, the server needs to have some
sort of switch statement based on the 'address' content and call the
appropriate procedure where the appropriate operation is performed.
Given the fact that I'm extremely lazy, in C I would solve this problem
with a simple table (possibly stored in a struct) with two elements, an
address and a function pointer initialized to a specific function. A
'for loop' will then check the function to call every time there's a new
request from the client (only problem is that with this approach the
function parameters should be standardized for all functions, but this
is a different problem).
Now, after all this chatter, comes the real question: is there a way to
write a 'table' (maybe an array of registers), in which one element is
the address and the other is a procedure call, in such a way that every
time I need to add a new address and a new procedure call I simply
extend the table without touching the 'for loop' part of the code?
I'm not sure the problem is clear and if the additional context is
helping understanding my question, but that was my intent.
Thank you all for any hint.
Al
this thread is intended for testbench only, no RTL needed.
I've just finished to read JB's 'Writing Testbenches' 2nd edition and I
must say that I found it quite enlightening.
The model he proposes to write testbenches is essentially to wrap away
the physical interface of the DUT and provide a level of abstraction to
the testcases so that interface implementation changes do not affect the
rewrite of the testcases.
The book covers well the fact that a package is not a 'structural
element' in VHDL, therefore you cannot abstract away the interface by
means of a package (you always need to pass all the signals in your
procedure call) and a bus functional model entity is proposed in place
(for details see pag. 325 - VHDL TEST HARNESS).
His proposal, as I think I have understood, is to use an entity with a
'server' process which is implementing the bus functional model while
serving 'abstract' requests from the client process which does not know
the details of the physical interface. Abstract signals to handle
handshake between client and server are also needed, but the great
advantage of the proposed method is that test cases are now at a much
higher level and have no details referred to the DUT (a test case for a
read/modify/write operation can be completely independent on the DUT and
the test case may be reused for very many projects where read/write
operations are meaningful).
I started out writing like hell the various elements of my bus
functional model, the test harness and some of the test cases, but now
my problem is the following: my 'server' has to perform abstract actions
(read_data, write_data, setup_interface, generate_input_pattern, ...)
which are essentially mapped to an 'address'. To be more specific, my
test case would call a procedure like this:
procedure exec( type: in bool; -- read/write
addr: in natural; -- what to do
data: inout natural; -- data provided or returned
signal: to_server: out to_srv_control; --handshake
signal: from_server: in frm_srv_control
while the test case will look like:
-- RD/WR are type defined as true/false
exec(RD, reg0, data, to_srv, frm_srv);
exec(WR, reg1, data, to_srv, frm_srv);
exec(WR, reg2, data, to_srv, frm_srv);
....
by changing the address (reg[0,1,2]) we may want to either send a pulse
to the interface or have a write cycle, the server needs to have some
sort of switch statement based on the 'address' content and call the
appropriate procedure where the appropriate operation is performed.
Given the fact that I'm extremely lazy, in C I would solve this problem
with a simple table (possibly stored in a struct) with two elements, an
address and a function pointer initialized to a specific function. A
'for loop' will then check the function to call every time there's a new
request from the client (only problem is that with this approach the
function parameters should be standardized for all functions, but this
is a different problem).
Now, after all this chatter, comes the real question: is there a way to
write a 'table' (maybe an array of registers), in which one element is
the address and the other is a procedure call, in such a way that every
time I need to add a new address and a new procedure call I simply
extend the table without touching the 'for loop' part of the code?
I'm not sure the problem is clear and if the additional context is
helping understanding my question, but that was my intent.
Thank you all for any hint.
Al