From 3ddb421fbf8fdd56dffb933212d1e7df052f0e29 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 6 Jan 2010 16:08:20 -0800 Subject: [PATCH] Add some single-step debugging Work out the basis for single-stepping events in the scheduler, and fill in some basic single-step results. --- vvp/schedule.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++++-- vvp/schedule.h | 1 + vvp/stop.cc | 8 +++++ vvp/vpi_priv.h | 3 ++ vvp/vthread.cc | 19 +++++++++-- vvp/vthread.h | 2 ++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/vvp/schedule.cc b/vvp/schedule.cc index c94fac1c3..4d9d87941 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -19,13 +19,15 @@ # include "schedule.h" # include "vthread.h" +# include "vpi_priv.h" # include "slab.h" +# include "compile.h" # include # include # include # include -# include +# include 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 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 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 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 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(); } diff --git a/vvp/schedule.h b/vvp/schedule.h index 7a55d9fc7..ce1edc494 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -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); diff --git a/vvp/stop.cc b/vvp/stop.cc index a404f1325..29d1028bf 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -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, diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 71df7fac4..7a9737029 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -116,6 +116,9 @@ struct __vpirt { template vpiHandle vpi_handle(T obj) { return &obj->base; } +template 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 diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 8e698ffdd..b98890557 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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; } diff --git a/vvp/vthread.h b/vvp/vthread.h index 0e8d47966..0bdb4225a 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -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