Add the .event statement and the %wait instruction.

This commit is contained in:
steve 2001-03-26 04:00:39 +00:00
parent f7f5ccce05
commit 79ce94b585
13 changed files with 352 additions and 25 deletions

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: README.txt,v 1.8 2001/03/24 22:59:28 steve Exp $
* $Id: README.txt,v 1.9 2001/03/26 04:00:39 steve Exp $
*/
VVP SIMULATION ENGINE
@ -186,6 +186,28 @@ position for that bit blank. Bits of .nets are initialized to
z. Unconnected bits keep the value z throughout the simulation.
EVENT STATEMENTS
Threads need to interact with the functors of a netlist synchronously,
as well as asynchronously. There are cases where the web of functors
needs to wake up a waiting thread. The web of functors signals threads
through .event objects, that are declare like so:
<label> .event <type>, <symbols_list>;
<label> .event "name";
This event statement declares an object that a %waitfor instruction
can take as an operand. When a thread executes a %waitfor, it puts
itself in the notification list of the event and suspends. The
<symbols_list> is a set of inputs that can trigger the event.
The <type> describes the conditions needed to trigger the event. It
may be posedge, negedge or edge. If the type is instead a "name"
string, then this is a named event which receives events by the %set
instruction instead of from the output of a functor.
THREAD STATEMENTS:
Thread statements create the initial threads for a simulation. These

View File

