Add some single-step debugging
Work out the basis for single-stepping events in the scheduler, and fill in some basic single-step results.
This commit is contained in:
parent
c74ca4a502
commit
3ddb421fbf
|
|
@ -19,13 +19,15 @@
|
|||
|
||||
# include "schedule.h"
|
||||
# include "vthread.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "slab.h"
|
||||
# include "compile.h"
|
||||
# include <new>
|
||||
# include <signal.h>
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
# include <stdio.h>
|
||||
# include <iostream>
|
||||
|
||||
unsigned long count_assign_events = 0;
|
||||
unsigned long count_gen_events = 0;
|
||||
|
|
@ -50,11 +52,19 @@ struct event_s {
|
|||
virtual ~event_s() { }
|
||||
virtual void run_run(void) =0;
|
||||
|
||||
// Write something about the event to stderr
|
||||
virtual void single_step_display(void);
|
||||
|
||||
// Fallback new/delete
|
||||
static void*operator new (size_t size) { return ::new char[size]; }
|
||||
static void operator delete(void*ptr) { ::delete[]( (char*)ptr ); }
|
||||
};
|
||||
|
||||
void event_s::single_step_display(void)
|
||||
{
|
||||
cerr << "event_s: Step into event " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
struct event_time_s {
|
||||
event_time_s() {
|
||||
count_time_events += 1;
|
||||
|
|
@ -90,6 +100,7 @@ vvp_gen_event_s::~vvp_gen_event_s()
|
|||
struct vthread_event_s : public event_s {
|
||||
vthread_t thr;
|
||||
void run_run(void);
|
||||
void single_step_display(void);
|
||||
|
||||
static void* operator new(size_t);
|
||||
static void operator delete(void*);
|
||||
|
|
@ -101,6 +112,14 @@ void vthread_event_s::run_run(void)
|
|||
vthread_run(thr);
|
||||
}
|
||||
|
||||
void vthread_event_s::single_step_display(void)
|
||||
{
|
||||
struct __vpiScope*scope = vthread_scope(thr);
|
||||
cerr << "vthread_event: Resume thread"
|
||||
<< " scope=" << vpip_get_str(vpiFullName, scope)
|
||||
<< endl;
|
||||
}
|
||||
|
||||
static const size_t VTHR_CHUNK_COUNT = 8192 / sizeof(struct vthread_event_s);
|
||||
static slab_t<sizeof(vthread_event_s),VTHR_CHUNK_COUNT> vthread_event_heap;
|
||||
|
||||
|
|
@ -118,6 +137,7 @@ void vthread_event_s::operator delete(void*ptr)
|
|||
struct del_thr_event_s : public event_s {
|
||||
vthread_t thr;
|
||||
void run_run(void);
|
||||
void single_step_display(void);
|
||||
};
|
||||
|
||||
void del_thr_event_s::run_run(void)
|
||||
|
|
@ -125,6 +145,13 @@ void del_thr_event_s::run_run(void)
|
|||
vthread_delete(thr);
|
||||
}
|
||||
|
||||
void del_thr_event_s::single_step_display(void)
|
||||
{
|
||||
struct __vpiScope*scope = vthread_scope(thr);
|
||||
cerr << "del_thr_event: Reap completed thread"
|
||||
<< " scope=" << vpip_get_str(vpiFullName, scope) << endl;
|
||||
}
|
||||
|
||||
struct assign_vector4_event_s : public event_s {
|
||||
/* The default constructor. */
|
||||
assign_vector4_event_s(const vvp_vector4_t&that) : val(that) { }
|
||||
|
|
@ -141,6 +168,7 @@ struct assign_vector4_event_s : public event_s {
|
|||
/* Width of the destination vector. */
|
||||
unsigned vwid;
|
||||
void run_run(void);
|
||||
void single_step_display(void);
|
||||
|
||||
static void* operator new(size_t);
|
||||
static void operator delete(void*);
|
||||
|
|
@ -155,6 +183,12 @@ void assign_vector4_event_s::run_run(void)
|
|||
vvp_send_vec4(ptr, val, 0);
|
||||
}
|
||||
|
||||
void assign_vector4_event_s::single_step_display(void)
|
||||
{
|
||||
cerr << "assign_vector4_event: Propagate val=" << val
|
||||
<< ", vwid=" << vwid << ", base=" << base << endl;
|
||||
}
|
||||
|
||||
static const size_t ASSIGN4_CHUNK_COUNT = 524288 / sizeof(struct assign_vector4_event_s);
|
||||
static slab_t<sizeof(assign_vector4_event_s),ASSIGN4_CHUNK_COUNT> assign4_heap;
|
||||
|
||||
|
|
@ -175,6 +209,7 @@ struct assign_vector8_event_s : public event_s {
|
|||
vvp_net_ptr_t ptr;
|
||||
vvp_vector8_t val;
|
||||
void run_run(void);
|
||||
void single_step_display(void);
|
||||
|
||||
static void* operator new(size_t);
|
||||
static void operator delete(void*);
|
||||
|
|
@ -186,6 +221,11 @@ void assign_vector8_event_s::run_run(void)
|
|||
vvp_send_vec8(ptr, val);
|
||||
}
|
||||
|
||||
void assign_vector8_event_s::single_step_display(void)
|
||||
{
|
||||
cerr << "assign_vector8_event: Propagate val=" << val << endl;
|
||||
}
|
||||
|
||||
static const size_t ASSIGN8_CHUNK_COUNT = 8192 / sizeof(struct assign_vector8_event_s);
|
||||
static slab_t<sizeof(assign_vector8_event_s),ASSIGN8_CHUNK_COUNT> assign8_heap;
|
||||
|
||||
|
|
@ -206,6 +246,7 @@ struct assign_real_event_s : public event_s {
|
|||
vvp_net_ptr_t ptr;
|
||||
double val;
|
||||
void run_run(void);
|
||||
void single_step_display(void);
|
||||
|
||||
static void* operator new(size_t);
|
||||
static void operator delete(void*);
|
||||
|
|
@ -217,6 +258,11 @@ void assign_real_event_s::run_run(void)
|
|||
vvp_send_real(ptr, val, 0);
|
||||
}
|
||||
|
||||
void assign_real_event_s::single_step_display(void)
|
||||
{
|
||||
cerr << "assign_real_event: Propagate val=" << val << endl;
|
||||
}
|
||||
|
||||
static const size_t ASSIGNR_CHUNK_COUNT = 8192 / sizeof(struct assign_real_event_s);
|
||||
static slab_t<sizeof(assign_real_event_s),ASSIGNR_CHUNK_COUNT> assignr_heap;
|
||||
|
||||
|
|
@ -397,6 +443,7 @@ static struct event_s* schedule_init_list = 0;
|
|||
*/
|
||||
static bool schedule_runnable = true;
|
||||
static bool schedule_stopped_flag = false;
|
||||
static bool schedule_single_step_flag = false;
|
||||
|
||||
void schedule_finish(int)
|
||||
{
|
||||
|
|
@ -408,6 +455,11 @@ void schedule_stop(int)
|
|||
schedule_stopped_flag = true;
|
||||
}
|
||||
|
||||
void schedule_single_step(int)
|
||||
{
|
||||
schedule_single_step_flag = true;
|
||||
}
|
||||
|
||||
bool schedule_finished(void)
|
||||
{
|
||||
return !schedule_runnable;
|
||||
|
|
@ -813,8 +865,8 @@ static void run_rosync(struct event_time_s*ctim)
|
|||
}
|
||||
|
||||
if (ctim->active || ctim->nbassign || ctim->rwsync) {
|
||||
fprintf(stderr, "SCHEDULER ERROR: read-only sync events "
|
||||
"created RW events!\n");
|
||||
cerr << "SCHEDULER ERROR: read-only sync events "
|
||||
<< "created RW events!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -822,9 +874,17 @@ void schedule_simulate(void)
|
|||
{
|
||||
schedule_time = 0;
|
||||
|
||||
if (verbose_flag) {
|
||||
vpi_mcd_printf(1, " ...execute EndOfCompile callbacks\n");
|
||||
}
|
||||
|
||||
// Execute end of compile callbacks
|
||||
vpiEndOfCompile();
|
||||
|
||||
if (verbose_flag) {
|
||||
vpi_mcd_printf(1, " ...propagate initialization events\n");
|
||||
}
|
||||
|
||||
// Execute initialization events.
|
||||
while (schedule_init_list) {
|
||||
struct event_s*cur = schedule_init_list;
|
||||
|
|
@ -834,11 +894,19 @@ void schedule_simulate(void)
|
|||
delete cur;
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
vpi_mcd_printf(1, " ...execute StartOfSim callbacks\n");
|
||||
}
|
||||
|
||||
// Execute start of simulation callbacks
|
||||
vpiStartOfSim();
|
||||
|
||||
signals_capture();
|
||||
|
||||
if (verbose_flag) {
|
||||
vpi_mcd_printf(1, " ...run scheduler\n");
|
||||
}
|
||||
|
||||
if (schedule_runnable) while (sched_list) {
|
||||
|
||||
if (schedule_stopped_flag) {
|
||||
|
|
@ -908,6 +976,12 @@ void schedule_simulate(void)
|
|||
ctim->active->next = cur->next;
|
||||
}
|
||||
|
||||
if (schedule_single_step_flag) {
|
||||
cur->single_step_display();
|
||||
schedule_stopped_flag = true;
|
||||
schedule_single_step_flag = false;
|
||||
}
|
||||
|
||||
cur->run_run();
|
||||
|
||||
delete (cur);
|
||||
|
|
@ -916,6 +990,10 @@ void schedule_simulate(void)
|
|||
|
||||
signals_revert();
|
||||
|
||||
if (verbose_flag) {
|
||||
vpi_mcd_printf(1, " ...execute Postsim callbacks\n");
|
||||
}
|
||||
|
||||
// Execute post-simulation callbacks
|
||||
vpiPostsim();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ extern vvp_time64_t schedule_simtime(void);
|
|||
*/
|
||||
extern void schedule_finish(int rc);
|
||||
extern void schedule_stop(int rc);
|
||||
extern void schedule_single_step(int flag);
|
||||
extern bool schedule_finished(void);
|
||||
extern bool schedule_stopped(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -197,6 +197,12 @@ static void cmd_cont(unsigned, char*[])
|
|||
interact_flag = false;
|
||||
}
|
||||
|
||||
static void cmd_step(unsigned, char*[])
|
||||
{
|
||||
interact_flag = false;
|
||||
schedule_single_step(0);
|
||||
}
|
||||
|
||||
static void cmd_finish(unsigned, char*[])
|
||||
{
|
||||
interact_flag = false;
|
||||
|
|
@ -403,6 +409,8 @@ static struct {
|
|||
"Pop one scope from the scope stack."},
|
||||
{ "push", &cmd_push,
|
||||
"Descend into the named scope."},
|
||||
{ "step", &cmd_step,
|
||||
"Single-step the scheduler for 1 event."},
|
||||
{ "time", &cmd_time,
|
||||
"Print the current simulation time."},
|
||||
{ "where", &cmd_where,
|
||||
|
|
|
|||
|
|
@ -116,6 +116,9 @@ struct __vpirt {
|
|||
template <class T> vpiHandle vpi_handle(T obj)
|
||||
{ return &obj->base; }
|
||||
|
||||
template <class T> char*vpip_get_str(int code, T obj)
|
||||
{ return obj->base.vpi_type->vpi_get_str_(code, vpi_handle(obj)); }
|
||||
|
||||
/*
|
||||
* The vpiHandle for an iterator has this structure. The definition of
|
||||
* the methods lives in vpi_iter.c
|
||||
|
|
|
|||
|
|
@ -116,8 +116,13 @@ struct vthread_s {
|
|||
unsigned fork_count :8;
|
||||
/* This points to the sole child of the thread. */
|
||||
struct vthread_s*child;
|
||||
/* This points to my parent, if I have one. */
|
||||
struct vthread_s*parent;
|
||||
union {
|
||||
/* This points to my parent, if I have one. */
|
||||
struct vthread_s*parent;
|
||||
/* If this is a header cell, then point to the
|
||||
containing scope. */
|
||||
struct __vpiScope*parent_scope;
|
||||
};
|
||||
/* This is used for keeping wait queues. */
|
||||
struct vthread_s*wait_next;
|
||||
/* These are used to keep the thread in a scope. */
|
||||
|
|
@ -129,6 +134,15 @@ struct vthread_s {
|
|||
uint64_t ecount;
|
||||
};
|
||||
|
||||
struct __vpiScope* vthread_scope(struct vthread_s*thr)
|
||||
{
|
||||
while (thr->bits4.size() > 0) {
|
||||
thr = thr->scope_next;
|
||||
}
|
||||
|
||||
return thr->parent_scope;
|
||||
}
|
||||
|
||||
struct vthread_s*running_thread = 0;
|
||||
|
||||
// this table maps the thread special index bit addresses to
|
||||
|
|
@ -412,6 +426,7 @@ vthread_t vthread_new(vvp_code_t pc, struct __vpiScope*scope)
|
|||
scope->threads->bits4 = vvp_vector4_t();
|
||||
scope->threads->child = 0;
|
||||
scope->threads->parent = 0;
|
||||
scope->threads->parent_scope = scope;
|
||||
scope->threads->scope_prev = scope->threads;
|
||||
scope->threads->scope_next = scope->threads;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ extern void vthread_run(vthread_t thr);
|
|||
*/
|
||||
extern void vthread_schedule_list(vthread_t thr);
|
||||
|
||||
extern struct __vpiScope*vthread_scope(vthread_t thr);
|
||||
|
||||
/*
|
||||
* This function returns a handle to the writable context of the currently
|
||||
* running thread. Normally the writable context is the context allocated
|
||||
|
|
|
|||
Loading…
Reference in New Issue