Remove last vestiges of the the .mem structures.
Before the .array support, we had .mem nodes. These are long since removed because the arrays to all the jobs of the .mem nodes.
This commit is contained in:
parent
2dcb1514a2
commit
007056d671
|
|
@ -70,14 +70,14 @@ check: all
|
|||
|
||||
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
||||
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
|
||||
vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
||||
|
||||
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
||||
concat.o \
|
||||
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
||||
ufunc.o codes.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
|
||||
event.o logic.o delay.o words.o $V
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ extern bool of_JOIN(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVX_P(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_VP0(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -127,7 +126,6 @@ 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_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_AV(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);
|
||||
|
|
@ -162,7 +160,6 @@ struct vvp_code_s {
|
|||
unsigned long number;
|
||||
vvp_net_t *net;
|
||||
vvp_code_t cptr;
|
||||
vvp_memory_t mem;
|
||||
vvp_array_t array;
|
||||
struct __vpiHandle*handle;
|
||||
struct __vpiScope*scope;
|
||||
|
|
|
|||
131
vvp/compile.cc
131
vvp/compile.cc
|
|
@ -22,7 +22,6 @@
|
|||
# include "logic.h"
|
||||
# include "resolv.h"
|
||||
# include "udp.h"
|
||||
# include "memory.h"
|
||||
# include "symbols.h"
|
||||
# include "codes.h"
|
||||
# include "schedule.h"
|
||||
|
|
@ -67,8 +66,6 @@ enum operand_e {
|
|||
OA_FUNC_PTR,
|
||||
/* The operand is a second functor pointer */
|
||||
OA_FUNC_PTR2,
|
||||
/* The operand is a pointer to a memory */
|
||||
OA_MEM_PTR,
|
||||
/* The operand is a VPI handle */
|
||||
OA_VPI_PTR,
|
||||
};
|
||||
|
|
@ -90,7 +87,6 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_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/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
|
|
@ -144,7 +140,6 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%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/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
|
|
@ -174,7 +169,6 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%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, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
|
|
@ -551,38 +545,6 @@ void code_label_lookup(struct vvp_code_s *code, char *label)
|
|||
resolv_submit(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup memories.
|
||||
*/
|
||||
struct memory_resolv_list_s: public resolv_list_s {
|
||||
memory_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool memory_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->mem = memory_find(label());
|
||||
if (code->mem != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Memory unresolved: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void compile_mem_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct memory_resolv_list_s *res
|
||||
= new struct memory_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
struct code_array_resolv_list_s: public resolv_list_s {
|
||||
code_array_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
|
|
@ -1504,90 +1466,6 @@ char **compile_udp_table(char **table, char *row)
|
|||
return table;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 narg, long *args)
|
||||
{
|
||||
/* Create an empty memory in the symbol table. */
|
||||
vvp_memory_t mem = memory_create(label);
|
||||
|
||||
assert( narg > 0 && narg%2 == 0 );
|
||||
|
||||
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,
|
||||
unsigned argc, struct symb_s *argv)
|
||||
{
|
||||
vvp_memory_t mem = memory_find(memid);
|
||||
free(memid);
|
||||
assert(mem);
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_memport*fun = new vvp_fun_memport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
inputs_connect(ptr, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser uses this function to compile and link an executable
|
||||
|
|
@ -1703,15 +1581,6 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
|
|||
code->number = opa->argv[idx].numb;
|
||||
break;
|
||||
|
||||
case OA_MEM_PTR:
|
||||
if (opa->argv[idx].ltype != L_SYMB) {
|
||||
yyerror("operand format");
|
||||
break;
|
||||
}
|
||||
|
||||
compile_mem_lookup(code, opa->argv[idx].symb.text);
|
||||
break;
|
||||
|
||||
case OA_VPI_PTR:
|
||||
/* The operand is a functor. Resolve the label to
|
||||
a functor pointer, or postpone the resolution
|
||||
|
|
|
|||
|
|
@ -335,14 +335,6 @@ extern void compile_array_port(char*label, char*name, char*addr);
|
|||
/* Index is a constant address */
|
||||
extern void compile_array_port(char*label, char*name, long addr);
|
||||
|
||||
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 argc, struct symb_s *argv);
|
||||
|
||||
extern void compile_memory_init(char *memid, unsigned idx, long val);
|
||||
|
||||
/*
|
||||
* Compile the .ufunc statement.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -161,9 +161,6 @@
|
|||
".udp" { return K_UDP; }
|
||||
".udp/c"(omb)? { return K_UDP_C; }
|
||||
".udp/s"(equ)? { return K_UDP_S; }
|
||||
".mem" { return K_MEM; }
|
||||
".mem/p"(ort)? { return K_MEM_P; }
|
||||
".mem/i"(nit)? { return K_MEM_I; }
|
||||
"-debug" { return K_DEBUG; }
|
||||
|
||||
/* instructions start with a % character. The compiler decides what
|
||||
|
|
|
|||
299
vvp/memory.cc
299
vvp/memory.cc
|
|
@ -1,299 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
*
|
||||
* 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.cc,v 1.29 2006/03/05 05:45:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "symbols.h"
|
||||
#include "schedule.h"
|
||||
#include "vpi_priv.h"
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef struct vvp_memory_port_s *vvp_memory_port_t;
|
||||
|
||||
struct vvp_memory_s
|
||||
{
|
||||
// Address ranges (1 or more)
|
||||
unsigned nrange;
|
||||
struct memory_address_range*ranges;
|
||||
|
||||
// Data port properties:
|
||||
unsigned width; // number of data bits
|
||||
|
||||
int msb, lsb; // Most/Least Significant data bit (VPI)
|
||||
|
||||
// Array of words.
|
||||
unsigned word_count;
|
||||
vvp_vector4_t*words;
|
||||
|
||||
// List of ports into this memory.
|
||||
class vvp_fun_memport* port_list;
|
||||
vpiHandle vpi_self;
|
||||
};
|
||||
|
||||
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
|
||||
|
||||
// Compilation
|
||||
|
||||
static symbol_table_t memory_table = 0;
|
||||
|
||||
vvp_memory_t memory_find(const char *label)
|
||||
{
|
||||
if (memory_table == 0)
|
||||
return 0;
|
||||
|
||||
symbol_value_t v = sym_get_value(memory_table, label);
|
||||
return (vvp_memory_t)v.ptr;
|
||||
}
|
||||
|
||||
vvp_memory_t memory_create(char *label)
|
||||
{
|
||||
if (!memory_table)
|
||||
memory_table = new_symbol_table();
|
||||
|
||||
assert(!memory_find(label));
|
||||
|
||||
vvp_memory_t mem = new struct vvp_memory_s;
|
||||
|
||||
symbol_value_t v;
|
||||
v.ptr = mem;
|
||||
sym_set_value(memory_table, label, v);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void memory_configure(vvp_memory_t mem,
|
||||
int msb, int lsb,
|
||||
unsigned nrange,
|
||||
const struct memory_address_range*ranges)
|
||||
{
|
||||
/* Get the word width details. */
|
||||
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
|
||||
mem->msb = msb;
|
||||
mem->lsb = lsb;
|
||||
|
||||
/* 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];
|
||||
|
||||
/* 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;
|
||||
|
||||
unsigned count = rp->msb > rp->lsb
|
||||
? rp->msb - rp->lsb + 1
|
||||
: rp->lsb - rp->msb + 1;
|
||||
|
||||
mem->word_count *= count;
|
||||
}
|
||||
|
||||
mem->words = new vvp_vector4_t [mem->word_count];
|
||||
assert(mem->words);
|
||||
|
||||
mem->port_list = 0;
|
||||
mem->vpi_self = 0;
|
||||
}
|
||||
|
||||
void memory_attach_self(vvp_memory_t mem, vpiHandle self)
|
||||
{
|
||||
assert(mem->vpi_self == 0);
|
||||
mem->vpi_self = self;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* If the address is out of range, then return a vector of all
|
||||
X bits. */
|
||||
if (addr >= mem->word_count) {
|
||||
vvp_vector4_t val (mem->width);
|
||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
||||
val.set_bit(idx, BIT4_X);
|
||||
return val;
|
||||
}
|
||||
|
||||
assert(addr <= mem->word_count);
|
||||
|
||||
if (mem->words[addr].size() == 0) {
|
||||
vvp_vector4_t tmp (mem->width);
|
||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
||||
tmp.set_bit(idx, BIT4_X);
|
||||
mem->words[addr] = tmp;
|
||||
}
|
||||
|
||||
return mem->words[addr];
|
||||
}
|
||||
|
||||
void memory_init_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
|
||||
{
|
||||
if (addr >= mem->word_count)
|
||||
return;
|
||||
|
||||
assert(val.size() == mem->width);
|
||||
mem->words[addr] = val;
|
||||
}
|
||||
|
||||
void memory_set_word(vvp_memory_t mem, unsigned addr,
|
||||
unsigned off, vvp_vector4_t val)
|
||||
{
|
||||
if (addr >= mem->word_count)
|
||||
return;
|
||||
|
||||
if (off >= mem->width)
|
||||
return;
|
||||
|
||||
if (off == 0 && val.size() == mem->width) {
|
||||
mem->words[addr] = val;
|
||||
|
||||
} else {
|
||||
if ((off + val.size()) > mem->width)
|
||||
val = val.subvalue(0, mem->width - off);
|
||||
|
||||
mem->words[addr].set_vec(off, val);
|
||||
}
|
||||
|
||||
for (vvp_fun_memport*cur = mem->port_list
|
||||
; cur ; cur = cur->next_) {
|
||||
cur->check_word_change(addr);
|
||||
}
|
||||
|
||||
vpip_run_memory_value_change(mem->vpi_self, addr);
|
||||
}
|
||||
|
||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
||||
vvp_vector4_t val, unsigned long delay)
|
||||
{
|
||||
fprintf(stderr, "XXXX Forgot how to schedule memory write.\n");
|
||||
}
|
||||
|
||||
vvp_fun_memport::vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net)
|
||||
: mem_(mem), net_(net)
|
||||
{
|
||||
addr_ = 0;
|
||||
next_ = mem_->port_list;
|
||||
mem_->port_list = this;
|
||||
}
|
||||
|
||||
vvp_fun_memport::~vvp_fun_memport()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_memport::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
{
|
||||
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_);
|
||||
vvp_send_vec4(port.ptr()->out, memory_get_word(mem_,addr_));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stdout, "XXXX write ports not implemented.\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.29 2006/03/05 05:45:58 steve
|
||||
* Add support for memory value change callbacks.
|
||||
*
|
||||
* Revision 1.28 2006/02/02 02:44:00 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.27 2005/06/22 00:04:49 steve
|
||||
* Reduce vvp_vector4 copies by using const references.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Revision 1.24 2005/03/05 05:44:32 steve
|
||||
* Get read width of unitialized memory words right.
|
||||
*
|
||||
* Revision 1.23 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
*/
|
||||
180
vvp/memory.h
180
vvp/memory.h
|
|
@ -1,180 +0,0 @@
|
|||
#ifndef __memory_H // -*- c++ -*-
|
||||
#define __memory_H
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: memory.h,v 1.13 2007/03/22 16:08:19 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "vvp_net.h"
|
||||
#include "vpi_user.h"
|
||||
|
||||
/*
|
||||
** vvp_memory_t is a memory
|
||||
** vvp_memory_index_t is a memory index range definition
|
||||
*/
|
||||
typedef struct vvp_memory_s *vvp_memory_t;
|
||||
|
||||
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);
|
||||
extern void memory_attach_self(vvp_memory_t mem, vpiHandle self);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
unsigned off,
|
||||
vvp_vector4_t val);
|
||||
|
||||
/*
|
||||
* This doesn't actually write the value to the memory word, but
|
||||
* schedules 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);
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
/* 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 than 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, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
vvp_memory_t mem_;
|
||||
|
||||
friend void memory_set_word(vvp_memory_t, unsigned,
|
||||
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.
|
||||
**
|
||||
** The memory_find function locates the memory device by name. If the
|
||||
** device does not exist, a nil is returned.
|
||||
**
|
||||
** The memory_create function creates 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(const char *label);
|
||||
vvp_memory_t memory_create(char *label);
|
||||
|
||||
/*
|
||||
* $Log: memory.h,v $
|
||||
* Revision 1.13 2007/03/22 16:08:19 steve
|
||||
* Spelling fixes from Larry
|
||||
*
|
||||
* Revision 1.12 2006/03/05 05:45:58 steve
|
||||
* Add support for memory value change callbacks.
|
||||
*
|
||||
* Revision 1.11 2006/02/02 02:44:00 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.10 2005/06/22 00:04:49 steve
|
||||
* Reduce vvp_vector4 copies by using const references.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
22
vvp/parse.y
22
vvp/parse.y
|
|
@ -82,7 +82,6 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
%token K_THREAD K_TIMESCALE K_UFUNC
|
||||
%token K_UDP K_UDP_C K_UDP_S
|
||||
%token K_MEM K_MEM_P K_MEM_I
|
||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
|
||||
%token K_disable K_fork
|
||||
%token K_vpi_module K_vpi_time_precision K_file_names
|
||||
|
|
@ -185,14 +184,6 @@ statement
|
|||
|
||||
/* Memory. Definition, port, initialization */
|
||||
|
||||
| T_LABEL K_MEM T_STRING ',' T_NUMBER ',' T_NUMBER ',' numbers ';'
|
||||
{ compile_memory($1, $3, $5, $7, $9.cnt, $9.nvec); }
|
||||
|
||||
| T_LABEL K_MEM_P T_SYMBOL ',' symbols ';'
|
||||
{ compile_memory_port($1, $3, $5.cnt, $5.vect); }
|
||||
|
||||
| mem_init_stmt
|
||||
|
||||
| T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ',' signed_t_number signed_t_number ';'
|
||||
{ compile_var_array($1, $3, $5, $6, $8, $9, 0); }
|
||||
|
||||
|
|
@ -904,19 +895,6 @@ udp_table
|
|||
{ $$ = compile_udp_table($1, $3); }
|
||||
;
|
||||
|
||||
mem_init_stmt
|
||||
: K_MEM_I symbol T_NUMBER ','
|
||||
{ compile_memory_init($2.text, $3, 0); }
|
||||
mem_init_list ';'
|
||||
;
|
||||
|
||||
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; }
|
||||
| '-' T_NUMBER { $$ = -$2; }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
# include "schedule.h"
|
||||
# include "memory.h"
|
||||
# include "vthread.h"
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
|
|
@ -141,20 +140,6 @@ void assign_real_event_s::run_run(void)
|
|||
vvp_send_real(ptr, val);
|
||||
}
|
||||
|
||||
struct assign_memory_word_s : public event_s {
|
||||
vvp_memory_t mem;
|
||||
unsigned adr;
|
||||
vvp_vector4_t val;
|
||||
unsigned off;
|
||||
void run_run(void);
|
||||
};
|
||||
|
||||
void assign_memory_word_s::run_run(void)
|
||||
{
|
||||
count_assign_events += 1;
|
||||
memory_set_word(mem, adr, off, val);
|
||||
}
|
||||
|
||||
struct assign_array_word_s : public event_s {
|
||||
vvp_array_t mem;
|
||||
unsigned adr;
|
||||
|
|
@ -500,20 +485,6 @@ void schedule_assign_vector(vvp_net_ptr_t ptr,
|
|||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_assign_memory_word(vvp_memory_t mem,
|
||||
unsigned word_addr,
|
||||
unsigned off,
|
||||
vvp_vector4_t val,
|
||||
vvp_time64_t delay)
|
||||
{
|
||||
struct assign_memory_word_s*cur = new struct assign_memory_word_s;
|
||||
cur->mem = mem;
|
||||
cur->adr = word_addr;
|
||||
cur->off = off;
|
||||
cur->val = val;
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_assign_array_word(vvp_array_t mem,
|
||||
unsigned word_addr,
|
||||
unsigned off,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
# include "vthread.h"
|
||||
# include "pointers.h"
|
||||
# include "vvp_net.h"
|
||||
# include "memory.h"
|
||||
# include "array.h"
|
||||
|
||||
/*
|
||||
|
|
@ -57,11 +56,6 @@ extern void schedule_assign_array_word(vvp_array_t mem,
|
|||
unsigned off,
|
||||
vvp_vector4_t val,
|
||||
vvp_time64_t delay);
|
||||
extern void schedule_assign_memory_word(vvp_memory_t mem,
|
||||
unsigned word_address,
|
||||
unsigned off,
|
||||
vvp_vector4_t val,
|
||||
vvp_time64_t delay);
|
||||
/*
|
||||
* This is very similar to schedule_assign_vector, but generates an
|
||||
* event in the active queue. It is used at link time to assign a
|
||||
|
|
|
|||
|
|
@ -162,10 +162,6 @@ static struct __vpiCallback* make_value_change(p_cb_data data)
|
|||
nev->callbacks = obj;
|
||||
break;
|
||||
|
||||
case vpiMemory:
|
||||
vpip_memory_value_change(obj, data->obj);
|
||||
break;
|
||||
|
||||
case vpiModule:
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
|
|
|
|||
|
|
@ -1,449 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com>
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "compile.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "memory.h"
|
||||
# include "statistics.h"
|
||||
# include <iostream>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
extern const char hex_digits[256];
|
||||
|
||||
static void memory_make_word_handles(struct __vpiMemory*rfp);
|
||||
|
||||
struct __vpiMemoryWord {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiMemory*mem;
|
||||
struct __vpiDecConst index;
|
||||
};
|
||||
|
||||
struct __vpiMemory {
|
||||
struct __vpiHandle base;
|
||||
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;
|
||||
struct __vpiDecConst word_right_range;
|
||||
|
||||
struct __vpiCallback*value_change_cb;
|
||||
};
|
||||
|
||||
struct __vpiMemWordIterator {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiMemory*mem;
|
||||
unsigned next;
|
||||
};
|
||||
|
||||
static vpiHandle memory_get_handle(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)obj;
|
||||
|
||||
assert(obj->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch(code){
|
||||
case vpiLeftRange:
|
||||
return &(rfp->left_range.base);
|
||||
|
||||
case vpiRightRange:
|
||||
return &(rfp->right_range.base);
|
||||
|
||||
case vpiScope:
|
||||
return &rfp->scope->base;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpi_memory_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return (int)memory_word_count(rfp->mem);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* memory_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
return generic_get_str(code, &rfp->scope->base, rfp->name, NULL);
|
||||
}
|
||||
|
||||
static vpiHandle memory_scan(vpiHandle ref, int)
|
||||
{
|
||||
struct __vpiMemWordIterator*obj = (struct __vpiMemWordIterator*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiIterator);
|
||||
|
||||
if (obj->next >= memory_word_count(obj->mem->mem)) {
|
||||
vpi_free_object(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &obj->mem->words[obj->next++].base;
|
||||
}
|
||||
|
||||
static int mem_iter_free_object(vpiHandle ref)
|
||||
{
|
||||
free(ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_mem_iter_rt = {
|
||||
vpiIterator,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
memory_scan,
|
||||
&mem_iter_free_object
|
||||
};
|
||||
|
||||
|
||||
static vpiHandle memory_iterate(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
case vpiMemoryWord: {
|
||||
memory_make_word_handles(rfp);
|
||||
|
||||
struct __vpiMemWordIterator*res =
|
||||
(struct __vpiMemWordIterator*)
|
||||
calloc(1, sizeof(struct __vpiMemWordIterator));
|
||||
assert(res);
|
||||
res->base.vpi_type = &vpip_mem_iter_rt;
|
||||
res->mem = rfp;
|
||||
res->next = 0;
|
||||
return &(res->base);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle memory_index(vpiHandle ref, int index)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//==============================
|
||||
|
||||
static vpiHandle memory_word_get_handle(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)obj;
|
||||
assert(obj->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
switch(code){
|
||||
case vpiLeftRange:
|
||||
return &(rfp->mem->word_left_range.base);
|
||||
|
||||
case vpiRightRange:
|
||||
return &(rfp->mem->word_right_range.base);
|
||||
|
||||
case vpiIndex:
|
||||
return &(rfp->index.base);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_word_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return memory_word_width(rfp->mem->mem);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val, int)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
|
||||
/* Get the width of the memory, and the byte index of the
|
||||
first byte of the word. */
|
||||
unsigned width = memory_word_width(rfp->mem->mem);
|
||||
unsigned word_addr = rfp->index.value;
|
||||
|
||||
/* Addresses are converted to canonical form by offsetting the
|
||||
address by the lowest index. */
|
||||
long addr_off = memory_left_range(rfp->mem->mem, 0);
|
||||
if (memory_right_range(rfp->mem->mem, 0) < addr_off)
|
||||
addr_off = memory_right_range(rfp->mem->mem, 0);
|
||||
|
||||
assert(addr_off >= 0 && (unsigned) addr_off <= word_addr);
|
||||
word_addr -= addr_off;
|
||||
|
||||
/* Build up the word value from whatever format the user
|
||||
supplies. */
|
||||
vvp_vector4_t put_val (width);
|
||||
|
||||
switch (val->format) {
|
||||
case vpiVectorVal:
|
||||
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;
|
||||
|
||||
case vpiIntVal: {
|
||||
int cur = val->value.integer;
|
||||
for (unsigned idx = 0; idx < width; idx += 1) {
|
||||
vvp_bit4_t bit = (cur&1)? BIT4_1 : BIT4_0;
|
||||
put_val.set_bit(idx, bit);
|
||||
cur >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiBinStrVal: {
|
||||
char*str = val->value.str;
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
switch (str[width-idx-1]) {
|
||||
case '0':
|
||||
put_val.set_bit(idx, BIT4_0);
|
||||
break;
|
||||
case '1':
|
||||
put_val.set_bit(idx, BIT4_1);
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
put_val.set_bit(idx, BIT4_X);
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
put_val.set_bit(idx, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported value %c(%d).\n",
|
||||
str[width-idx-1], str[width-idx-1]);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiOctStrVal: {
|
||||
char*str = val->value.str;
|
||||
vpip_oct_str_to_vec4(put_val, str);
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiDecStrVal: {
|
||||
char*str = val->value.str;
|
||||
vpip_dec_str_to_vec4(put_val, str, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiHexStrVal: {
|
||||
char*str = val->value.str;
|
||||
vpip_hex_str_to_vec4(put_val, str);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
cerr << "internal error: memory_word put_value format="
|
||||
<< val->format << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
memory_set_word(rfp->mem->mem, word_addr, 0, put_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char* memory_word_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
|
||||
char number[32];
|
||||
sprintf(number, "%d", rfp->index.value);
|
||||
|
||||
return generic_get_str(code, &rfp->mem->scope->base, rfp->mem->name, number);
|
||||
}
|
||||
|
||||
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_word_width(rfp->mem->mem);
|
||||
unsigned word_address = rfp->index.value;
|
||||
|
||||
vvp_vector4_t word_val = memory_get_word(rfp->mem->mem, word_address);
|
||||
|
||||
vpip_vec4_get_value(word_val, width, false /* never signed */, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_memory_rt = {
|
||||
vpiMemory,
|
||||
vpi_memory_get,
|
||||
memory_get_str,
|
||||
0,
|
||||
0,
|
||||
memory_get_handle,
|
||||
memory_iterate,
|
||||
memory_index,
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_memory_word_rt = {
|
||||
vpiMemoryWord,
|
||||
memory_word_get,
|
||||
memory_word_get_str,
|
||||
memory_word_get_value,
|
||||
memory_word_put,
|
||||
memory_word_get_handle,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
static void memory_make_word_handles(struct __vpiMemory*rfp)
|
||||
{
|
||||
if (rfp->words != 0)
|
||||
return;
|
||||
|
||||
unsigned word_count = memory_word_count(rfp->mem);
|
||||
|
||||
rfp->words = (struct __vpiMemoryWord*)
|
||||
calloc(word_count, sizeof (struct __vpiMemoryWord));
|
||||
|
||||
for (unsigned idx = 0 ; idx < word_count ; idx += 1) {
|
||||
struct __vpiMemoryWord*cur = rfp->words + idx;
|
||||
cur->base.vpi_type = &vpip_memory_word_rt;
|
||||
cur->mem = rfp;
|
||||
vpip_make_dec_const(&cur->index, idx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the callbacks for a memory value change. The memory.cc methods
|
||||
* call this method with the canonical address of the word that
|
||||
* changed, and we here run through all the callbacks for the memory,
|
||||
* passing the translated index through.
|
||||
*/
|
||||
void vpip_run_memory_value_change(vpiHandle ref, unsigned addr)
|
||||
{
|
||||
struct __vpiMemory*obj = reinterpret_cast<struct __vpiMemory*>(ref);
|
||||
|
||||
vvp_vector4_t word_val = memory_get_word(obj->mem, addr);
|
||||
unsigned width = memory_word_width(obj->mem);
|
||||
|
||||
for (struct __vpiCallback*cur=obj->value_change_cb;
|
||||
cur != 0 ; cur = cur->next) {
|
||||
|
||||
if (cur->cb_data.cb_rtn == 0)
|
||||
continue;
|
||||
|
||||
if (cur->cb_data.value)
|
||||
vpip_vec4_get_value(word_val, width, false, cur->cb_data.value);
|
||||
|
||||
cur->cb_data.index = addr;
|
||||
vpi_mode_flag = VPI_MODE_RWSYNC;
|
||||
(cur->cb_data.cb_rtn) (&cur->cb_data);
|
||||
vpi_mode_flag = VPI_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the callback to the memory.
|
||||
*/
|
||||
void vpip_memory_value_change(struct __vpiCallback*cbh, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*obj = reinterpret_cast<struct __vpiMemory*>(ref);
|
||||
cbh->next = obj->value_change_cb;
|
||||
obj->value_change_cb = cbh;
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name)
|
||||
{
|
||||
struct __vpiMemory*obj = (struct __vpiMemory*)
|
||||
malloc(sizeof(struct __vpiMemory));
|
||||
count_vpi_memories += 1;
|
||||
|
||||
obj->base.vpi_type = &vpip_memory_rt;
|
||||
obj->scope = vpip_peek_current_scope();
|
||||
obj->mem = mem;
|
||||
obj->name = vpip_name_string(name);
|
||||
obj->value_change_cb = 0;
|
||||
|
||||
memory_attach_self(mem, &(obj->base));
|
||||
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));
|
||||
|
||||
obj->words = 0;
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
# include "vpi_user.h"
|
||||
# include "pointers.h"
|
||||
# include "vvp_net.h"
|
||||
# include "memory.h"
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -308,12 +307,6 @@ extern void vpip_real_value_change(struct __vpiCallback*cbh,
|
|||
* the memory.
|
||||
*/
|
||||
|
||||
extern vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name);
|
||||
extern void vpip_memory_value_change(struct __vpiCallback*cbh,
|
||||
vpiHandle ref);
|
||||
|
||||
extern void vpip_run_memory_value_change(vpiHandle ref, unsigned adr);
|
||||
|
||||
/*
|
||||
* These are the various variable types.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -728,28 +728,6 @@ bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* %assign/mv <memory>, <delay>, <bit>
|
||||
* This generates an assignment event to a memory. Index register 0
|
||||
* contains the width of the vector (and the word) and index register
|
||||
* 3 contains the canonical address of the word in memory.
|
||||
*/
|
||||
bool of_ASSIGN_MV(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = thr->words[0].w_int;
|
||||
unsigned off = thr->words[1].w_int;
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
|
||||
assert(wid > 0);
|
||||
|
||||
unsigned delay = cp->bit_idx[0];
|
||||
unsigned bit = cp->bit_idx[1];
|
||||
|
||||
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
||||
|
||||
schedule_assign_memory_word(cp->mem, adr, off, value, delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_BLEND(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx[0] >= 4);
|
||||
|
|
@ -2314,38 +2292,6 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp)
|
|||
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);
|
||||
|
||||
if (word.size() != wid) {
|
||||
fprintf(stderr, "internal error: mem width=%u, word.size()=%u, wid=%u\n",
|
||||
memory_word_width(cp->mem), word.size(), wid);
|
||||
}
|
||||
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.
|
||||
*
|
||||
|
|
@ -3489,25 +3435,6 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 bit = cp->bit_idx[0];
|
||||
unsigned wid = cp->bit_idx[1];
|
||||
unsigned off = thr->words[1].w_int;
|
||||
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, off, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
||||
|
|
|
|||
Loading…
Reference in New Issue