Change the VPI call process so that loaded .vpi modules

use a function table instead of implicit binding.
This commit is contained in:
steve 2001-06-15 03:28:30 +00:00
parent e28b7f06c5
commit 7009dc8d9b
7 changed files with 179 additions and 90 deletions

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: README.txt,v 1.27 2001/06/07 03:09:03 steve Exp $
* $Id: README.txt,v 1.28 2001/06/15 03:28:30 steve Exp $
*/
VVP SIMULATION ENGINE
@ -296,28 +296,44 @@ 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.
ports. The addresses applied to the address port are expected to be
withing the ranges specified, not based at zero.
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.
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
the data port.
<label> .mem/port <memid>, <msb>,<lsb>, <symbols_list> ;
<label> .mem/port <memid>, <msb>,<lsb>, <aw>, <addr_bits> ;
<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
port range defined for the memory. The LSB of the data word is 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.
definition. <addr_bits> is a list of symbols, which connect to the
address inputs of this port. There are <aw> address bits (<aw> may
become a list of numbers, when multi-index memory ports become
supported).
Any address change, or any change in the addressed memory contents is
imediately propagated to the port outputs.
A write port is a superset of a read port. It is a vector of functors
that is wide enough to accept the address bits, an event input, a
write enable input, and the data inputs.
<label> .mem/port <memid>, <msb>,<lsb>, <aw>, <addr_bits>,
<event>, <we>, <data> ;
<event> is an event functor that triggers a write, if the <we> input
is true. <data> is a list of symbols that connect to the data input
port. For asynchronous transparent write operation, connect
<event> to C<z>, the RAM will transparently follow any changes on
address and data lines, while <we> is true.
There is no Verilog construct that calls for a structural write port
to a memory, but synthesis may ask for lpm_ram_d[pq] objects.
To initialize a memory, use:
.mem/init <memid>[<start>],

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: compile.cc,v 1.74 2001/06/10 17:12:51 steve Exp $"
#ident "$Id: compile.cc,v 1.75 2001/06/15 03:28:31 steve Exp $"
#endif
# include "arith.h"
@ -612,6 +612,7 @@ void compile_memory(char *label, char *name, int msb, int lsb,
void compile_memory_port(char *label, char *memid,
unsigned msb, unsigned lsb,
unsigned naddr,
unsigned argc, struct symb_s *argv)
{
vvp_memory_t mem = memory_find(memid);
@ -624,21 +625,25 @@ void compile_memory_port(char *label, char *memid,
assert (msb < memory_data_width(mem));
unsigned nbits = msb-lsb+1;
unsigned awidth = memory_addr_width(mem);
unsigned nfun = (awidth + 3)/4;
bool writable = argc >= (naddr + 2 + nbits);
unsigned nfun = naddr;
if (writable)
nfun += 2 + nbits;
assert(nfun == argc);
nfun = (nfun+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);
free(argv);
memory_port_new(mem, ix, nbits, lsb);
memory_port_new(mem, ix, nbits, lsb, naddr, writable);
}
void compile_memory_init(char *memid, unsigned i, unsigned char val)
@ -1335,6 +1340,10 @@ vvp_ipoint_t debug_lookup_functor(const char*name)
/*
* $Log: compile.cc,v $
* Revision 1.75 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.74 2001/06/10 17:12:51 steve
* Instructions can forward reference functors.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: compile.h,v 1.25 2001/06/07 03:09:03 steve Exp $"
#ident "$Id: compile.h,v 1.26 2001/06/15 03:28:31 steve Exp $"
#endif
# include <stdio.h>
@ -108,6 +108,7 @@ extern void compile_memory(char *label, char *name, int lsb, int msb,
extern void compile_memory_port(char *label, char *memid,
unsigned lsb, unsigned msb,
unsigned naddr,
unsigned argc, struct symb_s *argv);
extern void compile_memory_init(char *memid, unsigned idx, unsigned char val);
@ -190,6 +191,10 @@ extern void compile_net(char*label, char*name,
/*
* $Log: compile.h,v $
* Revision 1.26 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.25 2001/06/07 03:09:03 steve
* Implement .arith/sub subtraction.
*

View File

@ -19,7 +19,7 @@
; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
; This sample demonstrates memory, also including index register
; arithmetic.
; arithmetic. And a memory write port
main .scope "example";
@ -36,12 +36,20 @@ memory .mem "memory", 8,2, 27,5 ;
;;; An address/data port.
;
; reg [4:0] a;
; reg we;
; event wclk;
; reg [5:0] di;
; wire [5:0] d = memory[a][8:3];
; reg [6:0] m;
a .var "a", 4,0;
we .var "we", 0,0;
wclk .event "wclk";
di .var "di", 5,0;
d .net "d", 5,0, mem[0],mem[1],mem[2],mem[3],mem[4],mem[5];
mem .mem/port memory, 6,1, a[0],a[1],a[2],a[3],a[4];
mem .mem/port memory, 6,1,
5, a[0],a[1],a[2],a[3],a[4],
wclk, we, di[0],di[1],di[2],di[3],di[4],di[5];
m .var "m", 6,0;
;;; The data port mem[] does not connect to the LSB of the memory.
@ -76,6 +84,7 @@ m .var "m", 6,0;
; always
; begin
; #5 $display("a:%b d:%b", a, d);
; -> wclk;
; #5 a <= a+1;
; end
@ -85,6 +94,8 @@ always ;
%vpi_call "$display", "a:%b d:%b", a, d;
%set wclk, 0;
%delay 5;
%load 10, a[0];
@ -109,8 +120,18 @@ always ;
;
; initial
; begin
; we = 0;
; di = 'b 10zx10;
; a = 0;
; #320;
; #220;
; $readmemh("memory.hex", memory);
; #30;
; we = 1;
; #5;
; $display("write to a=%b", a);
; #5;
; we = 0;
; #60;
; memory[23] <= 'b 1xz01;
; #320;
; m = memory[9];
@ -121,6 +142,13 @@ always ;
.scope main;
initial ;
%set we, 0;
%set di[0], 0;
%set di[1], 1;
%set di[2], 2;
%set di[3], 3;
%set di[4], 0;
%set di[5], 1;
%set a[0], 0;
%set a[1], 0;
%set a[2], 0;
@ -129,7 +157,13 @@ initial ;
%delay 220;
%vpi_call "$readmemh", "memory.hex", memory;
%delay 100;
%delay 30;
%set we, 1;
%delay 5;
%vpi_call "$display", "write to a=%b", a;
%delay 5;
%set we, 0;
%delay 60;
;;; Memories are indexed by index register 3. The index register
;;; points to the bit position in the memory. Each memory word

View File

@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: memory.cc,v 1.3 2001/05/08 23:59:33 steve Exp $"
#ident "$Id: memory.cc,v 1.4 2001/06/15 03:28:31 steve Exp $"
#endif
#include "memory.h"
@ -37,7 +37,6 @@ struct vvp_memory_s
// 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
@ -55,18 +54,12 @@ 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
@ -76,11 +69,16 @@ struct vvp_memory_port_s : public vvp_fobj_s
vvp_memory_t mem;
vvp_ipoint_t ix;
unsigned naddr;
vvp_memory_port_t next;
int cur_addr;
vvp_memory_bits_t cur_bits;
int bitoff;
int nbits;
unsigned bitoff;
unsigned nbits;
bool writable;
};
@ -142,7 +140,6 @@ void memory_new(vvp_memory_t mem, char *name, int msb, int lsb,
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;
@ -156,19 +153,6 @@ void memory_new(vvp_memory_t mem, char *name, int msb, int lsb,
x->size = lsw - msw + 1;
x->first = msw;
}
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;
}
@ -182,19 +166,25 @@ void memory_new(vvp_memory_t mem, char *name, int msb, int lsb,
void memory_port_new(vvp_memory_t mem, vvp_ipoint_t ix,
unsigned nbits, unsigned bitoff)
unsigned nbits, unsigned bitoff,
unsigned naddr, bool writable)
{
vvp_memory_port_t a = new struct vvp_memory_port_s;
a->mem = mem;
a->ix = ix;
a->naddr = naddr;
a->writable = writable;
a->nbits = nbits;
a->bitoff = bitoff;
a->next = mem->addr_root;
a->mem->addr_root = a;
unsigned nfun = (a->mem->awidth+3)/4;
unsigned nfun = naddr;
if (writable)
nfun += 2 + nbits;
nfun = (nfun+3)/4;
if (nfun < nbits)
nfun = nbits;
@ -225,25 +215,14 @@ void memory_init_nibble(vvp_memory_t mem, unsigned idx, unsigned char val)
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);
assert(mem->a_idxs==1);
unsigned waddr = addr - mem->a_idx[0].first;
if (waddr >= mem->size)
return 0x0;
return mem->bits + waddr*mem->fwidth;
}
@ -294,7 +273,7 @@ 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);
assert(abit >= 0 && abit < addr->naddr);
int old = addr->cur_addr;
@ -319,7 +298,7 @@ static
void update_addr(vvp_memory_port_t addr)
{
addr->cur_addr = 2;
for (unsigned i=0; i < addr->mem->awidth; i++)
for (unsigned i=0; i < addr->naddr; i++)
{
update_addr_bit(addr, addr->ix+i);
if (addr->cur_addr == VVP_MEMORY_NO_ADDR)
@ -332,7 +311,7 @@ void update_data(vvp_memory_port_t data,
vvp_memory_bits_t bits)
{
assert(data);
for (int i=0; i < data->nbits; i++)
for (unsigned i=0; i < data->nbits; i++)
{
vvp_ipoint_t dx = ipoint_index(data->ix, i);
functor_t df = functor_index(dx);
@ -345,17 +324,6 @@ void update_data(vvp_memory_port_t data,
}
}
void vvp_memory_port_s::set(vvp_ipoint_t i, functor_t f, bool push)
{
if (update_addr_bit(this, i))
update_data(this, cur_bits);
}
unsigned vvp_memory_port_s::get(vvp_ipoint_t i, functor_t f)
{
assert(0);
}
static
void update_data_ports(vvp_memory_t mem, int addr, int bit,
unsigned char val)
@ -365,11 +333,10 @@ void update_data_ports(vvp_memory_t mem, int addr, int bit,
{
if (addr == a->cur_addr)
{
vvp_memory_port_t d = a; // historic
int i = bit - d->bitoff;
if (i >= 0 && i < d->nbits)
unsigned i = bit - a->bitoff;
if (i < a->nbits)
{
vvp_ipoint_t ix = ipoint_index(d->ix, i);
vvp_ipoint_t ix = ipoint_index(a->ix, i);
functor_t df = functor_index(ix);
if (df->oval != val)
{
@ -382,6 +349,55 @@ void update_data_ports(vvp_memory_t mem, int addr, int bit,
}
}
static inline
void write_event(vvp_memory_port_t p)
{
unsigned we = functor_get_input(p->ix + p->naddr + 1);
if (!we)
return;
for (unsigned i=0; i < p->nbits; i++)
{
unsigned val = functor_get_input(p->ix + p->naddr + 2 + i);
if (set_bit(p->cur_bits, i + p->bitoff, val))
{
// if a write would change the memory bit, but <we> is
// undefined (x or z), set the bit to x.
if (we > 1)
{
set_bit(p->cur_bits, i + p->bitoff, 2);
val = 2;
}
update_data_ports(p->mem, p->cur_addr, i + p->bitoff, val);
}
}
}
void vvp_memory_port_s::set(vvp_ipoint_t i, functor_t f, bool push)
{
if (i < ix+naddr)
{
if (update_addr_bit(this, i))
update_data(this, cur_bits);
}
// An event at ix+naddr always sets the value 0, and triggeres a write.
// If the write event port is 3, then it's not connected, and the
// write port is transparent, controlled by ix+naddr+1, the write enable.
if (i == ix+naddr
|| (writable && functor_get_input(ix+naddr) == 3))
{
assert(writable);
write_event(this);
}
}
unsigned vvp_memory_port_s::get(vvp_ipoint_t i, functor_t f)
{
assert(0);
}
// %set/mem

View File

@ -20,7 +20,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: memory.h,v 1.2 2001/05/08 23:59:33 steve Exp $"
#ident "$Id: memory.h,v 1.3 2001/06/15 03:28:31 steve Exp $"
#endif
#include "pointers.h"
@ -38,7 +38,9 @@ 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);
unsigned nbits, unsigned bitoff,
unsigned naddr, bool writable);
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);
@ -46,7 +48,6 @@ 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_size(vvp_memory_t mem);
char *memory_name(vvp_memory_t mem);
unsigned memory_data_width(vvp_memory_t mem);
@ -60,6 +61,10 @@ vvp_memory_t memory_create(char *label);
/*
* $Log: memory.h,v $
* 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)

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.29 2001/06/07 03:09:03 steve Exp $"
#ident "$Id: parse.y,v 1.30 2001/06/15 03:28:31 steve Exp $"
#endif
# include "parse_misc.h"
@ -139,8 +139,8 @@ statement
| 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); }
| T_LABEL K_MEM_P T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER ',' symbols ';'
{ compile_memory_port($1, $3, $5, $7, $9, $11.cnt, $11.vect); }
| mem_init_stmt
@ -458,6 +458,10 @@ int compile_design(const char*path)
/*
* $Log: parse.y,v $
* Revision 1.30 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.29 2001/06/07 03:09:03 steve
* Implement .arith/sub subtraction.
*