Document memory related opcodes,
parser uses numbv_s structures instead of the
symbv_s and a mess of unions,
Add the %is/sub instruction.
(Stephan Boettcher)
This commit is contained in:
parent
0f9eb13245
commit
a225fe304d
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: README.txt,v 1.22 2001/05/02 04:05:17 steve Exp $
|
||||
* $Id: README.txt,v 1.23 2001/05/02 23:16:50 steve Exp $
|
||||
*/
|
||||
|
||||
VVP SIMULATION ENGINE
|
||||
|
|
@ -170,10 +170,6 @@ A UDP functor instance is created so:
|
|||
Where <label> identifies the functor, <type> is the label of a UDP
|
||||
defined earlier, and <symbol_list> is a list of symbols, one for each
|
||||
input of the UDP.
|
||||
|
||||
ATTN: The "<name>" attribute of the UDP is pretty useless, and may go
|
||||
away in future versions. It may be useful for diagnostic messages,
|
||||
though.
|
||||
|
||||
|
||||
VARIABLE STATEMENTS:
|
||||
|
|
@ -334,18 +330,15 @@ initializes four memory bits. Two bits form each byte for each memory
|
|||
bit, in the ususal encoding.
|
||||
|
||||
Procedural access to the memory employs an index register to address a
|
||||
bit location in the mememory, via the commands:
|
||||
bit location in the memory, via the commands:
|
||||
|
||||
%load/mem <bit>, <memid>[<ix>] ;
|
||||
%set/mem <memid>[<ix>], <bit> ;
|
||||
%assign/mem <memid>[<ix>], <delay>, <bit> ;
|
||||
%load/m <bit>, <memid> ;
|
||||
%set/m <memid>, <bit> ;
|
||||
%assign/m <memid>, <delay>, <bit> ;
|
||||
|
||||
??? is "/mem" required, or shall functors and memories share a
|
||||
namespace? ???
|
||||
|
||||
<ix> identifies one of the four index registers of the current
|
||||
thread. The value of register <ix> is the index in the memories bit
|
||||
space, where each data word occupies a multiple of four bits.
|
||||
The memory bit is addressed by index register 3. The value of
|
||||
register 3 is the index in the memory's bit space, where each data
|
||||
word occupies a multiple of four bits.
|
||||
|
||||
|
||||
EVENT STATEMENTS
|
||||
|
|
|
|||
10
vvp/codes.h
10
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.22 2001/05/02 01:57:25 steve Exp $"
|
||||
#ident "$Id: codes.h,v 1.23 2001/05/02 23:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -52,6 +52,7 @@ extern bool of_INV(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_IX_ADD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_LOAD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_MUL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_SUB(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -126,6 +127,13 @@ extern void codespace_dump(FILE*fd);
|
|||
|
||||
/*
|
||||
* $Log: codes.h,v $
|
||||
* Revision 1.23 2001/05/02 23:16:50 steve
|
||||
* Document memory related opcodes,
|
||||
* parser uses numbv_s structures instead of the
|
||||
* symbv_s and a mess of unions,
|
||||
* Add the %is/sub instruction.
|
||||
* (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.22 2001/05/02 01:57:25 steve
|
||||
* Support behavioral subtraction.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.52 2001/05/02 04:05:17 steve Exp $"
|
||||
#ident "$Id: compile.cc,v 1.53 2001/05/02 23:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compile.h"
|
||||
|
|
@ -56,9 +56,8 @@ enum operand_e {
|
|||
OA_CODE_PTR,
|
||||
/* The operand is a variable or net pointer */
|
||||
OA_FUNC_PTR,
|
||||
/* The operand is a memory, with index ... */
|
||||
OA_MEM_X3, /* ... hardwired index register 3 */
|
||||
OA_MEM_I1 /* ... index register in bit1 */
|
||||
/* The operand is a pointer to a memory */
|
||||
OA_MEM_PTR,
|
||||
};
|
||||
|
||||
struct opcode_table_s {
|
||||
|
|
@ -73,7 +72,7 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%assign", of_ASSIGN, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/m",of_ASSIGN_MEM,3,{OA_MEM_X3, OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/m",of_ASSIGN_MEM,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%cmp/x", of_CMPX, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
|
|
@ -84,19 +83,20 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
{ "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
{ "%ix/sub", of_IX_SUB, 2, {OA_BIT1, OA_NUMBER, 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} },
|
||||
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%load", of_LOAD, 2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
|
||||
{ "%load/m", of_LOAD_MEM,2, {OA_BIT2, OA_MEM_I1, OA_NONE} },
|
||||
{ "%load/m", of_LOAD_MEM,2, {OA_BIT1, OA_MEM_PTR, OA_NONE} },
|
||||
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%set", of_SET, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%set/m", of_SET_MEM,2, {OA_MEM_I1, OA_BIT1, OA_NONE} },
|
||||
{ "%set/m", of_SET_MEM,2, {OA_MEM_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%sub", of_SUB, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
|
|
@ -692,8 +692,7 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
|
|||
code->number = opa->argv[idx].numb;
|
||||
break;
|
||||
|
||||
case OA_MEM_I1:
|
||||
case OA_MEM_X3:
|
||||
case OA_MEM_PTR:
|
||||
if (opa->argv[idx].ltype != L_SYMB) {
|
||||
yyerror("operand format");
|
||||
break;
|
||||
|
|
@ -701,26 +700,7 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
|
|||
|
||||
code->mem = memory_find(opa->argv[idx].symb.text);
|
||||
if (code->mem == 0) {
|
||||
yyerror("functor undefined");
|
||||
break;
|
||||
}
|
||||
|
||||
if (opa->argv[idx].symb.idx >= 4) {
|
||||
yyerror("index operand out of range (0..3)");
|
||||
break;
|
||||
}
|
||||
|
||||
switch(op->argt[idx]) {
|
||||
case OA_MEM_I1:
|
||||
code->bit_idx1 = (unsigned short)
|
||||
opa->argv[idx].symb.idx;
|
||||
break;
|
||||
case OA_MEM_X3:
|
||||
if (opa->argv[idx].symb.idx != 3)
|
||||
yyerror("index operand must be 3");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
yyerror("memory undefined");
|
||||
}
|
||||
|
||||
free(opa->argv[idx].symb.text);
|
||||
|
|
@ -1064,6 +1044,13 @@ void compile_dump(FILE*fd)
|
|||
|
||||
/*
|
||||
* $Log: compile.cc,v $
|
||||
* Revision 1.53 2001/05/02 23:16:50 steve
|
||||
* Document memory related opcodes,
|
||||
* parser uses numbv_s structures instead of the
|
||||
* symbv_s and a mess of unions,
|
||||
* Add the %is/sub instruction.
|
||||
* (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.52 2001/05/02 04:05:17 steve
|
||||
* Remove the init parameter of functors, and instead use
|
||||
* the special C<?> symbols to initialize inputs. This is
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: opcodes.txt,v 1.16 2001/05/02 01:57:26 steve Exp $
|
||||
* $Id: opcodes.txt,v 1.17 2001/05/02 23:16:50 steve Exp $
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -41,6 +41,15 @@ the assignment takes place. The delay may be 0. For blocking
|
|||
assignments, see %set. The <bit> is the address of the thread register
|
||||
that contains the bit value to assign.
|
||||
|
||||
|
||||
* %assign/m <memory-label>, <delay>, <bit>
|
||||
|
||||
This instruction does a non-blocking assignment to a bit in a memory
|
||||
from the specified thread register <bit>. The memory bit is addressed
|
||||
by index register 3. Bit address zero is the LSB of the first memory
|
||||
word.
|
||||
|
||||
|
||||
* %cmp/u <bit-l>, <bit-r>, <wid>
|
||||
* %cmp/s <bit-l>, <bit-r>, <wid>
|
||||
|
||||
|
|
@ -129,6 +138,16 @@ number. The idx value selects the index register, and may be 0, 1, 2
|
|||
or 3.
|
||||
|
||||
|
||||
* %ix/add <idx>, <value>
|
||||
* %ix/sub <idx>, <value>
|
||||
* %ix/mul <idx>, <value>
|
||||
|
||||
This instruction adds, subtracts, or multiplies an immediate value to
|
||||
the addressed index register. The index register holds numeric values,
|
||||
so the <value> is a number. The <idx> value selects the index register,
|
||||
and may be 0, 1, 2 or 3.
|
||||
|
||||
|
||||
* %jmp <code-label>
|
||||
|
||||
The %jmp instruction performs an unconditional branch to a given
|
||||
|
|
@ -169,6 +188,14 @@ functor within a vector of functors. This instruction loads only a
|
|||
single bit.
|
||||
|
||||
|
||||
* %load/m <bit>, <memory-label>
|
||||
|
||||
This instruction loads a value from a memory bit into the specified
|
||||
thread register bit. The memory bit is addressed by index register 3.
|
||||
Bit address zero is the LSB of the first memory word. This
|
||||
instruction loads only a single bit.
|
||||
|
||||
|
||||
* %mov <dst>, <src>, <wid>
|
||||
|
||||
This instruction copies a vector from one place in register space to
|
||||
|
|
@ -211,6 +238,14 @@ be read out of the variable. The <bit> is the address of the thread
|
|||
register that contains the bit value to assign.
|
||||
|
||||
|
||||
* %set/m <memory-label>, <bit>
|
||||
|
||||
This instruction set a bit in a memory from the specified thread
|
||||
register bit. The memory bit is addressed by index register 3. Bit
|
||||
address zero is the LSB of the first memory word. This instruction
|
||||
sets only a single bit.
|
||||
|
||||
|
||||
* %sub <bit-l>, <bit-r>, <wid>
|
||||
|
||||
This instruction arithmetically subtracts the right vector out of the
|
||||
|
|
|
|||
14
vvp/parse.y
14
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.24 2001/05/02 04:05:17 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.25 2001/05/02 23:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -45,6 +45,8 @@ extern FILE*yyin;
|
|||
struct symb_s symb;
|
||||
struct symbv_s symbv;
|
||||
|
||||
struct numbv_s numbv;
|
||||
|
||||
struct symb_s vect;
|
||||
|
||||
struct argv_s argv;
|
||||
|
|
@ -66,7 +68,8 @@ extern FILE*yyin;
|
|||
%token <vect> T_VECTOR
|
||||
|
||||
%type <symb> symbol symbol_opt
|
||||
%type <symbv> symbols symbols_net numbers
|
||||
%type <symbv> symbols symbols_net
|
||||
%type <numbv> numbers
|
||||
%type <text> label_opt
|
||||
%type <opa> operand operands operands_opt
|
||||
%type <table> udp_table
|
||||
|
|
@ -426,6 +429,13 @@ int compile_design(const char*path)
|
|||
|
||||
/*
|
||||
* $Log: parse.y,v $
|
||||
* Revision 1.25 2001/05/02 23:16:50 steve
|
||||
* Document memory related opcodes,
|
||||
* parser uses numbv_s structures instead of the
|
||||
* symbv_s and a mess of unions,
|
||||
* Add the %is/sub instruction.
|
||||
* (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.24 2001/05/02 04:05:17 steve
|
||||
* Remove the init parameter of functors, and instead use
|
||||
* the special C<?> symbols to initialize inputs. This is
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: parse_misc.cc,v 1.4 2001/05/01 01:09:39 steve Exp $"
|
||||
#ident "$Id: parse_misc.cc,v 1.5 2001/05/02 23:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -46,6 +46,12 @@ void symbv_add(struct symbv_s*obj, struct symb_s item)
|
|||
obj->cnt += 1;
|
||||
}
|
||||
|
||||
void numbv_init(struct numbv_s*obj)
|
||||
{
|
||||
obj->cnt = 0;
|
||||
obj->nvec = 0;
|
||||
}
|
||||
|
||||
void numbv_add(struct numbv_s*obj, long item)
|
||||
{
|
||||
obj->nvec = (long*) realloc(obj->nvec, (obj->cnt+1) * sizeof(long));
|
||||
|
|
@ -69,6 +75,13 @@ void argv_add(struct argv_s*obj, vpiHandle item)
|
|||
|
||||
/*
|
||||
* $Log: parse_misc.cc,v $
|
||||
* Revision 1.5 2001/05/02 23:16:50 steve
|
||||
* Document memory related opcodes,
|
||||
* parser uses numbv_s structures instead of the
|
||||
* symbv_s and a mess of unions,
|
||||
* Add the %is/sub instruction.
|
||||
* (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.4 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: parse_misc.h,v 1.4 2001/05/01 01:09:39 steve Exp $"
|
||||
#ident "$Id: parse_misc.h,v 1.5 2001/05/02 23:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -50,17 +50,18 @@ struct symb_s {
|
|||
|
||||
struct symbv_s {
|
||||
unsigned cnt;
|
||||
union {
|
||||
struct symb_s*vect;
|
||||
long*nvec;
|
||||
};
|
||||
struct symb_s*vect;
|
||||
};
|
||||
|
||||
extern void symbv_init(struct symbv_s*obj);
|
||||
extern void symbv_add(struct symbv_s*obj, struct symb_s item);
|
||||
|
||||
#define numbv_s symbv_s
|
||||
#define numbv_init symbv_init
|
||||
struct numbv_s {
|
||||
unsigned cnt;
|
||||
long*nvec;
|
||||
};
|
||||
|
||||
extern void numbv_init(struct numbv_s*obj);
|
||||
extern void numbv_add(struct numbv_s*obj, long item);
|
||||
|
||||
|
||||
|
|
@ -75,6 +76,13 @@ extern void argv_add(struct argv_s*obj, vpiHandle);
|
|||
|
||||
/*
|
||||
* $Log: parse_misc.h,v $
|
||||
* Revision 1.5 2001/05/02 23:16:50 steve
|
||||
* Document memory related opcodes,
|
||||
* parser uses numbv_s structures instead of the
|
||||
* symbv_s and a mess of unions,
|
||||
* Add the %is/sub instruction.
|
||||
* (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.4 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.33 2001/05/02 01:57:26 steve Exp $"
|
||||
#ident "$Id: vthread.cc,v 1.34 2001/05/02 23:16:50 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vthread.h"
|
||||
|
|
@ -168,6 +168,7 @@ vthread_t vthread_new(unsigned long pc, struct __vpiScope*scope)
|
|||
thr->is_scheduled = 0;
|
||||
thr->i_have_ended = 0;
|
||||
thr->waiting_for_event = 0;
|
||||
thr->is_scheduled = 0;
|
||||
|
||||
thr_put_bit(thr, 0, 0);
|
||||
thr_put_bit(thr, 1, 1);
|
||||
|
|
@ -626,20 +627,24 @@ bool of_INV(vthread_t thr, vvp_code_t cp)
|
|||
|
||||
|
||||
/*
|
||||
** Index registers, signed arithmetic.
|
||||
** Index registers, unsigned arithmetic.
|
||||
*/
|
||||
|
||||
bool of_IX_ADD(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
int number = (int)cp->number; // signed
|
||||
thr->index[cp->bit_idx1 & 3] += number;
|
||||
thr->index[cp->bit_idx1 & 3] += cp->number;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_IX_SUB(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
thr->index[cp->bit_idx1 & 3] -= cp->number;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_IX_MUL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
int number = (int)cp->number; // signed
|
||||
thr->index[cp->bit_idx1 & 3] *= number;
|
||||
thr->index[cp->bit_idx1 & 3] *= cp->number;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -714,9 +719,8 @@ bool of_LOAD(vthread_t thr, vvp_code_t cp)
|
|||
bool of_LOAD_MEM(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx1 >= 4);
|
||||
assert(cp->bit_idx2 < 4);
|
||||
unsigned char val = memory_get(cp->mem, thr->index[cp->bit_idx1]);
|
||||
thr_put_bit(thr, cp->bit_idx2, val);
|
||||
unsigned char val = memory_get(cp->mem, thr->index[3]);
|
||||
thr_put_bit(thr, cp->bit_idx1, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -809,9 +813,8 @@ bool of_SET(vthread_t thr, vvp_code_t cp)
|
|||
|
||||
bool of_SET_MEM(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx2 < 4);
|
||||
unsigned char val = thr_get_bit(thr, cp->bit_idx2);
|
||||
memory_set(cp->mem, thr->index[cp->bit_idx1], val);
|
||||
unsigned char val = thr_get_bit(thr, cp->bit_idx1);
|
||||
memory_set(cp->mem, thr->index[3], val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -966,6 +969,13 @@ bool of_ZOMBIE(vthread_t thr, vvp_code_t)
|
|||
|
||||
/*
|
||||
* $Log: vthread.cc,v $
|
||||
* Revision 1.34 2001/05/02 23:16:50 steve
|
||||
* Document memory related opcodes,
|
||||
* parser uses numbv_s structures instead of the
|
||||
* symbv_s and a mess of unions,
|
||||
* Add the %is/sub instruction.
|
||||
* (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.33 2001/05/02 01:57:26 steve
|
||||
* Support behavioral subtraction.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue