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:
Stephen Williams 2010-01-06 16:08:20 -08:00
parent c74ca4a502
commit 3ddb421fbf
6 changed files with 112 additions and 5 deletions

View File

@ -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();
}

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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