Add support for memory objects. (Stephan Boettcher)
This commit is contained in:
parent
972e9c866b
commit
8b4befd4fc
|
|
@ -16,7 +16,7 @@
|
|||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.14 2001/04/24 02:23:59 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.15 2001/05/01 01:09:39 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
|
@ -61,7 +61,7 @@ V = vpi_modules.o vpi_const.o vpi_iter.o vpi_mcd.o vpi_priv.o \
|
|||
vpi_scope.o vpi_signal.o vpi_tasks.o vpi_time.o
|
||||
|
||||
O = main.o parse.o parse_misc.o lexor.o compile.o functor.o symbols.o \
|
||||
codes.o vthread.o schedule.o tables.o udp.o $V
|
||||
codes.o vthread.o schedule.o tables.o udp.o memory.o $V
|
||||
|
||||
vvp: $O
|
||||
$(CXX) $(rdynamic) $(CXXFLAGS) $(LDFLAGS) -o vvp $O $(dllib)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: README.txt,v 1.20 2001/04/30 04:51:27 steve Exp $
|
||||
* $Id: README.txt,v 1.21 2001/05/01 01:09:39 steve Exp $
|
||||
*/
|
||||
|
||||
VVP SIMULATION ENGINE
|
||||
|
|
@ -281,6 +281,77 @@ This prevents any real functor being created and connected, and
|
|||
instead leaves the input unconnected and initializes the wire with the
|
||||
specified value, instead of the default z.
|
||||
|
||||
MEMORY STATEMENTS:
|
||||
|
||||
Three types of memory stetement perform (1) creation of a memory, (2)
|
||||
connecting a read port to an existing memory, and (3) initializing the
|
||||
memory's contents.
|
||||
|
||||
<label> .mem "name", <msb>,<lsb>, <last>,<first> ... ;
|
||||
|
||||
The pair of numbers <msb>,<lsb> defines the data port width. The pair
|
||||
<last>,<first> defines the address range. Multiple address ranges are
|
||||
allowed for multidimensional indexing.
|
||||
|
||||
Procedural access to the memory references the memory as single array
|
||||
of bits. For this purpose, the number of bits in a memory word is
|
||||
rounded up to the next multiple of four. That is, for an 18 bit wide
|
||||
data bus, bit 0 is the lsb of the first word, bit 20 is the lsb of the
|
||||
second word.
|
||||
|
||||
Structural read access is implemented in terms of address and data
|
||||
ports. An address port is the concatinations of the smallest number of
|
||||
address bits required to express each address range. The addresses
|
||||
applied to the address port are expected to be withing the ranges
|
||||
specified.
|
||||
|
||||
An port is a vector of functors that is wide enough to accept all
|
||||
address bits and at least as wide as the requested subset of the data
|
||||
port.
|
||||
|
||||
<label> .mem/port <memid>, <msb>,<lsb>, <symbols_list> ;
|
||||
|
||||
<label> identifies the vector of output functors, to allow connections
|
||||
to the data output. <memid> is the label of the memory. <msb>,<lsb>
|
||||
select a part of the data width. These are not relative to the data
|
||||
port range defined for the memory. The LSB of the data word if here
|
||||
referred to as 0, regardless to the range specified in the memory
|
||||
definition. The <symbols_list> connects to the address inputs of this
|
||||
port.
|
||||
|
||||
Any address change, or any change in the addressed memory contents is
|
||||
imediately propagated to the port outputs.
|
||||
|
||||
To initialize a memory, use:
|
||||
|
||||
.mem/init <memid>[<start>],
|
||||
val val val ...
|
||||
;
|
||||
|
||||
<memid> is the lavbel of the memory. [<start>] is optional,
|
||||
identifying the bits locattion where the first value is loaded.
|
||||
<start> must be a multiple of four, and defaults to zero, if omitted.
|
||||
|
||||
The values are decimal or hex numbers (0x prefix), which may be
|
||||
optionally separated by commata ','. Each number in the range 0..256
|
||||
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:
|
||||
|
||||
%load/mem <bit>, <memid>[<ix>] ;
|
||||
%set/mem <memid>[<ix>], <bit> ;
|
||||
%assign/mem <memid>[<ix>], <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.
|
||||
|
||||
|
||||
EVENT STATEMENTS
|
||||
|
||||
Threads need to interact with the functors of a netlist synchronously,
|
||||
|
|
|
|||
13
vvp/codes.h
13
vvp/codes.h
|
|
@ -19,11 +19,12 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: codes.h,v 1.20 2001/04/18 04:21:23 steve Exp $"
|
||||
#ident "$Id: codes.h,v 1.21 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
# include "pointers.h"
|
||||
# include "memory.h"
|
||||
# include "vthread.h"
|
||||
# include <stdio.h>
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ typedef bool (*vvp_code_fun)(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_ADD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_AND(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_MEM(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPS(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPU(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPX(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -47,17 +49,22 @@ 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);
|
||||
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_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_JMP1(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_LOAD_MEM(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_MOV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_NOOP(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_NORR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_OR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_MEM(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_WAIT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_XNOR(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -75,6 +82,7 @@ struct vvp_code_s {
|
|||
unsigned number;
|
||||
vvp_ipoint_t iptr;
|
||||
vvp_cpoint_t cptr;
|
||||
vvp_memory_t mem;
|
||||
struct __vpiHandle*handle;
|
||||
struct fork_extend*fork;
|
||||
};
|
||||
|
|
@ -117,6 +125,9 @@ extern void codespace_dump(FILE*fd);
|
|||
|
||||
/*
|
||||
* $Log: codes.h,v $
|
||||
* Revision 1.21 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.20 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
|
|
|
|||
108
vvp/compile.cc
108
vvp/compile.cc
|
|
@ -17,12 +17,13 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: compile.cc,v 1.47 2001/04/30 03:53:19 steve Exp $"
|
||||
#ident "$Id: compile.cc,v 1.48 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compile.h"
|
||||
# include "functor.h"
|
||||
# include "udp.h"
|
||||
# include "memory.h"
|
||||
# include "symbols.h"
|
||||
# include "codes.h"
|
||||
# include "schedule.h"
|
||||
|
|
@ -54,7 +55,10 @@ enum operand_e {
|
|||
/* The operand is a pointer to code space */
|
||||
OA_CODE_PTR,
|
||||
/* The operand is a variable or net pointer */
|
||||
OA_FUNC_PTR
|
||||
OA_FUNC_PTR,
|
||||
/* The operand is a memory, with index ... */
|
||||
OA_MEM_X3, /* ... hardwired index register 3 */
|
||||
OA_MEM_I1 /* ... index register in bit1 */
|
||||
};
|
||||
|
||||
struct opcode_table_s {
|
||||
|
|
@ -69,6 +73,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} },
|
||||
{ "%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} },
|
||||
|
|
@ -76,17 +81,22 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%delay", of_DELAY, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
{ "%ix/load",of_IX_LOAD,3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%ix/mul", of_IX_MUL, 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} },
|
||||
{ "%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} },
|
||||
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%xor", of_XOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
|
|
@ -94,6 +104,9 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
};
|
||||
|
||||
static unsigned opcode_count = 0;
|
||||
//static const unsigned opcode_count
|
||||
// = sizeof(opcode_table)/sizeof(*opcode_table) - 1;
|
||||
// No?
|
||||
|
||||
static int opcode_compare(const void*k, const void*r)
|
||||
{
|
||||
|
|
@ -406,6 +419,60 @@ void compile_udp_functor(char*label, char*type,
|
|||
}
|
||||
|
||||
|
||||
void compile_memory(char *label, char *name, int msb, int lsb,
|
||||
unsigned idxs, long *idx)
|
||||
{
|
||||
vvp_memory_t mem = memory_create(label);
|
||||
free(label);
|
||||
memory_new(mem, name, lsb, msb, idxs, idx);
|
||||
}
|
||||
|
||||
void compile_memory_port(char *label, char *memid,
|
||||
unsigned msb, unsigned lsb,
|
||||
unsigned argc, struct symb_s *argv)
|
||||
{
|
||||
vvp_memory_t mem = memory_find(memid);
|
||||
free(memid);
|
||||
assert(mem);
|
||||
|
||||
// These is not a Verilog bit range.
|
||||
// These is a data port bit range.
|
||||
assert (lsb >= 0 && lsb<=msb);
|
||||
assert (msb < memory_data_width(mem));
|
||||
unsigned nbits = msb-lsb+1;
|
||||
|
||||
unsigned awidth = memory_addr_width(mem);
|
||||
unsigned nfun = (awidth + 3)/4;
|
||||
if (nfun < nbits)
|
||||
nfun = nbits;
|
||||
|
||||
vvp_ipoint_t ix = functor_allocate(nfun);
|
||||
|
||||
assert(argc == awidth);
|
||||
define_functor_symbol(label, ix);
|
||||
free(label);
|
||||
|
||||
inputs_connect(ix, argc, argv);
|
||||
|
||||
memory_port_new(mem, ix, nbits, lsb);
|
||||
}
|
||||
|
||||
void compile_memory_init(char *memid, unsigned i, unsigned char val)
|
||||
{
|
||||
static vvp_memory_t mem = 0x0;
|
||||
static unsigned idx;
|
||||
if (memid)
|
||||
{
|
||||
mem = memory_find(memid);
|
||||
free(memid);
|
||||
idx = i/4;
|
||||
}
|
||||
assert(mem);
|
||||
memory_init_nibble(mem, idx, val);
|
||||
idx++;
|
||||
}
|
||||
|
||||
|
||||
void compile_event(char*label, char*type,
|
||||
unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
|
|
@ -625,6 +692,40 @@ 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:
|
||||
if (opa->argv[idx].ltype != L_SYMB) {
|
||||
yyerror("operand format");
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
free(opa->argv[idx].symb.text);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -963,6 +1064,9 @@ void compile_dump(FILE*fd)
|
|||
|
||||
/*
|
||||
* $Log: compile.cc,v $
|
||||
* Revision 1.48 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.47 2001/04/30 03:53:19 steve
|
||||
* Fix up functor inputs to support C<?> values.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.18 2001/04/25 04:35:05 steve Exp $"
|
||||
#ident "$Id: compile.h,v 1.19 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
|
@ -83,6 +83,20 @@ extern void compile_udp_functor(char*label, char*type,
|
|||
|
||||
extern char **compile_udp_table(char **table, char *row);
|
||||
|
||||
/*
|
||||
* Memory Instances, Ports, and Initialization
|
||||
*/
|
||||
|
||||
extern void compile_memory(char *label, char *name, int lsb, int msb,
|
||||
unsigned idxs, long *idx);
|
||||
|
||||
extern void compile_memory_port(char *label, char *memid,
|
||||
unsigned lsb, unsigned msb,
|
||||
unsigned argc, struct symb_s *argv);
|
||||
|
||||
extern void compile_memory_init(char *memid, unsigned idx, unsigned char val);
|
||||
|
||||
|
||||
/*
|
||||
* The compile_event function takes the parts of the event statement
|
||||
* and makes the various objects needed to simulate it. This includes
|
||||
|
|
@ -160,6 +174,9 @@ extern void compile_dump(FILE*fd);
|
|||
|
||||
/*
|
||||
* $Log: compile.h,v $
|
||||
* Revision 1.19 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.18 2001/04/25 04:35:05 steve
|
||||
* Document the UDP implementation.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.14 2001/04/24 02:23:59 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.15 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -77,7 +77,9 @@
|
|||
".udp" { return K_UDP; }
|
||||
".udp/c"(omb)? { return K_UDP_C; }
|
||||
".udp/s"(equ)? { return K_UDP_S; }
|
||||
|
||||
".mem" { return K_MEM; }
|
||||
".mem/p"(ort)? { return K_MEM_P; }
|
||||
".mem/i"(nit)? { return K_MEM_I; }
|
||||
|
||||
/* instructions start with a % character. The compiler decides what
|
||||
kind of instruction this really is. The few exceptions (that have
|
||||
|
|
@ -130,6 +132,9 @@ int yywrap()
|
|||
|
||||
/*
|
||||
* $Log: lexor.lex,v $
|
||||
* Revision 1.15 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.14 2001/04/24 02:23:59 steve
|
||||
* Support for UDP devices in VVP (Stephen Boettcher)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: memory.cc,v 1.1 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "symbols.h"
|
||||
#include "schedule.h"
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef struct vvp_memory_port_s *vvp_memory_port_t;
|
||||
|
||||
struct vvp_memory_s
|
||||
{
|
||||
char *name; // VPI scope.name
|
||||
|
||||
// Address port properties:
|
||||
unsigned size; // total number of data words
|
||||
unsigned awidth; // total number of address bits
|
||||
unsigned a_idxs; // number of address indices
|
||||
vvp_memory_index_t a_idx; // vector of address indices
|
||||
|
||||
// Data port properties:
|
||||
unsigned width; // number of data bits
|
||||
unsigned fwidth; // number of bytes (4bits) per data word
|
||||
int msb, lsb; // Most/Least Significant data bit (VPI)
|
||||
|
||||
vvp_memory_bits_t bits; // Array of bits
|
||||
vvp_memory_port_t addr_root; // Port list root;
|
||||
};
|
||||
|
||||
unsigned memory_data_width(vvp_memory_t mem)
|
||||
{
|
||||
return mem->width;
|
||||
}
|
||||
|
||||
unsigned memory_addr_width(vvp_memory_t mem)
|
||||
{
|
||||
return mem->awidth;
|
||||
}
|
||||
|
||||
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
|
||||
|
||||
struct vvp_memory_index_s
|
||||
{
|
||||
int first; // first memory address
|
||||
unsigned size; // number of valid addresses
|
||||
unsigned awidth; // width of address port
|
||||
};
|
||||
|
||||
struct vvp_memory_port_s : public vvp_fobj_s
|
||||
{
|
||||
vvp_memory_t mem;
|
||||
vvp_ipoint_t ix;
|
||||
vvp_memory_port_t next;
|
||||
int cur_addr;
|
||||
vvp_memory_bits_t cur_bits;
|
||||
int bitoff;
|
||||
int nbits;
|
||||
};
|
||||
|
||||
// Compilation
|
||||
|
||||
static symbol_table_t memory_table;
|
||||
|
||||
vvp_memory_t memory_find(char *label)
|
||||
{
|
||||
symbol_value_t v = sym_get_value(memory_table, label);
|
||||
return (vvp_memory_t)v.ptr;
|
||||
}
|
||||
|
||||
vvp_memory_t memory_create(char *label)
|
||||
{
|
||||
if (!memory_table)
|
||||
memory_table = new_symbol_table();
|
||||
|
||||
assert(!memory_find(label));
|
||||
|
||||
vvp_memory_t mem = new struct vvp_memory_s;
|
||||
|
||||
symbol_value_t v;
|
||||
v.ptr = mem;
|
||||
sym_set_value(memory_table, label, v);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void memory_new(vvp_memory_t mem, char *name, int msb, int lsb,
|
||||
unsigned idxs, long *idx)
|
||||
{
|
||||
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
|
||||
mem->msb = msb;
|
||||
mem->lsb = lsb;
|
||||
mem->fwidth = (mem->width+3)/4;
|
||||
|
||||
assert((idxs&1) == 0);
|
||||
mem->a_idxs = idxs/2;
|
||||
mem->a_idx = (vvp_memory_index_t)
|
||||
malloc(mem->a_idxs*sizeof(struct vvp_memory_index_s));
|
||||
assert(mem->a_idxs);
|
||||
|
||||
mem->size = 1;
|
||||
mem->awidth = 0;
|
||||
for (unsigned i=0; i < mem->a_idxs; i++)
|
||||
{
|
||||
vvp_memory_index_t x = mem->a_idx + i;
|
||||
int msw = *(idx++);
|
||||
int lsw = *(idx++);
|
||||
x->size = msw - lsw + 1;
|
||||
x->first = lsw;
|
||||
int m = lsw ^ msw;
|
||||
x->awidth = 0;
|
||||
if (m < 0)
|
||||
{
|
||||
if (lsw < 0)
|
||||
m = ~lsw | msw;
|
||||
else
|
||||
m = lsw | ~msw;
|
||||
x->awidth++;
|
||||
}
|
||||
for (int c=1; c<m; c<<=1)
|
||||
x->awidth ++;
|
||||
mem->awidth += x->awidth;
|
||||
mem->size *= x->size;
|
||||
}
|
||||
|
||||
mem->bits = (vvp_memory_bits_t) malloc(mem->size * mem->fwidth);
|
||||
assert(mem->bits);
|
||||
memset(mem->bits, 0xaa, mem->size * mem->fwidth);
|
||||
|
||||
mem->addr_root = 0x0;
|
||||
mem->name = name;
|
||||
}
|
||||
|
||||
static void port_functor_set(vvp_ipoint_t i, functor_t f, bool push);
|
||||
|
||||
void memory_port_new(vvp_memory_t mem, vvp_ipoint_t ix,
|
||||
unsigned nbits, unsigned bitoff)
|
||||
{
|
||||
vvp_memory_port_t a = new struct vvp_memory_port_s;
|
||||
a->set = port_functor_set;
|
||||
a->get = 0x0;
|
||||
|
||||
a->mem = mem;
|
||||
a->ix = ix;
|
||||
a->nbits = nbits;
|
||||
a->bitoff = bitoff;
|
||||
|
||||
a->next = mem->addr_root;
|
||||
a->mem->addr_root = a;
|
||||
|
||||
unsigned nfun = (a->mem->awidth+3)/4;
|
||||
if (nfun < nbits)
|
||||
nfun = nbits;
|
||||
|
||||
for (unsigned idx = 0; idx < nfun; idx ++)
|
||||
{
|
||||
vvp_ipoint_t ifdx = ipoint_index(ix, idx);
|
||||
functor_t iobj = functor_index(ifdx);
|
||||
|
||||
iobj->ival = 0xaa;
|
||||
iobj->oval = 0x02;
|
||||
iobj->mode = M42;
|
||||
iobj->out = 0;
|
||||
iobj->obj = a;
|
||||
}
|
||||
|
||||
a->cur_addr = VVP_MEMORY_NO_ADDR;
|
||||
a->cur_bits = 0x0;
|
||||
}
|
||||
|
||||
void memory_init_nibble(vvp_memory_t mem, unsigned idx, unsigned char val)
|
||||
{
|
||||
assert(idx < mem->size*mem->fwidth);
|
||||
mem->bits[idx] = val;
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
inline static
|
||||
vvp_memory_bits_t get_word(vvp_memory_t mem, int addr)
|
||||
{
|
||||
if (addr == VVP_MEMORY_NO_ADDR)
|
||||
return 0x0;
|
||||
|
||||
// Compute the word index into the bits array.
|
||||
unsigned waddr = 0;
|
||||
for (unsigned i = 0; i<mem->a_idxs; i++)
|
||||
{
|
||||
vvp_memory_index_t x = mem->a_idx + i;
|
||||
unsigned iwaddr = (addr - x->first) & ((1<<x->awidth) - 1);
|
||||
waddr *= x->size;
|
||||
// This fails for negative
|
||||
if (iwaddr >= x->size)
|
||||
return 0x0;
|
||||
waddr += iwaddr;
|
||||
addr >>= x->awidth;
|
||||
}
|
||||
|
||||
assert(waddr < mem->size);
|
||||
|
||||
return mem->bits + waddr*mem->fwidth;
|
||||
}
|
||||
|
||||
inline static
|
||||
bool set_bit(vvp_memory_bits_t bits, int bit, unsigned char val)
|
||||
{
|
||||
int ix = bit/4;
|
||||
int ip = 2*(bit%4);
|
||||
bool r = ((bits[ix] >> ip) & 3) != val;
|
||||
bits[ix] = (bits[ix] &~ (3<<ip)) | ((val&3) << ip);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline static
|
||||
unsigned char get_nibble(vvp_memory_bits_t bits, int bit)
|
||||
{
|
||||
if (!bits)
|
||||
return 0xaa;
|
||||
int ix = bit/4;
|
||||
return bits[ix];
|
||||
}
|
||||
|
||||
inline static
|
||||
unsigned char get_bit(vvp_memory_bits_t bits, int bit)
|
||||
{
|
||||
return (get_nibble(bits, bit) >> (2*(bit&3))) & 3;
|
||||
}
|
||||
|
||||
inline static
|
||||
unsigned char functor_get_inputs(vvp_ipoint_t ip)
|
||||
{
|
||||
functor_t fp = functor_index(ip);
|
||||
assert(fp);
|
||||
return fp->ival;
|
||||
}
|
||||
|
||||
inline static
|
||||
unsigned char functor_get_input(vvp_ipoint_t ip)
|
||||
{
|
||||
unsigned char bits = functor_get_inputs(ip);
|
||||
return (bits >> (2*ipoint_port(ip))) & 3;
|
||||
}
|
||||
|
||||
static void update_addr(vvp_memory_port_t addr);
|
||||
|
||||
static
|
||||
bool update_addr_bit(vvp_memory_port_t addr, vvp_ipoint_t ip)
|
||||
{
|
||||
unsigned abit = ip - addr->ix;
|
||||
|
||||
assert(abit >= 0 && abit < addr->mem->awidth);
|
||||
|
||||
int old = addr->cur_addr;
|
||||
|
||||
int abval = functor_get_input(ip);
|
||||
if (abval>1)
|
||||
addr->cur_addr = VVP_MEMORY_NO_ADDR;
|
||||
else if (addr->cur_addr == VVP_MEMORY_NO_ADDR)
|
||||
update_addr(addr);
|
||||
else if (abval)
|
||||
addr->cur_addr |= (1<<abit);
|
||||
else
|
||||
addr->cur_addr &=~ (1<<abit);
|
||||
|
||||
bool r = addr->cur_addr != old;
|
||||
if (r)
|
||||
addr->cur_bits = get_word(addr->mem, addr->cur_addr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static
|
||||
void update_addr(vvp_memory_port_t addr)
|
||||
{
|
||||
addr->cur_addr = 2;
|
||||
for (unsigned i=0; i < addr->mem->awidth; i++)
|
||||
{
|
||||
update_addr_bit(addr, addr->ix+i);
|
||||
if (addr->cur_addr == VVP_MEMORY_NO_ADDR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline static
|
||||
void update_data(vvp_memory_port_t data,
|
||||
vvp_memory_bits_t bits)
|
||||
{
|
||||
assert(data);
|
||||
for (int i=0; i < data->nbits; i++)
|
||||
{
|
||||
vvp_ipoint_t dx = ipoint_index(data->ix, i);
|
||||
functor_t df = functor_index(dx);
|
||||
unsigned char out = get_bit(bits, i + data->bitoff);
|
||||
if (out != df->oval)
|
||||
{
|
||||
df->oval = out;
|
||||
functor_propagate(dx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void port_functor_set(vvp_ipoint_t i, functor_t f, bool push)
|
||||
{
|
||||
vvp_memory_port_t addr = (vvp_memory_port_t)f->obj;
|
||||
if (update_addr_bit(addr, i))
|
||||
update_data(addr, addr->cur_bits);
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
void update_data_ports(vvp_memory_t mem, int addr, int bit,
|
||||
unsigned char val)
|
||||
{
|
||||
vvp_memory_port_t a = mem->addr_root;
|
||||
while (a)
|
||||
{
|
||||
if (addr == a->cur_addr)
|
||||
{
|
||||
vvp_memory_port_t d = a; // historic
|
||||
int i = bit - d->bitoff;
|
||||
if (i >= 0 && i < d->nbits)
|
||||
{
|
||||
vvp_ipoint_t ix = ipoint_index(d->ix, i);
|
||||
functor_t df = functor_index(ix);
|
||||
if (df->oval != val)
|
||||
{
|
||||
df->oval = val;
|
||||
functor_propagate(ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// %set/mem
|
||||
|
||||
void memory_set(vvp_memory_t mem, unsigned idx, unsigned char val)
|
||||
{
|
||||
if (!set_bit(mem->bits, idx, val))
|
||||
return;
|
||||
|
||||
update_data_ports(mem, idx/(4*mem->fwidth), idx%(4*mem->fwidth), val);
|
||||
}
|
||||
|
||||
// %load/mem
|
||||
|
||||
unsigned memory_get(vvp_memory_t mem, unsigned idx)
|
||||
{
|
||||
return get_bit(mem->bits, idx);
|
||||
}
|
||||
|
||||
// %assign/mem event scheduling
|
||||
|
||||
struct mem_assign_s: public vvp_gen_event_s
|
||||
{
|
||||
union
|
||||
{
|
||||
vvp_memory_t mem;
|
||||
struct mem_assign_s *next;
|
||||
};
|
||||
unsigned long idx;
|
||||
};
|
||||
|
||||
static struct mem_assign_s* ma_free_list = 0;
|
||||
|
||||
inline static struct mem_assign_s* ma_alloc()
|
||||
{
|
||||
struct mem_assign_s* cur = ma_free_list;
|
||||
if (!cur)
|
||||
cur = (struct mem_assign_s*) malloc(sizeof(struct mem_assign_s));
|
||||
else
|
||||
ma_free_list = cur->next;
|
||||
return cur;
|
||||
}
|
||||
|
||||
inline static void ma_free(struct mem_assign_s* cur)
|
||||
{
|
||||
cur->next = ma_free_list;
|
||||
ma_free_list = cur;
|
||||
}
|
||||
|
||||
static void run_mem_assign(vvp_gen_event_t obj, unsigned char val)
|
||||
{
|
||||
struct mem_assign_s *e = (struct mem_assign_s *) obj;
|
||||
memory_set(e->mem, e->idx, val);
|
||||
ma_free(e);
|
||||
}
|
||||
|
||||
void schedule_memory(vvp_memory_t mem, unsigned idx,
|
||||
unsigned char val, unsigned delay)
|
||||
{
|
||||
struct mem_assign_s *e = ma_alloc();
|
||||
e->run = run_mem_assign;
|
||||
e->mem = mem;
|
||||
e->idx = idx;
|
||||
schedule_generic(e, val, delay);
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef __memory_H // -*- c++ -*-
|
||||
#define __memory_H
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: memory.h,v 1.1 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "pointers.h"
|
||||
#include "functor.h"
|
||||
|
||||
typedef struct vvp_memory_s *vvp_memory_t;
|
||||
typedef unsigned char *vvp_memory_bits_t;
|
||||
typedef struct vvp_memory_index_s *vvp_memory_index_t;
|
||||
|
||||
void memory_new(vvp_memory_t mem, char *name, int lsb, int msb,
|
||||
unsigned idxs, long *idx);
|
||||
void memory_port_new(vvp_memory_t mem, vvp_ipoint_t ix,
|
||||
unsigned nbits, unsigned bitoff);
|
||||
void memory_init_nibble(vvp_memory_t mem, unsigned idx, unsigned char val);
|
||||
|
||||
void memory_set(vvp_memory_t mem, unsigned idx, unsigned char val);
|
||||
unsigned memory_get(vvp_memory_t mem, unsigned idx);
|
||||
void schedule_memory(vvp_memory_t mem, unsigned idx,
|
||||
unsigned char val, unsigned delay);
|
||||
|
||||
unsigned memory_addr_width(vvp_memory_t mem);
|
||||
unsigned memory_data_width(vvp_memory_t mem);
|
||||
|
||||
vvp_memory_t memory_find(char *label);
|
||||
vvp_memory_t memory_create(char *label);
|
||||
|
||||
/*
|
||||
* $Log: memory.h,v $
|
||||
* Revision 1.1 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
47
vvp/parse.y
47
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.22 2001/04/24 02:23:59 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.23 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -54,6 +54,7 @@ extern FILE*yyin;
|
|||
|
||||
%token K_EVENT K_EVENT_OR K_FUNCTOR K_NET K_NET_S K_SCOPE K_THREAD
|
||||
%token K_UDP K_UDP_C K_UDP_S
|
||||
%token K_MEM K_MEM_P K_MEM_I
|
||||
%token K_VAR K_VAR_S K_vpi_call K_disable K_fork
|
||||
%token K_vpi_module
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ extern FILE*yyin;
|
|||
%token <vect> T_VECTOR
|
||||
|
||||
%type <symb> symbol symbol_opt
|
||||
%type <symbv> symbols symbols_net
|
||||
%type <symbv> symbols symbols_net numbers
|
||||
%type <text> label_opt
|
||||
%type <opa> operand operands operands_opt
|
||||
%type <table> udp_table
|
||||
|
|
@ -128,6 +129,17 @@ statement
|
|||
{ compile_udp_functor($1, $3, $5.cnt, $5.vect); }
|
||||
|
||||
|
||||
/* Memory. Definition, port, initialization */
|
||||
|
||||
| T_LABEL K_MEM T_STRING ',' T_NUMBER ',' T_NUMBER ',' numbers ';'
|
||||
{ compile_memory($1, $3, $5, $7, $9.cnt, $9.nvec); }
|
||||
|
||||
| T_LABEL K_MEM_P T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' symbols ';'
|
||||
{ compile_memory_port($1, $3, $5, $7, $9.cnt, $9.vect); }
|
||||
|
||||
| mem_init_stmt
|
||||
|
||||
|
||||
/* Event statements take a label, a type (the first T_SYMBOL) and a
|
||||
list of inputs. If the type is instead a string, then we have a
|
||||
named event instead. */
|
||||
|
|
@ -323,6 +335,21 @@ symbols
|
|||
;
|
||||
|
||||
|
||||
numbers
|
||||
: T_NUMBER
|
||||
{ struct numbv_s obj;
|
||||
numbv_init(&obj);
|
||||
numbv_add(&obj, $1);
|
||||
$$ = obj;
|
||||
}
|
||||
| numbers ',' T_NUMBER
|
||||
{ struct numbv_s obj = $1;
|
||||
numbv_add(&obj, $3);
|
||||
$$ = obj;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
symbols_net
|
||||
: symbol_opt
|
||||
{ struct symbv_s obj;
|
||||
|
|
@ -358,6 +385,7 @@ symbol_opt
|
|||
{ $$.text = 0;
|
||||
$$.idx = 0;
|
||||
}
|
||||
;
|
||||
|
||||
udp_table
|
||||
: T_STRING
|
||||
|
|
@ -366,6 +394,18 @@ udp_table
|
|||
{ $$ = compile_udp_table($1, $3); }
|
||||
;
|
||||
|
||||
mem_init_stmt
|
||||
: K_MEM_I symbol ',' T_NUMBER o_komma
|
||||
{ compile_memory_init($2.text, $2.idx, $4); }
|
||||
| mem_init_stmt T_NUMBER o_komma
|
||||
{ compile_memory_init(0x0, 0, $2); }
|
||||
;
|
||||
|
||||
o_komma
|
||||
: /* empty */
|
||||
| ','
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
int compile_design(const char*path)
|
||||
|
|
@ -385,6 +425,9 @@ int compile_design(const char*path)
|
|||
|
||||
/*
|
||||
* $Log: parse.y,v $
|
||||
* Revision 1.23 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.22 2001/04/24 02:23:59 steve
|
||||
* Support for UDP devices in VVP (Stephen Boettcher)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.3 2001/03/20 06:16:24 steve Exp $"
|
||||
#ident "$Id: parse_misc.cc,v 1.4 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -46,6 +46,13 @@ void symbv_add(struct symbv_s*obj, struct symb_s item)
|
|||
obj->cnt += 1;
|
||||
}
|
||||
|
||||
void numbv_add(struct numbv_s*obj, long item)
|
||||
{
|
||||
obj->nvec = (long*) realloc(obj->nvec, (obj->cnt+1) * sizeof(long));
|
||||
obj->nvec[obj->cnt] = item;
|
||||
obj->cnt += 1;
|
||||
}
|
||||
|
||||
void argv_init(struct argv_s*obj)
|
||||
{
|
||||
obj->argc = 0;
|
||||
|
|
@ -62,6 +69,9 @@ void argv_add(struct argv_s*obj, vpiHandle item)
|
|||
|
||||
/*
|
||||
* $Log: parse_misc.cc,v $
|
||||
* Revision 1.4 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.3 2001/03/20 06:16:24 steve
|
||||
* Add support for variable vectors.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.3 2001/03/20 06:16:24 steve Exp $"
|
||||
#ident "$Id: parse_misc.h,v 1.4 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -50,12 +50,19 @@ struct symb_s {
|
|||
|
||||
struct symbv_s {
|
||||
unsigned cnt;
|
||||
struct symb_s*vect;
|
||||
union {
|
||||
struct symb_s*vect;
|
||||
long*nvec;
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
extern void numbv_add(struct numbv_s*obj, long item);
|
||||
|
||||
|
||||
|
||||
struct argv_s {
|
||||
|
|
@ -68,6 +75,9 @@ extern void argv_add(struct argv_s*obj, vpiHandle);
|
|||
|
||||
/*
|
||||
* $Log: parse_misc.h,v $
|
||||
* Revision 1.4 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.3 2001/03/20 06:16:24 steve
|
||||
* Add support for variable vectors.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: schedule.cc,v 1.6 2001/04/21 00:34:39 steve Exp $"
|
||||
#ident "$Id: schedule.cc,v 1.7 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "schedule.h"
|
||||
# include "functor.h"
|
||||
# include "memory.h"
|
||||
# include "vthread.h"
|
||||
# include <malloc.h>
|
||||
# include <assert.h>
|
||||
|
|
@ -32,6 +33,7 @@ struct event_s {
|
|||
union {
|
||||
vthread_t thr;
|
||||
vvp_ipoint_t fun;
|
||||
vvp_gen_event_t obj;
|
||||
};
|
||||
unsigned val :2;
|
||||
unsigned type :2;
|
||||
|
|
@ -39,11 +41,40 @@ struct event_s {
|
|||
struct event_s*next;
|
||||
struct event_s*last;
|
||||
};
|
||||
const unsigned TYPE_NOOP = 0;
|
||||
const unsigned TYPE_GEN = 0;
|
||||
const unsigned TYPE_THREAD = 1;
|
||||
const unsigned TYPE_PROP = 2;
|
||||
const unsigned TYPE_ASSIGN = 3;
|
||||
|
||||
/*
|
||||
** These event_s will be required a lot, at high frequency.
|
||||
** Once allocated, we never free them, but stash them away for next time.
|
||||
*/
|
||||
|
||||
static struct event_s* free_list = 0;
|
||||
|
||||
inline static struct event_s* e_alloc()
|
||||
{
|
||||
struct event_s* cur = free_list;
|
||||
if (!cur)
|
||||
{
|
||||
cur = (struct event_s*) malloc(sizeof(struct event_s));
|
||||
// cur = (struct event_s*) calloc(1, sizeof(struct event_s));
|
||||
}
|
||||
else
|
||||
{
|
||||
free_list = cur->next;
|
||||
// memset(cur, 0, sizeof(struct event_s));
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
inline static void e_free(struct event_s* cur)
|
||||
{
|
||||
cur->next = free_list;
|
||||
free_list = cur;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the head of the list of pending events.
|
||||
*/
|
||||
|
|
@ -114,8 +145,7 @@ static void schedule_event_(struct event_s*cur)
|
|||
|
||||
void schedule_vthread(vthread_t thr, unsigned delay)
|
||||
{
|
||||
struct event_s*cur = (struct event_s*)
|
||||
calloc(1, sizeof(struct event_s));
|
||||
struct event_s*cur = e_alloc();
|
||||
|
||||
cur->delay = delay;
|
||||
cur->thr = thr;
|
||||
|
|
@ -127,8 +157,7 @@ void schedule_vthread(vthread_t thr, unsigned delay)
|
|||
|
||||
void schedule_functor(vvp_ipoint_t fun, unsigned delay)
|
||||
{
|
||||
struct event_s*cur = (struct event_s*)
|
||||
calloc(1, sizeof(struct event_s));
|
||||
struct event_s*cur = e_alloc();
|
||||
|
||||
cur->delay = delay;
|
||||
cur->fun = fun;
|
||||
|
|
@ -139,8 +168,7 @@ void schedule_functor(vvp_ipoint_t fun, unsigned delay)
|
|||
|
||||
void schedule_assign(vvp_ipoint_t fun, unsigned char val, unsigned delay)
|
||||
{
|
||||
struct event_s*cur = (struct event_s*)
|
||||
calloc(1, sizeof(struct event_s));
|
||||
struct event_s*cur = e_alloc();
|
||||
|
||||
cur->delay = delay;
|
||||
cur->fun = fun;
|
||||
|
|
@ -148,7 +176,18 @@ void schedule_assign(vvp_ipoint_t fun, unsigned char val, unsigned delay)
|
|||
cur->type= TYPE_ASSIGN;
|
||||
|
||||
schedule_event_(cur);
|
||||
}
|
||||
|
||||
void schedule_generic(vvp_gen_event_t obj, unsigned char val, unsigned delay)
|
||||
{
|
||||
struct event_s*cur = e_alloc();
|
||||
|
||||
cur->delay = delay;
|
||||
cur->obj = obj;
|
||||
cur->val = val;
|
||||
cur->type= TYPE_GEN;
|
||||
|
||||
schedule_event_(cur);
|
||||
}
|
||||
|
||||
static unsigned long schedule_time;
|
||||
|
|
@ -188,14 +227,22 @@ void schedule_simulate(void)
|
|||
functor_set(cur->fun, cur->val);
|
||||
break;
|
||||
|
||||
case TYPE_GEN:
|
||||
if (cur->obj && cur->obj->run)
|
||||
cur->obj->run(cur->obj, cur->val);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
free(cur);
|
||||
e_free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: schedule.cc,v $
|
||||
* Revision 1.7 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.6 2001/04/21 00:34:39 steve
|
||||
* Working %disable and reap handling references from scheduler.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: schedule.h,v 1.4 2001/03/31 19:00:43 steve Exp $"
|
||||
#ident "$Id: schedule.h,v 1.5 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vthread.h"
|
||||
|
|
@ -46,6 +46,20 @@ extern void schedule_functor(vvp_ipoint_t fun, unsigned delay);
|
|||
extern void schedule_assign(vvp_ipoint_t fun, unsigned char val,
|
||||
unsigned delay);
|
||||
|
||||
/*
|
||||
* Create an abstract event.
|
||||
*/
|
||||
|
||||
typedef struct vvp_gen_event_s *vvp_gen_event_t;
|
||||
|
||||
extern void schedule_generic(vvp_gen_event_t obj, unsigned char val,
|
||||
unsigned delay);
|
||||
|
||||
struct vvp_gen_event_s
|
||||
{
|
||||
void (*run)(vvp_gen_event_t obj, unsigned char val);
|
||||
};
|
||||
|
||||
/*
|
||||
* This runs the simulator. It runs until all the functors run out or
|
||||
* the simulation is otherwise finished.
|
||||
|
|
@ -74,6 +88,9 @@ extern bool schedule_finished(void);
|
|||
|
||||
/*
|
||||
* $Log: schedule.h,v $
|
||||
* Revision 1.5 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.4 2001/03/31 19:00:43 steve
|
||||
* Add VPI support for the simulation time.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.29 2001/04/21 00:34:39 steve Exp $"
|
||||
#ident "$Id: vthread.cc,v 1.30 2001/05/01 01:09:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vthread.h"
|
||||
|
|
@ -82,6 +82,7 @@ struct vthread_s {
|
|||
unsigned long pc;
|
||||
/* These hold the private thread bits. */
|
||||
unsigned char *bits;
|
||||
long index[4];
|
||||
unsigned nbits :16;
|
||||
/* My parent sets this when it wants me to wake it up. */
|
||||
unsigned schedule_parent_on_end :1;
|
||||
|
|
@ -328,6 +329,13 @@ bool of_ASSIGN(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_ASSIGN_MEM(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx2);
|
||||
schedule_memory(cp->mem, thr->index[3], bit_val, cp->bit_idx1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_CMPS(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned eq = 1;
|
||||
|
|
@ -615,6 +623,32 @@ bool of_INV(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Index registers, signed 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;
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_IX_LOAD(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The various JMP instruction work simply by pulling the new program
|
||||
* counter from the instruction and resuming. If the jump is
|
||||
|
|
@ -676,6 +710,15 @@ bool of_LOAD(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_MOV(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx1 >= 4);
|
||||
|
|
@ -763,6 +806,15 @@ bool of_SET(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
// printf("thread %p: %%vpi_call\n", thr);
|
||||
|
|
@ -873,6 +925,9 @@ bool of_ZOMBIE(vthread_t thr, vvp_code_t)
|
|||
|
||||
/*
|
||||
* $Log: vthread.cc,v $
|
||||
* Revision 1.30 2001/05/01 01:09:39 steve
|
||||
* Add support for memory objects. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.29 2001/04/21 00:34:39 steve
|
||||
* Working %disable and reap handling references from scheduler.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue