iverilog/vvp/compile.cc

1723 lines
44 KiB
C++
Raw Normal View History

2001-03-11 01:29:38 +01:00
/*
* Copyright (c) 2001 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
*/
#if !defined(WINNT)
2001-10-09 04:28:16 +02:00
#ident "$Id: compile.cc,v 1.101 2001/10/09 02:28:16 steve Exp $"
2001-03-11 01:29:38 +01:00
#endif
2001-06-05 05:05:41 +02:00
# include "arith.h"
# include "bufif.h"
2001-10-09 04:28:16 +02:00
# include "npmos.h"
2001-03-11 01:29:38 +01:00
# include "compile.h"
# include "functor.h"
2001-05-09 04:53:25 +02:00
# include "resolv.h"
# include "udp.h"
# include "memory.h"
2001-03-11 01:29:38 +01:00
# include "symbols.h"
# include "codes.h"
# include "schedule.h"
# include "vpi_priv.h"
2001-03-11 01:29:38 +01:00
# include "vthread.h"
# include "parse_misc.h"
2001-09-15 20:27:04 +02:00
#ifdef HAVE_MALLOC_H
2001-03-11 01:29:38 +01:00
# include <malloc.h>
2001-09-15 20:27:04 +02:00
#endif
2001-03-11 01:29:38 +01:00
# include <stdlib.h>
2001-03-28 19:24:32 +02:00
# include <string.h>
2001-03-11 01:29:38 +01:00
# include <assert.h>
#ifdef __MINGW32__
#include <windows.h>
#endif
unsigned compile_errors = 0;
2001-03-11 01:29:38 +01:00
/*
* The opcode table lists all the code mnemonics, along with their
* opcode and operand types. The table is written sorted by mnemonic
* so that it can be searched by binary search. The opcode_compare
* function is a helper function for that lookup.
*/
enum operand_e {
/* Place holder for unused operand */
OA_NONE,
2001-03-12 00:06:49 +01:00
/* The operand is a number, an immediate unsigned integer */
2001-03-11 01:29:38 +01:00
OA_NUMBER,
/* The operand is a thread bit index */
2001-03-12 00:06:49 +01:00
OA_BIT1,
OA_BIT2,
2001-03-11 01:29:38 +01:00
/* The operand is a pointer to code space */
OA_CODE_PTR,
/* The operand is a variable or net pointer */
OA_FUNC_PTR,
/* The operand is a pointer to a memory */
OA_MEM_PTR,
2001-03-11 01:29:38 +01:00
};
struct opcode_table_s {
const char*mnemonic;
vvp_code_fun opcode;
unsigned argc;
enum operand_e argt[OPERAND_MAX];
};
const static struct opcode_table_s opcode_table[] = {
2001-03-31 03:59:58 +02:00
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
2001-04-01 08:12:13 +02:00
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%assign", of_ASSIGN, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%assign/m",of_ASSIGN_MEM,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
2001-08-27 00:59:32 +02:00
{ "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/x", of_CMPX, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%delay", of_DELAY, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
2001-07-19 06:40:55 +02:00
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
2001-05-01 07:00:02 +02:00
{ "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%ix/sub", of_IX_SUB, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
{ "%jmp/0", of_JMP0, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
2001-03-31 19:36:02 +02:00
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
2001-03-30 06:55:22 +02:00
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%load", of_LOAD, 2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
{ "%load/m", of_LOAD_MEM,2, {OA_BIT1, OA_MEM_PTR, OA_NONE} },
{ "%load/x", of_LOAD_X, 3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
2001-05-24 06:20:10 +02:00
{ "%mod", of_MOD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%nand/r", of_NANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
2001-04-01 08:12:13 +02:00
{ "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} },
2001-04-02 00:25:33 +02:00
{ "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%set", of_SET, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%set/m", of_SET_MEM,2, {OA_MEM_PTR, OA_BIT1, OA_NONE} },
2001-08-27 00:59:32 +02:00
{ "%set/x", of_SET_X, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
2001-06-23 20:26:26 +02:00
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
2001-05-02 03:57:25 +02:00
{ "%sub", of_SUB, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
2001-04-15 06:07:56 +02:00
{ "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%xnor/r", of_XNORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
2001-04-15 18:37:48 +02:00
{ "%xor", of_XOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%xor/r", of_XORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
2001-03-11 01:29:38 +01:00
{ 0, of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }
};
static const unsigned opcode_count =
sizeof(opcode_table)/sizeof(*opcode_table) - 1;
2001-03-11 01:29:38 +01:00
static int opcode_compare(const void*k, const void*r)
{
const char*kp = (const char*)k;
const struct opcode_table_s*rp = (const struct opcode_table_s*)r;
return strcmp(kp, rp->mnemonic);
}
/*
* Keep a symbol table of addresses within code space. Labels on
* executable opcodes are mapped to their address here.
*/
static symbol_table_t sym_codespace = 0;
/*
* Keep a symbol table of functors mentioned in the source. This table
* is used to resolve references as they come.
*/
static symbol_table_t sym_functors = 0;
/*
* VPI objects are indexed during compile time so that they can be
* linked together as they are created. This symbol table matches
* labels to vpiHandles.
*/
static symbol_table_t sym_vpi = 0;
2001-03-11 01:29:38 +01:00
/*
* If a functor parameter makes a forward reference to a functor, then
* I need to save that reference and resolve it after the functors are
* created. Use this structure to keep the unresolved references in an
* unsorted singly linked list.
*
* The postpone_functor_input arranges for a functor input to be
* resolved and connected at cleanup. This is used if the symbol is
* defined after its use in a functor. The ptr parameter is the
* complete vvp_input_t for the input port.
2001-03-11 01:29:38 +01:00
*/
2001-08-25 19:22:32 +02:00
/*
* Add a functor to the symbol table
*/
#if 0
static void define_fvector_symbol(char*label, vvp_fvector_t v)
{
symbol_value_t val;
val.ptr = v;
sym_set_value(sym_functors, label, val);
}
#endif
#if 0
static void define_functor_symbol(char*label, vvp_ipoint_t ipt, unsigned wid)
{
vvp_fvector_t v = vvp_fvector_continuous_new(wid, ipt);
define_fvector_symbol(label, v);
}
#else
static void define_functor_symbol(const char*label, vvp_ipoint_t ipt)
{
symbol_value_t val;
val.num = ipt;
sym_set_value(sym_functors, label, val);
}
static vvp_ipoint_t lookup_functor_symbol(const char*label)
{
symbol_value_t val = sym_get_value(sym_functors, label);
return val.num;
}
#endif
/*
2001-08-10 06:31:09 +02:00
* The resolv_list_s is the base class for a symbol resolve action, and
* the resolv_list is an unordered list of these resolve actions. Some
* function creates an instance of a resolv_list_s object that
* contains the data pertinent to that resolution request, and
* executes it with the resolv_submit function. If the operation can
* complete, then the resolv_submit deletes the object. Otherwise, it
* pushes it onto the resolv_list for later processing.
*
* Derived classes implement the resolve function to perform the
* actual binding or resolution that the instance requires. If the
* function succeeds, the resolve method returns true and the object
* can be deleted any time.
*
* The mes parameter of the resolve method tells the resolver that
* this call is its last chance. If it cannot complete the operation,
* it must print an error message and return false.
*/
static struct resolv_list_s*resolv_list = 0;
2001-03-11 01:29:38 +01:00
struct resolv_list_s {
struct resolv_list_s*next;
virtual bool resolve(bool mes = false) = 0;
};
2001-08-10 06:31:09 +02:00
static void resolv_submit(struct resolv_list_s*cur)
{
2001-08-10 06:31:09 +02:00
if (cur->resolve()) {
delete cur;
return;
}
2001-03-20 07:16:23 +01:00
2001-08-10 06:31:09 +02:00
cur->next = resolv_list;
resolv_list = cur;
}
2001-08-10 06:31:09 +02:00
/*
* And the application to functor input lookup
*/
struct functor_resolv_list_s: public resolv_list_s {
2001-03-11 01:29:38 +01:00
char*source;
2001-03-20 07:16:23 +01:00
unsigned idx;
vvp_ipoint_t port;
virtual bool resolve(bool mes);
2001-03-11 01:29:38 +01:00
};
bool functor_resolv_list_s::resolve(bool mes)
{
2001-08-25 19:22:32 +02:00
vvp_ipoint_t tmp = lookup_functor_symbol(source);
if (tmp) {
tmp = ipoint_index(tmp, idx);
functor_t fport = functor_index(tmp);
functor_t iobj = functor_index(port);
iobj->port[ipoint_port(port)] = fport->out;
fport->out = port;
free(source);
return true;
}
if (mes)
fprintf(stderr, "unresolved functor reference: %s\n", source);
return false;
}
2001-03-11 01:29:38 +01:00
inline static
void postpone_functor_input(vvp_ipoint_t ptr, char*lab, unsigned idx)
{
2001-08-10 06:31:09 +02:00
struct functor_resolv_list_s*res = new struct functor_resolv_list_s;
res->port = ptr;
res->source = lab;
res->idx = idx;
2001-08-10 06:31:09 +02:00
resolv_submit(res);
}
/*
* fvector_set lookup
*/
struct fvector_resolv_list_s: public resolv_list_s {
char*source;
unsigned idx;
vvp_fvector_t vec;
unsigned vidx;
virtual bool resolve(bool mes);
};
bool fvector_resolv_list_s::resolve(bool mes)
{
2001-08-25 19:22:32 +02:00
vvp_ipoint_t tmp = lookup_functor_symbol(source);
if (tmp) {
tmp = ipoint_index(tmp, idx);
vvp_fvector_set(vec, vidx, tmp);
free(source);
return true;
}
2001-08-25 19:22:32 +02:00
if (mes) {
fprintf(stderr,
"unresolved functor reference (net input): %s\n",
source);
2001-08-25 19:22:32 +02:00
}
return false;
}
inline static
void postpone_fvector_input(vvp_fvector_t vec, unsigned vidx,
char*lab, unsigned idx)
{
2001-08-10 06:31:09 +02:00
struct fvector_resolv_list_s*res = new struct fvector_resolv_list_s;
res->vec = vec;
res->vidx = vidx;
res->source = lab;
res->idx = idx;
2001-08-10 06:31:09 +02:00
resolv_submit(res);
}
/*
* vpiHandle lookup
*/
struct vpi_handle_resolv_list_s: public resolv_list_s {
vpiHandle *handle;
char *label;
virtual bool resolve(bool mes);
};
bool vpi_handle_resolv_list_s::resolve(bool mes)
{
symbol_value_t val = sym_get_value(sym_vpi, label);
if (!val.ptr) {
// check for thread vector T<base,wid>
unsigned base, wid;
unsigned n;
if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n)
&& n == strlen(label)) {
val.ptr = vpip_make_vthr_vector(base, wid);
sym_set_value(sym_vpi, label, val);
}
}
if (!val.ptr) {
// check for memory word M<mem,base,wid>
}
if (val.ptr) {
*handle = (vpiHandle) val.ptr;
free(label);
return true;
}
if (mes)
fprintf(stderr, "unresolved vpi name lookup: %s\n", label);
return false;
}
void compile_vpi_lookup(vpiHandle *handle, char*label)
{
2001-08-10 06:31:09 +02:00
struct vpi_handle_resolv_list_s*res
= new struct vpi_handle_resolv_list_s;
res->handle = handle;
res->label = label;
2001-08-10 06:31:09 +02:00
resolv_submit(res);
}
/*
* Code Label lookup
*/
struct code_label_resolv_list_s: public resolv_list_s {
struct vvp_code_s *code;
char *label;
virtual bool resolve(bool mes);
};
bool code_label_resolv_list_s::resolve(bool mes)
{
symbol_value_t val = sym_get_value(sym_codespace, label);
if (val.num) {
if (code->opcode == of_FORK)
code->fork->cptr = val.num;
else
code->cptr = val.num;
free(label);
return true;
}
if (mes)
fprintf(stderr,
"unresolved code label: %s\n",
label);
return false;
}
inline static
void code_label_lookup(struct vvp_code_s *code, char *label)
{
2001-08-10 06:31:09 +02:00
struct code_label_resolv_list_s *res
= new struct code_label_resolv_list_s;
res->code = code;
res->label = label;
2001-08-10 06:31:09 +02:00
resolv_submit(res);
}
2001-03-22 06:28:41 +01:00
/*
* functor label lookup
2001-03-22 06:28:41 +01:00
*/
struct code_functor_resolv_list_s: public resolv_list_s {
struct vvp_code_s *code;
char *label;
unsigned idx;
virtual bool resolve(bool mes);
2001-03-22 06:28:41 +01:00
};
bool code_functor_resolv_list_s::resolve(bool mes)
{
2001-08-25 19:22:32 +02:00
vvp_ipoint_t tmp;
/* First, look to see if the symbol is a signal, whether net
or reg. If so, get the correct bit out. */
symbol_value_t val = sym_get_value(sym_vpi, label);
if (val.ptr) {
2001-08-25 19:22:32 +02:00
vpiHandle vpi = (vpiHandle) val.ptr;
assert((vpi->vpi_type->type_code == vpiNet)
|| (vpi->vpi_type->type_code == vpiReg));
__vpiSignal*sig = (__vpiSignal*)vpi;
tmp = vvp_fvector_get(sig->bits, idx);
if (tmp == 0)
goto error_out;
assert(tmp);
code->iptr = tmp;
free(label);
return true;
}
2001-08-25 19:22:32 +02:00
/* Failing that, look for a general functor. */
tmp = lookup_functor_symbol(label);
if (tmp) {
code->iptr = ipoint_index(tmp, idx);
free(label);
return true;
}
error_out:
/* lookup failed. Possibly try again. */
if (mes)
fprintf(stderr,
"unresolved code reference to functor: %s\n",
label);
return false;
}
inline static
void code_functor_lookup(struct vvp_code_s *code, char *label, unsigned idx)
{
2001-08-10 06:31:09 +02:00
struct code_functor_resolv_list_s *res
= new struct code_functor_resolv_list_s;
res->code = code;
res->label = label;
res->idx = idx;
2001-08-10 06:31:09 +02:00
resolv_submit(res);
}
/*
* When parsing is otherwise complete, this function is called to do
* the final stuff. Clean up deferred linking here.
*/
void compile_cleanup(void)
{
int lnerrs = -1;
int nerrs = 0;
int last;
do {
struct resolv_list_s *res = resolv_list;
resolv_list = 0x0;
last = nerrs == lnerrs;
lnerrs = nerrs;
nerrs = 0;
while (res) {
struct resolv_list_s *cur = res;
res = res->next;
if (cur->resolve(last))
delete cur;
else {
nerrs++;
cur->next = resolv_list;
resolv_list = cur;
}
}
if (last && nerrs)
fprintf(stderr,
"compile_cleanup: %d unresolved items\n",
nerrs);
} while (nerrs && nerrs != lnerrs && !last);
compile_errors += nerrs;
}
2001-03-11 01:29:38 +01:00
void compile_vpi_symbol(const char*label, vpiHandle obj)
{
symbol_value_t val;
val.ptr = obj;
sym_set_value(sym_vpi, label, val);
}
2001-03-11 01:29:38 +01:00
/*
* Initialize the compiler by allocation empty symbol tables and
* initializing the various address spaces.
*/
void compile_init(void)
{
sym_vpi = new_symbol_table();
compile_vpi_symbol("$time", vpip_sim_time());
2001-03-11 01:29:38 +01:00
sym_functors = new_symbol_table();
functor_init();
2001-03-11 01:29:38 +01:00
sym_codespace = new_symbol_table();
codespace_init();
}
2001-03-23 03:40:22 +01:00
void compile_load_vpi_module(char*name)
{
vpip_load_module(name);
2001-03-23 03:40:22 +01:00
free(name);
}
void compile_vpi_time_precision(long pre)
{
vpip_set_time_precision(pre);
}
/*
* Run through the arguments looking for the functors that are
* connected to my input ports. For each source functor that I
* find, connect the output of that functor to the indexed
* input by inserting myself (complete with the port number in
* the vvp_ipoint_t) into the list that the source heads.
*
* If the source functor is not declared yet, then don't do
* the link yet. Save the reference to be resolved later.
*
* If the source is a constant value, then set the ival of the functor
* and skip the symbol lookup.
*/
static void inputs_connect(vvp_ipoint_t fdx, unsigned argc, struct symb_s*argv)
{
for (unsigned idx = 0; idx < argc; idx += 1) {
/* Find the functor for this input. This assumes that
wide (more then 4 inputs) gates are consecutive
functors. */
vvp_ipoint_t ifdx = ipoint_input_index(fdx, idx);
functor_t iobj = functor_index(ifdx);
if (strcmp(argv[idx].text, "C<0>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 0, St0);
continue;
}
if (strcmp(argv[idx].text, "C<pu0>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 0, Pu0);
continue;
}
if (strcmp(argv[idx].text, "C<su0>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 0, Su0);
continue;
}
if (strcmp(argv[idx].text, "C<1>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 1, St1);
continue;
}
if (strcmp(argv[idx].text, "C<pu1>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 1, Pu1);
continue;
}
if (strcmp(argv[idx].text, "C<su1>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 1, Su1);
continue;
}
2001-05-09 04:53:25 +02:00
if (strcmp(argv[idx].text, "C<x>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 2, StX);
2001-05-09 04:53:25 +02:00
continue;
}
if (strcmp(argv[idx].text, "C<z>") == 0) {
free(argv[idx].text);
functor_put_input(iobj, idx, 3, HiZ);
2001-05-09 04:53:25 +02:00
continue;
}
postpone_functor_input(ifdx, argv[idx].text, argv[idx].idx);
}
}
2001-03-11 01:29:38 +01:00
/*
* The parser calls this function to create a functor. I allocate a
* functor, and map the name to the vvp_ipoint_t address for the
* functor. Also resolve the inputs to the functor.
*/
void compile_functor(char*label, char*type, unsigned argc, struct symb_s*argv)
2001-03-11 01:29:38 +01:00
{
2001-03-20 07:16:23 +01:00
vvp_ipoint_t fdx = functor_allocate(1);
2001-03-11 01:29:38 +01:00
functor_t obj = functor_index(fdx);
2001-03-18 01:37:55 +01:00
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-03-11 01:29:38 +01:00
assert(argc <= 4);
obj->ival = 0xaa;
2001-03-11 23:42:11 +01:00
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive1 = 6;
obj->mode = 0;
2001-05-09 04:53:25 +02:00
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
2001-03-11 23:42:11 +01:00
if (strcmp(type, "OR") == 0) {
obj->table = ft_OR;
} else if (strcmp(type, "AND") == 0) {
obj->table = ft_AND;
2001-04-01 23:31:46 +02:00
} else if (strcmp(type, "BUF") == 0) {
obj->table = ft_BUF;
2001-04-30 01:13:33 +02:00
} else if (strcmp(type, "BUFIF0") == 0) {
obj->obj = new vvp_bufif0_s;
obj->mode = M42;
2001-04-30 01:13:33 +02:00
} else if (strcmp(type, "BUFIF1") == 0) {
obj->obj = new vvp_bufif1_s;
obj->mode = M42;
2001-04-30 01:13:33 +02:00
2001-10-09 04:28:16 +02:00
} else if (strcmp(type, "PMOS") == 0) {
obj->obj = new vvp_pmos_s;
obj->mode = M42;
} else if (strcmp(type, "NMOS") == 0) {
obj->obj = new vvp_nmos_s;
obj->mode = M42;
} else if (strcmp(type, "MUXZ") == 0) {
obj->table = ft_MUXZ;
} else if (strcmp(type, "EEQ") == 0) {
obj->table = ft_EEQ;
2001-04-21 04:04:01 +02:00
} else if (strcmp(type, "NAND") == 0) {
obj->table = ft_NAND;
2001-03-25 21:38:23 +02:00
} else if (strcmp(type, "NOR") == 0) {
obj->table = ft_NOR;
} else if (strcmp(type, "NOT") == 0) {
obj->table = ft_NOT;
2001-04-21 04:04:01 +02:00
} else if (strcmp(type, "XNOR") == 0) {
obj->table = ft_XNOR;
2001-04-15 18:37:48 +02:00
} else if (strcmp(type, "XOR") == 0) {
obj->table = ft_XOR;
2001-03-11 23:42:11 +01:00
} else {
yyerror("invalid functor type.");
}
/* Connect the inputs of this functor to the given symbols. If
there are C<X> inputs, set the ival appropriately. */
inputs_connect(fdx, argc, argv);
2001-06-05 05:05:41 +02:00
free(argv);
/* Recalculate the output based on the given ival. if the oval
turns out to *not* be x, then schedule the functor so that
the value gets propagated. */
unsigned char out = obj->table[obj->ival >> 2];
obj->oval = 3 & (out >> 2 * (obj->ival&3));
if (obj->oval != 2)
schedule_functor(fdx, 0);
2001-03-11 01:29:38 +01:00
free(label);
free(type);
}
2001-06-07 05:09:03 +02:00
static void connect_arith_inputs(vvp_ipoint_t fdx, long wid,
vvp_arith_* arith,
unsigned argc, struct symb_s*argv)
{
unsigned opcount = argc / wid;
struct symb_s tmp_argv[4];
for (int idx = 0 ; idx < wid ; idx += 1) {
2001-06-07 05:09:03 +02:00
vvp_ipoint_t ptr = ipoint_index(fdx,idx);
functor_t obj = functor_index(ptr);
obj->ival = 0xaa >> 2*(4 - opcount);
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive1 = 6;
obj->mode = M42;
obj->obj = arith;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
for (unsigned cdx = 0 ; cdx < opcount ; cdx += 1)
tmp_argv[cdx] = argv[idx + wid*cdx];
inputs_connect(ptr, opcount, tmp_argv);
}
/* This runs a calculation, so that the output is propagated. */
arith->set(fdx, functor_index(fdx), false);
2001-06-07 05:09:03 +02:00
free(argv);
}
void compile_arith_mult(char*label, long wid,
unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
if ((long)argc != 2*wid) {
fprintf(stderr, "%s; .arith has wrong number of symbols\n", label);
compile_errors += 1;
free(label);
return;
}
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
vvp_arith_mult*arith = new vvp_arith_mult(fdx, wid);
connect_arith_inputs(fdx, wid, arith, argc, argv);
}
2001-06-07 05:09:03 +02:00
void compile_arith_sub(char*label, long wid, unsigned argc, struct symb_s*argv)
2001-06-05 05:05:41 +02:00
{
assert( wid > 0 );
if ((argc % wid) != 0) {
fprintf(stderr, "%s; .arith has wrong number of symbols\n", label);
compile_errors += 1;
free(label);
return;
}
unsigned opcount = argc / wid;
if (opcount > 4) {
fprintf(stderr, "%s; .arith has too many operands.\n", label);
compile_errors += 1;
free(label);
return;
}
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-06-05 05:05:41 +02:00
2001-06-07 05:09:03 +02:00
vvp_arith_sub*arith = new vvp_arith_sub(fdx, wid);
2001-06-05 05:05:41 +02:00
2001-06-07 05:09:03 +02:00
connect_arith_inputs(fdx, wid, arith, argc, argv);
}
2001-06-05 05:05:41 +02:00
2001-06-07 05:09:03 +02:00
void compile_arith_sum(char*label, long wid, unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
2001-06-05 05:05:41 +02:00
2001-06-07 05:09:03 +02:00
if ((argc % wid) != 0) {
fprintf(stderr, "%s; .arith has wrong number of symbols\n", label);
compile_errors += 1;
free(label);
return;
}
2001-06-05 05:05:41 +02:00
2001-06-07 05:09:03 +02:00
unsigned opcount = argc / wid;
if (opcount > 4) {
fprintf(stderr, "%s; .arith has too many operands.\n", label);
compile_errors += 1;
free(label);
return;
2001-06-05 05:05:41 +02:00
}
2001-06-07 05:09:03 +02:00
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-06-07 05:09:03 +02:00
vvp_arith_sum*arith = new vvp_arith_sum(fdx, wid);
connect_arith_inputs(fdx, wid, arith, argc, argv);
2001-06-05 05:05:41 +02:00
}
void compile_cmp_ge(char*label, long wid, unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
if ((long)argc != 2*wid) {
fprintf(stderr, "%s; .cmp has wrong number of symbols\n", label);
compile_errors += 1;
free(label);
return;
}
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
vvp_cmp_ge*cmp = new vvp_cmp_ge(fdx, wid);
connect_arith_inputs(fdx, wid, cmp, argc, argv);
}
void compile_cmp_gt(char*label, long wid, unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
if ((long)argc != 2*wid) {
fprintf(stderr, "%s; .cmp has wrong number of symbols\n", label);
compile_errors += 1;
free(label);
return;
}
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
vvp_cmp_gt*cmp = new vvp_cmp_gt(fdx, wid);
connect_arith_inputs(fdx, wid, cmp, argc, argv);
}
2001-07-07 04:57:33 +02:00
static void compile_shift_inputs(vvp_arith_*dev, vvp_ipoint_t fdx,
long wid, unsigned argc, struct symb_s*argv)
{
for (int idx = 0 ; idx < wid ; idx += 1) {
2001-07-07 04:57:33 +02:00
vvp_ipoint_t ptr = ipoint_index(fdx,idx);
functor_t obj = functor_index(ptr);
if ((wid+idx) >= (long)argc)
2001-07-07 04:57:33 +02:00
obj->ival = 0x02;
else
obj->ival = 0x0a;
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive1 = 6;
obj->mode = M42;
obj->obj = dev;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
struct symb_s tmp_argv[3];
unsigned tmp_argc = 1;
tmp_argv[0] = argv[idx];
if ((wid+idx) < (long)argc) {
2001-07-07 04:57:33 +02:00
tmp_argv[1] = argv[wid+idx];
tmp_argc += 1;
}
inputs_connect(ptr, tmp_argc, tmp_argv);
}
}
/*
* A .shift/l statement creates an array of functors for the
* width. The 0 input is the data vector to be shifted and the 1 input
* is the amount of the shift. An unconnected shift amount is set to 0.
*/
2001-07-06 06:46:44 +02:00
void compile_shiftl(char*label, long wid, unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
if ((long)argc < (wid+1)) {
2001-07-06 06:46:44 +02:00
fprintf(stderr, "%s; .shift/l has too few symbols\n", label);
compile_errors += 1;
free(label);
return;
}
if ((long)argc > (wid*2)) {
fprintf(stderr, "%s; .shift/l has too many symbols\n", label);
compile_errors += 1;
free(label);
return;
}
2001-07-06 06:46:44 +02:00
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-07-06 06:46:44 +02:00
vvp_shiftl*dev = new vvp_shiftl(fdx, wid);
2001-07-07 04:57:33 +02:00
compile_shift_inputs(dev, fdx, wid, argc, argv);
2001-07-06 06:46:44 +02:00
2001-07-07 04:57:33 +02:00
free(argv);
}
2001-07-07 04:57:33 +02:00
void compile_shiftr(char*label, long wid, unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
2001-07-06 06:46:44 +02:00
if ((long)argc < (wid+1)) {
2001-07-07 04:57:33 +02:00
fprintf(stderr, "%s; .shift/r has too few symbols\n", label);
compile_errors += 1;
free(label);
return;
}
2001-07-06 06:46:44 +02:00
if ((long)argc > (wid*2)) {
2001-07-07 04:57:33 +02:00
fprintf(stderr, "%s; .shift/r has too many symbols\n", label);
compile_errors += 1;
free(label);
return;
2001-07-06 06:46:44 +02:00
}
2001-07-07 04:57:33 +02:00
vvp_ipoint_t fdx = functor_allocate(wid);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-07-07 04:57:33 +02:00
vvp_shiftr*dev = new vvp_shiftr(fdx, wid);
compile_shift_inputs(dev, fdx, wid, argc, argv);
2001-07-06 06:46:44 +02:00
free(argv);
}
2001-05-09 04:53:25 +02:00
void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
{
vvp_ipoint_t fdx = functor_allocate(1);
functor_t obj = functor_index(fdx);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-05-09 04:53:25 +02:00
assert(argc <= 4);
obj->ival = 0xaa;
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive1 = 6;
obj->mode = M42;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
if (strcmp(type,"tri") == 0) {
obj->obj = new vvp_resolv_s;
} else {
fprintf(stderr, "invalid resolver type: %s\n", type);
compile_errors += 1;
}
2001-05-09 04:53:25 +02:00
/* Connect the inputs of this functor to the given symbols. If
there are C<X> inputs, set the ival appropriately. */
inputs_connect(fdx, argc, argv);
2001-06-05 05:05:41 +02:00
free(argv);
2001-05-09 04:53:25 +02:00
2001-05-13 23:05:06 +02:00
/* This causes the output value to be set from the existing
inputs, and if the output is not x, a propagation event is
created. */
obj->obj->set(fdx, obj, false);
2001-05-09 04:53:25 +02:00
free(label);
free(type);
}
void compile_udp_def(int sequ, char *label, char *name,
unsigned nin, unsigned init, char **table)
{
struct vvp_udp_s *u = udp_create(label);
u->name = name;
u->sequ = sequ;
u->nin = nin;
u->init = init;
u->compile_table(table);
free(label);
}
char **compile_udp_table(char **table, char *row)
{
if (table)
assert(strlen(*table)==strlen(row));
char **tt;
for (tt = table; tt && *tt; tt++);
int n = (tt-table) + 2;
table = (char**)realloc(table, n*sizeof(char*));
table[n-2] = row;
table[n-1] = 0x0;
return table;
}
void compile_udp_functor(char*label, char*type,
unsigned argc, struct symb_s*argv)
{
struct vvp_udp_s *u = udp_find(type);
assert (argc == u->nin);
2001-04-26 05:10:55 +02:00
int nfun = (argc+3)/4;
vvp_ipoint_t fdx = functor_allocate(nfun);
functor_t obj = functor_index(fdx);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
free(label);
2001-04-26 05:10:55 +02:00
for (unsigned idx = 0; idx < argc; idx += 4)
{
vvp_ipoint_t ifdx = ipoint_input_index(fdx, idx);
functor_t iobj = functor_index(ifdx);
iobj->ival = 0xaa;
iobj->old_ival = obj->ival;
iobj->oval = u->init;
iobj->mode = M42;
#if defined(WITH_DEBUG)
iobj->breakpoint = 0;
#endif
2001-04-26 05:10:55 +02:00
if (idx)
{
iobj->out = fdx;
iobj->obj = 0;
2001-04-26 05:10:55 +02:00
}
else
{
iobj->obj = u;
2001-04-26 05:10:55 +02:00
}
}
inputs_connect(fdx, argc, argv);
2001-06-05 05:05:41 +02:00
free(argv);
}
void compile_memory(char *label, char *name, int msb, int lsb,
unsigned idxs, long *idx)
{
vvp_memory_t mem = memory_create(label);
memory_new(mem, name, lsb, msb, idxs, idx);
vpiHandle obj = vpip_make_memory(mem);
compile_vpi_symbol(label, obj);
free(label);
}
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);
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;
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);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, ix);
free(label);
for (unsigned i=0; i<nfun; i++) {
vvp_ipoint_t iix = ipoint_index(ix, i);
functor_t ip = functor_index(iix);
ip->ival = 0xaa;
}
inputs_connect(ix, argc, argv);
2001-06-05 05:05:41 +02:00
free(argv);
memory_port_new(mem, ix, nbits, lsb, naddr, writable);
}
void compile_memory_init(char *memid, unsigned i, unsigned char val)
{
static vvp_memory_t mem = 0x0;
static unsigned idx;
if (memid)
{
mem = memory_find(memid);
free(memid);
idx = i/4;
}
assert(mem);
memory_init_nibble(mem, idx, val);
idx++;
}
void compile_event(char*label, char*type,
unsigned argc, struct symb_s*argv)
{
vvp_ipoint_t fdx = functor_allocate(1);
functor_t obj = functor_index(fdx);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
assert(argc <= 4);
/* Run through the arguments looking for the functors that are
connected to my input ports. For each source functor that I
find, connect the output of that functor to the indexed
input by inserting myself (complete with the port number in
the vvp_ipoint_t) into the list that the source heads.
If the source functor is not declared yet, then don't do
the link yet. Save the reference to be resolved later. */
inputs_connect(fdx, argc, argv);
2001-06-05 05:05:41 +02:00
free(argv);
obj->ival = 0xaa;
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive0 = 6;
obj->mode = 1;
2001-04-14 07:10:56 +02:00
obj->out = 0;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
obj->event = (struct vvp_event_s*) malloc(sizeof (struct vvp_event_s));
obj->event->threads = 0;
obj->event->ival = obj->ival;
if (strcmp(type,"posedge") == 0)
obj->event->vvp_edge_tab = vvp_edge_posedge;
else if (strcmp(type,"negedge") == 0)
obj->event->vvp_edge_tab = vvp_edge_negedge;
else if (strcmp(type,"edge") == 0)
obj->event->vvp_edge_tab = vvp_edge_anyedge;
else
obj->event->vvp_edge_tab = 0;
free(type);
free(label);
}
void compile_named_event(char*label, char*name)
{
vvp_ipoint_t fdx = functor_allocate(1);
functor_t obj = functor_index(fdx);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
obj->ival = 0xaa;
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive1 = 6;
obj->mode = 2;
2001-04-14 07:10:56 +02:00
obj->out = 0;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
obj->event = (struct vvp_event_s*) malloc(sizeof (struct vvp_event_s));
obj->event->threads = 0;
obj->event->ival = obj->ival;
free(label);
free(name);
}
2001-04-14 07:10:56 +02:00
void compile_event_or(char*label, unsigned argc, struct symb_s*argv)
{
vvp_ipoint_t fdx = functor_allocate(1);
functor_t obj = functor_index(fdx);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-04-14 07:10:56 +02:00
obj->ival = 0xaa;
obj->oval = 2;
obj->odrive0 = 6;
obj->odrive1 = 6;
2001-04-14 07:10:56 +02:00
obj->mode = 2;
obj->out = 0;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
2001-04-14 07:10:56 +02:00
obj->event = new struct vvp_event_s;
obj->event->threads = 0;
obj->event->ival = obj->ival;
2001-07-30 05:53:01 +02:00
obj->event->vvp_edge_tab = 0;
2001-04-14 07:10:56 +02:00
/* Link the outputs of the named events to me. */
for (unsigned idx = 0 ; idx < argc ; idx += 1) {
2001-08-25 19:22:32 +02:00
vvp_ipoint_t tmp = lookup_functor_symbol(argv[idx].text);
assert(tmp);
tmp = ipoint_index(tmp, argv[idx].idx);
2001-04-14 07:10:56 +02:00
functor_t fport = functor_index(tmp);
2001-07-30 05:53:01 +02:00
assert(fport);
2001-04-14 07:10:56 +02:00
assert(fport->out == 0);
fport->out = fdx;
2001-04-14 07:10:56 +02:00
free(argv[idx].text);
}
free(argv);
free(label);
}
2001-03-11 01:29:38 +01:00
/*
* The parser uses this function to compile an link an executable
* opcode. I do this by looking up the opcode in the opcode_table. The
* table gives the operand structure that is acceptible, so I can
* process the operands here as well.
*/
void compile_code(char*label, char*mnem, comp_operands_t opa)
{
/* First, I can give the label a value that is the current
codespace pointer. Don't need the text of the label after
this is done. */
if (label)
compile_codelabel(label);
vvp_cpoint_t ptr = codespace_allocate();
2001-03-11 01:29:38 +01:00
/* Lookup the opcode in the opcode table. */
struct opcode_table_s*op = (struct opcode_table_s*)
bsearch(mnem, opcode_table, opcode_count,
sizeof(struct opcode_table_s), &opcode_compare);
if (op == 0) {
yyerror("Invalid opcode");
return;
}
assert(op);
/* Build up the code from the information about the opcode and
the information from the compiler. */
2001-03-11 01:29:38 +01:00
vvp_code_t code = codespace_index(ptr);
code->opcode = op->opcode;
if (op->argc != (opa? opa->argc : 0)) {
yyerror("operand count");
return;
}
/* Pull the operands that the instruction expects from the
list that the parser supplied. */
for (unsigned idx = 0 ; idx < op->argc ; idx += 1) {
2001-03-18 01:37:55 +01:00
2001-03-11 01:29:38 +01:00
switch (op->argt[idx]) {
case OA_NONE:
break;
2001-03-12 00:06:49 +01:00
case OA_BIT1:
2001-03-11 01:29:38 +01:00
if (opa->argv[idx].ltype != L_NUMB) {
yyerror("operand format");
break;
}
2001-03-12 00:06:49 +01:00
code->bit_idx1 = opa->argv[idx].numb;
break;
case OA_BIT2:
if (opa->argv[idx].ltype != L_NUMB) {
yyerror("operand format");
break;
}
code->bit_idx2 = opa->argv[idx].numb;
2001-03-11 01:29:38 +01:00
break;
case OA_CODE_PTR:
2001-03-20 07:16:23 +01:00
if (opa->argv[idx].ltype != L_SYMB) {
2001-03-11 01:29:38 +01:00
yyerror("operand format");
break;
}
2001-03-20 07:16:23 +01:00
assert(opa->argv[idx].symb.idx == 0);
code_label_lookup(code, opa->argv[idx].symb.text);
2001-03-11 01:29:38 +01:00
break;
case OA_FUNC_PTR:
/* The operand is a functor. Resolve the label to
a functor pointer, or postpone the resolution
if it is not defined yet. */
2001-03-20 07:16:23 +01:00
if (opa->argv[idx].ltype != L_SYMB) {
2001-03-11 01:29:38 +01:00
yyerror("operand format");
break;
}
code_functor_lookup(code,
opa->argv[idx].symb.text,
opa->argv[idx].symb.idx);
2001-03-11 01:29:38 +01:00
break;
case OA_NUMBER:
if (opa->argv[idx].ltype != L_NUMB) {
yyerror("operand format");
break;
}
code->number = opa->argv[idx].numb;
break;
case OA_MEM_PTR:
if (opa->argv[idx].ltype != L_SYMB) {
yyerror("operand format");
break;
}
code->mem = memory_find(opa->argv[idx].symb.text);
if (code->mem == 0) {
yyerror("memory undefined");
}
free(opa->argv[idx].symb.text);
break;
2001-03-11 01:29:38 +01:00
}
}
if (opa) free(opa);
free(mnem);
}
void compile_codelabel(char*label)
{
symbol_value_t val;
vvp_cpoint_t ptr = codespace_next();
val.num = ptr;
sym_set_value(sym_codespace, label, val);
free(label);
}
2001-04-18 06:21:23 +02:00
void compile_disable(char*label, struct symb_s symb)
{
if (label)
compile_codelabel(label);
2001-04-18 06:21:23 +02:00
vvp_cpoint_t ptr = codespace_allocate();
2001-04-18 06:21:23 +02:00
/* Fill in the basics of the %disable in the instruction. */
vvp_code_t code = codespace_index(ptr);
code->opcode = of_DISABLE;
compile_vpi_lookup(&code->handle, symb.text);
2001-04-18 06:21:23 +02:00
}
/*
* The %fork instruction is a little different from other instructions
* in that it has an extended field that holds the information needed
* to create the new thread. This includes the target PC and scope.
* I get these from the parser in the form of symbols.
*/
void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
{
if (label)
compile_codelabel(label);
2001-04-18 06:21:23 +02:00
vvp_cpoint_t ptr = codespace_allocate();
2001-04-18 06:21:23 +02:00
/* Fill in the basics of the %fork in the instruction. */
vvp_code_t code = codespace_index(ptr);
code->opcode = of_FORK;
code->fork = new struct fork_extend;
/* Figure out the target PC. */
code_label_lookup(code, dest.text);
2001-04-18 06:21:23 +02:00
/* Figure out the target SCOPE. */
compile_vpi_lookup((vpiHandle*)&code->fork->scope, scope.text);
2001-04-18 06:21:23 +02:00
}
void compile_vpi_call(char*label, char*name, unsigned argc, vpiHandle*argv)
{
if (label)
compile_codelabel(label);
vvp_cpoint_t ptr = codespace_allocate();
/* Create an instruction in the code space. */
vvp_code_t code = codespace_index(ptr);
code->opcode = &of_VPI_CALL;
/* Create a vpiHandle that bundles the call information, and
store that handle in the instruction. */
2001-05-20 02:46:12 +02:00
code->handle = vpip_build_vpi_call(name, 0, 0, argc, argv);
if (code->handle == 0)
compile_errors += 1;
/* Done with the lexor-allocated name string. */
free(name);
}
void compile_vpi_func_call(char*label, char*name,
unsigned vbit, unsigned vwid,
unsigned argc, vpiHandle*argv)
{
if (label)
compile_codelabel(label);
2001-05-20 02:46:12 +02:00
vvp_cpoint_t ptr = codespace_allocate();
/* Create an instruction in the code space. */
vvp_code_t code = codespace_index(ptr);
code->opcode = &of_VPI_CALL;
/* Create a vpiHandle that bundles the call information, and
store that handle in the instruction. */
code->handle = vpip_build_vpi_call(name, vbit, vwid, argc, argv);
if (code->handle == 0)
compile_errors += 1;
/* Done with the lexor-allocated name string. */
free(name);
}
2001-03-11 01:29:38 +01:00
/*
* When the parser finds a thread statement, I create a new thread
* with the start address referenced by the program symbol passed to
* me.
*/
void compile_thread(char*start_sym)
{
2001-03-18 01:37:55 +01:00
symbol_value_t tmp = sym_get_value(sym_codespace, start_sym);
vvp_cpoint_t pc = tmp.num;
2001-03-11 01:29:38 +01:00
if (pc == 0) {
yyerror("unresolved address");
return;
}
2001-04-18 06:21:23 +02:00
vthread_t thr = vthread_new(pc, vpip_peek_current_scope());
2001-03-11 01:29:38 +01:00
schedule_vthread(thr, 0);
free(start_sym);
}
/*
* A variable is a special functor, so we allocate that functor and
* write the label into the symbol table.
*/
void compile_variable(char*label, char*name, int msb, int lsb,
bool signed_flag)
2001-03-11 01:29:38 +01:00
{
2001-03-20 07:16:23 +01:00
unsigned wid = ((msb > lsb)? msb-lsb : lsb-msb) + 1;
vvp_ipoint_t fdx = functor_allocate(wid);
vvp_fvector_t vec = vvp_fvector_continuous_new(wid, fdx);
2001-08-25 19:22:32 +02:00
define_functor_symbol(label, fdx);
2001-03-11 01:29:38 +01:00
2001-03-20 07:16:23 +01:00
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
functor_t obj = functor_index(ipoint_index(fdx,idx));
obj->table = ft_var;
obj->ival = 0x22;
obj->oval = 0x02;
obj->odrive0 = 6;
obj->odrive1 = 6;
obj->mode = 0;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
2001-03-20 07:16:23 +01:00
}
/* Make the vpiHandle for the reg. */
vpiHandle obj = vpip_make_reg(name, msb, lsb, signed_flag, vec);
compile_vpi_symbol(label, obj);
2001-06-10 18:47:49 +02:00
vpip_attach_to_current_scope(obj);
free(label);
2001-03-11 01:29:38 +01:00
}
static vvp_ipoint_t make_const_functor(unsigned val,
unsigned str0,
unsigned str1)
{
vvp_ipoint_t fdx = functor_allocate(1);
functor_t obj = functor_index(fdx);
obj->table = ft_var;
obj->ival = val;
obj->oval = val;
obj->odrive0 = str0;
obj->odrive1 = str1;
obj->mode = 0;
#if defined(WITH_DEBUG)
obj->breakpoint = 0;
#endif
schedule_functor(fdx, 0);
return fdx;
}
void compile_net(char*label, char*name, int msb, int lsb, bool signed_flag,
2001-03-25 01:35:35 +01:00
unsigned argc, struct symb_s*argv)
{
unsigned wid = ((msb > lsb)? msb-lsb : lsb-msb) + 1;
vvp_fvector_t vec = vvp_fvector_new(wid);
2001-08-25 19:22:32 +02:00
//define_fvector_symbol(label, vec);
2001-03-25 01:35:35 +01:00
assert(argc == wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_ipoint_t ipt = 0;
2001-04-23 02:37:58 +02:00
if (argv[idx].text == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(3,6,6);
ipt = cf;
} else
2001-04-23 02:37:58 +02:00
2001-04-30 00:59:46 +02:00
if (strcmp(argv[idx].text, "C<0>") == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(0,6,6);
ipt = cf;
} else
2001-04-30 00:59:46 +02:00
if (strcmp(argv[idx].text, "C<su0>") == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(0,7,7);
ipt = cf;
} else
2001-04-30 00:59:46 +02:00
if (strcmp(argv[idx].text, "C<1>") == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(1,6,6);
ipt = cf;
} else
2001-04-30 00:59:46 +02:00
if (strcmp(argv[idx].text, "C<su1>") == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(1,7,7);
ipt = cf;
} else
2001-04-30 00:59:46 +02:00
if (strcmp(argv[idx].text, "C<x>") == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(2,6,6);
ipt = cf;
} else
2001-04-30 00:59:46 +02:00
if (strcmp(argv[idx].text, "C<z>") == 0) {
static vvp_ipoint_t cf=0;
if (!cf)
cf = make_const_functor(3,6,6);
ipt = cf;
} else {
postpone_fvector_input(vec, idx,
argv[idx].text, argv[idx].idx);
2001-04-30 00:59:46 +02:00
continue;
}
vvp_fvector_set(vec, idx, ipt);
2001-03-25 01:35:35 +01:00
}
/* Make the vpiHandle for the reg. */
vpiHandle obj = vpip_make_net(name, msb, lsb, signed_flag, vec);
2001-03-25 01:35:35 +01:00
compile_vpi_symbol(label, obj);
2001-06-10 18:47:49 +02:00
vpip_attach_to_current_scope(obj);
2001-03-25 01:35:35 +01:00
free(label);
free(argv);
}
/*
* These functions are in support of the debugger.
*
* debug_lookup_functor
* Use a name to locate a functor address. This only gets the LSB
* of a vector, but it is enough to locate the object, or, is it?
*/
vvp_ipoint_t debug_lookup_functor(const char*name)
{
2001-08-25 19:22:32 +02:00
return lookup_functor_symbol(name);
}
2001-03-11 01:29:38 +01:00
/*
* $Log: compile.cc,v $
2001-10-09 04:28:16 +02:00
* Revision 1.101 2001/10/09 02:28:16 steve
* Add the PMOS and NMOS functor types.
*
2001-09-15 20:27:04 +02:00
* Revision 1.100 2001/09/15 18:27:04 steve
* Make configure detect malloc.h
*
* Revision 1.99 2001/09/11 01:54:58 steve
* initial structural memory propagation (Stephan Boettcher)
*
2001-08-27 00:59:32 +02:00
* Revision 1.98 2001/08/26 22:59:32 steve
* Add the assign/x0 and set/x opcodes.
*
2001-08-25 19:22:32 +02:00
* Revision 1.97 2001/08/25 17:22:32 steve
* Only use fvectors for nets and vars.
*
2001-08-10 06:31:09 +02:00
* Revision 1.96 2001/08/10 04:31:09 steve
* Neaten and document the resolv object.
*
* Revision 1.95 2001/08/10 00:50:50 steve
* Make sure arithmetic objects run at time 0.
*
* Revision 1.94 2001/08/09 19:38:23 steve
* Nets (wires) do not use their own functors.
* Modifications to propagation of values.
* (Stephan Boettcher)
*
* Revision 1.93 2001/08/08 01:05:06 steve
* Initial implementation of vvp_fvectors.
* (Stephan Boettcher)
*
2001-07-30 05:53:01 +02:00
* Revision 1.92 2001/07/30 03:53:01 steve
* Initialize initial functor tables.
*
* Revision 1.91 2001/07/28 03:12:39 steve
* Support C<su0> and C<su1> special symbols.
*
* Revision 1.90 2001/07/26 03:13:51 steve
* Make the -M flag add module search paths.
*
* Revision 1.89 2001/07/22 00:04:50 steve
* Add the load/x instruction for bit selects.
*
2001-07-19 06:40:55 +02:00
* Revision 1.88 2001/07/19 04:40:55 steve
* Add support for the delayx opcode.
*
* Revision 1.87 2001/07/11 04:43:57 steve
* support postpone of $systask parameters. (Stephan Boettcher)
*
2001-07-07 04:57:33 +02:00
* Revision 1.86 2001/07/07 02:57:33 steve
* Add the .shift/r functor.
*
* Revision 1.85 2001/07/06 05:02:43 steve
* Properly initialize unconnected shift inputs.
*
2001-07-06 06:46:44 +02:00
* Revision 1.84 2001/07/06 04:46:44 steve
* Add structural left shift (.shift/l)
*
* Revision 1.83 2001/06/30 23:03:16 steve
* support fast programming by only writing the bits
* that are listed in the input file.
*
* Revision 1.82 2001/06/30 21:07:26 steve
* Support non-const right shift (unsigned).
*
2001-06-23 20:26:26 +02:00
* Revision 1.81 2001/06/23 18:26:26 steve
* Add the %shiftl/i0 instruction.
*
* Revision 1.80 2001/06/23 01:04:07 steve
* Allow forward references of task scopes. (Stephan Boettcher)
*
* Revision 1.79 2001/06/19 03:01:10 steve
* Add structural EEQ gates (Stephan Boettcher)
2001-03-11 01:29:38 +01:00
*/