added initial version of actsim support
This commit is contained in:
parent
952cf050c8
commit
3f8293e16a
|
@ -40,3 +40,6 @@ ASSURA/
|
|||
ncvlog.log
|
||||
ConnectedPinsLog.txt
|
||||
UnconnectedPinsLog.txt
|
||||
*.os
|
||||
*.csv
|
||||
*.so
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 2018 Rajit Manohar
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
TARGETLIBS=actsim_test_bench_lib.so
|
||||
TARGETCONF=actsim_test_bench_lib.conf
|
||||
|
||||
SHOBJS=test_bench_lib.os
|
||||
|
||||
|
||||
SRCS= $(SHOBJS:.os=.c)
|
||||
|
||||
include $(ACT_HOME)/scripts/Makefile.std
|
||||
|
||||
$(TARGETLIBS): $(SHOBJS)
|
||||
$(ACT_HOME)/scripts/linkso $(TARGETLIBS) $(SHOBJS)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
begin sim
|
||||
|
||||
begin extern
|
||||
string_tablex libs "test_bench_lib"
|
||||
begin test_bench_lib
|
||||
string path "$ACT_HOME/lib/actsim_test_bench_lib.so"
|
||||
string sim::testbench::fsource_init "source_init"
|
||||
string sim::testbench::fsource_next "source_next"
|
||||
string sim::testbench::fsource_get "source_get"
|
||||
string sim::testbench::fcheck_out_of_order "check_out_of_order"
|
||||
string sim::testbench::fcheck_in_order "check_in_order"
|
||||
string sim::testbench::fcheck_next "check_next"
|
||||
string sim::testbench::fdump_to_file "dump_to_file"
|
||||
string sim::testbench::fcontrol_next "control_next"
|
||||
string sim::testbench::fcontrol_next "control_get"
|
||||
string sim::testbench::fcontrol_next "control_wait"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,127 @@
|
|||
|
||||
/*************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2022 Ole Richter - University of Groningen
|
||||
* Copyright 2022 Michele Mastella - University of Groningen
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
namespace sim::testbench {
|
||||
|
||||
function fsource_init(int verbose) : int;
|
||||
function fsource_next(int id; int sim_step) : int;
|
||||
function fsource_get(int id; int bit_width) : int;
|
||||
function fcheck_next(int id; int sim_step) : int;
|
||||
function fcheck_in_order(int id; int data) : int;
|
||||
function fcheck_out_of_order(int id; int data) : int;
|
||||
function fdump_to_file(int id; int sim_step; int data) : int;
|
||||
|
||||
template<pint BIT_WIDTH;pint ID>
|
||||
defproc channel_source(chan!(int<BIT_WIDTH>) out; chan?(int) sim_step; chan!(int) done)
|
||||
{
|
||||
int current_step, t,data;
|
||||
chp {
|
||||
*[ sim_step?current_step; t := 1;
|
||||
*[ t = 1 -> t := fchannel_source_next(ID,current_step);
|
||||
[ t = 1 -> data := fchannel_source_get(ID,BIT_WIDTH); out!data ; log("send ", data, " on source ", ID)
|
||||
[] else -> done!1
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template<pint BIT_WIDTH;pint ID>
|
||||
defproc channel_checker_in_order(chan?(int<BIT_WIDTH>) in; chan?(int) sim_step; chan!(int) done)
|
||||
{
|
||||
int current_step, t, check, data;
|
||||
chp {
|
||||
*[ sim_step?current_step; t := 1;
|
||||
*[ t = 1 -> t := fcheck_next(ID,current_step);
|
||||
[ t = 1 -> in?data; check := fcheck_in_order(ID,data);
|
||||
[check = 1 -> log("[success] got ",data, " on check ", ID)
|
||||
[] else -> log("[failure] got wrong ",data, " on check ", ID, " see log")
|
||||
]
|
||||
[] else -> done!1
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template<pint BIT_WIDTH;pint ID>
|
||||
defproc channel_checker_out_of_order(chan?(int<BIT_WIDTH>) in; chan?(int) sim_step; chan!(int<1>) done)
|
||||
{
|
||||
int current_step, t, check, data;
|
||||
chp {
|
||||
*[ sim_step?current_step; t := 1;
|
||||
*[ t = 1 -> t := fcheck_next(ID,current_step);
|
||||
[ t = 1 -> in?data; check := fcheck_out_of_order(ID,data);
|
||||
[check = 1 -> log("[success] got ",data, " on check ", ID)
|
||||
[] else -> log("[failure] got wrong ",data, " on check ", ID, " see log")
|
||||
]
|
||||
[] else -> done!1
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template<pint BIT_WIDTH;pint ID>
|
||||
defproc channel_dump(chan?(int<BIT_WIDTH>) in; chan?(int) sim_step)
|
||||
{
|
||||
int current_step, t;
|
||||
chp {
|
||||
*[ [ #sim_step -> sim_step?current_step
|
||||
| #in -> t:=fdump_to_file(ID,current_step,in)
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template<pint NUMBER_SOURCE,NUMBER_CHECKER,NUMBER_DUMP;pbool HALT_ON_FALIURE>
|
||||
defproc control(chan(int) sim_step_source[NUMBER_SOURCE]; chan(int) sim_step_checker[NUMBER_CHECKER]; chan(int) sim_step_dump[NUMBER_DUMP]; chan?(int<1>) done_source[NUMBER_SOURCE]; chan?(int<1>) done_checker[NUMBER_CHECKER])
|
||||
{
|
||||
int current_step, wait;
|
||||
int<1> t, success, failure_free;
|
||||
chp {
|
||||
t:=1;
|
||||
failure_free:=1;
|
||||
*[ t = 1 -> current_step := fcontrol_get();
|
||||
[ current_step = 0 -> skip; // reset here
|
||||
[] else ->
|
||||
(,:j:1..NUMBER_SOURCE: sim_step_source[j]!current_step),
|
||||
(,:j:1..NUMBER_CHECKER: sim_step_checker[j]!current_step),
|
||||
(,:j:1..NUMBER_DUMP: sim_step_dump[j]!current_step);
|
||||
(:j:1..NUMBER_SOURCE: done_source[j]?success; failure_free := failure_free & success);
|
||||
(:j:1..NUMBER_CHECKER: done_checker[j]?success; failure_free := failure_free & success);
|
||||
];
|
||||
wait := fcontrol_wait();
|
||||
[ wait > 0 -> skip // exec cycle
|
||||
[] else -> skip
|
||||
];
|
||||
[ HALT_ON_FALIURE & ~failure_free -> t := 0; log("stopped testbech because of failure")
|
||||
[] else -> t:=fcontrol_next()
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,466 @@
|
|||
/*************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2022 Ole Richter - University of Groningen
|
||||
* Copyright 2022 Michele Mastella - University of Groningen
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* this file contains all the helper fucntions to read the CSV test benches.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <act/actsim_ext.h>
|
||||
|
||||
/**
|
||||
* the arrays are staticly allocated, like how many sources aor checks there are, they can be easily increased and recompiled
|
||||
* the defaults are thought to be fine for most smaller test benches
|
||||
* also the standard file naming and that the csv is using a ; as seperator can be changed
|
||||
*/
|
||||
|
||||
#define MAX_SOURCES 100
|
||||
#define MAX_CHECKERS 100
|
||||
#define MAX_CHECKS 100000
|
||||
#define MAX_DUMP 100
|
||||
#define CSV_FORMAT "%u; %lu"
|
||||
#define CSV_WRITE_FORMAT "%d; %d\n"
|
||||
#define SOURCE_FILENAME "source_%d.csv"
|
||||
#define CHECK_FILENAME "check_%d.csv"
|
||||
#define DUMP_FILENAME "dump_%d.csv"
|
||||
#define CONTROL_FILENAME "control.csv"
|
||||
#define LOG_FILENAME "test_bench_helper.log"
|
||||
|
||||
/**
|
||||
* as the testbench is calling the functions, all state variables need to be static so they are the same state whenever called
|
||||
*
|
||||
*/
|
||||
|
||||
// all opened files for the text bench
|
||||
static FILE *source_file[MAX_SOURCES];
|
||||
static FILE *check_file[MAX_CHECKERS];
|
||||
static FILE *dump_file[MAX_DUMP];
|
||||
static FILE *control_file;
|
||||
|
||||
// the data variable buffers, as we can only deliver one variable at a time,
|
||||
// so first is there a variable and than the varibale itself
|
||||
static unsigned int source_sim_step[MAX_SOURCES];
|
||||
static unsigned int check_sim_step[MAX_CHECKERS];
|
||||
static unsigned long source_data_buffer[MAX_SOURCES];
|
||||
static unsigned long check_data_buffer[MAX_CHECKERS][MAX_CHECKS];
|
||||
static unsigned short check_data_used[MAX_CHECKERS][MAX_CHECKS];
|
||||
static unsigned int check_data_number[MAX_CHECKERS];
|
||||
|
||||
// as printing does not get dispayed in actsim, print to logfile
|
||||
static FILE *logfile = NULL;
|
||||
|
||||
// show more info like words/tests read
|
||||
static int verbose = 0;
|
||||
|
||||
// keep a memory at which simulation step we are in the files
|
||||
static unsigned long last_sim_step = 0;
|
||||
static unsigned int first_sim_step = 0;
|
||||
static unsigned long current_sim_step = 0;
|
||||
static unsigned long current_sim_wait = 1;
|
||||
static unsigned int check_errors = 0;
|
||||
|
||||
/**
|
||||
* Init opens all the files and reads the control
|
||||
* it requires one int:
|
||||
* verbose: 0 for normal pinting, 1 for verbose printing
|
||||
* it returns true on success
|
||||
*/
|
||||
struct expr_res init (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0;
|
||||
t.width = 1;
|
||||
check_errors = 0;
|
||||
logfile = fopen(LOG_FILENAME, "w");
|
||||
if (num !=1 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in init"); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
verbose = args[0].v;
|
||||
fprintf(logfile,"==== initialising control ====\n"); fflush(logfile);
|
||||
control_file = fopen (CONTROL_FILENAME, "r");
|
||||
int success = 0;
|
||||
success = fscanf(control_file, CSV_FORMAT, &first_sim_step, &last_sim_step);
|
||||
if (success != 2) {
|
||||
if(ferror(source_file[args[0].v])){
|
||||
fprintf(logfile,"read error on control\n"); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
else {
|
||||
fprintf(logfile,"empty file for control\n"); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(logfile,"==== initialising source ====\n"); fflush(logfile);
|
||||
int i = 0;
|
||||
for (i = 0; i<MAX_SOURCES; i++){
|
||||
source_sim_step[i] = 0;
|
||||
char filename[255];
|
||||
snprintf(filename, 255, SOURCE_FILENAME,i);
|
||||
source_file[i] = fopen (filename, "r");
|
||||
if (source_file[i]){
|
||||
fprintf(logfile, "source id %d -> %s\n",i,filename); fflush(logfile);
|
||||
}
|
||||
}
|
||||
fprintf(logfile,"==== initialising check ====\n"); fflush(logfile);
|
||||
|
||||
for (i = 0; i<MAX_CHECKERS; i++){
|
||||
check_sim_step[i] = 0;
|
||||
char filename[255];
|
||||
snprintf(filename, 255, CHECK_FILENAME,i);
|
||||
check_file[i] = fopen (filename, "r");
|
||||
if (check_file[i]){
|
||||
fprintf(logfile, "check id %d -> %s\n",i,filename); fflush(logfile);
|
||||
}
|
||||
}
|
||||
fprintf(logfile,"==== initialising done ====\n"); fflush(logfile);
|
||||
t.v = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* check_next looks if there is an other check availible in that simulation step
|
||||
* if a new simulation step is loaded all checks from this step will be cashed into the arrays
|
||||
* it requires 2 int:
|
||||
* id: the id of the checker
|
||||
* simstep: the simulation step the next test to be loaded from
|
||||
* it returns 1 if there is a check availible, 0 if not or an error occured
|
||||
*/
|
||||
struct expr_res check_next (int num, struct expr_res *args){
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 1;
|
||||
if (num !=2 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in channel_check\n"); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
if (!check_file[args[0].v]) {
|
||||
fprintf(logfile,"[ERROR] could not read check %d, file not open or does not exist\n",args[0].v); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
int step_done = 0, i = 0;
|
||||
unsigned int check_sim_step_file = 0;
|
||||
unsigned long int sim_data_file = 0;
|
||||
// check if we need to advnce one step
|
||||
if (check_sim_step[args[0].v] != args[1].v){
|
||||
// print all missed steps
|
||||
for (i = 0; i < check_data_number[args[0].v]; i++){
|
||||
if (check_data_used[args[0].v][i] == 0) {
|
||||
check_errors++;
|
||||
fprintf(logfile,"[FAILURE] missed %d on check %d - %d for simstep %d; Error count: %d\n",check_data_buffer[args[0].v],args[0].v,i,check_sim_step[args[0].v],check_errors); fflush(logfile);
|
||||
}
|
||||
}
|
||||
// load next step
|
||||
rewind(check_file[args[0].v]);
|
||||
check_sim_step[args[0].v] = args[1].v;
|
||||
unsigned int count = 0;
|
||||
// read next steps
|
||||
while (!step_done){
|
||||
int success = 0;
|
||||
success = fscanf(check_file[args[0].v], CSV_FORMAT, &check_sim_step_file, &sim_data_file);
|
||||
if (success != 2) {
|
||||
if(ferror(check_file[args[0].v])) fprintf(logfile,"read error on check %d\n",args[0].v);
|
||||
if(verbose) fprintf(logfile,"EOF on check %d\n",args[0].v); fflush(logfile);
|
||||
step_done = 1;
|
||||
}
|
||||
else if (count >= MAX_CHECKS) {
|
||||
fprintf(logfile,"[ERROR] checks for sim step %d on checker %d, exceed the maximum number of checks, increase and recompile\n",args[0].v); fflush(logfile);
|
||||
}
|
||||
else if (check_sim_step_file == check_sim_step[args[0].v]){
|
||||
check_data_buffer[args[0].v][count] = sim_data_file;
|
||||
check_data_used[args[0].v][count] = 0;
|
||||
if(verbose) fprintf(logfile,"%d check %d on %d\n",count,check_data_buffer[args[0].v][count],args[0].v); fflush(logfile);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
check_data_number[args[0].v] = count;
|
||||
}
|
||||
// check if any checks have not been used yet
|
||||
for (i = 0; i < check_data_number[args[0].v]; i++){
|
||||
if (check_data_used[args[0].v][i] == 0) {
|
||||
t.v = 1 ;
|
||||
i = check_data_number[args[0].v];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* check_in_order compares a word to the next avaible word in the csv,
|
||||
* check_next has to be called before
|
||||
* it requres 2 ints:
|
||||
* id: the id of the checker
|
||||
* word to check: the word to compare
|
||||
* returns 1 on success and 0 on failure
|
||||
*/
|
||||
struct expr_res check_in_order (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 0;
|
||||
if (num !=2 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in channel_check\n");
|
||||
return t;
|
||||
}
|
||||
for (int i = 0; i < check_data_number[args[0].v]; i++){
|
||||
if (check_data_used[args[0].v][i] == 0) {
|
||||
if (check_data_buffer[args[0].v][i] == args[1].v){
|
||||
fprintf(logfile,"[SUCCESS] got %d = %d on check %d - %d\n",check_data_buffer[args[0].v],args[1].v,args[0].v,i); fflush(logfile);
|
||||
t.v = 1;
|
||||
}
|
||||
else {
|
||||
check_errors++
|
||||
fprintf(logfile,"[FAILURE] expected %d got %d on check %d - %d; Error count %d\n",check_data_buffer[args[0].v],args[1].v,args[0].v,i,check_errors); fflush(logfile);
|
||||
t.v = 0;
|
||||
}
|
||||
check_data_used[args[0].v][i] = 1;
|
||||
i = check_data_number[args[0].v];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t.width = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* check_out_of_order compares a word to the all avaible word in the csv for that step,
|
||||
* each word can only be used once.
|
||||
* check_next has to be called before
|
||||
* it requres 2 ints:
|
||||
* id: the id of the checker
|
||||
* word to check: the word to compare
|
||||
* returns 1 on success and 0 on failure
|
||||
*/
|
||||
struct expr_res check_out_of_order (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 0;
|
||||
if (num !=2 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in channel_check\n");
|
||||
return t;
|
||||
}
|
||||
for (int i = 0; i < check_data_number[args[0].v]; i++){
|
||||
if (check_data_used[args[0].v][i] == 0) {
|
||||
if (check_data_buffer[args[0].v][i] == args[1].v){
|
||||
fprintf(logfile,"[SUCCESS] got %d = %d on check %d - %d\n",check_data_buffer[args[0].v],args[1].v,args[0].v,i); fflush(logfile);
|
||||
t.v = 1;
|
||||
check_data_used[args[0].v][i] = 1;
|
||||
i = check_data_number[args[0].v];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (t.v == 0){
|
||||
check_errors++;
|
||||
fprintf(logfile,"[FAILURE] could not find %d on check %d; Error count: %d\n",check_data_buffer[args[0].v],args[1].v,args[0].v,check_errors); fflush(logfile);
|
||||
}s
|
||||
t.width = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* source_next looks if there is an other word availible to be send in the current simulation step
|
||||
* it loads that work into the buffer.
|
||||
* if a new simulation step is loaded the file is read from the beginning again.
|
||||
* it requires 2 int:
|
||||
* id: the id of the source
|
||||
* simstep: the simulation step the next test to be loaded from
|
||||
* it returns 1 if there is a source word availible, 0 if not or an error occured
|
||||
*/
|
||||
struct expr_res source_next (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 0;
|
||||
if (num !=2 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in channel_source_next\n"); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
if (!source_file[args[0].v]) {
|
||||
fprintf(logfile,"[ERROR] could not read source %d, file not open or does not exist\n",args[0].v); fflush(logfile);
|
||||
return t;
|
||||
}
|
||||
int step_done = 0;
|
||||
unsigned int source_sim_step_file = 0;
|
||||
unsigned long int sim_data_file = 0;
|
||||
if (source_sim_step[args[0].v] != args[1].v){
|
||||
rewind(source_file[args[0].v]);
|
||||
source_sim_step[args[0].v] = args[1].v;
|
||||
}
|
||||
while (!step_done){
|
||||
int success = 0;
|
||||
success = fscanf(source_file[args[0].v], CSV_FORMAT, &source_sim_step_file, &sim_data_file);
|
||||
if (success != 2) {
|
||||
if(ferror(source_file[args[0].v])) fprintf(logfile,"read error on source %d\n",args[0].v);
|
||||
source_data_buffer[args[0].v] = 0;
|
||||
if(verbose) fprintf(logfile,"EOF on source %d\n",args[0].v); fflush(logfile);
|
||||
t.v = 0 ;
|
||||
t.width = 1;
|
||||
return t;
|
||||
}
|
||||
if (source_sim_step_file == source_sim_step[args[0].v]){
|
||||
step_done = 1;
|
||||
source_data_buffer[args[0].v]= sim_data_file;
|
||||
if(verbose) fprintf(logfile,"read %d on source %d\n",sim_data_file,args[0].v); fflush(logfile);
|
||||
t.v = 1;
|
||||
t.width = 1;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* source get reads the buffer and returns the word that was placed by source_next
|
||||
* it requires 2 int:
|
||||
* id: the id of the source
|
||||
* width: the number of bits the source word is supposed to have
|
||||
* it returns the next word placed by source_next
|
||||
*/
|
||||
struct expr_res source_get (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 0;
|
||||
if (num !=2 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in channel_source_get\n");
|
||||
return t;
|
||||
}
|
||||
t.v = source_data_buffer[args[0].v];
|
||||
t.width = args[1].v;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* dump to file writes every inforamtion it gets into a csv file.
|
||||
* the file is created and opend on the first write, to not create a lot of empty files that are not required.
|
||||
* it requires 3 ints:
|
||||
* id: the id of the dump file
|
||||
* simstep: the current simulation step
|
||||
* word: the data word to be written
|
||||
* it return 1 on success
|
||||
*/
|
||||
struct expr_res dump_to_file (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 1;
|
||||
if (num !=3 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in dump_to_file\n");
|
||||
return t;
|
||||
}
|
||||
if (!dump_file[args[0].v]){
|
||||
char filename[255];
|
||||
snprintf(filename, 255, DUMP_FILENAME,args[0].v);
|
||||
dump_file[args[0].v] = fopen(filename,"w");
|
||||
}
|
||||
if (dump_file[args[0].v]){
|
||||
fprintf(dump_file[args[0].v], CSV_WRITE_FORMAT, args[1].v, args[2].v); fflush(dump_file[args[0].v]);
|
||||
t.v = 1;
|
||||
return t;
|
||||
}
|
||||
else{
|
||||
fprintf(logfile,"[ERROR] writing failed, file not open for dump %d\n",args[0].v); fflush(logfile);
|
||||
t.v = 0;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* control next hecks if there is a next simulation step to be loaded and if a delay needs to be triggered
|
||||
* it requires 1 ints:
|
||||
* ignored: cant have a function call without
|
||||
* it returns 1 if there is a new step
|
||||
*/
|
||||
struct expr_res control_next (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = 0 ;
|
||||
t.width = 1;
|
||||
if (num !=1 ){
|
||||
fprintf(logfile,"[ERROR] wrong number of arguments in dump_to_file\n");
|
||||
return t;
|
||||
}
|
||||
if (current_sim_step < first_sim_step) {
|
||||
current_sim_step = first_sim_step;
|
||||
t.v = 1 ;
|
||||
}
|
||||
else if (current_sim_step >= last_sim_step){
|
||||
return t;
|
||||
}
|
||||
else {
|
||||
current_sim_step++;
|
||||
t.v = 1 ;
|
||||
}
|
||||
int step_done = 0;
|
||||
unsigned int sim_step_file = 0;
|
||||
unsigned long int sim_data_file = 0;
|
||||
while (!step_done){
|
||||
int success = 0;
|
||||
success = fscanf(control_file, CSV_FORMAT, &sim_step_file, &sim_data_file);
|
||||
if (success != 2) {
|
||||
if(ferror(control_file)) fprintf(logfile,"read error on contol\n");
|
||||
if(verbose) fprintf(logfile,"EOF on ctl\n"); fflush(logfile);
|
||||
current_sim_wait = 0;
|
||||
step_done = 1;
|
||||
}
|
||||
if (sim_step_file == current_sim_step){
|
||||
step_done = 1;
|
||||
if(verbose) fprintf(logfile,"wait %d\n",sim_data_file); fflush(logfile);
|
||||
current_sim_wait = sim_data_file;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* control_get returns the current time_step, to advance a step call control_next
|
||||
* ignores all input
|
||||
* returns the current simstep
|
||||
*/
|
||||
struct expr_res control_get (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = current_sim_step;
|
||||
t.width = 32;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* control_get returns the wait time required after the current time_step, to advance a step call control_next
|
||||
* ignores all input
|
||||
* returns the current wait time
|
||||
*/
|
||||
struct expr_res control_wait (int num, struct expr_res *args)
|
||||
{
|
||||
struct expr_res t;
|
||||
t.v = current_sim_wait;
|
||||
t.width = 32;
|
||||
return t;
|
||||
}
|
118
readme.md
118
readme.md
|
@ -1 +1,117 @@
|
|||
# function lib test bench
|
||||
# lib test bench
|
||||
|
||||
is build to load test vectors from CSV files into your actsim or mixed signal simulation.
|
||||
the library contains multiple source and check as well as dump helpers.
|
||||
|
||||
## The Concept
|
||||
|
||||
each test bench consists out of:
|
||||
|
||||
- a DUT - device under test
|
||||
- multiple sources
|
||||
- multiple checker or dumpers
|
||||
- a controller - responcible for syncronising the release of test vectors
|
||||
|
||||
the execution order of the test bench is defined by the simulation steps and the order of the test vectors inside the simulation step
|
||||
|
||||
before the test bench proceeds to the next simulation step, it waits untill
|
||||
- all sources have sent their test vectors
|
||||
- all checkes have recieved all exspeced inputs
|
||||
- the specified wait time for the simulation step has elapsed after the 2 conditions above have been satisfied.
|
||||
|
||||
|
||||
the reason the test bench lib is splitt in components is that you can assable it to your need without writing it new for evert DUT
|
||||
|
||||
the reason to load a control file is that you can run different test suits with the same test
|
||||
bench by changing the set of csv files.
|
||||
|
||||
### Limitations for verilog
|
||||
Cadence AMS:
|
||||
|
||||
\- the test vector files can contain a maximum of 2.2M rows per simulation step, as they are cached for out of order checks
|
||||
(`` `parameter integer MAX_CHECKS = 2200000; ``\`)
|
||||
|
||||
## The Control
|
||||
|
||||
a test bench includes one test bench controller that excecutes reset (verilog, prs), the
|
||||
simulation step and the time out/end of the simulation (verilog)
|
||||
|
||||
Note:
|
||||
because the controller sets the time out in verilog set your simulation time in your simulator to way more than needed, the TB will end the simulation for you!
|
||||
|
||||
this unit is called **control**, it reads a file with the name `control.csv`.
|
||||
|
||||
the csv format is, one line per simulation step:
|
||||
``` first line: <start step>, <end step> all other lines: <simulation step>, <time to wait for> ```
|
||||
|
||||
step 0 is the test initialisation - so the reset sequence - and is always
|
||||
executed, it can not be used in the test bench.
|
||||
|
||||
verilog: wait statements are in ns (default for candence AMS) but can be changed in the simulatior options.
|
||||
|
||||
actsim: 0 means no wait, any positive number is waiting untill all signals have settled "cycle" (@TODO not supported yet)
|
||||
|
||||
the controll needs to be connected to sources, checkers and dumps, with both sim_step and done (excep dump)
|
||||
|
||||
before the test bench proceeds to the next simulation step, it waits until
|
||||
- all sources have sent their test vectors
|
||||
- all checkes have recieved all exspeced inputs
|
||||
- the specified wait time for the simulation step has elapsed after the 2 conditions above have been satisfied.
|
||||
|
||||
## The Sources
|
||||
|
||||
the async sources present a word and initiate a handshake.
|
||||
|
||||
the csv format is: ``` <simulation_step>; <data to send>```
|
||||
|
||||
the file name is `source_<ID>.csv`. the ID is a variable specified during the buiding of the test bench, the numbering does not have to be consecutive.
|
||||
|
||||
for the normal sources excl. fifo/serial, the maximum vector width is assumed with 64 bits, as limited by actsim plugin system
|
||||
|
||||
the simultaion_step has to be >= 1
|
||||
|
||||
## The Checkers
|
||||
|
||||
the testers compare the in coming data to the vectors written in the csv
|
||||
file.
|
||||
|
||||
|
||||
there are different checkers:
|
||||
|
||||
- check in order: all vectors have to appear in the order of the file inside a simulation step
|
||||
- check out of order: all vector can appear in random order, but each vector can only be used once.
|
||||
|
||||
the csv format is: ``` <simulation_step>; <data to send>```
|
||||
|
||||
the file name is `check_<ID>.csv`. the ID is a variable specified during the buiding of the test bench, the numbering does not have to be consecutive.
|
||||
|
||||
for the normal checkers excl. fifo/serial, the maximum vector width is assumed with 64 bits, as limited by actsim plugin system
|
||||
|
||||
## The Dumpers
|
||||
|
||||
the dumpers just write any incomming vector to file with format:
|
||||
|
||||
the csv format is: ``` <simulation_step>; <data to send>```
|
||||
|
||||
the file name is `dump_<ID>.csv`. the ID is a variable specified during the buiding of the test bench, the numbering does not have to be consecutive.
|
||||
|
||||
the maximum vector width is assumed with 64 bits, as limited by actsim plugin system
|
||||
|
||||
## CSV file stucture and location
|
||||
|
||||
currenty the files are read and searched in the excecution folder of actsim.
|
||||
|
||||
## running actsim
|
||||
|
||||
the config file has to be included to load the test bench,
|
||||
|
||||
call `make install`
|
||||
|
||||
and after you can run ``` actsim -cnf=$ACT_HOME/tech/generic/actsim_test_bench_lib.conf <act file> <process> ```
|
||||
|
||||
## outstanding features:
|
||||
|
||||
- [ ] sources with seperate address and data buses
|
||||
- [ ] verilog files in oa structure - what to do with symbols?
|
||||
- [ ] serial sources and checkers like scanchain/fifo/spi
|
||||
- [ ] actsim PRS support (incl reset) as ref=1
|
||||
|
|
Loading…
Reference in New Issue