Rearrange how memories are supported as vvp_vector4 arrays.

This commit is contained in:
steve 2005-03-03 04:33:10 +00:00
parent 04604188df
commit 85286cc086
18 changed files with 627 additions and 414 deletions

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: ivl_target.h,v 1.143 2005/02/19 02:43:38 steve Exp $"
#ident "$Id: ivl_target.h,v 1.144 2005/03/03 04:34:42 steve Exp $"
#endif
#ifdef __cplusplus
@ -576,6 +576,9 @@ extern unsigned ivl_expr_width(ivl_expr_t net);
/*
* Memory.
* Memories are declared in Verilog source as 2 dimensional arrays of
* reg bits. This means that they are simple arrays of vectors. The
* vectors in the array are called "words".
*
* ivl_memory_name (DEPRECATED)
*
@ -583,6 +586,13 @@ extern unsigned ivl_expr_width(ivl_expr_t net);
* This returns the base name of the memory object. The base name
* does not include the name of the scopes that contains the object.
*
* ivl_memory_root
* The root of the memory is the value to add to a calculated
* address to get to a canonical (0-based) address. This value is
* used when external code wishes to access a word. All the
* compiled references to the word within the compiled design are
* converted to cannonical form by the compiler.
*
* ivl_memory_size
* ivl_memory_width
* These functions return the dimensions of the memory. The size is
@ -1527,6 +1537,9 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.144 2005/03/03 04:34:42 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.143 2005/02/19 02:43:38 steve
* Support shifts and divide.
*

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.14 2004/12/12 18:15:06 steve Exp $"
#ident "$Id: Makefile.in,v 1.15 2005/03/03 04:34:42 steve Exp $"
#
#
SHELL = /bin/sh
@ -52,7 +52,7 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = stub.o statement.o
O = stub.o memory.o statement.o
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl

34
tgt-stub/memory.c Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2000-2005 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
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: memory.c,v 1.1 2005/03/03 04:34:42 steve Exp $"
#endif
# include "config.h"
# include "priv.h"
# include <assert.h>
void show_memory(ivl_memory_t mem)
{
fprintf(out, " mem [%u] %s [%u] <root=%d>\n",
ivl_memory_width(mem),
ivl_memory_basename(mem),
ivl_memory_size(mem),
ivl_memory_root(mem));
}

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: stub.c,v 1.111 2005/02/19 02:43:39 steve Exp $"
#ident "$Id: stub.c,v 1.112 2005/03/03 04:34:42 steve Exp $"
#endif
# include "config.h"
@ -1080,12 +1080,15 @@ static int show_scope(ivl_scope_t net, void*x)
for (idx = 0 ; idx < ivl_scope_vars(net) ; idx += 1)
show_variable(ivl_scope_var(net, idx));
for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1)
show_event(ivl_scope_event(net, idx));
for (idx = 0 ; idx < ivl_scope_sigs(net) ; idx += 1)
show_signal(ivl_scope_sig(net, idx));
for (idx = 0 ; idx < ivl_scope_mems(net) ; idx += 1)
show_memory(ivl_scope_mem(net, idx));
for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1)
show_event(ivl_scope_event(net, idx));
for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1)
show_logic(ivl_scope_log(net, idx));
@ -1122,6 +1125,9 @@ int target_design(ivl_design_t des)
/*
* $Log: stub.c,v $
* Revision 1.112 2005/03/03 04:34:42 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.111 2005/02/19 02:43:39 steve
* Support shifts and divide.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_expr.c,v 1.115 2005/02/15 07:12:55 steve Exp $"
#ident "$Id: eval_expr.c,v 1.116 2005/03/03 04:34:42 steve Exp $"
#endif
# include "vvp_priv.h"
@ -1467,11 +1467,15 @@ static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid)
return res;
}
/*
* Draw code to evaluate a memory word index expression and write the
* value into index register 3. This expression converts the run-time
* calculated value to cannonical form that the %load/mv takes.
*/
void draw_memory_index_expr(ivl_memory_t mem, ivl_expr_t ae)
{
int root = ivl_memory_root(mem);
unsigned width = ivl_memory_width(mem);
width = (width+3) & ~3;
switch (ivl_expr_type(ae)) {
case IVL_EX_NUMBER: {
@ -1493,14 +1497,14 @@ void draw_memory_index_expr(ivl_memory_t mem, ivl_expr_t ae)
unknown_flag = 1;
break;
}
fprintf(vvp_out, " %%ix/load 3, %lu;\n", (v-root)*width);
fprintf(vvp_out, " %%ix/load 3, %lu;\n", v-root);
fprintf(vvp_out, " %%mov 4, %c, 1;\n",
unknown_flag?'1':'0');
break;
}
case IVL_EX_ULONG: {
unsigned v = ivl_expr_uvalue(ae);
fprintf(vvp_out, " %%ix/load 3, %u;\n", (v-root)*width);
fprintf(vvp_out, " %%ix/load 3, %u;\n", v-root);
fprintf(vvp_out, " %%mov 4, 0, 1;\n");
break;
}
@ -1511,8 +1515,6 @@ void draw_memory_index_expr(ivl_memory_t mem, ivl_expr_t ae)
clr_vector(addr);
if (root>0)
fprintf(vvp_out, " %%ix/sub 3, %u;\n", root);
if (width>1)
fprintf(vvp_out, " %%ix/mul 3, %u;\n", width);
break;
}
}
@ -1523,7 +1525,6 @@ static struct vector_info draw_memory_expr(ivl_expr_t exp, unsigned wid)
unsigned swid = ivl_expr_width(exp);
ivl_memory_t mem = ivl_expr_memory(exp);
struct vector_info res;
unsigned idx;
draw_memory_index_expr(mem, ivl_expr_oper1(exp));
@ -1533,12 +1534,8 @@ static struct vector_info draw_memory_expr(ivl_expr_t exp, unsigned wid)
res.base = allocate_vector(wid);
res.wid = wid;
for (idx = 0 ; idx < swid ; idx += 1) {
if (idx)
fprintf(vvp_out, " %%ix/add 3, 1;\n");
fprintf(vvp_out, " %%load/m %u, M_%s;\n",
res.base+idx, vvp_memory_label(mem));
}
fprintf(vvp_out, " %%load/mv %u, M_%s, %u;\n",
res.base, vvp_memory_label(mem), swid);
/* Pad the signal value with zeros. */
if (swid < wid)
@ -2130,6 +2127,9 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag)
/*
* $Log: eval_expr.c,v $
* Revision 1.116 2005/03/03 04:34:42 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.115 2005/02/15 07:12:55 steve
* Support constant part select writes to l-values, and large part select reads from signals.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_process.c,v 1.101 2005/02/15 07:12:55 steve Exp $"
#ident "$Id: vvp_process.c,v 1.102 2005/03/03 04:34:42 steve Exp $"
#endif
# include "vvp_priv.h"
@ -29,6 +29,7 @@
# include <stdlib.h>
static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
static void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
unsigned local_count = 0;
unsigned thread_count = 0;
@ -71,14 +72,12 @@ unsigned bitchar_to_idx(char bit)
* nexus.
*/
static void set_to_lvariable(ivl_lval_t lval, unsigned idx,
static void set_to_lvariable(ivl_lval_t lval,
unsigned bit, unsigned wid)
{
ivl_signal_t sig = ivl_lval_sig(lval);
unsigned part_off = ivl_lval_part_off(lval);
assert(idx == 0);
if (ivl_lval_mux(lval)) {
unsigned skip_set = transient_id++;
@ -112,6 +111,8 @@ static void set_to_lvariable(ivl_lval_t lval, unsigned idx,
}
}
#if 0
/* OBSOLETE */
static void set_to_memory(ivl_memory_t mem, unsigned idx, unsigned bit)
{
if (idx)
@ -119,6 +120,20 @@ static void set_to_memory(ivl_memory_t mem, unsigned idx, unsigned bit)
fprintf(vvp_out, " %%set/m M_%s, %u;\n",
vvp_memory_label(mem), bit);
}
#endif
/*
* This function writes the code to set a vector to a memory word. The
* idx is the thread register that contains the address of the word in
* the memory, and bit is the base of the thread vector. The wid is
* the width of the vector to be written to the word.
*/
static void set_to_memory_word(ivl_memory_t mem, unsigned idx,
unsigned bit, unsigned wid)
{
fprintf(vvp_out, " %%set/mv M_%s, %u, %u;\n",
vvp_memory_label(mem), bit, wid);
}
/*
* This generates an assign to a single bit of an lvalue variable. If
@ -173,7 +188,7 @@ static void assign_to_memory(ivl_memory_t mem, unsigned idx,
* This function, in addition to setting the value into index 0, sets
* bit 4 to 1 if the value is unknown.
*/
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
static void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
{
struct vector_info vec;
int word;
@ -226,7 +241,6 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
unsigned skip_set = transient_id++;
unsigned skip_set_flag = 0;
unsigned idx;
unsigned bit_limit = wid - cur_rbit;
lval = ivl_stmt_lval(net, lidx);
@ -246,25 +260,14 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
bit_limit = ivl_lval_width(lval);
if (mem) {
for (idx = 0 ; idx < bit_limit ; idx += 1) {
unsigned bidx = res.base < 4
? res.base
: (res.base+cur_rbit);
set_to_memory(mem, idx, bidx);
cur_rbit += 1;
}
#if 0
for (idx = bit_limit; idx < ivl_lval_pins(lval); idx += 1)
set_to_memory(mem, idx, 0);
#else
assert(0);
#endif
set_to_memory_word(mem, 3, res.base, res.wid);
} else {
unsigned bidx = res.base < 4
? res.base
: (res.base+cur_rbit);
set_to_lvariable(lval, 0, bidx, bit_limit);
set_to_lvariable(lval, bidx, bit_limit);
cur_rbit += bit_limit;
}
@ -342,6 +345,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
bit_limit = ivl_lval_width(lval);
if (mem) {
#if 0
for (idx = 0 ; idx < bit_limit ; idx += 1) {
set_to_memory(mem, idx,
bitchar_to_idx(bits[cur_rbit]));
@ -352,7 +356,9 @@ static int show_stmt_assign_vector(ivl_statement_t net)
for (idx = bit_limit
; idx < ivl_lval_width(lval) ; idx += 1)
set_to_memory(mem, idx, 0);
#else
assert(0);
#endif
} else {
/* Here we have the case of a blocking
@ -388,7 +394,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
}
/* write out the value into the .var. */
set_to_lvariable(lval, 0, vect.base, vect.wid);
set_to_lvariable(lval, vect.base, vect.wid);
clr_vector(vect);
}
@ -1560,6 +1566,9 @@ int draw_func_definition(ivl_scope_t scope)
/*
* $Log: vvp_process.c,v $
* Revision 1.102 2005/03/03 04:34:42 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.101 2005/02/15 07:12:55 steve
* Support constant part select writes to l-values, and large part select reads from signals.
*

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: README.txt,v 1.57 2005/02/07 22:42:42 steve Exp $
* $Id: README.txt,v 1.58 2005/03/03 04:33:10 steve Exp $
*/
VVP SIMULATION ENGINE
@ -289,25 +289,28 @@ functor pointer, though.
MEMORY STATEMENTS:
Memories are arrays of words, each word a vvp_vector4_t vector of the
same width. The memory is cannonically addressed as a 1-dimensional
array of words, although indices are stored with the memory for
calculating a canonical address from a multi-dimensional address.
Three types of memory statement 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
The pair of numbers <msb>,<lsb> defines the word width. The pair
<last>,<first> defines the address range. Multiple address ranges are
allowed for multidimensional indexing.
allowed for multidimensional indexing. This statement creates the
memory array and makes it available to procedural code.
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.
of words.
Structural read access is implemented in terms of address and data
ports. The addresses applied to the address port are expected to be
withing the ranges specified, not based at zero.
within the ranges specified, not based at zero.
A read port is a vector of functors that is wide enough to accept all
provided address bits and at least as wide as the requested subset of
@ -346,18 +349,14 @@ to a memory, but synthesis may ask for lpm_ram_d[pq] objects.
To initialize a memory, use:
.mem/init <memid>[<start>],
val val val ...
;
.mem/init <memid> <start>, val , val ... ;
<memid> is the label of the memory. [<start>] is optional,
identifying the bits location where the first value is loaded.
<start> must be a multiple of four, and defaults to zero, if omitted.
<memid> is the label of the memory, and the <start> is the start
address (cannonical) of the first word to be initialized. The start
address allows mustliple statements be used to initialize words of a
memory.
The values are decimal or hex numbers (0x prefix), which may be
optionally separated by comma ','. Each number in the range 0..256
initializes four memory bits. Two bits form each byte for each memory
bit, in the usual encoding.
The values are one per word.
Procedural access to the memory employs an index register to address a
bit location in the memory, via the commands:

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: codes.h,v 1.69 2004/12/17 04:47:47 steve Exp $"
#ident "$Id: codes.h,v 1.70 2005/03/03 04:33:10 steve Exp $"
#endif
@ -42,6 +42,7 @@ extern bool of_AND(vthread_t thr, vvp_code_t code);
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_D(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_MEM(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_MV(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_V0(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_X0(vthread_t thr, vvp_code_t code);
@ -79,6 +80,7 @@ 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_MEM(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_MV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_WR(vthread_t thr, vvp_code_t code);
@ -99,7 +101,7 @@ extern bool of_OR(vthread_t thr, vvp_code_t code);
extern bool of_ORR(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
extern bool of_SET_MEM(vthread_t thr, vvp_code_t code);
extern bool of_SET_MV(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
@ -169,6 +171,9 @@ extern vvp_code_t codespace_null(void);
/*
* $Log: codes.h,v $
* Revision 1.70 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.69 2004/12/17 04:47:47 steve
* Replace single release with release/net and release/reg.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: compile.cc,v 1.188 2005/02/19 01:32:53 steve Exp $"
#ident "$Id: compile.cc,v 1.189 2005/03/03 04:33:10 steve Exp $"
#endif
# include "arith.h"
@ -90,6 +90,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%assign/d", of_ASSIGN_D, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%assign/m",of_ASSIGN_MEM,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/wr",of_ASSIGN_WR,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
@ -125,6 +126,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%load/m", of_LOAD_MEM,2, {OA_BIT1, OA_MEM_PTR, OA_NONE} },
{ "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} },
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/wr",of_LOAD_WR,2, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
@ -145,7 +147,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%release/net",of_RELEASE_NET,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%release/reg",of_RELEASE_REG,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%set/m", of_SET_MEM,2, {OA_MEM_PTR, OA_BIT1, OA_NONE} },
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
{ "%set/x0", of_SET_X0, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
@ -1235,18 +1237,39 @@ void compile_udp_functor(char*label, char*type,
#endif
}
/*
* Take the detailed parse items from a .mem statement and generate
* the necessary internal structures.
*
* <label> .mem <name>, <msb>, <lsb>, <idxs...> ;
*
*/
void compile_memory(char *label, char *name, int msb, int lsb,
unsigned idxs, long *idx)
unsigned narg, long *args)
{
vvp_memory_t mem = memory_create(label);
memory_new(mem, name, lsb, msb, idxs, idx);
/* Create an empty memory in the symbol table. */
vvp_memory_t mem = memory_create(label);
vpiHandle obj = vpip_make_memory(mem);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
assert( narg > 0 && narg%2 == 0 );
free(label);
struct memory_address_range*ranges
= new struct memory_address_range[narg/2];
for (unsigned idx = 0 ; idx < narg ; idx += 2) {
ranges[idx/2].msb = args[idx+0];
ranges[idx/2].lsb = args[idx+1];
}
memory_configure(mem, msb, lsb, narg/2, ranges);
delete[]ranges;
vpiHandle obj = vpip_make_memory(mem, name);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
free(label);
free(name);
}
void compile_memory_port(char *label, char *memid,
@ -1279,19 +1302,36 @@ void compile_memory_port(char *label, char *memid,
#endif
}
void compile_memory_init(char *memid, unsigned i, unsigned char val)
/*
* The parser calls this multiple times to parse a .mem/init
* statement. The first call includes a memid label and is used to
* select the memory and the start address. Subsequent calls contain
* only the word value to assign.
*/
void compile_memory_init(char *memid, unsigned i, long 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++;
static vvp_memory_t current_mem = 0;
static unsigned current_word;
if (memid) {
current_mem = memory_find(memid);
free(memid);
current_word = i;
return;
}
assert(current_mem);
unsigned word_wid = memory_word_width(current_mem);
vvp_vector4_t val4 (word_wid);
for (unsigned idx = 0 ; idx < word_wid ; idx += 1) {
vvp_bit4_t bit = val & 1 ? BIT4_1 : BIT4_0;
val4.set_bit(idx, bit);
}
memory_init_word(current_mem, current_word, val4);
current_word += 1;
}
/*
@ -1617,6 +1657,9 @@ void compile_param_string(char*label, char*name, char*str, char*value)
/*
* $Log: compile.cc,v $
* Revision 1.189 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.188 2005/02/19 01:32:53 steve
* Implement .arith/div.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: compile.h,v 1.62 2005/02/07 22:42:42 steve Exp $"
#ident "$Id: compile.h,v 1.63 2005/03/03 04:33:10 steve Exp $"
#endif
# include <stdio.h>
@ -204,7 +204,7 @@ extern void compile_memory_port(char *label, char *memid,
unsigned naddr,
unsigned argc, struct symb_s *argv);
extern void compile_memory_init(char *memid, unsigned idx, unsigned char val);
extern void compile_memory_init(char *memid, unsigned idx, long val);
/*
* Compile the .ufunc statement.
@ -297,6 +297,9 @@ extern void compile_net(char*label, char*name,
/*
* $Log: compile.h,v $
* Revision 1.63 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.62 2005/02/07 22:42:42 steve
* Add .repeat functor and BIFIF functors.
*

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
*
@ -18,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: memory.cc,v 1.22 2004/10/04 01:10:59 steve Exp $"
#ident "$Id: memory.cc,v 1.23 2005/03/03 04:33:10 steve Exp $"
#endif
#include "memory.h"
@ -36,39 +37,26 @@ typedef struct vvp_memory_port_s *vvp_memory_port_t;
struct vvp_memory_s
{
char *name; // VPI scope.name
// Address ranges (1 or more)
unsigned nrange;
struct memory_address_range*ranges;
// Address port properties:
unsigned size; // total number of data words
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
// 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)
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;
// Array of words.
unsigned word_count;
vvp_vector4_t*words;
// List of ports into this memory.
vvp_memory_port_t port_list;
};
unsigned memory_data_width(vvp_memory_t mem)
{
return mem->width;
}
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
struct vvp_memory_index_s
{
int first; // first memory address
unsigned size; // number of valid addresses
// Added to correctly support vpiLeftRange and vpiRightRange
int left;
int right;
};
#if 0
struct vvp_memory_port_s : public functor_s
{
void set(vvp_ipoint_t i, bool push, unsigned val, unsigned str);
@ -86,47 +74,7 @@ struct vvp_memory_port_s : public functor_s
bool writable;
};
unsigned memory_size(vvp_memory_t mem)
{
return mem->size;
}
unsigned memory_root(vvp_memory_t mem, unsigned ix)
{
if (ix >= mem->a_idxs)
return 0;
return mem->a_idx[ix].first;
}
unsigned memory_left_range(vvp_memory_t mem, unsigned ix)
{
if (ix >= mem->a_idxs)
return 0;
return mem->a_idx[ix].left;
}
unsigned memory_right_range(vvp_memory_t mem, unsigned ix)
{
if (ix >= mem->a_idxs)
return 0;
return mem->a_idx[ix].right;
}
unsigned memory_word_left_range(vvp_memory_t mem)
{
return mem->msb;
}
unsigned memory_word_right_range(vvp_memory_t mem)
{
return mem->lsb;
}
char *memory_name(vvp_memory_t mem)
{
return mem->name;
}
#endif
// Compilation
@ -143,65 +91,114 @@ vvp_memory_t memory_find(char *label)
vvp_memory_t memory_create(char *label)
{
if (!memory_table)
memory_table = new_symbol_table();
if (!memory_table)
memory_table = new_symbol_table();
assert(!memory_find(label));
assert(!memory_find(label));
vvp_memory_t mem = new struct vvp_memory_s;
vvp_memory_t mem = new struct vvp_memory_s;
symbol_value_t v;
v.ptr = mem;
sym_set_value(memory_table, label, v);
symbol_value_t v;
v.ptr = mem;
sym_set_value(memory_table, label, v);
return mem;
return mem;
}
void memory_new(vvp_memory_t mem, char *name, int msb, int lsb,
unsigned idxs, long *idx)
void memory_configure(vvp_memory_t mem,
int msb, int lsb,
unsigned nrange,
const struct memory_address_range*ranges)
{
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
mem->msb = msb;
mem->lsb = lsb;
mem->fwidth = (mem->width+3)/4;
/* Get the word width details. */
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
mem->msb = msb;
mem->lsb = lsb;
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);
/* Make a private copy of the memory address ranges. */
assert(nrange > 0);
mem->nrange = nrange;
mem->ranges = new struct memory_address_range[nrange];
for (unsigned idx = 0 ; idx < nrange ; idx += 1)
mem->ranges[idx] = ranges[idx];
mem->size = 1;
for (unsigned i=0; i < mem->a_idxs; i++)
{
vvp_memory_index_t x = mem->a_idx + i;
int msw = *(idx++);
int lsw = *(idx++);
/* Scan the indices (multiplying each range) to add up the
total number of words in this memory. */
mem->word_count = 1;
for (unsigned idx = 0 ; idx < mem->nrange ; idx += 1) {
struct memory_address_range*rp = mem->ranges+idx;
x->left = msw;
x->right = lsw;
unsigned count = rp->msb > rp->lsb
? rp->msb - rp->lsb + 1
: rp->lsb - rp->msb + 1;
if (msw > lsw) {
x->size = msw - lsw + 1;
x->first = lsw;
mem->word_count *= count;
}
else {
x->size = lsw - msw + 1;
x->first = msw;
}
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->words = new vvp_vector4_t [mem->word_count];
assert(mem->words);
mem->addr_root = 0x0;
mem->name = name;
mem->port_list = 0;
}
static void update_addr(vvp_memory_port_t addr);
unsigned memory_word_width(vvp_memory_t mem)
{
return mem->width;
}
unsigned memory_word_count(vvp_memory_t mem)
{
return mem->word_count;
}
long memory_word_left_range(vvp_memory_t mem)
{
return mem->msb;
}
long memory_word_right_range(vvp_memory_t mem)
{
return mem->lsb;
}
long memory_left_range(vvp_memory_t mem, unsigned ix)
{
assert(ix < mem->nrange);
return mem->ranges[ix].msb;
}
long memory_right_range(vvp_memory_t mem, unsigned ix)
{
assert(ix < mem->nrange);
return mem->ranges[ix].lsb;
}
vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned addr)
{
// XXXX For now, assume this can't happen
assert(addr <= mem->word_count);
return mem->words[addr];
}
void memory_init_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
{
if (addr >= mem->word_count)
return;
mem->words[addr] = val;
}
void memory_set_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
{
memory_init_word(mem, addr, val);
if (mem->port_list)
fprintf(stderr, "XXXX memory_set_word(%u, ...)"
" not fully implemented\n", addr);
}
#if 0
vvp_ipoint_t memory_port_new(vvp_memory_t mem,
unsigned nbits, unsigned bitoff,
unsigned naddr, bool writable)
@ -240,21 +237,23 @@ vvp_ipoint_t memory_port_new(vvp_memory_t mem,
return a->ix;
}
#endif
void memory_init_nibble(vvp_memory_t mem, unsigned idx, unsigned char val)
void schedule_memory(vvp_memory_t mem, unsigned addr,
vvp_vector4_t val, unsigned long delay)
{
assert(idx < mem->size*mem->fwidth);
mem->bits[idx] = val;
fprintf(stderr, "XXXX Forgot how to schedule memory write.\n");
}
// Utilities
#if 0
inline static
vvp_memory_bits_t get_word_ix(vvp_memory_t mem, unsigned idx)
{
return mem->bits + idx*mem->fwidth;
}
#endif
#if 0
inline static
vvp_memory_bits_t get_word(vvp_memory_t mem, int addr)
{
@ -266,7 +265,8 @@ vvp_memory_bits_t get_word(vvp_memory_t mem, int addr)
return get_word_ix(mem, waddr);
}
#endif
#if 0
inline static
bool set_bit(vvp_memory_bits_t bits, int bit, unsigned char val)
{
@ -276,7 +276,8 @@ bool set_bit(vvp_memory_bits_t bits, int bit, unsigned char val)
bits[ix] = (bits[ix] &~ (3<<ip)) | ((val&3) << ip);
return r;
}
#endif
#if 0
inline static
unsigned char get_nibble(vvp_memory_bits_t bits, int bit)
{
@ -285,13 +286,15 @@ unsigned char get_nibble(vvp_memory_bits_t bits, int bit)
int ix = bit/4;
return bits[ix];
}
#endif
#if 0
inline static
unsigned char get_bit(vvp_memory_bits_t bits, int bit)
{
return (get_nibble(bits, bit) >> (2*(bit&3))) & 3;
}
#endif
#if 0
inline static
unsigned char functor_get_inputs(vvp_ipoint_t ip)
{
@ -299,14 +302,16 @@ unsigned char functor_get_inputs(vvp_ipoint_t ip)
assert(fp);
return fp->ival;
}
#endif
#if 0
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;
}
#endif
#if 0
static
bool update_addr_bit(vvp_memory_port_t addr, vvp_ipoint_t ip)
{
@ -330,7 +335,9 @@ bool update_addr_bit(vvp_memory_port_t addr, vvp_ipoint_t ip)
return addr->cur_addr != old;
}
#endif
#if 0
static
void update_addr(vvp_memory_port_t addr)
{
@ -342,7 +349,9 @@ void update_addr(vvp_memory_port_t addr)
break;
}
}
#endif
#if 0
inline static
void update_data(vvp_memory_port_t data)
{
@ -355,7 +364,9 @@ void update_data(vvp_memory_port_t data)
df->put_oval(out, true);
}
}
#endif
#if 0
static
void update_data_ports(vvp_memory_t mem, vvp_memory_bits_t bits, int bit,
unsigned char val)
@ -379,7 +390,9 @@ void update_data_ports(vvp_memory_t mem, vvp_memory_bits_t bits, int bit,
a = a->next;
}
}
#endif
#if 0
static inline
void write_event(vvp_memory_port_t p)
{
@ -406,7 +419,9 @@ void write_event(vvp_memory_port_t p)
}
}
}
#endif
#if 0
void vvp_memory_port_s::set(vvp_ipoint_t i, bool, unsigned val, unsigned)
{
// !attention! "i" may not correspond to "this"
@ -431,10 +446,11 @@ void vvp_memory_port_s::set(vvp_ipoint_t i, bool, unsigned val, unsigned)
write_event(this);
}
}
#endif
// %set/mem
#if 0
void memory_set(vvp_memory_t mem, unsigned idx, unsigned char val)
{
if (idx/4 >= (mem->size * mem->fwidth))
@ -448,9 +464,10 @@ void memory_set(vvp_memory_t mem, unsigned idx, unsigned char val)
update_data_ports(mem, get_word_ix(mem, widx), bidx, val);
}
#endif
// %load/mem
#if 0
unsigned memory_get(vvp_memory_t mem, unsigned idx)
{
if (idx/4 >= (mem->size * mem->fwidth))
@ -458,7 +475,7 @@ unsigned memory_get(vvp_memory_t mem, unsigned idx)
return get_bit(mem->bits, idx);
}
#endif
// %assign/mem event scheduling
struct mem_assign_s: public vvp_gen_event_s
@ -490,41 +507,18 @@ inline static void ma_free(struct mem_assign_s* cur)
ma_free_list = cur;
}
#if 0
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, false);
}
#endif
/*
* $Log: memory.cc,v $
* Revision 1.22 2004/10/04 01:10:59 steve
* Clean up spurious trailing white space.
*
* Revision 1.21 2003/09/09 00:56:45 steve
* Reimpelement scheduler to divide nonblocking assign queue out.
*
* Revision 1.20 2003/02/09 23:33:26 steve
* Spelling fixes.
*
* Revision 1.19 2002/09/17 00:42:22 steve
* Proper initialization of the memories table.
*
* Revision 1.18 2002/08/12 01:35:08 steve
* conditional ident string using autoconfig.
*
* Revision 1.17 2002/08/11 23:47:05 steve
* Add missing Log and Ident strings.
* Revision 1.23 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
*/

