Put threads into scopes.
This commit is contained in:
parent
41ce198a1f
commit
9e8005f7b7
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: README.txt,v 1.15 2001/04/14 05:10:56 steve Exp $
|
||||
* $Id: README.txt,v 1.16 2001/04/18 04:21:23 steve Exp $
|
||||
*/
|
||||
|
||||
VVP SIMULATION ENGINE
|
||||
|
|
@ -293,16 +293,11 @@ vvp.txt for .scope declarations.) The .thread statement placed in the
|
|||
assembly source after a .scope statement causes the thread to join the
|
||||
named scope.
|
||||
|
||||
Transient threads initially inherit the scope of the parent
|
||||
thread. Right after the %fork statement, the new thread is created
|
||||
within the scope of the thread that executes the %fork
|
||||
statement. Transient threads leaf the parent scope and join a new
|
||||
scope with the %scope instruction.
|
||||
|
||||
A thread normally executes a %scope instruction only once. At any
|
||||
rate, a thread is only in a single scope, and does not remember past
|
||||
scopes that it might have been a part of. This is how a new thread
|
||||
switches out of the parent scope and into its own scope.
|
||||
Transient threads join a scope that is the operand to the %fork
|
||||
instruction. The scope is referenced by name, and the thread created
|
||||
by the fork atomically joins that scope. Once the transient thread
|
||||
joins the scope, it stays there until it ends. Threads never change
|
||||
scopes, not even transient threads.
|
||||
|
||||
TRUTH TABLES
|
||||
|
||||
|
|
|
|||
12
vvp/codes.h
12
vvp/codes.h
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: codes.h,v 1.19 2001/04/15 16:37:48 steve Exp $"
|
||||
#ident "$Id: codes.h,v 1.20 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -43,6 +43,7 @@ extern bool of_CMPU(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_CMPX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPZ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAY(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_END(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_INV(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -75,12 +76,18 @@ struct vvp_code_s {
|
|||
vvp_ipoint_t iptr;
|
||||
vvp_cpoint_t cptr;
|
||||
struct __vpiHandle*handle;
|
||||
struct fork_extend*fork;
|
||||
};
|
||||
|
||||
unsigned short bit_idx1;
|
||||
unsigned short bit_idx2;
|
||||
};
|
||||
|
||||
struct fork_extend {
|
||||
vvp_cpoint_t cptr;
|
||||
struct __vpiScope*scope;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This function clears the code space, ready for initialization. This
|
||||
|
|
@ -110,6 +117,9 @@ extern void codespace_dump(FILE*fd);
|
|||
|
||||
/*
|
||||
* $Log: codes.h,v $
|
||||
* Revision 1.20 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.19 2001/04/15 16:37:48 steve
|
||||
* add XOR support.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: compile.cc,v 1.34 2001/04/15 16:37:48 steve Exp $"
|
||||
#ident "$Id: compile.cc,v 1.35 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compile.h"
|
||||
|
|
@ -74,7 +74,6 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%delay", of_DELAY, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%fork", of_FORK, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%jmp/0", of_JMP0, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
|
|
@ -548,6 +547,72 @@ void compile_codelabel(char*label)
|
|||
free(label);
|
||||
}
|
||||
|
||||
void compile_disable(char*label, struct symb_s symb)
|
||||
{
|
||||
vvp_cpoint_t ptr = codespace_allocate();
|
||||
|
||||
/* First, I can give the label a value that is the current
|
||||
codespace pointer. Don't need the text of the label after
|
||||
this is done. */
|
||||
if (label) {
|
||||
symbol_value_t val;
|
||||
val.num = ptr;
|
||||
sym_set_value(sym_codespace, label, val);
|
||||
}
|
||||
|
||||
|
||||
/* Fill in the basics of the %disable in the instruction. */
|
||||
vvp_code_t code = codespace_index(ptr);
|
||||
code->opcode = of_DISABLE;
|
||||
|
||||
/* Figure out the target SCOPE. */
|
||||
code->handle = compile_vpi_lookup(symb.text);
|
||||
assert(code->handle);
|
||||
|
||||
free(label);
|
||||
free(symb.text);
|
||||
}
|
||||
|
||||
/*
|
||||
* The %fork instruction is a little different from other instructions
|
||||
* in that it has an extended field that holds the information needed
|
||||
* to create the new thread. This includes the target PC and scope.
|
||||
* I get these from the parser in the form of symbols.
|
||||
*/
|
||||
void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
|
||||
{
|
||||
symbol_value_t tmp;
|
||||
vvp_cpoint_t ptr = codespace_allocate();
|
||||
|
||||
/* First, I can give the label a value that is the current
|
||||
codespace pointer. Don't need the text of the label after
|
||||
this is done. */
|
||||
if (label) {
|
||||
symbol_value_t val;
|
||||
val.num = ptr;
|
||||
sym_set_value(sym_codespace, label, val);
|
||||
}
|
||||
|
||||
/* Fill in the basics of the %fork in the instruction. */
|
||||
vvp_code_t code = codespace_index(ptr);
|
||||
code->opcode = of_FORK;
|
||||
code->fork = new struct fork_extend;
|
||||
|
||||
/* Figure out the target PC. */
|
||||
tmp = sym_get_value(sym_codespace, dest.text);
|
||||
code->fork->cptr = tmp.num;
|
||||
assert(code->fork->cptr);
|
||||
|
||||
/* Figure out the target SCOPE. */
|
||||
vpiHandle sh = compile_vpi_lookup(scope.text);
|
||||
assert(sh);
|
||||
code->fork->scope = (struct __vpiScope*)sh;
|
||||
|
||||
free(label);
|
||||
free(dest.text);
|
||||
free(scope.text);
|
||||
}
|
||||
|
||||
void compile_vpi_call(char*label, char*name, unsigned argc, vpiHandle*argv)
|
||||
{
|
||||
vvp_cpoint_t ptr = codespace_allocate();
|
||||
|
|
@ -590,7 +655,7 @@ void compile_thread(char*start_sym)
|
|||
return;
|
||||
}
|
||||
|
||||
vthread_t thr = vthread_new(pc);
|
||||
vthread_t thr = vthread_new(pc, vpip_peek_current_scope());
|
||||
schedule_vthread(thr, 0);
|
||||
free(start_sym);
|
||||
}
|
||||
|
|
@ -763,6 +828,9 @@ void compile_dump(FILE*fd)
|
|||
|
||||
/*
|
||||
* $Log: compile.cc,v $
|
||||
* Revision 1.35 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.34 2001/04/15 16:37:48 steve
|
||||
* add XOR support.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: compile.h,v 1.15 2001/04/14 05:10:56 steve Exp $"
|
||||
#ident "$Id: compile.h,v 1.16 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
|
@ -104,8 +104,11 @@ struct comp_operands_s {
|
|||
typedef struct comp_operands_s*comp_operands_t;
|
||||
|
||||
extern void compile_code(char*label, char*mnem, comp_operands_t opa);
|
||||
extern void compile_disable(char*label, struct symb_s symb);
|
||||
extern void compile_vpi_call(char*label, char*name,
|
||||
unsigned argc, vpiHandle*argv);
|
||||
extern void compile_fork(char*label, struct symb_s targ_s,
|
||||
struct symb_s scope_s);
|
||||
extern void compile_codelabel(char*label);
|
||||
|
||||
/*
|
||||
|
|
@ -139,6 +142,9 @@ extern void compile_dump(FILE*fd);
|
|||
|
||||
/*
|
||||
* $Log: compile.h,v $
|
||||
* Revision 1.16 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.15 2001/04/14 05:10:56 steve
|
||||
* support the .event/or statement.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: functor.cc,v 1.11 2001/04/14 05:10:56 steve Exp $"
|
||||
#ident "$Id: functor.cc,v 1.12 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "functor.h"
|
||||
|
|
@ -274,8 +274,8 @@ void functor_dump(FILE*fd)
|
|||
{
|
||||
for (unsigned idx = 1 ; idx < functor_count ; idx += 1) {
|
||||
functor_t cur = functor_index(idx*4);
|
||||
fprintf(fd, "%10p: out=%x port={%x %x %x %x}\n",
|
||||
(void*)(idx*4), cur->out, cur->port[0],
|
||||
fprintf(fd, "%08x: out=%x port={%x %x %x %x}\n",
|
||||
(idx*4), cur->out, cur->port[0],
|
||||
cur->port[1], cur->port[2], cur->port[3]);
|
||||
}
|
||||
}
|
||||
|
|
@ -306,6 +306,9 @@ const unsigned char ft_var[16] = {
|
|||
|
||||
/*
|
||||
* $Log: functor.cc,v $
|
||||
* Revision 1.12 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.11 2001/04/14 05:10:56 steve
|
||||
* support the .event/or statement.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: lexor.lex,v 1.12 2001/04/14 05:10:56 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.13 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -80,8 +80,9 @@
|
|||
kind of instruction this really is. The few exceptions (that have
|
||||
exceptional parameter requirements) are listed first. */
|
||||
|
||||
"%vpi_call" {
|
||||
return K_vpi_call; }
|
||||
"%vpi_call" { return K_vpi_call; }
|
||||
"%disable" { return K_disable; }
|
||||
"%fork" { return K_fork; }
|
||||
|
||||
"%"[.$_/a-zA-Z0-9]+ {
|
||||
yylval.text = strdup(yytext);
|
||||
|
|
@ -126,6 +127,9 @@ int yywrap()
|
|||
|
||||
/*
|
||||
* $Log: lexor.lex,v $
|
||||
* Revision 1.13 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.12 2001/04/14 05:10:56 steve
|
||||
* support the .event/or statement.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: opcodes.txt,v 1.13 2001/04/15 16:37:48 steve Exp $
|
||||
* $Id: opcodes.txt,v 1.14 2001/04/18 04:21:23 steve Exp $
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -87,7 +87,14 @@ future to reschedule, and is >= 0. If the %delay is zero, then the
|
|||
thread yields the processor for another thread, but will be resumed in
|
||||
the current time step.
|
||||
|
||||
* %fork <code-label>
|
||||
* %disable <scope-label>
|
||||
|
||||
This instruction terminates threads that are part of a specific
|
||||
scope. The label identifies the scope in question, and the threads are
|
||||
the threads that are currently within that scope.
|
||||
|
||||
|
||||
* %fork <code-label>, <scope-label>
|
||||
|
||||
This instruction is similar to %jmp, except that it creates a new
|
||||
thread to start executing at the specified address. The new thread is
|
||||
|
|
|
|||
17
vvp/parse.y
17
vvp/parse.y
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: parse.y,v 1.19 2001/04/14 05:10:56 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.20 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -52,7 +52,7 @@ extern FILE*yyin;
|
|||
|
||||
|
||||
%token K_EVENT K_EVENT_OR K_FUNCTOR K_NET K_NET_S K_SCOPE K_THREAD
|
||||
%token K_VAR K_VAR_S K_vpi_call
|
||||
%token K_VAR K_VAR_S K_vpi_call K_disable K_fork
|
||||
%token K_vpi_module
|
||||
|
||||
%token <text> T_INSTR
|
||||
|
|
@ -144,6 +144,16 @@ statement
|
|||
| label_opt K_vpi_call T_STRING argument_opt ';'
|
||||
{ compile_vpi_call($1, $3, $4.argc, $4.argv); }
|
||||
|
||||
/* %disable statements are instructions that takes a scope reference
|
||||
as an operand. It therefore is parsed uniquely. */
|
||||
|
||||
| label_opt K_disable symbol ';'
|
||||
{ compile_disable($1, $3); }
|
||||
|
||||
|
||||
| label_opt K_fork symbol ',' symbol ';'
|
||||
{ compile_fork($1, $3, $5); }
|
||||
|
||||
|
||||
/* Scope statements come in two forms. There are the scope
|
||||
declaration and the scope recall. */
|
||||
|
|
@ -329,6 +339,9 @@ int compile_design(const char*path)
|
|||
|
||||
/*
|
||||
* $Log: parse.y,v $
|
||||
* Revision 1.20 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.19 2001/04/14 05:10:56 steve
|
||||
* support the .event/or statement.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: schedule.cc,v 1.4 2001/03/31 19:00:43 steve Exp $"
|
||||
#ident "$Id: schedule.cc,v 1.5 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "schedule.h"
|
||||
|
|
@ -39,9 +39,10 @@ struct event_s {
|
|||
struct event_s*next;
|
||||
struct event_s*last;
|
||||
};
|
||||
const unsigned TYPE_THREAD = 0;
|
||||
const unsigned TYPE_PROP = 1;
|
||||
const unsigned TYPE_ASSIGN = 2;
|
||||
const unsigned TYPE_NOOP = 0;
|
||||
const unsigned TYPE_THREAD = 1;
|
||||
const unsigned TYPE_PROP = 2;
|
||||
const unsigned TYPE_ASSIGN = 3;
|
||||
|
||||
/*
|
||||
* This is the head of the list of pending events.
|
||||
|
|
@ -194,6 +195,9 @@ void schedule_simulate(void)
|
|||
|
||||
/*
|
||||
* $Log: schedule.cc,v $
|
||||
* Revision 1.5 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.4 2001/03/31 19:00:43 steve
|
||||
* Add VPI support for the simulation time.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_priv.h,v 1.12 2001/04/05 01:34:26 steve Exp $"
|
||||
#ident "$Id: vpi_priv.h,v 1.13 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
|
|
@ -85,8 +85,11 @@ struct __vpiScope {
|
|||
/* Keep an array of internal scope items. */
|
||||
struct __vpiHandle**intern;
|
||||
unsigned nintern;
|
||||
/* Keep a list of threads in the scope. */
|
||||
vthread_t threads;
|
||||
};
|
||||
extern vpiHandle vpip_peek_current_scope(void);
|
||||
|
||||
extern struct __vpiScope* vpip_peek_current_scope(void);
|
||||
extern void vpip_attach_to_current_scope(vpiHandle obj);
|
||||
|
||||
/*
|
||||
|
|
@ -96,7 +99,7 @@ extern void vpip_attach_to_current_scope(vpiHandle obj);
|
|||
*/
|
||||
struct __vpiSignal {
|
||||
struct __vpiHandle base;
|
||||
vpiHandle scope;
|
||||
struct __vpiScope* scope;
|
||||
/* The name of this reg/net object */
|
||||
char*name;
|
||||
/* The indices that define the width and access offset. */
|
||||
|
|
@ -128,7 +131,7 @@ struct __vpiUserSystf {
|
|||
|
||||
struct __vpiSysTaskCall {
|
||||
struct __vpiHandle base;
|
||||
vpiHandle scope;
|
||||
struct __vpiScope* scope;
|
||||
struct __vpiUserSystf*defn;
|
||||
unsigned nargs;
|
||||
vpiHandle*args;
|
||||
|
|
@ -193,6 +196,9 @@ vpiHandle vpip_sim_time(void);
|
|||
|
||||
/*
|
||||
* $Log: vpi_priv.h,v $
|
||||
* Revision 1.13 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.12 2001/04/05 01:34:26 steve
|
||||
* Add the .var/s and .net/s statements for VPI support.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_scope.cc,v 1.3 2001/04/03 03:46:14 steve Exp $"
|
||||
#ident "$Id: vpi_scope.cc,v 1.4 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compile.h"
|
||||
|
|
@ -94,12 +94,12 @@ static void attach_to_scope_(struct __vpiScope*scope, vpiHandle obj)
|
|||
*/
|
||||
void compile_scope_decl(char*label, char*name, char*parent)
|
||||
{
|
||||
struct __vpiScope*scope = (struct __vpiScope*)
|
||||
malloc(sizeof(struct __vpiScope));
|
||||
struct __vpiScope*scope = new struct __vpiScope;
|
||||
scope->base.vpi_type = &vpip_scope_rt;
|
||||
scope->name = name;
|
||||
scope->intern = 0;
|
||||
scope->nintern = 0;
|
||||
scope->threads = 0;
|
||||
|
||||
current_scope = scope;
|
||||
|
||||
|
|
@ -121,9 +121,9 @@ void compile_scope_recall(char*symbol)
|
|||
free(symbol);
|
||||
}
|
||||
|
||||
vpiHandle vpip_peek_current_scope(void)
|
||||
struct __vpiScope* vpip_peek_current_scope(void)
|
||||
{
|
||||
return ¤t_scope->base;
|
||||
return current_scope;
|
||||
}
|
||||
|
||||
void vpip_attach_to_current_scope(vpiHandle obj)
|
||||
|
|
@ -134,6 +134,9 @@ void vpip_attach_to_current_scope(vpiHandle obj)
|
|||
|
||||
/*
|
||||
* $Log: vpi_scope.cc,v $
|
||||
* Revision 1.4 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.3 2001/04/03 03:46:14 steve
|
||||
* VPI access time as a decimal string, and
|
||||
* stub vpi access to the scopes.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vpi_tasks.cc,v 1.4 2001/03/22 22:38:14 steve Exp $"
|
||||
#ident "$Id: vpi_tasks.cc,v 1.5 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -39,7 +39,7 @@ static vpiHandle systask_handle(int type, vpiHandle ref)
|
|||
|
||||
switch (type) {
|
||||
case vpiScope:
|
||||
return rfp->scope;
|
||||
return &rfp->scope->base;
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
|
|
@ -197,6 +197,9 @@ void vpi_register_systf(const struct t_vpi_systf_data*ss)
|
|||
|
||||
/*
|
||||
* $Log: vpi_tasks.cc,v $
|
||||
* Revision 1.5 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.4 2001/03/22 22:38:14 steve
|
||||
* Detect undefined system tasks at compile time.
|
||||
*
|
||||
|
|
|
|||
189
vvp/vthread.cc
189
vvp/vthread.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vthread.cc,v 1.26 2001/04/15 16:37:48 steve Exp $"
|
||||
#ident "$Id: vthread.cc,v 1.27 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vthread.h"
|
||||
|
|
@ -85,14 +85,16 @@ struct vthread_s {
|
|||
unsigned nbits :16;
|
||||
/* My parent sets this when it wants me to wake it up. */
|
||||
unsigned schedule_parent_on_end :1;
|
||||
unsigned i_have_ended :1;
|
||||
unsigned i_have_ended :1;
|
||||
unsigned waiting_for_event :1;
|
||||
/* 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;
|
||||
/* This is used for keeping wait queues. */
|
||||
struct vthread_s*next;
|
||||
struct vthread_s*wait_next;
|
||||
/* These are used to keep the thread in a scope. */
|
||||
struct vthread_s*scope_next, *scope_prev;
|
||||
};
|
||||
|
||||
static void thr_check_addr(struct vthread_s*thr, unsigned addr)
|
||||
|
|
@ -129,7 +131,7 @@ static inline void thr_put_bit(struct vthread_s*thr,
|
|||
/*
|
||||
* Create a new thread with the given start address.
|
||||
*/
|
||||
vthread_t vthread_new(unsigned long pc)
|
||||
vthread_t vthread_new(unsigned long pc, struct __vpiScope*scope)
|
||||
{
|
||||
vthread_t thr = new struct vthread_s;
|
||||
thr->pc = pc;
|
||||
|
|
@ -137,7 +139,28 @@ vthread_t vthread_new(unsigned long pc)
|
|||
thr->nbits = 16*4;
|
||||
thr->child = 0;
|
||||
thr->parent = 0;
|
||||
thr->next = 0;
|
||||
thr->wait_next = 0;
|
||||
|
||||
/* If the target scope never held a thread, then create a
|
||||
header cell for it. This is a stub to make circular lists
|
||||
easier to work with. */
|
||||
if (scope->threads == 0) {
|
||||
scope->threads = new struct vthread_s;
|
||||
scope->threads->pc = 0;
|
||||
scope->threads->bits = 0;
|
||||
scope->threads->nbits = 0;
|
||||
scope->threads->child = 0;
|
||||
scope->threads->parent = 0;
|
||||
scope->threads->scope_prev = scope->threads;
|
||||
scope->threads->scope_next = scope->threads;
|
||||
}
|
||||
|
||||
{ vthread_t tmp = scope->threads;
|
||||
thr->scope_next = tmp->scope_next;
|
||||
thr->scope_prev = tmp;
|
||||
thr->scope_next->scope_prev = thr;
|
||||
thr->scope_prev->scope_next = thr;
|
||||
}
|
||||
|
||||
thr->schedule_parent_on_end = 0;
|
||||
thr->i_have_ended = 0;
|
||||
|
|
@ -147,20 +170,30 @@ vthread_t vthread_new(unsigned long pc)
|
|||
thr_put_bit(thr, 1, 1);
|
||||
thr_put_bit(thr, 2, 2);
|
||||
thr_put_bit(thr, 3, 3);
|
||||
|
||||
return thr;
|
||||
}
|
||||
|
||||
static void vthread_reap(vthread_t thr)
|
||||
{
|
||||
assert(thr->next == 0);
|
||||
assert(thr->wait_next == 0);
|
||||
assert(thr->child == 0);
|
||||
|
||||
free(thr->bits);
|
||||
thr->bits = 0;
|
||||
|
||||
if (thr->child)
|
||||
thr->child->parent = thr->parent;
|
||||
if (thr->parent)
|
||||
thr->parent->child = thr->child;
|
||||
|
||||
thr->child = 0;
|
||||
thr->parent = 0;
|
||||
|
||||
thr->scope_next->scope_prev = thr->scope_prev;
|
||||
thr->scope_prev->scope_next = thr->scope_next;
|
||||
|
||||
thr->pc = 0;
|
||||
delete thr;
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +220,7 @@ void vthread_run(vthread_t thr)
|
|||
}
|
||||
|
||||
/*
|
||||
* This is called by an event functor to wait up all the threads on
|
||||
* This is called by an event functor to wake up all the threads on
|
||||
* its list. I in fact created that list in the %wait instruction, and
|
||||
* I also am certain that the waiting_for_event flag is set.
|
||||
*/
|
||||
|
|
@ -195,9 +228,10 @@ void vthread_schedule_list(vthread_t thr)
|
|||
{
|
||||
while (thr) {
|
||||
vthread_t tmp = thr;
|
||||
thr = thr->next;
|
||||
thr = thr->wait_next;
|
||||
assert(tmp->waiting_for_event);
|
||||
tmp->waiting_for_event = 0;
|
||||
tmp->wait_next = 0;
|
||||
schedule_vthread(tmp, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -430,30 +464,87 @@ bool of_DELAY(vthread_t thr, vvp_code_t cp)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the %disable instruction by scanning the target scope for
|
||||
* all the target threads. Kill the target threads and wake up a
|
||||
* parent that is attempting a %join.
|
||||
*
|
||||
* XXXX BUG BUG!
|
||||
* The scheduler probably still has a pointer to me, and this reaping
|
||||
* will destroy this object. The result: dangling pointer.
|
||||
*/
|
||||
bool of_DISABLE(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
struct __vpiScope*scope = (struct __vpiScope*)cp->handle;
|
||||
if (scope->threads == 0)
|
||||
return true;
|
||||
|
||||
struct vthread_s*head = scope->threads;
|
||||
|
||||
while (head->scope_next != head) {
|
||||
vthread_t tmp = head->scope_next;
|
||||
|
||||
/* Pull the target thread out of the scope. */
|
||||
tmp->scope_next->scope_prev = tmp->scope_prev;
|
||||
tmp->scope_prev->scope_next = tmp->scope_next;
|
||||
|
||||
/* XXXX I don't support disabling threads with children. */
|
||||
assert(tmp->child == 0);
|
||||
assert(tmp != thr);
|
||||
/* XXXX Not supported yet. */
|
||||
assert(tmp->waiting_for_event);
|
||||
|
||||
tmp->pc = 0;
|
||||
tmp->i_have_ended = 1;
|
||||
|
||||
/* If a parent is waiting in a %join, wake it up. */
|
||||
if (tmp->schedule_parent_on_end) {
|
||||
assert(tmp->parent);
|
||||
schedule_vthread(tmp->parent, 0);
|
||||
}
|
||||
|
||||
if (tmp->parent == 0) {
|
||||
vthread_reap(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This terminates the current thread. If there is a parent who is
|
||||
* waiting for me to die, then I schedule it. At any rate, I mark
|
||||
* myself as a zombie by setting my pc to 0.
|
||||
*/
|
||||
bool of_END(vthread_t thr, vvp_code_t cp)
|
||||
bool of_END(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
assert(! thr->waiting_for_event);
|
||||
|
||||
thr->i_have_ended = 1;
|
||||
thr->pc = 0;
|
||||
|
||||
#if 0
|
||||
/* Reap direct descendents that have already ended. Do
|
||||
this in a loop until I run out of dead children. */
|
||||
|
||||
while (thr->child && (thr->child->i_have_ended)) {
|
||||
fprintf(stderr, "vvp warning: A thread left dangling "
|
||||
"children at %%end. This is caused\n"
|
||||
" : by a missing %%join.\n");
|
||||
vthread_t tmp = thr->child;
|
||||
vthread_reap(tmp);
|
||||
}
|
||||
#else
|
||||
/* If this thread has children, then there is a programming
|
||||
error as there were not enough %join instructions to reap
|
||||
all the children. */
|
||||
assert(thr->child == 0);
|
||||
#endif
|
||||
|
||||
|
||||
/* If I have a parent who is waiting for me, then mark that I
|
||||
have ended, and schedule that parent. The parent will reap
|
||||
me, so don't do it here. */
|
||||
me with a %join, so don't do it here. */
|
||||
if (thr->schedule_parent_on_end) {
|
||||
assert(thr->parent);
|
||||
schedule_vthread(thr->parent, 0);
|
||||
|
|
@ -464,10 +555,12 @@ bool of_END(vthread_t thr, vvp_code_t cp)
|
|||
no reason to stick around. This can happen, for example if
|
||||
I am an ``initial'' thread. */
|
||||
if (thr->parent == 0) {
|
||||
#if 0
|
||||
if (thr->child)
|
||||
fprintf(stderr, "vvp warning: A thread left dangling "
|
||||
"children. This is probably caused\n"
|
||||
" : a missing %%join in this thread.\n");
|
||||
"children at delete. This is caused\n"
|
||||
" : by a missing %%join.\n");
|
||||
#endif
|
||||
vthread_reap(thr);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -486,7 +579,7 @@ bool of_END(vthread_t thr, vvp_code_t cp)
|
|||
*/
|
||||
bool of_FORK(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vthread_t child = vthread_new(cp->cptr);
|
||||
vthread_t child = vthread_new(cp->fork->cptr, cp->fork->scope);
|
||||
|
||||
child->child = thr->child;
|
||||
child->parent = thr;
|
||||
|
|
@ -562,11 +655,14 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp)
|
|||
{
|
||||
assert(thr->child);
|
||||
assert(thr->child->parent == thr);
|
||||
|
||||
/* If the child has already ended, reap it now. */
|
||||
if (thr->child->i_have_ended) {
|
||||
vthread_reap(thr->child);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, I get to start waiting. */
|
||||
thr->child->schedule_parent_on_end = 1;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -683,7 +779,7 @@ bool of_WAIT(vthread_t thr, vvp_code_t cp)
|
|||
functor_t fp = functor_index(cp->iptr);
|
||||
assert((fp->mode == 1) || (fp->mode == 2));
|
||||
vvp_event_t ep = fp->event;
|
||||
thr->next = ep->threads;
|
||||
thr->wait_next = ep->threads;
|
||||
ep->threads = thr;
|
||||
|
||||
return false;
|
||||
|
|
@ -764,13 +860,20 @@ bool of_XOR(vthread_t thr, vvp_code_t cp)
|
|||
}
|
||||
|
||||
|
||||
bool of_ZOMBIE(vthread_t, vvp_code_t)
|
||||
bool of_ZOMBIE(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
thr->pc = 0;
|
||||
if ((thr->parent == 0) && (thr->child == 0))
|
||||
delete thr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vthread.cc,v $
|
||||
* Revision 1.27 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.26 2001/04/15 16:37:48 steve
|
||||
* add XOR support.
|
||||
*
|
||||
|
|
@ -794,61 +897,5 @@ bool of_ZOMBIE(vthread_t, vvp_code_t)
|
|||
*
|
||||
* Revision 1.19 2001/04/01 07:22:08 steve
|
||||
* Implement the less-then and %or instructions.
|
||||
*
|
||||
* Revision 1.18 2001/04/01 06:12:14 steve
|
||||
* Add the bitwise %and instruction.
|
||||
*
|
||||
* Revision 1.17 2001/04/01 04:34:28 steve
|
||||
* Implement %cmp/x and %cmp/z instructions.
|
||||
*
|
||||
* Revision 1.16 2001/03/31 17:36:02 steve
|
||||
* Add the jmp/1 instruction.
|
||||
*
|
||||
* Revision 1.15 2001/03/31 01:59:59 steve
|
||||
* Add the ADD instrunction.
|
||||
*
|
||||
* Revision 1.14 2001/03/30 04:55:22 steve
|
||||
* Add fork and join instructions.
|
||||
*
|
||||
* Revision 1.13 2001/03/29 03:46:36 steve
|
||||
* Support named events as mode 2 functors.
|
||||
*
|
||||
* Revision 1.12 2001/03/26 04:00:39 steve
|
||||
* Add the .event statement and the %wait instruction.
|
||||
*
|
||||
* Revision 1.11 2001/03/25 03:54:26 steve
|
||||
* Add JMP0XZ and postpone net inputs when needed.
|
||||
*
|
||||
* Revision 1.10 2001/03/23 04:56:03 steve
|
||||
* eq is x if either value of cmp/u has x or z.
|
||||
*
|
||||
* Revision 1.9 2001/03/23 01:53:46 steve
|
||||
* Support set of functors from thread bits.
|
||||
*
|
||||
* Revision 1.8 2001/03/23 01:11:06 steve
|
||||
* Handle vectors pulled out of a constant bit.
|
||||
*
|
||||
* Revision 1.7 2001/03/22 05:08:00 steve
|
||||
* implement %load, %inv, %jum/0 and %cmp/u
|
||||
*
|
||||
* Revision 1.6 2001/03/20 06:16:24 steve
|
||||
* Add support for variable vectors.
|
||||
*
|
||||
* Revision 1.5 2001/03/19 01:55:38 steve
|
||||
* Add support for the vpiReset sim control.
|
||||
*
|
||||
* Revision 1.4 2001/03/16 01:44:34 steve
|
||||
* Add structures for VPI support, and all the %vpi_call
|
||||
* instruction. Get linking of VPI modules to work.
|
||||
*
|
||||
* Revision 1.3 2001/03/11 23:06:49 steve
|
||||
* Compact the vvp_code_s structure.
|
||||
*
|
||||
* Revision 1.2 2001/03/11 22:42:11 steve
|
||||
* Functor values and propagation.
|
||||
*
|
||||
* Revision 1.1 2001/03/11 00:29:39 steve
|
||||
* Add the vvp engine to cvs.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vthread.h,v 1.3 2001/04/13 03:55:18 steve Exp $"
|
||||
#ident "$Id: vthread.h,v 1.4 2001/04/18 04:21:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -40,7 +40,7 @@ typedef struct vthread_s*vthread_t;
|
|||
* address. The generated thread is ready to run, but is not yet
|
||||
* scheduled.
|
||||
*/
|
||||
extern vthread_t vthread_new(unsigned long sa);
|
||||
extern vthread_t vthread_new(unsigned long sa, struct __vpiScope*scope);
|
||||
|
||||
/*
|
||||
* Cause this thread to execute instructions until in is put to sleep
|
||||
|
|
@ -59,6 +59,9 @@ extern void vthread_schedule_list(vthread_t thr);
|
|||
|
||||
/*
|
||||
* $Log: vthread.h,v $
|
||||
* Revision 1.4 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
* Revision 1.3 2001/04/13 03:55:18 steve
|
||||
* More complete reap of all threads.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue