diff --git a/vvp/README.txt b/vvp/README.txt index b46a792d8..c8f91fdda 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -1,7 +1,7 @@ /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) * - * $Id: README.txt,v 1.10 2001/03/29 03:46:36 steve Exp $ + * $Id: README.txt,v 1.11 2001/03/30 04:55:22 steve Exp $ */ VVP SIMULATION ENGINE @@ -29,7 +29,7 @@ semicolon that terminates a statement. Like so: The semicolon is required, whether the comment is there or not. Statements may span multiple lines, as long as there is no text (other -then the first character of a label) in the first column of hte +then the first character of a label) in the first column of the continuation line. HEADER SYNTAX @@ -54,7 +54,7 @@ Labels and symbols consist of the characters: a-z A-Z 0-9 - .$_ + .$_<> Labels and symbols may not start with a digit or a '.', so that they are easily distinguished from keywords and numbers. A Label is a @@ -229,6 +229,25 @@ This statement creates a thread with a starting address at the instruction given by . +THREADS IN GENERAL: + +Thread statements create the initial threads of a design. These +include the ``initial'' and ``always'' statements of the original +Verilog, and possibly some other synthetic threads for various +purposes. It is also possible to create transient threads from +behavioral code. These are needed to support such constructs as +fork/join, named blocks and task activation. + +A transient thread is created with a %fork instruction. When a +transient thread is created this way, the operand to the %fork gives +the starting address, and the new thread is said to be a child of the +forking thread. The children of a thread are pushed onto a stack of +children. + +A transient thread is reaped with a %join instruction. %join waits for +the top thread in the stack of children to complete, then +continues. It is an error to %join when there are no children. + TRUTH TABLES The logic that a functor represents is expressed as a truth table. The @@ -425,6 +444,17 @@ becomes: a .var "a", 0, 0; +* named events + +Events in general are implemented as functors, but named events in +partinular have no inputs and only the event output. The way to +generate code for these is like so: + + a .event "name"; + +This creates a functor and makes it into a mode-2 functor. Then the +trigger statement, "-> a", cause a ``%set a, 0;'' statement be +generated. This is sufficient to trigger the event. /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) diff --git a/vvp/codes.h b/vvp/codes.h index dbcd9fc6a..3fd3508a6 100644 --- a/vvp/codes.h +++ b/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.7 2001/03/26 04:00:39 steve Exp $" +#ident "$Id: codes.h,v 1.8 2001/03/30 04:55:22 steve Exp $" #endif @@ -39,10 +39,12 @@ extern bool of_ASSIGN(vthread_t thr, vvp_code_t code); extern bool of_CMPU(vthread_t thr, vvp_code_t code); extern bool of_DELAY(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); 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); +extern bool of_JOIN(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); @@ -93,6 +95,9 @@ extern void codespace_dump(FILE*fd); /* * $Log: codes.h,v $ + * Revision 1.8 2001/03/30 04:55:22 steve + * Add fork and join instructions. + * * Revision 1.7 2001/03/26 04:00:39 steve * Add the .event statement and the %wait instruction. * diff --git a/vvp/compile.cc b/vvp/compile.cc index 7a4b46a7f..ec055ffc3 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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.18 2001/03/29 03:46:36 steve Exp $" +#ident "$Id: compile.cc,v 1.19 2001/03/30 04:55:22 steve Exp $" #endif # include "compile.h" @@ -69,10 +69,12 @@ const static struct opcode_table_s opcode_table[] = { { "%cmp/u", of_CMPU, 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} }, { "%jmp/0xz",of_JMP0XZ, 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} }, { "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%set", of_SET, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, @@ -685,6 +687,9 @@ void compile_dump(FILE*fd) /* * $Log: compile.cc,v $ + * Revision 1.19 2001/03/30 04:55:22 steve + * Add fork and join instructions. + * * Revision 1.18 2001/03/29 03:46:36 steve * Support named events as mode 2 functors. * diff --git a/vvp/examples/fork.vvp b/vvp/examples/fork.vvp new file mode 100644 index 000000000..3f8374c3e --- /dev/null +++ b/vvp/examples/fork.vvp @@ -0,0 +1,33 @@ +: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 sample demonstrates the behavior of %fork and %join. + +S_main .scope "main"; + +child %vpi_call "$display", "I'm a child"; + %end; + +parent %fork child; + %vpi_call "$display", "I'm a parent"; + %join; + %vpi_call "$display", "reaped"; + %end; + + .thread parent; diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 4c1403fab..7635a22e3 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1,7 +1,7 @@ /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) * - * $Id: opcodes.txt,v 1.6 2001/03/26 04:00:39 steve Exp $ + * $Id: opcodes.txt,v 1.7 2001/03/30 04:55:22 steve Exp $ */ @@ -9,7 +9,9 @@ EXECUTABLE INSTRUCTION OPCODES Instruction opcodes all start with a % character and have 0 or more -operands. In no case are there more then 3 operands. +operands. In no case are there more then 3 operands. This chapter +describes the specific behavior of each opcode, in hopefully enough +detail that its complete effect can be predicted. * %assign , , @@ -68,9 +70,29 @@ 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 + +This instruction is similar to %jmp, except that it creates a new +thread to start executing at the specified address. The new thread is +created and pushed onto the child stack. It is also marked runnable, +but is not necessarily started until the current thread yields. + +The %fork instruction has no effect other then to push a child thread. + +See also %join. + + * %inv , -Perform a bitwise invert of the vector starting at . +Perform a bitwise invert of the vector starting at . The result +replaces the input. Invert means the following, independently for each +bit: + + 0 --> 1 + 1 --> 0 + x --> x + z --> x + * %jmp @@ -87,6 +109,21 @@ values in the part after the /, the jump is taken. For example: will jump to T_label if bit 8 is x or z. +* %join + +This is the partner to %fork. This instruction causes the thread to +wait for the top thread in the child stack to terminate, then +continues. It has no effect in the current thread other then to wait +until the top child is cleared. + +It is an error to execute %join if there are no children in the child +stack. If a child thread terminates before this instruction is called, +it remains in the stack as a zombie until the %join reaps it. + +If a thread terminates (i.e. executes %end) all its children are +terminated as well. + + * %load , This instruction loads a value from the given functor output into the diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 2ab97ffe2..83c1af2db 100644 --- a/vvp/vthread.cc +++ b/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.13 2001/03/29 03:46:36 steve Exp $" +#ident "$Id: vthread.cc,v 1.14 2001/03/30 04:55:22 steve Exp $" #endif # include "vthread.h" @@ -34,6 +34,10 @@ struct vthread_s { unsigned long pc; unsigned char *bits; unsigned short nbits; + /* This points to the top (youngest) child of the thread. */ + struct vthread_s*child; + /* This is set if the parent is waiting for me to end. */ + struct vthread_s*reaper; /* This is used for keeping wait queues. */ struct vthread_s*next; }; @@ -78,6 +82,8 @@ vthread_t v_newthread(unsigned long pc) thr->pc = pc; thr->bits = (unsigned char*)malloc(16); thr->nbits = 16*4; + thr->child = 0; + thr->reaper = 0; thr->next = 0; thr_put_bit(thr, 0, 0); @@ -87,6 +93,13 @@ vthread_t v_newthread(unsigned long pc) return thr; } +static void vthread_reap(vthread_t thr) +{ + assert(thr->next == 0); + assert(thr->child == 0); + free(thr); +} + /* * This function runs a thread by fetching an instruction, @@ -169,10 +182,21 @@ bool of_DELAY(vthread_t thr, vvp_code_t cp) bool of_END(vthread_t thr, vvp_code_t cp) { - //printf("thread %p: %%end\n", thr); + if (thr->reaper) + schedule_vthread(thr->reaper, 0); + thr->reaper = thr; return false; } +bool of_FORK(vthread_t thr, vvp_code_t cp) +{ + vthread_t child = v_newthread(cp->cptr); + child->child = thr->child; + thr->child = child; + schedule_vthread(child, 0); + return true; +} + bool of_INV(vthread_t thr, vvp_code_t cp) { assert(cp->bit_idx1 >= 4); @@ -214,6 +238,19 @@ bool of_JMP0XZ(vthread_t thr, vvp_code_t cp) return true; } +bool of_JOIN(vthread_t thr, vvp_code_t cp) +{ + assert(thr->child); + if (thr->child->reaper == thr->child) { + vthread_reap(thr->child); + return true; + } + + assert(thr->child->reaper == 0); + thr->child->reaper = thr; + return false; +} + bool of_LOAD(vthread_t thr, vvp_code_t cp) { assert(cp->bit_idx1 >= 4); @@ -278,6 +315,9 @@ bool of_WAIT(vthread_t thr, vvp_code_t cp) /* * $Log: vthread.cc,v $ + * 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. *