@ -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.6 2001/03/25 03:54:26 steve Exp $"
#ident "$Id: codes.h,v 1.7 2001/03/26 04:00:39 steve Exp $"
#endif
@ -46,6 +46,7 @@ extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
extern bool of_LOAD(vthread_t thr, vvp_code_t code);
extern bool of_MOV(vthread_t thr, vvp_code_t code);
extern bool of_SET(vthread_t thr, vvp_code_t code);
extern bool of_WAIT(vthread_t thr, vvp_code_t code);
extern bool of_NOOP(vthread_t thr, vvp_code_t code);
extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code);
@ -92,6 +93,9 @@ extern void codespace_dump(FILE*fd);
/*
* $Log: codes.h,v $
* Revision 1.7 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.6 2001/03/25 03:54:26 steve
* Add JMP0XZ and postpone net inputs when needed.
*

View File

@ -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.15 2001/03/25 19:38:23 steve Exp $"
#ident "$Id: compile.cc,v 1.16 2001/03/26 04:00:39 steve Exp $"
#endif
# include "compile.h"
@ -75,6 +75,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%load", of_LOAD, 2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%set", of_SET, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ 0, of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }
};
@ -226,6 +227,7 @@ void compile_functor(char*label, char*type, unsigned init,
obj->ival = init;
obj->oval = 2;
obj->mode = 0;
if (strcmp(type, "OR") == 0) {
obj->table = ft_OR;
@ -248,6 +250,71 @@ void compile_functor(char*label, char*type, unsigned init,
free(type);
}
void compile_event(char*label, char*type,
unsigned argc, struct symb_s*argv)
{
vvp_ipoint_t fdx = functor_allocate(1);
functor_t obj = functor_index(fdx);
{ symbol_value_t val;
val.num = fdx;
sym_set_value(sym_functors, label, val);
}
assert(argc <= 4);
/* Run through the arguments looking for the functors that are
connected to my input ports. For each source functor that I
find, connect the output of that functor to the indexed
input by inserting myself (complete with the port number in
the vvp_ipoint_t) into the list that the source heads.
If the source functor is not declared yet, then don't do
the link yet. Save the reference to be resolved later. */
for (unsigned idx = 0 ; idx < argc ; idx += 1) {
symbol_value_t val = sym_get_value(sym_functors, argv[idx].text);
vvp_ipoint_t tmp = val.num;
if (tmp) {
tmp = ipoint_index(tmp, argv[idx].idx);
functor_t fport = functor_index(tmp);
obj->port[idx] = fport->out;
fport->out = ipoint_make(fdx, idx);
free(argv[idx].text);
} else {
postpone_functor_input(ipoint_make(fdx, idx),
argv[idx].text,
argv[idx].idx);
}
}
free(argv);
obj->ival = 0xaa;
obj->oval = 2;
obj->mode = 1;
obj->event = (struct vvp_event_s*) malloc(sizeof (struct vvp_event_s));
obj->event->threads = 0;
obj->event->ival = obj->ival;
if (strcmp(type,"posedge") == 0)
obj->event->vvp_edge_tab = vvp_edge_posedge;
else if (strcmp(type,"negedge") == 0)
obj->event->vvp_edge_tab = vvp_edge_negedge;
else if (strcmp(type,"edge") == 0)
obj->event->vvp_edge_tab = vvp_edge_anyedge;
else
obj->event->vvp_edge_tab = 0;
free(type);
free(label);
}
/*
* The parser uses this function to compile an link an executable
* opcode. I do this by looking up the opcode in the opcode_table. The
@ -453,6 +520,7 @@ void compile_variable(char*label, char*name, int msb, int lsb)
obj->table = ft_var;
obj->ival = 0x22;
obj->oval = 0x02;
obj->mode = 0;
}
/* Make the vpiHandle for the reg. */
@ -477,6 +545,7 @@ void compile_net(char*label, char*name, int msb, int lsb,
obj->table = ft_var;
obj->ival = 0x22;
obj->oval = 0x02;
obj->mode = 0;
}
assert(argc == wid);
@ -593,6 +662,9 @@ void compile_dump(FILE*fd)
/*
* $Log: compile.cc,v $
* Revision 1.16 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.15 2001/03/25 19:38:23 steve
* Support NOR and NOT gates.
*

View File

@ -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.10 2001/03/25 00:35:35 steve Exp $"
#ident "$Id: compile.h,v 1.11 2001/03/26 04:00:39 steve Exp $"
#endif
# include <stdio.h>
@ -65,6 +65,15 @@ extern void compile_functor(char*label, char*type, unsigned init,
extern void compile_vpi_symbol(const char*label, vpiHandle obj);
extern vpiHandle compile_vpi_lookup(const char*label);
/*
* The compile_event function takes the parts of the event statement
* and makes the various objects needed to simulate it. This includes
* the functor that receives the signals and the event_t that holds
* the threads.
*/
extern void compile_event(char*label, char*type,
unsigned argc, struct symb_s*argv);
/*
* A code statement is a label, an opcode and up to 3 operands. There
* are a few lexical types that the parser recognizes of the operands,
@ -123,6 +132,9 @@ extern void compile_dump(FILE*fd);
/*
* $Log: compile.h,v $
* Revision 1.11 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.10 2001/03/25 00:35:35 steve
* Add the .net statement.
*

52
vvp/examples/edge.vvp Normal file
View File

@ -0,0 +1,52 @@
:vpi_module "system";
; Copyright (c) 2001 Stephen Williams (steve@icarus.com)
;
; This source code is free software; you can redistribute it
; and/or modify it in source code form under the terms of the GNU
; General Public License as published by the Free Software
; Foundation; either version 2 of the License, or (at your option)
; any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
; This example tests the operation of a simple posedge event. The module
; that would generate code like this would be:
;
; module main;
; reg a;
;
; initial begin
; a = 0;
; #1 a = 1;
; end
;
; always @(posedge a) $display("Got a posedge.");
;
; endmodule
;
main .scope "main";
V_main.a .var "a", 0, 0;
V_main.b .event posedge, V_main.a;
code
%set V_main.a, 0;
%delay 1;
%set V_main.a, 1;
%end;
.thread code;
loop %wait V_main.b;
%vpi_call "$display", "Got a posedge.";
%jmp loop;
.thread loop;

View File

@ -17,11 +17,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: functor.cc,v 1.6 2001/03/25 00:35:35 steve Exp $"
#ident "$Id: functor.cc,v 1.7 2001/03/26 04:00:39 steve Exp $"
#endif
# include "functor.h"
# include "schedule.h"
# include "vthread.h"
# include <assert.h>
/*
@ -131,6 +132,63 @@ functor_t functor_index(vvp_ipoint_t point)
return functor_table[point]->table[index1]->table + index0;
}
static void functor_set_mode0(vvp_ipoint_t ptr, functor_t fp)
{
/* Locate the new output value in the table. */
unsigned char out = fp->table[fp->ival >> 2];
out >>= 2 * (fp->ival&0x03);
out &= 0x03;
/* If the output changes, then create a propagation event. */
if (out != fp->oval) {
fp->oval = out;
schedule_functor(ptr, 0);
}
}
const unsigned char vvp_edge_posedge[16] = {
0, 1, 1, 1, // 0 -> ...
0, 0, 0, 0, // 1 -> ...
0, 1, 0, 0, // x -> ...
0, 1, 0, 0 // z -> ...
};
const unsigned char vvp_edge_negedge[16] = {
0, 0, 0, 0, // 0 -> ...
1, 0, 1, 1, // 1 -> ...
1, 0, 0, 0, // x -> ...
1, 0, 0, 0 // z -> ...
};
const unsigned char vvp_edge_anyedge[16] = {
0, 1, 1, 1, // 0 -> ...
1, 0, 1, 1, // 1 -> ...
1, 1, 0, 1, // x -> ...
1, 1, 1, 0 // z -> ...
};
static void functor_set_mode1(functor_t fp)
{
vvp_event_t ep = fp->event;
for (unsigned idx = 0 ; ep->threads && (idx < 4) ; idx += 1) {
unsigned oval = (ep->ival >> 2*idx) & 3;
unsigned nval = (fp->ival >> 2*idx) & 3;
unsigned val = (oval << 2) | nval;
unsigned char edge_p = ep->vvp_edge_tab[val];
if (edge_p) {
vthread_t tmp = ep->threads;
ep->threads = 0;
vthread_schedule_list(tmp);
}
}
/* the new value is the new old value. */
ep->ival = fp->ival;
}
/*
* Set the addressed bit of the functor, and recalculate the
* output. If the output changes any, then generate the necessary
@ -148,15 +206,13 @@ void functor_set(vvp_ipoint_t ptr, unsigned bit)
unsigned char mask = mask_table[pp];
fp->ival = (fp->ival & mask) | (bit << (2*pp));
/* Locate the new output value in the table. */
unsigned char out = fp->table[fp->ival >> 2];
out >>= 2 * (fp->ival&0x03);
out &= 0x03;
/* If the output changes, then create a propagation event. */
if (out != fp->oval) {
fp->oval = out;
schedule_functor(ptr, 0);
switch (fp->mode) {
case 0:
functor_set_mode0(ptr, fp);
break;
case 1:
functor_set_mode1(fp);
break;
}
}
@ -226,6 +282,9 @@ const unsigned char ft_var[16] = {
/*
* $Log: functor.cc,v $
* Revision 1.7 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.6 2001/03/25 00:35:35 steve
* Add the .net statement.
*

View File

@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: functor.h,v 1.5 2001/03/25 19:38:23 steve Exp $"
#ident "$Id: functor.h,v 1.6 2001/03/26 04:00:39 steve Exp $"
#endif
# include "pointers.h"
# include <stdio.h>
typedef const unsigned char*vvp_truth_t;
/*
* The vvp_ipoint_t is an integral type that is 32bits. The low 2 bits
@ -45,11 +44,25 @@ typedef const unsigned char*vvp_truth_t;
* 1'b1 : 01
* 1'bx : 10
* 1'bz : 11
*
* The function of the functor is defined by the table/event
* union. Normally, the truth table is the behavior and the functor
* output value is picked from the lookup table that the table pointer
* points to.
*
* If the functor is an event functor, however, the event member
* points to an extended structure where thread state is stored.
*
* The major mode is selected by the mode parameter.
*/
struct functor_s {
/* This is the truth table for the device */
vvp_truth_t table;
union {
vvp_truth_t table;
vvp_event_t event;
};
/* This is the output for the device. */
vvp_ipoint_t out;
/* These are the input ports. */
@ -57,10 +70,26 @@ struct functor_s {
/* These are the input values. */
unsigned char ival;
unsigned char oval;
/* functor mode: 0 == table ; 1 == event */
unsigned char mode;
};
typedef struct functor_s *functor_t;
/*
* If functor mode is 1, the event member is valid and the vvp_event_s
* points to the extended event information.
*/
extern const unsigned char vvp_edge_posedge[16];
extern const unsigned char vvp_edge_negedge[16];
extern const unsigned char vvp_edge_anyedge[16];
struct vvp_event_s {
vthread_t threads;
unsigned char ival;
const unsigned char*vvp_edge_tab;
};
/*
* Initialize the functors address space. This function must be called
* exactly once before any of the other functor functions may be
@ -115,6 +144,9 @@ extern const unsigned char ft_var[];
/*
* $Log: functor.h,v $
* Revision 1.6 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.5 2001/03/25 19:38:23 steve
* Support NOR and NOT gates.
*

View File

@ -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.8 2001/03/25 19:36:45 steve Exp $"
#ident "$Id: lexor.lex,v 1.9 2001/03/26 04:00:39 steve Exp $"
#endif
# include "parse_misc.h"
@ -48,6 +48,7 @@
/* These are some keywords that are recognized. */
".event" { return K_EVENT; }
".functor" { return K_FUNCTOR; }
".net" { return K_NET; }
".scope" { return K_SCOPE; }
@ -104,6 +105,9 @@ int yywrap()
/*
* $Log: lexor.lex,v $
* Revision 1.9 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.8 2001/03/25 19:36:45 steve
* Accept <> characters in labels and symbols.
*

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: opcodes.txt,v 1.5 2001/03/22 05:08:00 steve Exp $
* $Id: opcodes.txt,v 1.6 2001/03/26 04:00:39 steve Exp $
*/
@ -115,7 +115,7 @@ declared using VPI. The operands are compiled down to a vpiHandle for
the call. The instruction contains only the vpiHandle for the
call. See the vpi.txt file for more on system task/function calls.
* %waitfor <functor-label>
* %wait <functor-label>
When a thread executes this instruction, it places itself in the
sensitive list for the addressed functor. The functor holds all the

View File

@ -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.12 2001/03/25 00:35:35 steve Exp $"
#ident "$Id: parse.y,v 1.13 2001/03/26 04:00:39 steve Exp $"
#endif
# include "parse_misc.h"
@ -49,7 +49,7 @@ extern FILE*yyin;
};
%token K_FUNCTOR K_NET K_SCOPE K_THREAD K_VAR K_vpi_call
%token K_EVENT K_FUNCTOR K_NET K_SCOPE K_THREAD K_VAR K_vpi_call
%token K_vpi_module
%token <text> T_INSTR
@ -106,6 +106,14 @@ statement
| T_LABEL K_FUNCTOR T_SYMBOL',' T_NUMBER ';'
{ compile_functor($1, $3, $5, 0, 0); }
/* Event statements take a label, a type (the first T_SYMBOL) and a
list of inputs. */
| T_LABEL K_EVENT T_SYMBOL ',' symbols ';'
{ struct symbv_s obj = $5;
compile_event($1, $3, obj.cnt, obj.vect);
}
/* Instructions may have a label, and have zero or more
operands. The meaning of and restrictions on the operands depends
on the specific instruction. */
@ -295,6 +303,9 @@ int compile_design(const char*path)
/*
* $Log: parse.y,v $
* Revision 1.13 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.12 2001/03/25 00:35:35 steve
* Add the .net statement.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pointers.h,v 1.2 2001/03/20 06:16:24 steve Exp $"
#ident "$Id: pointers.h,v 1.3 2001/03/26 04:00:39 steve Exp $"
#endif
/*
@ -77,8 +77,26 @@ inline unsigned ipoint_port(vvp_ipoint_t func)
typedef unsigned vvp_cpoint_t;
/*
* The truth table that functors point to are addressed with this
* typedef.
*/
typedef const unsigned char*vvp_truth_t;
/*
* The functor event mode uses a pointer of this type to point to the
* extended event data.
*/
typedef struct vvp_event_s *vvp_event_t;
typedef struct vthread_s*vthread_t;
/*
* $Log: pointers.h,v $
* Revision 1.3 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.2 2001/03/20 06:16:24 steve
* Add support for variable vectors.
*

View File

@ -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.11 2001/03/25 03:54:26 steve Exp $"
#ident "$Id: vthread.cc,v 1.12 2001/03/26 04:00:39 steve Exp $"
#endif
# include "vthread.h"
@ -34,6 +34,8 @@ struct vthread_s {
unsigned long pc;
unsigned char *bits;
unsigned short nbits;
/* This is used for keeping wait queues. */
struct vthread_s*next;
};
static void thr_check_addr(struct vthread_s*thr, unsigned addr)
@ -76,6 +78,7 @@ vthread_t v_newthread(unsigned long pc)
thr->pc = pc;
thr->bits = (unsigned char*)malloc(16);
thr->nbits = 16*4;
thr->next = 0;
thr_put_bit(thr, 0, 0);
thr_put_bit(thr, 1, 1);
@ -106,6 +109,15 @@ void vthread_run(vthread_t thr)
}
}
void vthread_schedule_list(vthread_t thr)
{
while (thr) {
vthread_t tmp = thr;
thr = thr->next;
schedule_vthread(tmp, 0);
}
}
bool of_ASSIGN(vthread_t thr, vvp_code_t cp)
{
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx2);
@ -249,8 +261,26 @@ bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
return schedule_finished()? false : true;
}
/*
* Implement the wait by locating the functor for the event, and
* adding this thread to the threads list for the event.
*/
bool of_WAIT(vthread_t thr, vvp_code_t cp)
{
functor_t fp = functor_index(cp->iptr);
assert(fp->mode == 1);
vvp_event_t ep = fp->event;
thr->next = ep->threads;
ep->threads = thr;
return false;
}
/*
* $Log: vthread.cc,v $
* 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.
*

View File

@ -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.1 2001/03/11 00:29:39 steve Exp $"
#ident "$Id: vthread.h,v 1.2 2001/03/26 04:00:39 steve Exp $"
#endif
/*
@ -48,8 +48,19 @@ extern vthread_t v_newthread(unsigned long sa);
*/
extern void vthread_run(vthread_t thr);
/*
* This function schedules all the threads in the list to be scheduled
* for execution with delay 0. the thr pointer is taken to be the head
* of a list.
*/
extern void vthread_schedule_list(vthread_t thr);
/*
* $Log: vthread.h,v $
* Revision 1.2 2001/03/26 04:00:39 steve
* Add the .event statement and the %wait instruction.
*
* Revision 1.1 2001/03/11 00:29:39 steve
* Add the vvp engine to cvs.
*