reimplement memory ports.
This commit is contained in:
parent
72240c460e
commit
789c95b1c1
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: README.txt,v 1.58 2005/03/03 04:33:10 steve Exp $
|
||||
* $Id: README.txt,v 1.59 2005/03/09 04:52:40 steve Exp $
|
||||
*/
|
||||
|
||||
VVP SIMULATION ENGINE
|
||||
|
|
@ -306,42 +306,36 @@ 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 words.
|
||||
of words, with the base address==0, and the last address the size (in
|
||||
words) of the memory -1. It is up to the compiler to convert Verilog
|
||||
index sets to a cannonical address. The multi-dimensional index set is
|
||||
available for VPI use.
|
||||
|
||||
Structural read access is implemented in terms of address and data
|
||||
ports. The addresses applied to the address port are expected to be
|
||||
within the ranges specified, not based at zero.
|
||||
in cannonical form.
|
||||
|
||||
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.
|
||||
A read port is a functor that takes a single input, the read address,
|
||||
and outputs the word value at the given (cannonical) address.
|
||||
|
||||
<label> .mem/port <memid>, <msb>,<lsb>, <aw>, <addr_bits> ;
|
||||
<label> .mem/port <memid>, <address> ;
|
||||
|
||||
<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 is here
|
||||
referred to as 0, regardless to the range specified in the memory
|
||||
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).
|
||||
to the data output. <memid> is the label of the memory.
|
||||
|
||||
Any address change, or any change in the addressed memory contents is
|
||||
immediately propagated to the port outputs.
|
||||
Any address inputchange, or any change in the addressed memory
|
||||
contents, is immediately propagated to the port output.
|
||||
|
||||
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.
|
||||
A write port is a superset of a read port. It is a 4-input functor
|
||||
that accepts the word address, an event input, a write enable input,
|
||||
and the data input.
|
||||
|
||||
<label> .mem/port <memid>, <msb>,<lsb>, <aw>, <addr_bits>,
|
||||
<event>, <we>, <data> ;
|
||||
<label> .mem/port <memid>, <address>, <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
|
||||
is true. <data> is the input 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
|
||||
<event> to C4<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
|
||||
|
|
|
|||
|
|
@ -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.189 2005/03/03 04:33:10 steve Exp $"
|
||||
#ident "$Id: compile.cc,v 1.190 2005/03/09 04:52:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "arith.h"
|
||||
|
|
@ -1273,33 +1273,21 @@ 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)
|
||||
{
|
||||
#if 0
|
||||
vvp_memory_t mem = memory_find(memid);
|
||||
free(memid);
|
||||
assert(mem);
|
||||
vvp_memory_t mem = memory_find(memid);
|
||||
free(memid);
|
||||
assert(mem);
|
||||
|
||||
// This is not a Verilog bit range.
|
||||
// This is a data port bit range.
|
||||
assert (lsb >= 0 && lsb<=msb);
|
||||
assert (msb < memory_data_width(mem));
|
||||
unsigned nbits = msb-lsb+1;
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_memport*fun = new vvp_fun_memport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
bool writable = argc >= (naddr + 2 + nbits);
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
vvp_ipoint_t ix = memory_port_new(mem, nbits, lsb, naddr, writable);
|
||||
|
||||
define_functor_symbol(label, ix);
|
||||
free(label);
|
||||
|
||||
inputs_connect(ix, argc, argv);
|
||||
free(argv);
|
||||
#else
|
||||
fprintf(stderr, "XXXX compile_memory_port not implemented.\n");
|
||||
#endif
|
||||
inputs_connect(ptr, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1657,6 +1645,9 @@ void compile_param_string(char*label, char*name, char*str, char*value)
|
|||
|
||||
/*
|
||||
* $Log: compile.cc,v $
|
||||
* Revision 1.190 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.189 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.63 2005/03/03 04:33:10 steve Exp $"
|
||||
#ident "$Id: compile.h,v 1.64 2005/03/09 04:52:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
|
@ -200,8 +200,6 @@ 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 naddr,
|
||||
unsigned argc, struct symb_s *argv);
|
||||
|
||||
extern void compile_memory_init(char *memid, unsigned idx, long val);
|
||||
|
|
@ -297,6 +295,9 @@ extern void compile_net(char*label, char*name,
|
|||
|
||||
/*
|
||||
* $Log: compile.h,v $
|
||||
* Revision 1.64 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.63 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
|
|
|
|||
373
vvp/memory.cc
373
vvp/memory.cc
|
|
@ -19,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.25 2005/03/06 17:07:48 steve Exp $"
|
||||
#ident "$Id: memory.cc,v 1.26 2005/03/09 04:52:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
|
|
@ -51,31 +51,11 @@ struct vvp_memory_s
|
|||
vvp_vector4_t*words;
|
||||
|
||||
// List of ports into this memory.
|
||||
vvp_memory_port_t port_list;
|
||||
class vvp_fun_memport* port_list;
|
||||
};
|
||||
|
||||
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
|
||||
|
||||
#if 0
|
||||
struct vvp_memory_port_s : public functor_s
|
||||
{
|
||||
void set(vvp_ipoint_t i, bool push, unsigned val, unsigned str);
|
||||
|
||||
vvp_memory_t mem;
|
||||
vvp_ipoint_t ix;
|
||||
|
||||
unsigned naddr;
|
||||
|
||||
vvp_memory_port_t next;
|
||||
int cur_addr;
|
||||
vvp_memory_bits_t cur_bits;
|
||||
unsigned bitoff;
|
||||
unsigned nbits;
|
||||
|
||||
bool writable;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Compilation
|
||||
|
||||
static symbol_table_t memory_table = 0;
|
||||
|
|
@ -209,51 +189,11 @@ 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)
|
||||
{
|
||||
unsigned nfun = naddr;
|
||||
if (writable)
|
||||
nfun += 2 + nbits;
|
||||
nfun = (nfun+3)/4;
|
||||
if (nfun < nbits)
|
||||
nfun = nbits;
|
||||
|
||||
vvp_memory_port_t a = new struct vvp_memory_port_s;
|
||||
|
||||
a->mem = mem;
|
||||
a->naddr = naddr;
|
||||
a->writable = writable;
|
||||
a->nbits = nbits;
|
||||
a->bitoff = bitoff;
|
||||
a->next = mem->addr_root;
|
||||
mem->addr_root = a;
|
||||
|
||||
a->ix = functor_allocate(nfun);
|
||||
functor_define(a->ix, a);
|
||||
|
||||
if (nfun > 1)
|
||||
{
|
||||
extra_ports_functor_s *fu = new extra_ports_functor_s[nfun-1];
|
||||
for (unsigned i = 0; i< nfun - 1; i++) {
|
||||
fu[i].base_ = a->ix;
|
||||
functor_define(ipoint_index(a->ix, i+1), fu+i);
|
||||
for (vvp_fun_memport*cur = mem->port_list
|
||||
; cur ; cur = cur->next_) {
|
||||
cur->check_word_change(addr);
|
||||
}
|
||||
}
|
||||
|
||||
a->cur_addr = VVP_MEMORY_NO_ADDR;
|
||||
a->cur_bits = 0x0;
|
||||
|
||||
return a->ix;
|
||||
}
|
||||
#endif
|
||||
|
||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
||||
vvp_vector4_t val, unsigned long delay)
|
||||
|
|
@ -261,279 +201,58 @@ void schedule_memory(vvp_memory_t mem, unsigned addr,
|
|||
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)
|
||||
vvp_fun_memport::vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net)
|
||||
: mem_(mem), net_(net)
|
||||
{
|
||||
return mem->bits + idx*mem->fwidth;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
inline static
|
||||
vvp_memory_bits_t get_word(vvp_memory_t mem, int addr)
|
||||
{
|
||||
assert(mem->a_idxs==1);
|
||||
unsigned waddr = addr - mem->a_idx[0].first;
|
||||
|
||||
if (waddr >= mem->size)
|
||||
return 0x0;
|
||||
|
||||
return get_word_ix(mem, waddr);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
inline static
|
||||
unsigned char get_nibble(vvp_memory_bits_t bits, int bit)
|
||||
{
|
||||
if (!bits)
|
||||
return 0xaa;
|
||||
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)
|
||||
{
|
||||
functor_t fp = functor_index(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)
|
||||
{
|
||||
unsigned abit = ip - addr->ix;
|
||||
|
||||
assert(abit >= 0 && abit < addr->naddr);
|
||||
|
||||
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);
|
||||
|
||||
addr->cur_bits = get_word(addr->mem, addr->cur_addr);
|
||||
|
||||
return addr->cur_addr != old;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static
|
||||
void update_addr(vvp_memory_port_t addr)
|
||||
{
|
||||
addr->cur_addr = 0;
|
||||
for (unsigned i=0; i < addr->naddr; i++)
|
||||
{
|
||||
update_addr_bit(addr, addr->ix+i);
|
||||
if (addr->cur_addr == VVP_MEMORY_NO_ADDR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
inline static
|
||||
void update_data(vvp_memory_port_t data)
|
||||
{
|
||||
assert(data);
|
||||
for (unsigned 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(data->cur_bits, i + data->bitoff);
|
||||
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)
|
||||
{
|
||||
if (!bits)
|
||||
return;
|
||||
|
||||
vvp_memory_port_t a = mem->addr_root;
|
||||
while (a)
|
||||
{
|
||||
if (bits == a->cur_bits)
|
||||
{
|
||||
unsigned i = bit - a->bitoff;
|
||||
if (i < a->nbits)
|
||||
{
|
||||
vvp_ipoint_t ix = ipoint_index(a->ix, i);
|
||||
functor_t df = functor_index(ix);
|
||||
df->put_oval(val, true);
|
||||
}
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static inline
|
||||
void write_event(vvp_memory_port_t p)
|
||||
{
|
||||
if (!p->cur_bits)
|
||||
return;
|
||||
|
||||
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_bits, i + p->bitoff, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void vvp_memory_port_s::set(vvp_ipoint_t i, bool, unsigned val, unsigned)
|
||||
{
|
||||
// !attention! "i" may not correspond to "this"
|
||||
functor_t ifu = functor_index(i);
|
||||
ifu->put(i, val);
|
||||
|
||||
if (i < ix+naddr)
|
||||
{
|
||||
if (update_addr_bit(this, i))
|
||||
update_data(this);
|
||||
}
|
||||
|
||||
// port ix+naddr is the write clock. If its input value is
|
||||
// undefined, we do asynchronous write. Else any event on ix+naddr
|
||||
// is a valid write clock edge. Connect an appropriate edge event
|
||||
// functor.
|
||||
|
||||
if (i == ix+naddr
|
||||
|| (writable && functor_get_input(ix+naddr) == 3))
|
||||
{
|
||||
assert(writable);
|
||||
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))
|
||||
return;
|
||||
|
||||
if (!set_bit(mem->bits, idx, val))
|
||||
return;
|
||||
|
||||
unsigned widx = idx/(4*mem->fwidth);
|
||||
unsigned bidx = idx%(4*mem->fwidth);
|
||||
|
||||
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))
|
||||
return 2;
|
||||
|
||||
return get_bit(mem->bits, idx);
|
||||
}
|
||||
#endif
|
||||
// %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;
|
||||
addr_ = 0;
|
||||
next_ = mem_->port_list;
|
||||
mem_->port_list = this;
|
||||
}
|
||||
|
||||
inline static void ma_free(struct mem_assign_s* cur)
|
||||
vvp_fun_memport::~vvp_fun_memport()
|
||||
{
|
||||
cur->next = ma_free_list;
|
||||
ma_free_list = cur;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void run_mem_assign(vvp_gen_event_t obj, unsigned char val)
|
||||
void vvp_fun_memport::recv_vec4(vvp_net_ptr_t port, vvp_vector4_t bit)
|
||||
{
|
||||
struct mem_assign_s *e = (struct mem_assign_s *) obj;
|
||||
memory_set(e->mem, e->idx, val);
|
||||
ma_free(e);
|
||||
bool addr_valid_flag;
|
||||
|
||||
switch (port.port()) {
|
||||
|
||||
case 0: // Address input
|
||||
addr_valid_flag = vector4_to_value(bit, addr_);
|
||||
if (! addr_valid_flag)
|
||||
addr_ = memory_word_count(mem_);
|
||||
bit = memory_get_word(mem_, addr_);
|
||||
vvp_send_vec4(port.ptr()->out, bit);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stdout, "XXXX write ports not implemented.\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function is called by the memory itself to tell this port that
|
||||
* the given address had a content change. The device itself figures
|
||||
* out what to do with that information.
|
||||
*/
|
||||
void vvp_fun_memport::check_word_change(unsigned long addr)
|
||||
{
|
||||
if (addr != addr_)
|
||||
return;
|
||||
|
||||
vvp_vector4_t bit = memory_get_word(mem_, addr_);
|
||||
vvp_send_vec4(net_->out, bit);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: memory.cc,v $
|
||||
* Revision 1.26 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.25 2005/03/06 17:07:48 steve
|
||||
* Non blocking assign to memory words.
|
||||
*
|
||||
|
|
|
|||
52
vvp/memory.h
52
vvp/memory.h
|
|
@ -20,7 +20,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: memory.h,v 1.8 2005/03/03 04:33:10 steve Exp $"
|
||||
#ident "$Id: memory.h,v 1.9 2005/03/09 04:52:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "vvp_net.h"
|
||||
|
|
@ -84,12 +84,6 @@ void schedule_memory(vvp_memory_t mem, unsigned addr,
|
|||
*/
|
||||
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
|
||||
|
||||
|
||||
/* Number of words in the memory. */
|
||||
unsigned memory_word_count(vvp_memory_t mem);
|
||||
|
|
@ -103,6 +97,47 @@ long memory_right_range(vvp_memory_t mem, unsigned ix);
|
|||
long memory_word_left_range(vvp_memory_t mem);
|
||||
long memory_word_right_range(vvp_memory_t mem);
|
||||
|
||||
/* vvp_fun_memport
|
||||
* The vvp_fum_memport is a structural port into a vvp_memory_t
|
||||
* object. The output is the word that is read from the addressed
|
||||
* memory, and the inputs are the address and optional write controls.
|
||||
*
|
||||
* 0 -- Address
|
||||
* This addresses the word in the memory. The output follows this
|
||||
* address as it changes, and also follows the value of the addressed
|
||||
* word.
|
||||
*
|
||||
* 1 -- Write event
|
||||
*
|
||||
* 2 -- Write enable
|
||||
*
|
||||
* 3 -- Write data
|
||||
*
|
||||
* NOTE: This functor is unique in that it needs to store the
|
||||
* vvp_net_t pointer associated with it. It needs this because it can
|
||||
* received input from other then its ports. Notably, the memory
|
||||
* itself reports word changes.
|
||||
*/
|
||||
class vvp_fun_memport : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net);
|
||||
~vvp_fun_memport();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, vvp_vector4_t bit);
|
||||
|
||||
private:
|
||||
vvp_memory_t mem_;
|
||||
|
||||
friend void memory_set_word(vvp_memory_t, unsigned, vvp_vector4_t);
|
||||
void check_word_change(unsigned long address);
|
||||
class vvp_fun_memport*next_;
|
||||
|
||||
unsigned long addr_;
|
||||
|
||||
vvp_net_t*net_;
|
||||
};
|
||||
|
||||
/*
|
||||
** Access to the memory symbol table.
|
||||
**
|
||||
|
|
@ -117,6 +152,9 @@ vvp_memory_t memory_create(char *label);
|
|||
|
||||
/*
|
||||
* $Log: memory.h,v $
|
||||
* Revision 1.9 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.8 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.67 2005/03/03 04:33:10 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.68 2005/03/09 04:52:40 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -159,8 +159,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 ',' T_NUMBER ',' symbols ';'
|
||||
{ compile_memory_port($1, $3, $5, $7, $9, $11.cnt, $11.vect); }
|
||||
| T_LABEL K_MEM_P T_SYMBOL ',' symbols ';'
|
||||
{ compile_memory_port($1, $3, $5.cnt, $5.vect); }
|
||||
|
||||
| mem_init_stmt
|
||||
|
||||
|
|
@ -673,6 +673,9 @@ int compile_design(const char*path)
|
|||
|
||||
/*
|
||||
* $Log: parse.y,v $
|
||||
* Revision 1.68 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.67 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue