Skip to content

Commit

Permalink
Cover saturate toggle (#919)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blebowski authored Jul 21, 2024
1 parent 7a43c3c commit abdfb43
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 55 deletions.
1 change: 1 addition & 0 deletions src/cov/cov-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ typedef enum {
COV_SRC_LOOP_STMT,
COV_SRC_CONDITION,
COV_SRC_STATEMENT,
COV_SRC_PSL_COVER,
COV_SRC_UNKNOWN,
} cover_src_t;

Expand Down
30 changes: 27 additions & 3 deletions src/cov/cov-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "object.h"
#include "option.h"
#include "tree.h"
#include "psl/psl-node.h"
#include "type.h"

#include <assert.h>
Expand Down Expand Up @@ -117,6 +118,16 @@ static cover_src_t get_cover_source(cover_item_kind_t kind, object_t *obj)
}
}

psl_node_t p = psl_from_object(obj);
if (p != NULL) {
switch (kind) {
case COV_ITEM_FUNCTIONAL:
return COV_SRC_PSL_COVER;
default:
return COV_SRC_UNKNOWN;
}
}

return COV_SRC_UNKNOWN;
}

Expand Down Expand Up @@ -666,13 +677,19 @@ cover_item_t *cover_add_items_for(cover_data_t *data, object_t *obj,

static void cover_merge_one_item(cover_item_t *item, int32_t data)
{
int32_t inc;

switch (item->kind) {
case COV_ITEM_STMT:
case COV_ITEM_FUNCTIONAL:
case COV_ITEM_BRANCH:
case COV_ITEM_STATE:
case COV_ITEM_EXPRESSION:
item->data += data;
inc = item->data + data;
if (likely(inc >= item->data))
item->data = inc;
else
item->data = INT32_MAX;
break;

// Highest bit of run-time data for COV_ITEM_TOGGLE is used to track
Expand All @@ -683,10 +700,17 @@ static void cover_merge_one_item(cover_item_t *item, int32_t data)
// the other was driven. So, If the unreachability is detected, enforce
// its propagation further to the merged database
case COV_ITEM_TOGGLE:
if (item->data & COV_FLAG_UNREACHABLE)

if ((item->data & COV_FLAG_UNREACHABLE) || (data & COV_FLAG_UNREACHABLE))
item->data = COV_FLAG_UNREACHABLE;
else
item->data += data;
{
inc = item->data + data;
if (likely(inc >= item->data))
item->data = inc;
else
item->data = INT32_MAX;
}
break;

default:
Expand Down
35 changes: 21 additions & 14 deletions src/cov/cov-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ typedef struct {
typedef struct {
cover_line_t *line;
cover_item_t *item;
int flags;
} cover_pair_t;

typedef struct {
Expand Down Expand Up @@ -604,6 +603,7 @@ static void cover_print_item_title(FILE *f, cover_pair_t *pair)
[COV_SRC_LOOP_STMT] = "Loop statement",
[COV_SRC_STATEMENT] = "Sequential statement",
[COV_SRC_CONDITION] = "Condition",
[COV_SRC_PSL_COVER] = "PSL cover point",
[COV_SRC_UNKNOWN] = "",
};

Expand All @@ -612,6 +612,7 @@ static void cover_print_item_title(FILE *f, cover_pair_t *pair)
switch (pair->item->kind) {
case COV_ITEM_STMT:
case COV_ITEM_BRANCH:
case COV_ITEM_FUNCTIONAL:
fprintf(f, "%s:", text[pair->item->source]);
break;
case COV_ITEM_EXPRESSION:
Expand All @@ -632,8 +633,6 @@ static void cover_print_code_loc(FILE *f, cover_pair_t *pair)
cover_line_t *curr_line = pair->line;
cover_line_t *last_line = pair->line + loc.line_delta;

cover_print_item_title(f, pair);

if (loc.line_delta == 0) {
fprintf(f, "<code>");
fprintf(f, "%d:", loc.first_line);
Expand Down Expand Up @@ -665,7 +664,8 @@ static void cover_print_code_loc(FILE *f, cover_pair_t *pair)
curr_char++;
}

fprintf(f, "<br>");
if (curr_line < last_line)
fprintf(f, "<br>");
curr_line++;

} while (curr_line <= last_line);
Expand Down Expand Up @@ -705,6 +705,8 @@ static void cover_print_bin(FILE *f, cover_pair_t *pair, uint32_t flag,
fprintf(f, "<td>%s</td>", val);
}

fprintf(f, "<td>%d</td>", pair->item->data);

if (pkind == PAIR_UNCOVERED)
cover_print_get_exclude_button(f, pair->item, flag, true);

Expand All @@ -731,6 +733,8 @@ static void cover_print_bin_header(FILE *f, cov_pair_kind_t pkind, int cols, ...
fprintf(f, "<th>%s</th>", val);
}

fprintf(f, "<th>Count</th>");

if (pkind == PAIR_UNCOVERED)
fprintf(f, "<th>Exclude Command</th>");

Expand All @@ -752,7 +756,7 @@ static void cover_print_bins(FILE *f, cover_pair_t *first_pair, cov_pair_kind_t
cover_print_bin(f, pair, COV_FLAG_TRUE, pkind, 1, "True");
cover_print_bin(f, pair, COV_FLAG_FALSE, pkind, 1, "False");

if (pair->flags & COV_FLAG_CHOICE) {
if (pair->item->flags & COV_FLAG_CHOICE) {
int curr = loc.first_column;
int last = (loc.line_delta) ? strlen(pair->line->text) :
loc.column_delta + curr;
Expand Down Expand Up @@ -820,20 +824,24 @@ static void cover_print_pairs(FILE *f, cover_pair_t *first, cov_pair_kind_t pkin
int step;

do {
step = 1;
fprintf(f, " <p>");

step = curr->item->consecutive;

switch (curr->item->kind) {
case COV_ITEM_STMT:
if (pkind == PAIR_UNCOVERED)
cover_print_get_exclude_button(f, curr->item, 0, false);
if (pkind == PAIR_EXCLUDED)
fprintf(f, "<div style=\"float: right\"><b>Excluded due to:</b> Exclude file</div>");

cover_print_item_title(f, curr);
cover_print_code_loc(f, curr);
fprintf(f, "<br><b>Count:</b> %d", curr->item->data);
break;

case COV_ITEM_BRANCH:
cover_print_item_title(f, curr);
cover_print_code_loc(f, curr);
cover_print_bin_header(f, pkind, 1, (curr->item->flags & COV_FLAG_CHOICE) ?
"Choice of" : "Evaluated to");
Expand All @@ -852,32 +860,33 @@ static void cover_print_pairs(FILE *f, cover_pair_t *first, cov_pair_kind_t pkin

cover_print_bin_header(f, pkind, 2, "From", "To");
cover_print_bins(f, curr, pkind);
step = curr->item->consecutive;
break;

case COV_ITEM_EXPRESSION:
cover_print_item_title(f, curr);
cover_print_code_loc(f, curr);

if ((curr->item->flags & COV_FLAG_TRUE) || (curr->item->flags & COV_FLAG_FALSE))
cover_print_bin_header(f, pkind, 1, "Evaluated to");
else
cover_print_bin_header(f, pkind, 2, "LHS", "RHS");

cover_print_bins(f, curr, pkind);
step = curr->item->consecutive;
break;

case COV_ITEM_STATE:
cover_print_item_title(f, curr);
cover_print_code_loc(f, curr);
cover_print_bin_header(f, pkind, 1, "State");
cover_print_bins(f, curr, pkind);

step = curr->item->consecutive;
break;

case COV_ITEM_FUNCTIONAL:
if (pkind == PAIR_UNCOVERED)
cover_print_get_exclude_button(f, curr->item, 0, false);
cover_print_item_title(f, curr);
cover_print_code_loc(f, curr);
fprintf(f, "<br><b>Count:</b> %d", curr->item->data);
break;

default:
Expand Down Expand Up @@ -964,7 +973,7 @@ static void cover_print_chain(FILE *f, cover_data_t *data, cover_chain_t *chn,
else if (kind == COV_ITEM_STATE)
fprintf(f, "FSM states:");
else if (kind == COV_ITEM_FUNCTIONAL)
fprintf(f, "sequences:");
fprintf(f, "functional coverage:");
fprintf(f, "</h2>\n");

fprintf(f, " <section style=\"padding:0px 10px;\">\n");
Expand Down Expand Up @@ -1034,8 +1043,6 @@ static bool cover_bin_unreachable(cover_report_ctx_t *ctx, cover_item_t *item)
return false;
}

// TODO: Remove "flag" from "cover_pair_t" once all cover item kinds are reworked
// to contain only single bin. It will not be needed then!
#define CHAIN_APPEND(chn, type, first_chn_item, curr_item, curr_line) \
do { \
if (chn->n_##type == chn->alloc_##type) { \
Expand Down Expand Up @@ -1106,7 +1113,7 @@ static int cover_append_item_to_chain(cover_report_ctx_t *ctx, cover_item_t *fir
nested_total = &(ctx->nested_stats.total_functional);
flat_hits = &(ctx->flat_stats.hit_functional);
nested_hits = &(ctx->nested_stats.hit_functional);
chn = &(ctx->ch_expression);
chn = &(ctx->ch_functional);
break;
default:
fatal("unsupported type of code coverage: %d at 'cover_append_item_to_chain'!",
Expand Down
92 changes: 54 additions & 38 deletions src/rt/cover.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ enum std_ulogic {
_DC = 0x8
};

#define INCS_I32(i32_ptr) \
do { \
if (unlikely(__builtin_add_overflow(*i32_ptr, 1, i32_ptr))) \
*i32_ptr = INT32_MAX; \
} while (0)

//#define COVER_DEBUG_CALLBACK

///////////////////////////////////////////////////////////////////////////////
Expand All @@ -55,54 +61,65 @@ static inline void cover_toggle_check_0_1(uint8_t old, uint8_t new,
int32_t *toggle_01, int32_t *toggle_10)
{
if (old == _0 && new == _1)
(*toggle_01)++;
if (old == _1 && new == _0)
(*toggle_10)++;
}

static inline void cover_toggle_check_u(uint8_t old, uint8_t new,
int32_t *toggle_01, int32_t *toggle_10)
{
if (old == _U && new == _1)
(*toggle_01)++;
if (old == _U && new == _0)
(*toggle_10)++;
}

static inline void cover_toggle_check_z(uint8_t old, uint8_t new,
int32_t *toggle_01, int32_t *toggle_10)
{
if (old == _0 && new == _Z)
(*toggle_01)++;
if (old == _Z && new == _1)
(*toggle_01)++;

if (old == _1 && new == _Z)
(*toggle_10)++;
if (old == _Z && new == _0)
(*toggle_10)++;
INCS_I32(toggle_01);
else if (old == _1 && new == _0)
INCS_I32(toggle_10);
}

static inline void cover_toggle_check_0_1_u(uint8_t old, uint8_t new,
int32_t *toggle_01, int32_t *toggle_10)
{
cover_toggle_check_0_1(old, new, toggle_01, toggle_10);
cover_toggle_check_u(old, new, toggle_01, toggle_10);
if (old == _0 && new == _1)
INCS_I32(toggle_01);
else if (old == _1 && new == _0)
INCS_I32(toggle_10);

else if (old == _U && new == _1)
INCS_I32(toggle_01);
else if (old == _U && new == _0)
INCS_I32(toggle_10);
}

static inline void cover_toggle_check_0_1_z(uint8_t old, uint8_t new,
int32_t *toggle_01, int32_t *toggle_10)
{
cover_toggle_check_0_1(old, new, toggle_01, toggle_10);
cover_toggle_check_z(old, new, toggle_01, toggle_10);
if (old == _0 && new == _1)
INCS_I32(toggle_01);
else if (old == _1 && new == _0)
INCS_I32(toggle_10);

else if (old == _0 && new == _Z)
INCS_I32(toggle_01);
else if (old == _Z && new == _1)
INCS_I32(toggle_01);
else if (old == _1 && new == _Z)
INCS_I32(toggle_10);
else if (old == _Z && new == _0)
INCS_I32(toggle_10);
}

static inline void cover_toggle_check_0_1_u_z(uint8_t old, uint8_t new,
int32_t *toggle_01, int32_t *toggle_10)
{
cover_toggle_check_0_1(old, new, toggle_01, toggle_10);
cover_toggle_check_u(old, new, toggle_01, toggle_10);
cover_toggle_check_z(old, new, toggle_01, toggle_10);

if (old == _0 && new == _1)
INCS_I32(toggle_01);
else if (old == _1 && new == _0)
INCS_I32(toggle_10);

else if (old == _U && new == _1)
INCS_I32(toggle_01);
else if (old == _U && new == _0)
INCS_I32(toggle_10);

else if (old == _0 && new == _Z)
INCS_I32(toggle_01);
else if (old == _Z && new == _1)
INCS_I32(toggle_01);
else if (old == _1 && new == _Z)
INCS_I32(toggle_10);
else if (old == _Z && new == _0)
INCS_I32(toggle_10);
}

#ifdef COVER_DEBUG_CALLBACK
Expand All @@ -129,6 +146,7 @@ static inline void cover_toggle_check_0_1_u_z(uint8_t old, uint8_t new,
#define COVER_TGL_SIGNAL_DETAILS(signal, size)
#endif

// TODO: Could multi-bit signals be optimized with vector instructions ?
#define DEFINE_COVER_TOGGLE_CB(name, check_fnc) \
static void name(uint64_t now, rt_signal_t *s, rt_watch_t *w, void *user) \
{ \
Expand Down Expand Up @@ -195,8 +213,8 @@ void x_cover_setup_toggle_cb(sig_shared_t *ss, int32_t tag)
for (int i = 0; i < s->shared.size; i++) {
// Remember constant driver in run-time data.
// Unreachable mask not available at run-time.
*toggle_01 |= COV_FLAG_UNREACHABLE;
*toggle_10 |= COV_FLAG_UNREACHABLE;
*toggle_01 = COV_FLAG_UNREACHABLE;
*toggle_10 = COV_FLAG_UNREACHABLE;
toggle_01 += 2;
toggle_10 += 2;
}
Expand Down Expand Up @@ -231,9 +249,7 @@ static void cover_state_cb(uint64_t now, rt_signal_t *s, rt_watch_t *w, void *us
rt_model_t *m = get_model();
int32_t *mask = get_cover_counter(m, ((uintptr_t)user) + offset);

int32_t mask_inc = *mask + 1;
if (mask_inc > *mask)
*mask = mask_inc;
INCS_I32(mask);
}

void x_cover_setup_state_cb(sig_shared_t *ss, int64_t low, int32_t tag)
Expand Down
Loading

0 comments on commit abdfb43

Please sign in to comment.