View File

@ -20,75 +20,105 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: memory.h,v 1.7 2004/10/04 01:10:59 steve Exp $"
#ident "$Id: memory.h,v 1.8 2005/03/03 04:33:10 steve Exp $"
#endif
#include "pointers.h"
#include "functor.h"
#include "vvp_net.h"
/*
** vvp_memory_t is a memory
** vvp_memory_bits_t are bits in a memory
** vvp_memory_index_t is a memory index range definition
*/
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);
struct memory_address_range {
int msb;
int lsb;
};
/*
* Given a memory device, the memory_configure function configures it
* by defining the dimensions of the device. It is an error to
* redefine the dimensions of a device already configured.
*
* The lsb and msb define the dimensions of a word. They are in
* Verilog form. The actual word contents are vvp_vector4_t values.
*
* The idx array is an array of address ranges that describe the
* complete multi-dimensional array. In a normal Verilog array, idxs
* is 1, and idx is a pointer to a single memory_address_range. The
* table does not need to be persistent.
*/
extern void memory_configure(vvp_memory_t mem, int msb, int lsb,
unsigned idxs,
const struct memory_address_range *idx);
/*
* init_word and set_word functions take the memory to be manipulated
* and write a word value at the given word address. The idx is the
* canonical (0-based, 1-dimensional) address of the word to be
* written. The caller needs to have converted any multi-dimensional
* address into a canonical address first.
*
* The difference between init_word and set_word are that the set_word
* function causes values to be propagated through structural ports,
* but the init_word does not.
*/
extern void memory_init_word(vvp_memory_t mem,
unsigned idx,
vvp_vector4_t val);
extern void memory_set_word(vvp_memory_t mem,
unsigned idx,
vvp_vector4_t val);
/*
* this doesn't actually write the value to the memory word, but
* scedules for the write to happen some time in the future. The delay
* is in simulation clock units
*/
void schedule_memory(vvp_memory_t mem, unsigned addr,
vvp_vector4_t val, unsigned long delay);
/*
* Get the word value at the given index into the memory.
*/
extern vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned idx);
#if 0
vvp_ipoint_t memory_port_new(vvp_memory_t mem,
unsigned nbits, unsigned bitoff,
unsigned naddr, bool writable);
#endif
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_size(vvp_memory_t mem);
char *memory_name(vvp_memory_t mem);
unsigned memory_data_width(vvp_memory_t mem);
unsigned memory_root(vvp_memory_t mem, unsigned ix = 0);
unsigned memory_left_range(vvp_memory_t mem, unsigned ix = 0);
unsigned memory_right_range(vvp_memory_t mem, unsigned ix = 0);
unsigned memory_word_left_range(vvp_memory_t mem);
unsigned memory_word_right_range(vvp_memory_t mem);
/* Number of words in the memory. */
unsigned memory_word_count(vvp_memory_t mem);
/* Width of a word */
unsigned memory_word_width(vvp_memory_t mem);
/* Get the user declared geometry of the memory address. This is the
msb and lsb values for each pair in the multi-dimensional array. */
long memory_left_range(vvp_memory_t mem, unsigned ix);
long memory_right_range(vvp_memory_t mem, unsigned ix);
/* Get the user defined geometry for the memory *word*. */
long memory_word_left_range(vvp_memory_t mem);
long memory_word_right_range(vvp_memory_t mem);
/*
** Access to the memory symbol table.
**
** The memory_find function locates the memory device by name. If the
** device does not exist, a nil is returned.
**
** The memory_create functio create a new memory device with the given
** name. It is a fatal error to try to create a device that already exists.
*/
vvp_memory_t memory_find(char *label);
vvp_memory_t memory_create(char *label);
/*
* $Log: memory.h,v $
* Revision 1.7 2004/10/04 01:10:59 steve
* Clean up spurious trailing white space.
*
* Revision 1.6 2002/08/12 01:35:08 steve
* conditional ident string using autoconfig.
*
* Revision 1.5 2002/01/31 04:28:17 steve
* Full support for $readmem ranges (Tom Verbeure)
*
* Revision 1.4 2001/10/31 04:27:47 steve
* Rewrite the functor type to have fewer functor modes,
* and use objects to manage the different types.
* (Stephan Boettcher)
*
* Revision 1.3 2001/06/15 03:28:31 steve
* Change the VPI call process so that loaded .vpi modules
* use a function table instead of implicit binding.
*
* Revision 1.2 2001/05/08 23:59:33 steve
* Add ivl and vvp.tgt support for memories in
* expressions and l-values. (Stephan Boettcher)
*
* Revision 1.1 2001/05/01 01:09:39 steve
* Add support for memory objects. (Stephan Boettcher)
* Revision 1.8 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
*/

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
*
* $Id: opcodes.txt,v 1.60 2005/02/14 01:50:23 steve Exp $
* $Id: opcodes.txt,v 1.61 2005/03/03 04:33:10 steve Exp $
*/
@ -70,13 +70,25 @@ The %assign/d instruction is exactly the same as the %assign
instruction, except that the <delay> specifies one of the index
registers, that contain a calculated delay.
* %assign/m <memory-label>, <delay>, <bit>
* %assign/m <memory-label>, <delay>, <bit> (OBSOLETE)
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.
* %assign/mv <memory-label>, <delay>, <bit>
the %assign/mv instruction assigns a vector value to a word in the
labeled memory. The <delay> is the delay in simulation time to the
assignment (0 for non-blocking assignment) and the <bit> is the base
of the vector to write.
The width of the word is retrived from index register 0.
The address of the word in the memory is from index register 3. The
address is cannonical form.
* %assign/v0 <var-label>, <delay>, <bit>
The %assign/v0 instruction is a vector version of non-blocking
@ -342,13 +354,18 @@ If the matching child instruction is still running, a %join suspends
the calling thread until the child ends. If the child is already
ended, then the %join does not block or yield the thread.
* %load/m <bit>, <memory-label>
* %load/m <bit>, <memory-label> (OBSOLETE)
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.
* %load/mv <bit>, <memory-label>, <wid>
this inctruction loads a word from the specified memory. The word
address is in index register 3. The width should match the width of
the memory word.
* %load/nx <bit>, <vpi-label>, <idx>
@ -508,12 +525,13 @@ addressed variable bit and working up. If the <bit> is one of the
constant bits, then the value is repeated for the width. Otherwise,
the vector is taken from increasing thread bit addresses.
* %set/m <memory-label>, <bit>
* %set/mv <memory-label>, <bit>, <wid>
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.
This sets a thread vector to a memory word. The <memory-label>
addresses a memory device, and the <bit>,<wid> describe a vector to be
written. Index register 3 contains the address of the word within the
memory. The address (in canonical form) is precalculated and loaded
into index register 3.
* %set/wr <vpi-label>, <bit>

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: parse.y,v 1.66 2005/02/07 22:42:42 steve Exp $"
#ident "$Id: parse.y,v 1.67 2005/03/03 04:33:10 steve Exp $"
#endif
# include "parse_misc.h"
@ -626,16 +626,17 @@ udp_table
;
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); }
;
: K_MEM_I symbol T_NUMBER ','
{ compile_memory_init($2.text, $3, 0); }
mem_init_list ';'
;
o_komma
: /* empty */
| ','
;
mem_init_list
: mem_init_list ',' T_NUMBER
{ compile_memory_init(0, 0, $3); }
| T_NUMBER
{ compile_memory_init(0, 0, $1); }
;
signed_t_number
: T_NUMBER { $$ = $1; }
@ -672,6 +673,9 @@ int compile_design(const char*path)
/*
* $Log: parse.y,v $
* Revision 1.67 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.66 2005/02/07 22:42:42 steve
* Add .repeat functor and BIFIF functors.
*

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2005 Stephen Williams (steve@icarus.com>
* Copyright (c) 1999-2000 Picture Elements, Inc.
* Stephen Williams (steve@picturel.com)
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
@ -27,7 +28,7 @@
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_memory.cc,v 1.23 2004/05/19 03:30:46 steve Exp $"
#ident "$Id: vpi_memory.cc,v 1.24 2005/03/03 04:33:10 steve Exp $"
#endif
# include "vpi_priv.h"
@ -54,6 +55,7 @@ struct __vpiMemory {
struct __vpiScope* scope;
struct __vpiMemoryWord*words;
vvp_memory_t mem;
const char*name; /* Permanently allocated string. */
struct __vpiDecConst left_range;
struct __vpiDecConst right_range;
struct __vpiDecConst word_left_range;
@ -96,7 +98,7 @@ static int vpi_memory_get(int code, vpiHandle ref)
switch (code) {
case vpiSize:
return (int)memory_size(rfp->mem);
return (int)memory_word_count(rfp->mem);
default:
return 0;
@ -110,17 +112,16 @@ static char* memory_get_str(int code, vpiHandle ref)
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
char *bn = strdup(vpi_get_str(vpiFullName, &rfp->scope->base));
char *nm = memory_name(rfp->mem);
char *rbuf = need_result_buf(strlen(bn) + strlen(nm) + 2, RBUF_STR);
char *rbuf = need_result_buf(strlen(bn)+strlen(rfp->name)+2, RBUF_STR);
switch (code) {
case vpiFullName:
sprintf(rbuf, "%s.%s", bn, nm);
sprintf(rbuf, "%s.%s", bn, rfp->name);
free(bn);
return rbuf;
case vpiName:
strcpy(rbuf, nm);
strcpy(rbuf, rfp->name);
free(bn);
return rbuf;
}
@ -134,7 +135,7 @@ static vpiHandle memory_scan(vpiHandle ref, int)
struct __vpiMemWordIterator*obj = (struct __vpiMemWordIterator*)ref;
assert(ref->vpi_type->type_code == vpiIterator);
if (obj->next >= memory_size(obj->mem->mem)) {
if (obj->next >= memory_word_count(obj->mem->mem)) {
vpi_free_object(ref);
return 0;
}
@ -189,9 +190,10 @@ static vpiHandle memory_index(vpiHandle ref, int index)
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
assert(ref->vpi_type->type_code==vpiMemory);
index -= memory_root(rfp->mem);
if (index >= (int)memory_size(rfp->mem)) return 0;
if (index < 0) return 0;
if (index >= (int)memory_word_count(rfp->mem))
return 0;
if (index < 0)
return 0;
memory_make_word_handles(rfp);
return &(rfp->words[index].base);
@ -226,7 +228,7 @@ static int memory_word_get(int code, vpiHandle ref)
switch (code) {
case vpiSize:
return memory_data_width(rfp->mem->mem);
return memory_word_width(rfp->mem->mem);
default:
return 0;
@ -241,26 +243,32 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
/* Get the width of the memory, and the byte index of the
first byte of the word. */
unsigned width = memory_data_width(rfp->mem->mem);
unsigned word_offset = memory_root(rfp->mem->mem);
unsigned bidx = (rfp->index.value - word_offset) * ((width+3)&~3);
unsigned width = memory_word_width(rfp->mem->mem);
unsigned word_addr = rfp->index.value;
/* Build up the word value from whatever format the user
supplies. */
vvp_vector4_t put_val (width);
switch (val->format) {
case vpiVectorVal:
for (unsigned widx = 0; widx < width; widx += 32) {
p_vpi_vecval cur = val->value.vector + (widx/32);
for (unsigned idx = widx
; idx < width && idx < widx+32
; idx += 1) {
int aval = (cur->aval >> (idx%32)) & 1;
int bval = (cur->bval >> (idx%32)) & 1;
unsigned char val = (bval<<1) | (aval^bval);
memory_set(rfp->mem->mem, bidx+idx, val);
for (unsigned idx = 0 ; idx < width ; idx += 1) {
p_vpi_vecval cur = val->value.vector + (idx/32);
int aval = (cur->aval >> (idx%32)) & 1;
int bval = (cur->bval >> (idx%32)) & 1;
/* Check this bit value conversion. This is
specifically defined by the IEEE1364 standard. */
vvp_bit4_t bit;
if (bval) {
bit = aval? BIT4_Z : BIT4_X;
} else {
bit = aval? BIT4_1 : BIT4_0;
}
put_val.set_bit(idx, bit);
}
break;
#if 0
case vpiIntVal:
for (unsigned widx = 0; widx < width; widx += 32) {
int cur = val->value.integer;
@ -273,7 +281,8 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
}
}
break;
#endif
#if 0
/* If the caller tries to set a HexStrVal, convert it to
bits and write the bits into the word. */
case vpiHexStrVal: {
@ -290,7 +299,8 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
delete[]bits;
break;
}
#endif
#if 0
case vpiDecStrVal: {
unsigned char*bits = new unsigned char[width];
vpip_dec_str_to_bits(bits, width, val->value.str, false);
@ -302,7 +312,8 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
delete[]bits;
break;
}
#endif
#if 0
case vpiOctStrVal: {
unsigned char*bits = new unsigned char[(width+3) / 4];
vpip_oct_str_to_bits(bits, width, val->value.str, false);
@ -317,7 +328,8 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
delete[]bits;
break;
}
#endif
#if 0
case vpiBinStrVal: {
unsigned char*bits = new unsigned char[(width+3) / 4];
vpip_bin_str_to_bits(bits, width, val->value.str, false);
@ -332,11 +344,12 @@ static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val)
delete[]bits;
break;
}
#endif
default:
assert(0);
}
memory_set_word(rfp->mem->mem, word_addr, put_val);
return 0;
}
@ -347,7 +360,7 @@ static char* memory_word_get_str(int code, vpiHandle ref)
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
char *bn = strdup(vpi_get_str(vpiFullName, &rfp->mem->scope->base));
char *nm = memory_name(rfp->mem->mem);
const char *nm = rfp->mem->name;
char *rbuf = need_result_buf(strlen(bn) + strlen(nm) + 10 + 4, RBUF_STR);
@ -374,9 +387,10 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
assert(rfp->base.vpi_type->type_code==vpiMemoryWord);
unsigned width = memory_data_width(rfp->mem->mem);
unsigned word_offset = memory_root(rfp->mem->mem);
unsigned bidx = (rfp->index.value - word_offset) * ((width+3)&~3);
unsigned width = memory_word_width(rfp->mem->mem);
unsigned word_address = rfp->index.value;
vvp_vector4_t word_val = memory_get_word(rfp->mem->mem, word_address);
char *rbuf = 0;
@ -385,16 +399,16 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
assert("format not implemented");
case vpiBinStrVal:
rbuf = need_result_buf(width+1, RBUF_VAL);
for (unsigned idx = 0 ; idx < width ; idx += 1) {
unsigned bit = memory_get(rfp->mem->mem, bidx+idx);
rbuf = need_result_buf(width+1, RBUF_VAL);
for (unsigned idx = 0 ; idx < width ; idx += 1) {
vvp_bit4_t bit = word_val.value(idx);
rbuf[width-idx-1] = "01xz"[bit];
}
rbuf[width] = 0;
vp->value.str = rbuf;
break;
}
rbuf[width] = 0;
vp->value.str = rbuf;
break;
#if 0
/* XXXX Needs to be converted. */
case vpiOctStrVal: {
unsigned hwid = (width+2) / 3;
unsigned char*bits = new unsigned char[width];
@ -416,7 +430,9 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
vp->value.str = rbuf;
break;
}
#endif
#if 0
/* XXXX Needs to be converted. */
case vpiHexStrVal: {
unsigned hval, hwid;
hwid = (width + 3) / 4;
@ -455,7 +471,8 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
vp->value.str = rbuf;
break;
}
#endif
#if 0
case vpiDecStrVal: {
unsigned char*bits = new unsigned char[width];
@ -469,7 +486,8 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
vp->value.str = rbuf;
break;
}
#endif
#if 0
case vpiIntVal:
assert(width <= 8 * sizeof vp->value.integer);
@ -485,7 +503,8 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
vp->value.integer |= bit << idx;
}
break;
#endif
#if 0
case vpiVectorVal: {
unsigned hwid = (width - 1)/32 + 1;
@ -519,7 +538,8 @@ static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
}
}
break;
}
}
#endif
}
}
@ -550,8 +570,7 @@ static void memory_make_word_handles(struct __vpiMemory*rfp)
if (rfp->words != 0)
return;
unsigned word_count = memory_size(rfp->mem);
unsigned word_offset = memory_root(rfp->mem);
unsigned word_count = memory_word_count(rfp->mem);
rfp->words = (struct __vpiMemoryWord*)
calloc(word_count, sizeof (struct __vpiMemoryWord));
@ -560,11 +579,11 @@ static void memory_make_word_handles(struct __vpiMemory*rfp)
struct __vpiMemoryWord*cur = rfp->words + idx;
cur->base.vpi_type = &vpip_memory_word_rt;
cur->mem = rfp;
vpip_make_dec_const(&cur->index, idx + word_offset);
vpip_make_dec_const(&cur->index, idx);
}
}
vpiHandle vpip_make_memory(vvp_memory_t mem)
vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name)
{
struct __vpiMemory*obj = (struct __vpiMemory*)
malloc(sizeof(struct __vpiMemory));
@ -573,8 +592,10 @@ vpiHandle vpip_make_memory(vvp_memory_t mem)
obj->base.vpi_type = &vpip_memory_rt;
obj->scope = vpip_peek_current_scope();
obj->mem = mem;
vpip_make_dec_const(&obj->left_range, memory_left_range(mem));
vpip_make_dec_const(&obj->right_range, memory_right_range(mem));
obj->name = vpip_name_string(name);
vpip_make_dec_const(&obj->left_range, memory_left_range(mem, 0));
vpip_make_dec_const(&obj->right_range, memory_right_range(mem, 0));
vpip_make_dec_const(&obj->word_left_range, memory_word_left_range(mem));
vpip_make_dec_const(&obj->word_right_range,memory_word_right_range(mem));
@ -585,6 +606,9 @@ vpiHandle vpip_make_memory(vvp_memory_t mem)
/*
* $Log: vpi_memory.cc,v $
* Revision 1.24 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.23 2004/05/19 03:30:46 steve
* Support delayed/non-blocking assignment to reals and others.
*
@ -625,41 +649,4 @@ vpiHandle vpip_make_memory(vvp_memory_t mem)
* temporary buffers for *_get_str() data,
* dynamic storage for vpi_get_data() in memory types
* shared with signal white space
*
* Revision 1.11 2002/07/01 15:36:12 steve
* Limit word writing to vector limits.
*
* Revision 1.10 2002/06/30 04:35:47 steve
* Get vpiVectorVal for memories.
*
* Revision 1.9 2002/05/17 04:12:19 steve
* Rewire vpiMemory and vpiMemoryWord handles to
* support proper iteration of words, and the
* vpiIndex value.
*
* Revision 1.8 2002/05/11 04:39:35 steve
* Set and get memory words by string value.
*
* Revision 1.7 2002/05/10 16:00:57 steve
* Support scope iterate over vpiNet,vpiReg/vpiMemory.
*
* Revision 1.6 2002/05/03 15:44:11 steve
* Add vpiModule iterator to vpiScope objects.
*
* Revision 1.5 2002/02/06 04:48:34 steve
* get bin or hex string values of memory words.
*
* Revision 1.4 2002/01/31 04:28:17 steve
* Full support for $readmem ranges (Tom Verbeure)
*
* Revision 1.3 2001/12/07 23:23:05 steve
* vpi_put_value of vpiIntVal for memory words.
*
* Revision 1.2 2001/11/09 03:39:07 steve
* Support vpiIntVal from memory.
*
* Revision 1.1 2001/05/08 23:59:33 steve
* Add ivl and vvp.tgt support for memories in
* expressions and l-values. (Stephan Boettcher)
*
*/

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_priv.h,v 1.60 2004/12/11 02:31:30 steve Exp $"
#ident "$Id: vpi_priv.h,v 1.61 2005/03/03 04:33:10 steve Exp $"
#endif
# include "vpi_user.h"
@ -216,7 +216,7 @@ extern void vpip_real_value_change(struct __vpiCallback*cbh,
* the memory.
*/
extern vpiHandle vpip_make_memory(vvp_memory_t mem);
extern vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name);
/*
* These are the various variable types.
@ -417,6 +417,9 @@ extern char *need_result_buf(unsigned cnt, vpi_rbuf_t type);
/*
* $Log: vpi_priv.h,v $
* Revision 1.61 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.60 2004/12/11 02:31:30 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_signal.cc,v 1.63 2004/12/11 02:31:30 steve Exp $"
#ident "$Id: vpi_signal.cc,v 1.64 2005/03/03 04:33:10 steve Exp $"
#endif
/*
@ -491,27 +491,26 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
rfp = (struct __vpiSignal*)ref;
vvp_net_ptr_t destination (rfp->node, 0);
wid = (rfp->msb >= rfp->lsb)
? (rfp->msb - rfp->lsb + 1)
: (rfp->lsb - rfp->msb + 1);
vvp_vector4_t val (wid);
switch (vp->format) {
case vpiIntVal: {
if (wid > 8*sizeof(long)) {
fprintf(stderr, "internal error: wid(%u) "
"too large.\n", wid);
assert(0);
}
long val = vp->value.integer;
long vpi_val = vp->value.integer;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
functor_poke(rfp, idx, val&1, (val&1)? St1 : St0, 0);
val >>= 1;
vvp_bit4_t bit = vpi_val&1 ? BIT4_1 : BIT4_0;
val.set_bit(idx, bit);
vpi_val >>= 1;
}
break;
}
#if 0
case vpiScalarVal:
switch (vp->value.scalar) {
case vpi0:
@ -530,7 +529,8 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
assert(0);
}
break;
#endif
#if 0
case vpiVectorVal:
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
unsigned long aval = vp->value.vector[idx/32].aval;
@ -554,7 +554,8 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
}
}
break;
#endif
#if 0
case vpiBinStrVal: {
unsigned char*bits = new unsigned char[(wid+3) / 4];
vpip_bin_str_to_bits(bits, wid, vp->value.str, false);
@ -583,7 +584,8 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
delete[]bits;
break;
}
#endif
#if 0
case vpiOctStrVal: {
unsigned char*bits = new unsigned char[(wid+3) / 4];
vpip_oct_str_to_bits(bits, wid, vp->value.str, false);
@ -612,7 +614,8 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
delete[]bits;
break;
}
#endif
#if 0
case vpiHexStrVal: {
unsigned char*bits = new unsigned char[(wid+3) / 4];
vpip_hex_str_to_bits(bits, wid, vp->value.str, false);
@ -641,7 +644,8 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
delete[]bits;
break;
}
#endif
#if 0
case vpiDecStrVal: {
unsigned char*bits = new unsigned char[wid];
vpip_dec_str_to_bits(bits, wid, vp->value.str, false);
@ -667,7 +671,7 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
delete[]bits;
break;
}
#endif
case vpiStringVal:
signal_put_stringval(rfp, wid, vp->value.str);
break;
@ -681,6 +685,8 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
}
vvp_send_vec4(destination, val);
return ref;
}
@ -772,6 +778,9 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb,
/*
* $Log: vpi_signal.cc,v $
* Revision 1.64 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.63 2004/12/11 02:31:30 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vthread.cc,v 1.129 2005/02/14 01:50:23 steve Exp $"
#ident "$Id: vthread.cc,v 1.130 2005/03/03 04:33:10 steve Exp $"
#endif
# include "config.h"
@ -613,8 +613,18 @@ bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_MEM(vthread_t thr, vvp_code_t cp)
{
#if 0
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx[1]);
schedule_memory(cp->mem, thr->words[3].w_int, bit_val, cp->bit_idx[0]);
#else
fprintf(stderr, "XXXX %%assign/m is obsolete.\n");
#endif
return true;
}
bool of_ASSIGN_MV(vthread_t thr, vvp_code_t cp)
{
fprintf(stderr, "XXXX %%assign/mv not implemented yet\n");
return true;
}
@ -1670,12 +1680,44 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp)
bool of_LOAD_MEM(vthread_t thr, vvp_code_t cp)
{
#if 0
assert(cp->bit_idx[0] >= 4);
unsigned char val = memory_get(cp->mem, thr->words[3].w_int);
thr_put_bit(thr, cp->bit_idx[0], val);
#else
fprintf(stderr, "XXXX %%load/m is obsolete\n");
#endif
return true;
}
/*
* %load/mv <bit>, <mem-label>, <wid> ;
*
* <bit> is the thread bit address for the result
* <mem-label> is the memory device to access, and
* <wid> is the width of the word to read.
*
* The address of the word in the memory is in index register 3.
*/
bool of_LOAD_MV(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
unsigned adr = thr->words[3].w_int;
vvp_vector4_t word = memory_get_word(cp->mem, adr);
assert(word.size() == wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1, bit += 1) {
vvp_bit4_t val = word.value(idx);
thr_put_bit(thr, bit, val);
}
return true;
}
/*
* %load/nx <bit>, <vpi-label>, <idx> ; Load net/indexed.
*
@ -2607,14 +2649,25 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp)
static const unsigned char strong_values[4] = {St0, St1, StX, HiZ};
bool of_SET_MEM(vthread_t thr, vvp_code_t cp)
/*
* This implements the "%set/mv <label>, <bit>, <wid>" instruction. In
* this case, the <label> is a memory label, and the <bit> and <wid>
* are the thread vector of a value to be written in.
*/
bool of_SET_MV(vthread_t thr, vvp_code_t cp)
{
unsigned char val = thr_get_bit(thr, cp->bit_idx[0]);
memory_set(cp->mem, thr->words[3].w_int, val);
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
unsigned adr = thr->words[3].w_int;
/* Make a vector of the desired width. */
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
memory_set_word(cp->mem, adr, value);
return true;
}
/*
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
*
@ -3042,6 +3095,9 @@ bool of_JOIN_UFUNC(vthread_t thr, vvp_code_t cp)
/*
* $Log: vthread.cc,v $
* Revision 1.130 2005/03/03 04:33:10 steve
* Rearrange how memories are supported as vvp_vector4 arrays.
*
* Revision 1.129 2005/02/14 01:50:23 steve
* Signals may receive part vectors from %set/x0
* instructions. Re-implement the %set/x0 to do