2001-03-11 01:29:38 +01:00
|
|
|
/*
|
2003-01-26 00:48:05 +01:00
|
|
|
* Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
|
2001-03-11 01:29:38 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2005-03-22 06:18:34 +01:00
|
|
|
#ident "$Id: compile.cc,v 1.195 2005/03/22 05:18:34 steve Exp $"
|
2001-03-11 01:29:38 +01:00
|
|
|
#endif
|
|
|
|
|
|
2001-06-05 05:05:41 +02:00
|
|
|
# include "arith.h"
|
2001-03-11 01:29:38 +01:00
|
|
|
# include "compile.h"
|
|
|
|
|
# include "functor.h"
|
2003-07-30 03:13:28 +02:00
|
|
|
# include "logic.h"
|
2001-05-09 04:53:25 +02:00
|
|
|
# include "resolv.h"
|
2004-10-04 03:10:51 +02:00
|
|
|
# include "udp.h"
|
2001-11-01 04:00:19 +01:00
|
|
|
# include "memory.h"
|
2004-10-04 03:10:51 +02:00
|
|
|
# include "force.h"
|
2001-03-11 01:29:38 +01:00
|
|
|
# include "symbols.h"
|
|
|
|
|
# include "codes.h"
|
|
|
|
|
# include "schedule.h"
|
2001-03-16 02:44:34 +01:00
|
|
|
# include "vpi_priv.h"
|
2001-03-11 01:29:38 +01:00
|
|
|
# include "parse_misc.h"
|
2002-07-05 22:08:44 +02:00
|
|
|
# include "statistics.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>
|
|
|
|
|
|
2001-05-22 04:14:47 +02:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-03-22 23:38:13 +01:00
|
|
|
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,
|
2001-11-01 04:00:19 +01:00
|
|
|
/* The operand is a thread bit index or short integer */
|
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 */
|
2001-05-01 03:09:39 +02:00
|
|
|
OA_FUNC_PTR,
|
2001-11-01 04:00:19 +01:00
|
|
|
/* The operand is a second functor pointer */
|
|
|
|
|
OA_FUNC_PTR2,
|
|
|
|
|
/* The operand is a pointer to a memory */
|
2001-05-03 01:16:50 +02:00
|
|
|
OA_MEM_PTR,
|
2002-08-28 19:15:06 +02:00
|
|
|
/* The operand is a VPI handle */
|
|
|
|
|
OA_VPI_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} },
|
2003-01-26 00:48:05 +01:00
|
|
|
{ "%add/wr", of_ADD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2002-05-29 18:29:34 +02:00
|
|
|
{ "%addi", of_ADDI, 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} },
|
2001-06-18 03:09:32 +02:00
|
|
|
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2002-11-08 05:59:57 +01:00
|
|
|
{ "%assign/d", of_ASSIGN_D, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
2001-05-03 01:16:50 +02:00
|
|
|
{ "%assign/m",of_ASSIGN_MEM,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
|
2005-03-03 05:33:10 +01:00
|
|
|
{ "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
|
2002-11-08 05:59:57 +01:00
|
|
|
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
2004-05-19 05:26:24 +02:00
|
|
|
{ "%assign/wr",of_ASSIGN_WR,3,{OA_VPI_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} },
|
2002-08-22 05:38:40 +02:00
|
|
|
{ "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-05-06 01:55:46 +02:00
|
|
|
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
2004-12-11 03:31:25 +01:00
|
|
|
{ "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
2001-04-05 03:12:27 +02:00
|
|
|
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-03-22 06:08:00 +01:00
|
|
|
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2003-01-26 00:48:05 +01:00
|
|
|
{ "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2001-04-01 06:34:28 +02:00
|
|
|
{ "%cmp/x", of_CMPX, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
|
|
|
|
{ "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2002-06-02 20:55:58 +02:00
|
|
|
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2003-01-26 19:16:22 +01:00
|
|
|
{ "%cvt/ir", of_CVT_IR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
|
|
|
|
{ "%cvt/ri", of_CVT_RI, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2003-02-27 21:36:29 +01:00
|
|
|
{ "%cvt/vr", of_CVT_VR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2004-12-11 03:31:25 +01:00
|
|
|
{ "%deassign",of_DEASSIGN,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
2001-03-22 06:08:00 +01:00
|
|
|
{ "%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} },
|
2001-10-16 03:26:54 +02:00
|
|
|
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2002-04-14 20:41:34 +02:00
|
|
|
{ "%div/s", of_DIV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2003-03-28 03:33:56 +01:00
|
|
|
{ "%div/wr", of_DIV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2001-03-22 06:08:00 +01:00
|
|
|
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
2004-12-15 18:17:42 +01:00
|
|
|
{ "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
2001-03-22 06:08:00 +01:00
|
|
|
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2001-05-01 03:09:39 +02:00
|
|
|
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
2001-05-10 02:26:53 +02:00
|
|
|
{ "%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} },
|
2001-05-01 03:09:39 +02:00
|
|
|
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
2001-05-03 01:16:50 +02:00
|
|
|
{ "%ix/sub", of_IX_SUB, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
2001-03-22 06:08:00 +01:00
|
|
|
{ "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
|
|
|
|
|
{ "%jmp/0", of_JMP0, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
2001-03-25 05:54:26 +02:00
|
|
|
{ "%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} },
|
2001-05-03 01:16:50 +02:00
|
|
|
{ "%load/m", of_LOAD_MEM,2, {OA_BIT1, OA_MEM_PTR, OA_NONE} },
|
2005-03-03 05:33:10 +01:00
|
|
|
{ "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} },
|
2002-08-28 19:15:06 +02:00
|
|
|
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
2002-11-07 03:32:39 +01:00
|
|
|
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
2003-01-26 00:48:05 +01:00
|
|
|
{ "%load/wr",of_LOAD_WR,2, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
2003-07-22 22:30:24 +02:00
|
|
|
{ "%load/x", of_LOAD_X, 3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
2003-01-26 00:48:05 +01:00
|
|
|
{ "%loadi/wr",of_LOADI_WR,3,{OA_BIT1, OA_NUMBER, OA_BIT2} },
|
2001-05-24 06:20:10 +02:00
|
|
|
{ "%mod", of_MOD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2004-06-19 17:52:53 +02:00
|
|
|
{ "%mod/s", of_MOD_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-03-22 06:08:00 +01:00
|
|
|
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-06-17 01:45:05 +02:00
|
|
|
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2003-01-26 00:48:05 +01:00
|
|
|
{ "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2002-05-31 22:04:22 +02:00
|
|
|
{ "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2002-09-12 17:49:43 +02:00
|
|
|
{ "%nand", of_NAND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-06-18 03:09:32 +02:00
|
|
|
{ "%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} },
|
2002-09-18 06:29:55 +02:00
|
|
|
{ "%nor", of_NOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-04-02 00:25:33 +02:00
|
|
|
{ "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-04-01 09:22:08 +02:00
|
|
|
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-06-18 03:09:32 +02:00
|
|
|
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2004-12-17 05:47:47 +01:00
|
|
|
{ "%release/net",of_RELEASE_NET,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
|
|
|
|
{ "%release/reg",of_RELEASE_REG,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
2005-03-03 05:33:10 +01:00
|
|
|
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
|
2002-11-07 03:32:39 +01:00
|
|
|
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
2003-01-26 00:48:05 +01:00
|
|
|
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
2005-03-22 06:18:34 +01:00
|
|
|
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
2005-02-14 02:50:23 +01:00
|
|
|
// { "%set/x0/x",of_SET_X0_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} },
|
2001-06-30 23:07:26 +02:00
|
|
|
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
|
2003-06-18 05:55:18 +02:00
|
|
|
{ "%shiftr/s/i0", of_SHIFTR_S_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} },
|
2003-02-06 18:41:47 +01:00
|
|
|
{ "%sub/wr", of_SUB_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
2002-08-28 20:38:07 +02:00
|
|
|
{ "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
2001-03-26 06:00:39 +02:00
|
|
|
{ "%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} },
|
2001-06-18 03:09:32 +02:00
|
|
|
{ "%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} },
|
2001-06-18 03:09:32 +02:00
|
|
|
{ "%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} }
|
|
|
|
|
};
|
|
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
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;
|
|
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
/*
|
|
|
|
|
* 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.
|
2001-03-25 05:54:26 +02:00
|
|
|
*
|
|
|
|
|
* 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-09 21:38:23 +02:00
|
|
|
|
|
|
|
|
|
2001-08-25 19:22:32 +02:00
|
|
|
/*
|
|
|
|
|
* Add a functor to the symbol table
|
|
|
|
|
*/
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
void define_functor_symbol(const char*label, vvp_net_t*net)
|
2001-08-25 19:22:32 +02:00
|
|
|
{
|
|
|
|
|
symbol_value_t val;
|
2004-12-11 03:31:25 +01:00
|
|
|
val.net = net;
|
2001-08-25 19:22:32 +02:00
|
|
|
sym_set_value(sym_functors, label, val);
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
static vvp_net_t*lookup_functor_symbol(const char*label)
|
2001-08-25 19:22:32 +02:00
|
|
|
{
|
2002-07-05 06:40:59 +02:00
|
|
|
assert(sym_functors);
|
2001-08-25 19:22:32 +02:00
|
|
|
symbol_value_t val = sym_get_value(sym_functors, label);
|
2004-12-11 03:31:25 +01:00
|
|
|
return val.net;
|
2001-08-25 19:22:32 +02:00
|
|
|
}
|
2001-10-12 04:53:47 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
static vvp_net_t* vvp_net_lookup(const char*label)
|
2001-10-12 04:53:47 +02:00
|
|
|
{
|
2003-04-23 05:09:25 +02:00
|
|
|
/* First, look to see if the symbol is a vpi object of some
|
|
|
|
|
sort. If it is, then get the vvp_ipoint_t pointer out of
|
|
|
|
|
the vpiHandle. */
|
2001-10-12 04:53:47 +02:00
|
|
|
symbol_value_t val = sym_get_value(sym_vpi, label);
|
|
|
|
|
if (val.ptr) {
|
|
|
|
|
vpiHandle vpi = (vpiHandle) val.ptr;
|
2003-04-23 05:09:25 +02:00
|
|
|
switch (vpi->vpi_type->type_code) {
|
|
|
|
|
case vpiNet:
|
|
|
|
|
case vpiReg:
|
|
|
|
|
case vpiIntegerVar: {
|
|
|
|
|
__vpiSignal*sig = (__vpiSignal*)vpi;
|
2004-12-11 03:31:25 +01:00
|
|
|
return sig->node;
|
2003-04-23 05:09:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case vpiNamedEvent: {
|
|
|
|
|
__vpiNamedEvent*tmp = (__vpiNamedEvent*)vpi;
|
|
|
|
|
return tmp->funct;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2001-10-12 04:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2001-10-12 04:53:47 +02:00
|
|
|
/* Failing that, look for a general functor. */
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t*tmp = lookup_functor_symbol(label);
|
2001-10-12 04:53:47 +02:00
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
2001-08-25 19:22:32 +02:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
/*
|
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.
|
2001-08-09 21:38:23 +02:00
|
|
|
*/
|
|
|
|
|
static struct resolv_list_s*resolv_list = 0;
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
struct resolv_list_s {
|
2004-12-11 03:31:25 +01:00
|
|
|
virtual ~resolv_list_s() { }
|
2001-03-11 01:29:38 +01:00
|
|
|
struct resolv_list_s*next;
|
2001-08-09 21:38:23 +02:00
|
|
|
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-09 21:38:23 +02:00
|
|
|
{
|
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-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
2001-08-10 06:31:09 +02:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
/*
|
2004-12-11 03:31:25 +01:00
|
|
|
* Look up vvp_nets in the symbol table. The "source" is the label for
|
|
|
|
|
* the net that I want to feed, and net->port[port] is the vvp_net
|
|
|
|
|
* input that I want that node to feed into. When the name is found,
|
|
|
|
|
* put net->port[port] into the fan-out list for that node.
|
2001-08-09 21:38:23 +02:00
|
|
|
*/
|
2004-12-11 03:31:25 +01:00
|
|
|
struct vvp_net_resolv_list_s: public resolv_list_s {
|
|
|
|
|
// node to locate
|
2001-03-11 01:29:38 +01:00
|
|
|
char*source;
|
2004-12-11 03:31:25 +01:00
|
|
|
// port to be driven by the located node.
|
|
|
|
|
vvp_net_ptr_t port;
|
2001-08-09 21:38:23 +02:00
|
|
|
virtual bool resolve(bool mes);
|
2001-03-11 01:29:38 +01:00
|
|
|
};
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
bool vvp_net_resolv_list_s::resolve(bool mes)
|
2001-08-09 21:38:23 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t*tmp = vvp_net_lookup(source);
|
2001-08-25 19:22:32 +02:00
|
|
|
|
|
|
|
|
if (tmp) {
|
2004-12-11 03:31:25 +01:00
|
|
|
// Link the input port to the located output.
|
|
|
|
|
vvp_net_t*net = port.ptr();
|
|
|
|
|
net->port[port.port()] = tmp->out;
|
|
|
|
|
tmp->out = port;
|
2001-08-25 19:22:32 +02:00
|
|
|
|
|
|
|
|
free(source);
|
|
|
|
|
return true;
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mes)
|
2004-12-11 03:31:25 +01:00
|
|
|
fprintf(stderr, "unresolved vvp_net reference: %s\n", source);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
inline static
|
2004-12-11 03:31:25 +01:00
|
|
|
void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
2001-03-25 05:54:26 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s;
|
2001-03-25 05:54:26 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
res->port = port;
|
2001-03-25 05:54:26 +02:00
|
|
|
res->source = lab;
|
2001-08-09 21:38:23 +02:00
|
|
|
|
2001-08-10 06:31:09 +02:00
|
|
|
resolv_submit(res);
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
/*
|
2001-10-09 18:57:47 +02:00
|
|
|
* Generic functor reference lookup.
|
2001-08-09 21:38:23 +02:00
|
|
|
*/
|
|
|
|
|
|
2001-10-09 18:57:47 +02:00
|
|
|
struct functor_gen_resolv_list_s: public resolv_list_s {
|
2001-08-09 21:38:23 +02:00
|
|
|
char*source;
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t**ref;
|
2001-08-09 21:38:23 +02:00
|
|
|
virtual bool resolve(bool mes);
|
|
|
|
|
};
|
|
|
|
|
|
2001-10-09 18:57:47 +02:00
|
|
|
bool functor_gen_resolv_list_s::resolve(bool mes)
|
2001-08-09 21:38:23 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t*tmp = vvp_net_lookup(source);
|
2001-10-09 18:57:47 +02:00
|
|
|
|
2001-08-25 19:22:32 +02:00
|
|
|
if (tmp) {
|
2001-10-09 18:57:47 +02:00
|
|
|
*ref = tmp;
|
|
|
|
|
|
2001-08-25 19:22:32 +02:00
|
|
|
free(source);
|
|
|
|
|
return true;
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
2001-10-09 18:57:47 +02:00
|
|
|
if (mes)
|
|
|
|
|
fprintf(stderr, "unresolved functor reference: %s\n", source);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
2001-08-09 21:38:23 +02:00
|
|
|
{
|
2004-10-04 03:10:51 +02:00
|
|
|
struct functor_gen_resolv_list_s*res =
|
2001-10-09 18:57:47 +02:00
|
|
|
new struct functor_gen_resolv_list_s;
|
2001-08-09 21:38:23 +02:00
|
|
|
|
2001-10-09 18:57:47 +02:00
|
|
|
res->ref = ref;
|
2001-08-09 21:38:23 +02:00
|
|
|
res->source = lab;
|
|
|
|
|
|
2001-08-10 06:31:09 +02:00
|
|
|
resolv_submit(res);
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
2002-05-07 06:15:43 +02:00
|
|
|
unsigned n = 0;
|
2002-04-14 04:56:19 +02:00
|
|
|
char ss[32];
|
2004-10-04 03:10:51 +02:00
|
|
|
if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n)
|
2001-08-09 21:38:23 +02:00
|
|
|
&& n == strlen(label)) {
|
2002-04-14 04:56:19 +02:00
|
|
|
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
2001-08-09 21:38:23 +02:00
|
|
|
sym_set_value(sym_vpi, label, val);
|
2002-04-14 04:56:19 +02:00
|
|
|
|
|
|
|
|
} else if (3 <= sscanf(label, "T<%u,%u,%[su]>%n", &base,
|
2004-10-04 03:10:51 +02:00
|
|
|
&wid, ss, &n)
|
2002-04-14 04:56:19 +02:00
|
|
|
&& n == strlen(label)) {
|
|
|
|
|
|
|
|
|
|
bool signed_flag = false;
|
|
|
|
|
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
|
|
|
|
case 's':
|
|
|
|
|
signed_flag = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'u':
|
|
|
|
|
signed_flag = false;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
|
|
|
|
sym_set_value(sym_vpi, label, val);
|
|
|
|
|
|
2003-01-26 19:16:22 +01:00
|
|
|
} else if (2 == sscanf(label, "W<%u,%[r]>%n", &base, ss, &n)
|
|
|
|
|
&& n == strlen(label)) {
|
|
|
|
|
|
|
|
|
|
val.ptr = vpip_make_vthr_word(base, ss);
|
|
|
|
|
sym_set_value(sym_vpi, label, val);
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
2003-01-26 19:16:22 +01:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!val.ptr) {
|
|
|
|
|
// check for memory word M<mem,base,wid>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val.ptr) {
|
|
|
|
|
*handle = (vpiHandle) val.ptr;
|
|
|
|
|
free(label);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
if (mes)
|
|
|
|
|
fprintf(stderr, "unresolved vpi name lookup: %s\n", label);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void compile_vpi_lookup(vpiHandle *handle, char*label)
|
|
|
|
|
{
|
2002-12-21 01:55:57 +01:00
|
|
|
if (strcmp(label, "$time") == 0) {
|
|
|
|
|
*handle = vpip_sim_time(vpip_peek_current_scope());
|
|
|
|
|
free(label);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp(label, "$stime") == 0) {
|
|
|
|
|
*handle = vpip_sim_time(vpip_peek_current_scope());
|
|
|
|
|
free(label);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-27 01:14:37 +01:00
|
|
|
if (strcmp(label, "$realtime") == 0) {
|
2003-02-01 06:50:04 +01:00
|
|
|
*handle = vpip_sim_realtime(vpip_peek_current_scope());
|
2003-01-27 01:14:37 +01:00
|
|
|
free(label);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-03 02:09:20 +01:00
|
|
|
if (strcmp(label, "$simtime") == 0) {
|
|
|
|
|
*handle = vpip_sim_time(0);
|
|
|
|
|
free(label);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-10 06:31:09 +02:00
|
|
|
struct vpi_handle_resolv_list_s*res
|
|
|
|
|
= new struct vpi_handle_resolv_list_s;
|
2001-08-09 21:38:23 +02:00
|
|
|
|
|
|
|
|
res->handle = handle;
|
|
|
|
|
res->label = label;
|
2001-08-10 06:31:09 +02:00
|
|
|
resolv_submit(res);
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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)
|
2003-07-03 22:03:36 +02:00
|
|
|
code->cptr2 = reinterpret_cast<vvp_code_t>(val.ptr);
|
2001-08-09 21:38:23 +02:00
|
|
|
else
|
2003-07-03 22:03:36 +02:00
|
|
|
code->cptr = reinterpret_cast<vvp_code_t>(val.ptr);
|
2001-08-09 21:38:23 +02:00
|
|
|
free(label);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mes)
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"unresolved code label: %s\n",
|
|
|
|
|
label);
|
|
|
|
|
|
|
|
|
|
return false;
|
2001-03-25 05:54:26 +02:00
|
|
|
}
|
|
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
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;
|
2001-08-09 21:38:23 +02:00
|
|
|
|
|
|
|
|
res->code = code;
|
|
|
|
|
res->label = label;
|
|
|
|
|
|
2001-08-10 06:31:09 +02:00
|
|
|
resolv_submit(res);
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
2001-03-25 05:54:26 +02:00
|
|
|
|
2002-09-18 04:55:18 +02:00
|
|
|
/*
|
|
|
|
|
* Lookup memories.
|
|
|
|
|
*/
|
|
|
|
|
struct memory_resolv_list_s: public resolv_list_s {
|
|
|
|
|
struct vvp_code_s *code;
|
|
|
|
|
char *label;
|
|
|
|
|
virtual bool resolve(bool mes);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool memory_resolv_list_s::resolve(bool mes)
|
|
|
|
|
{
|
|
|
|
|
code->mem = memory_find(label);
|
|
|
|
|
if (code->mem != 0) {
|
|
|
|
|
free(label);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
res->code = code;
|
|
|
|
|
res->label = label;
|
|
|
|
|
|
|
|
|
|
resolv_submit(res);
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
/*
|
|
|
|
|
* 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;
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-07-15 02:21:42 +02:00
|
|
|
if (verbose_flag) {
|
|
|
|
|
fprintf(stderr, " ... Linking\n");
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-09 21:38:23 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-10-09 18:57:47 +02:00
|
|
|
if (nerrs && last)
|
2004-10-04 03:10:51 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"compile_cleanup: %d unresolved items\n",
|
2001-08-09 21:38:23 +02:00
|
|
|
nerrs);
|
2001-10-09 18:57:47 +02:00
|
|
|
} while (nerrs && !last);
|
2001-08-09 21:38:23 +02:00
|
|
|
|
|
|
|
|
compile_errors += nerrs;
|
2002-07-05 04:50:57 +02:00
|
|
|
|
2002-07-15 02:21:42 +02:00
|
|
|
if (verbose_flag) {
|
|
|
|
|
fprintf(stderr, " ... Removing symbol tables\n");
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-05 06:40:59 +02:00
|
|
|
/* After compile is complete, the vpi symbol table is no
|
|
|
|
|
longer needed. VPI objects are located by following
|
|
|
|
|
scopes. */
|
2002-07-05 04:50:57 +02:00
|
|
|
delete_symbol_table(sym_vpi);
|
|
|
|
|
sym_vpi = 0;
|
2002-07-05 06:40:59 +02:00
|
|
|
|
|
|
|
|
/* Don't need the code labels. The instructions have numeric
|
|
|
|
|
pointers in them, the symbol table is no longer needed. */
|
|
|
|
|
delete_symbol_table(sym_codespace);
|
|
|
|
|
sym_codespace = 0;
|
|
|
|
|
|
|
|
|
|
delete_symbol_table(sym_functors);
|
|
|
|
|
sym_functors = 0;
|
2001-08-09 21:38:23 +02:00
|
|
|
}
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2001-03-31 21:00:43 +02: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)
|
|
|
|
|
{
|
2001-03-21 06:13:03 +01:00
|
|
|
sym_vpi = new_symbol_table();
|
2001-03-31 21:00:43 +02:00
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
sym_functors = new_symbol_table();
|
|
|
|
|
functor_init();
|
2001-03-31 21:00:43 +02:00
|
|
|
|
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)
|
|
|
|
|
{
|
2001-07-26 05:13:51 +02:00
|
|
|
vpip_load_module(name);
|
2001-03-23 03:40:22 +01:00
|
|
|
free(name);
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-01 01:03:16 +02:00
|
|
|
void compile_vpi_time_precision(long pre)
|
|
|
|
|
{
|
|
|
|
|
vpip_set_time_precision(pre);
|
|
|
|
|
}
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
/*
|
2004-12-11 03:31:25 +01:00
|
|
|
* Run through the arguments looking for the nodes that are
|
2001-04-28 22:24:03 +02:00
|
|
|
* 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.
|
2004-10-04 03:10:51 +02:00
|
|
|
*
|
2001-04-28 22:24:03 +02:00
|
|
|
* If the source functor is not declared yet, then don't do
|
2001-04-30 05:53:19 +02:00
|
|
|
* 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.
|
|
|
|
|
*/
|
2001-04-28 22:24:03 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
void input_connect(vvp_net_t*fdx, unsigned port, char*label)
|
2001-04-28 22:24:03 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_ptr_t ifdx = vvp_net_ptr_t(fdx, port);
|
|
|
|
|
char*tp;
|
|
|
|
|
|
|
|
|
|
/* Is this a vvp_vector4_t constant value? */
|
|
|
|
|
if ((strncmp(label, "C4<", 3) == 0)
|
|
|
|
|
&& ((tp = strchr(label,'>')))
|
|
|
|
|
&& (tp[1] == 0)
|
|
|
|
|
&& (strspn(label+3, "01xz") == (tp-label-3))) {
|
|
|
|
|
|
|
|
|
|
size_t v4size = tp-label-3;
|
|
|
|
|
vvp_vector4_t tmp (v4size);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < v4size ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit;
|
|
|
|
|
switch (label[3+idx]) {
|
|
|
|
|
case '0':
|
|
|
|
|
bit = BIT4_0;
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
bit = BIT4_1;
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
bit = BIT4_X;
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
bit = BIT4_Z;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
tmp.set_bit(v4size-idx-1, bit);
|
|
|
|
|
}
|
2001-04-28 22:24:03 +02:00
|
|
|
|
2005-01-29 18:53:25 +01:00
|
|
|
// Inputs that are constants are schedule to execute as
|
|
|
|
|
// soon at the simulation starts. In Verilog, constants
|
|
|
|
|
// start propagating when the simulation starts, just
|
|
|
|
|
// like any other signal value. But letting the
|
|
|
|
|
// scheduler distribute the constant value has the
|
|
|
|
|
// additional advantage that the constant is not
|
|
|
|
|
// propagated until the network is fully linked.
|
|
|
|
|
schedule_set_vector(ifdx, tmp);
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
free(label);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-07-28 05:12:39 +02:00
|
|
|
|
2005-02-12 04:27:18 +01:00
|
|
|
/* Is this a vvp_vector8_t constant value? */
|
|
|
|
|
if ((strncmp(label, "C8<", 3) == 0)
|
|
|
|
|
&& ((tp = strchr(label,'>')))
|
|
|
|
|
&& (tp[1] == 0)
|
|
|
|
|
&& (strspn(label+3, "01234567xz") == (tp-label-3))) {
|
|
|
|
|
|
|
|
|
|
size_t vsize = tp-label-3;
|
|
|
|
|
assert(vsize%3 == 0);
|
|
|
|
|
vsize /= 3;
|
|
|
|
|
|
|
|
|
|
vvp_vector8_t tmp (vsize);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < vsize ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit = BIT4_Z;
|
|
|
|
|
unsigned dr0 = label[3+idx*3+0] - '0';
|
|
|
|
|
unsigned dr1 = label[3+idx*3+1] - '0';
|
|
|
|
|
|
|
|
|
|
switch (label[3+idx*3+2]) {
|
|
|
|
|
case '0':
|
|
|
|
|
bit = BIT4_0;
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
bit = BIT4_1;
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
bit = BIT4_X;
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
bit = BIT4_Z;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
tmp.set_bit(vsize-idx-1, vvp_scalar_t(bit, dr0, dr1));
|
2005-02-12 04:27:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
schedule_set_vector(ifdx, tmp);
|
|
|
|
|
|
|
|
|
|
free(label);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/* Handle the general case that this is a label for a node in
|
|
|
|
|
the vvp net. This arranges for the label to be preserved in
|
|
|
|
|
a linker list, and linked when the symbol table is
|
|
|
|
|
complete. */
|
|
|
|
|
postpone_functor_input(ifdx, label);
|
|
|
|
|
}
|
2001-05-09 04:53:25 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
void inputs_connect(vvp_net_t*fdx, unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert(argc <= 4);
|
2001-10-31 05:27:46 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
for (unsigned idx = 0; idx < argc; idx += 1) {
|
2001-05-09 04:53:25 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
input_connect(fdx, idx, argv[idx].text);
|
2001-04-30 05:53:19 +02:00
|
|
|
}
|
2001-04-28 22:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2001-10-09 18:57:47 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
struct const_functor_s: public functor_s {
|
2004-10-04 03:10:51 +02:00
|
|
|
const_functor_s(unsigned str0, unsigned str1)
|
2001-10-31 05:27:46 +01:00
|
|
|
{ odrive0 = str0; odrive1 = str1; }
|
2004-10-04 03:10:51 +02:00
|
|
|
virtual void set(vvp_ipoint_t, bool, unsigned, unsigned);
|
2001-10-31 05:27:46 +01:00
|
|
|
};
|
2004-10-04 03:10:51 +02:00
|
|
|
void const_functor_s::set(vvp_ipoint_t p, bool, unsigned val, unsigned)
|
2001-10-31 05:27:46 +01:00
|
|
|
{
|
2002-03-08 06:41:45 +01:00
|
|
|
fprintf(stderr, "internal error: Set value to const_functor 0x%x\n", p);
|
|
|
|
|
fprintf(stderr, " : Value is %u, trying to set %u\n",
|
|
|
|
|
oval, val);
|
|
|
|
|
fprintf(stderr, " : I'm driving functor 0x%x\n", out);
|
|
|
|
|
assert(0);
|
2001-10-31 05:27:46 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
#if 0
|
2004-10-04 03:10:51 +02:00
|
|
|
static vvp_ipoint_t make_const_functor(unsigned val,
|
|
|
|
|
unsigned str0,
|
2001-10-09 18:57:47 +02:00
|
|
|
unsigned str1)
|
|
|
|
|
{
|
|
|
|
|
vvp_ipoint_t fdx = functor_allocate(1);
|
2001-10-31 05:27:46 +01:00
|
|
|
functor_t obj = new const_functor_s(str0, str1);
|
|
|
|
|
functor_define(fdx, obj);
|
|
|
|
|
|
2001-12-06 04:31:24 +01:00
|
|
|
obj->put_oval(val, false);
|
2001-10-31 05:27:46 +01:00
|
|
|
|
2001-10-09 18:57:47 +02:00
|
|
|
return fdx;
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
#endif
|
2001-10-09 18:57:47 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
/* Lookup a functor[idx] and save the ipoint in *ref. */
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
#if 0
|
2001-10-09 18:57:47 +02:00
|
|
|
static void functor_reference(vvp_ipoint_t *ref, char *lab, unsigned idx)
|
|
|
|
|
{
|
2001-10-12 04:53:47 +02:00
|
|
|
if (lab == 0)
|
|
|
|
|
*ref = make_const_functor(3,6,6);
|
|
|
|
|
|
|
|
|
|
else if (strcmp(lab, "C<0>") == 0)
|
|
|
|
|
*ref = make_const_functor(0,6,6);
|
|
|
|
|
|
|
|
|
|
else if (strcmp(lab, "C<su0>") == 0)
|
|
|
|
|
*ref = make_const_functor(0,7,7);
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
else if (strcmp(lab, "C<pu0>") == 0)
|
2001-10-12 04:53:47 +02:00
|
|
|
*ref = make_const_functor(0,5,5);
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
else if (strcmp(lab, "C<we0>") == 0)
|
2002-01-06 04:15:13 +01:00
|
|
|
*ref = make_const_functor(0,3,3);
|
|
|
|
|
|
2001-10-12 04:53:47 +02:00
|
|
|
else if (strcmp(lab, "C<1>") == 0)
|
|
|
|
|
*ref = make_const_functor(1,6,6);
|
2001-10-09 18:57:47 +02:00
|
|
|
|
2001-10-12 04:53:47 +02:00
|
|
|
else if (strcmp(lab, "C<su1>") == 0)
|
|
|
|
|
*ref = make_const_functor(1,7,7);
|
|
|
|
|
|
|
|
|
|
else if (strcmp(lab, "C<pu1>") == 0)
|
|
|
|
|
*ref = make_const_functor(1,5,5);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-01-06 04:15:13 +01:00
|
|
|
else if (strcmp(lab, "C<we1>") == 0)
|
|
|
|
|
*ref = make_const_functor(1,3,3);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-10-12 04:53:47 +02:00
|
|
|
else if (strcmp(lab, "C<x>") == 0)
|
|
|
|
|
*ref = make_const_functor(2,6,6);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-10-12 04:53:47 +02:00
|
|
|
else if (strcmp(lab, "C<z>") == 0)
|
|
|
|
|
*ref = make_const_functor(3,6,6);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-10-12 04:53:47 +02:00
|
|
|
else {
|
2001-10-09 18:57:47 +02:00
|
|
|
functor_ref_lookup(ref, lab, idx);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
free(lab);
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
#endif
|
2001-10-09 18:57:47 +02:00
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
static void make_arith(vvp_arith_ *arith,
|
2004-10-04 03:10:51 +02:00
|
|
|
char*label, long wid,
|
2001-10-31 05:27:46 +01:00
|
|
|
unsigned argc, struct symb_s*argv)
|
2001-06-07 05:09:03 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t* ptr = new vvp_net_t;
|
|
|
|
|
ptr->fun = arith;
|
2001-10-31 05:27:46 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
define_functor_symbol(label, ptr);
|
2001-10-31 05:27:46 +01:00
|
|
|
free(label);
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(argc == 2);
|
|
|
|
|
inputs_connect(ptr, argc, argv);
|
2001-06-07 05:09:03 +02:00
|
|
|
|
|
|
|
|
free(argv);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-30 04:15:57 +02:00
|
|
|
void compile_arith_div(char*label, long wid, bool signed_flag,
|
2001-10-16 04:47:37 +02:00
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2005-02-19 02:32:52 +01:00
|
|
|
if (argc != 2) {
|
2005-01-28 06:34:25 +01:00
|
|
|
fprintf(stderr, "%s; .arith/div has wrong number of symbols\n", label);
|
2001-10-16 04:47:37 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-30 04:15:57 +02:00
|
|
|
vvp_arith_ *arith = new vvp_arith_div(wid, signed_flag);
|
2001-10-31 05:27:46 +01:00
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-10-16 04:47:37 +02:00
|
|
|
}
|
|
|
|
|
|
2002-01-03 05:19:01 +01:00
|
|
|
void compile_arith_mod(char*label, long wid,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2005-03-12 07:42:28 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .arith/mod has wrong number of symbols\n", label);
|
2002-01-03 05:19:01 +01:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 07:42:28 +01:00
|
|
|
vvp_arith_ *arith = new vvp_arith_mod(wid, false);
|
2002-01-03 05:19:01 +01:00
|
|
|
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-17 01:45:05 +02:00
|
|
|
void compile_arith_mult(char*label, long wid,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2005-01-28 06:34:25 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .arith/mult has wrong number of symbols\n", label);
|
2001-06-17 01:45:05 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
vvp_arith_ *arith = new vvp_arith_mult(wid);
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-06-17 01:45:05 +02:00
|
|
|
}
|
|
|
|
|
|
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 );
|
|
|
|
|
|
2005-01-30 06:06:49 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .arith has wrong number of symbols\n", label);
|
2001-06-05 05:05:41 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
vvp_arith_ *arith = new vvp_arith_sub(wid);
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-06-07 05:09:03 +02:00
|
|
|
}
|
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
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .arith has wrong number of symbols\n", label);
|
2001-06-07 05:09:03 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
2001-06-05 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
vvp_arith_ *arith = new vvp_arith_sum(wid);
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-06-05 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
2005-01-22 02:06:20 +01:00
|
|
|
void compile_cmp_eeq(char*label, long wid,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .cmp/eeq has wrong number of symbols\n",label);
|
|
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_arith_ *arith = new vvp_cmp_eeq(wid);
|
|
|
|
|
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-09 06:52:03 +01:00
|
|
|
void compile_cmp_nee(char*label, long wid,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .cmp/eeq has wrong number of symbols\n",label);
|
|
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_arith_ *arith = new vvp_cmp_nee(wid);
|
|
|
|
|
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-16 18:33:25 +02:00
|
|
|
void compile_cmp_eq(char*label, long wid, unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2005-01-22 17:21:11 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .cmp/eq has wrong number of symbols\n",label);
|
2004-06-16 18:33:25 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_arith_ *arith = new vvp_cmp_eq(wid);
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void compile_cmp_ne(char*label, long wid, unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2005-01-22 17:21:11 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .cmp/ne has wrong number of symbols\n",label);
|
2004-06-16 18:33:25 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_arith_ *arith = new vvp_cmp_ne(wid);
|
|
|
|
|
make_arith(arith, label, wid, argc, argv);
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-11 07:15:38 +02:00
|
|
|
void compile_cmp_ge(char*label, long wid, bool signed_flag,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
2001-06-15 06:07:57 +02:00
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2005-01-16 05:19:08 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf(stderr, "%s .cmp/ge has wrong number of symbols\n", label);
|
2001-06-15 06:07:57 +02:00
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-11 07:15:38 +02:00
|
|
|
vvp_arith_ *arith = new vvp_cmp_ge(wid, signed_flag);
|
2001-06-15 06:07:57 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-06-15 06:07:57 +02:00
|
|
|
}
|
|
|
|
|
|
2003-04-11 07:15:38 +02:00
|
|
|
void compile_cmp_gt(char*label, long wid, bool signed_flag,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
2001-06-15 06:07:57 +02:00
|
|
|
{
|
|
|
|
|
assert( wid > 0 );
|
|
|
|
|
|
2001-08-08 03:05:06 +02:00
|
|
|
if ((long)argc != 2*wid) {
|
2001-06-15 06:07:57 +02:00
|
|
|
fprintf(stderr, "%s; .cmp has wrong number of symbols\n", label);
|
|
|
|
|
compile_errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-11 07:15:38 +02:00
|
|
|
vvp_arith_ *arith = new vvp_cmp_gt(wid, signed_flag);
|
2001-06-15 06:07:57 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-06-15 06:07:57 +02:00
|
|
|
}
|
|
|
|
|
|
2001-07-07 04:57:33 +02:00
|
|
|
|
2001-07-06 07:02:43 +02:00
|
|
|
/*
|
|
|
|
|
* 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 );
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
vvp_arith_ *arith = new vvp_shiftl(wid);
|
2005-03-19 07:23:49 +01:00
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-07-07 04:57:33 +02:00
|
|
|
}
|
2001-07-06 07:02:43 +02:00
|
|
|
|
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
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
vvp_arith_ *arith = new vvp_shiftr(wid);
|
2005-03-19 07:23:49 +01:00
|
|
|
make_arith(arith, label, wid, argc, argv);
|
2001-07-06 06:46:44 +02:00
|
|
|
}
|
|
|
|
|
|
2001-05-09 04:53:25 +02:00
|
|
|
void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
|
|
|
|
assert(argc <= 4);
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_fun_t* obj = 0;
|
2001-05-09 04:53:25 +02:00
|
|
|
|
2001-05-12 22:38:06 +02:00
|
|
|
if (strcmp(type,"tri") == 0) {
|
2005-03-12 05:27:42 +01:00
|
|
|
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0));
|
2001-12-15 02:54:38 +01:00
|
|
|
|
|
|
|
|
} else if (strcmp(type,"tri0") == 0) {
|
2005-03-12 05:27:42 +01:00
|
|
|
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5));
|
2001-12-15 02:54:38 +01:00
|
|
|
|
|
|
|
|
} else if (strcmp(type,"tri1") == 0) {
|
2005-03-12 05:27:42 +01:00
|
|
|
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5));
|
2001-05-12 22:38:06 +02:00
|
|
|
|
2003-07-30 03:13:28 +02:00
|
|
|
} else if (strcmp(type,"triand") == 0) {
|
2004-12-11 03:31:25 +01:00
|
|
|
obj = new table_functor_s(ft_TRIAND);
|
2003-07-30 03:13:28 +02:00
|
|
|
|
|
|
|
|
} else if (strcmp(type,"trior") == 0) {
|
2004-12-11 03:31:25 +01:00
|
|
|
obj = new table_functor_s(ft_TRIOR);
|
2003-07-30 03:13:28 +02:00
|
|
|
|
2001-05-12 22:38:06 +02:00
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "invalid resolver type: %s\n", type);
|
|
|
|
|
compile_errors += 1;
|
|
|
|
|
}
|
2001-05-09 04:53:25 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
if (obj) {
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t*net = new vvp_net_t;
|
2004-12-31 06:54:46 +01:00
|
|
|
net->fun = obj;
|
2004-12-11 03:31:25 +01:00
|
|
|
define_functor_symbol(label, net);
|
|
|
|
|
inputs_connect(net, argc, argv);
|
2001-10-31 05:27:46 +01:00
|
|
|
}
|
2001-05-09 04:53:25 +02:00
|
|
|
free(type);
|
2001-10-31 05:27:46 +01:00
|
|
|
free(label);
|
|
|
|
|
free(argv);
|
2001-05-09 04:53:25 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
void compile_force(char*label, struct symb_s signal,
|
|
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
#if 0
|
2001-11-01 04:00:19 +01:00
|
|
|
vvp_ipoint_t ifofu = functor_allocate(argc);
|
|
|
|
|
define_functor_symbol(label, ifofu);
|
|
|
|
|
|
|
|
|
|
for (unsigned i=0; i<argc; i++) {
|
|
|
|
|
functor_t obj = new force_functor_s;
|
|
|
|
|
vvp_ipoint_t iobj = ipoint_index(ifofu, i);
|
|
|
|
|
functor_define(iobj, obj);
|
|
|
|
|
|
|
|
|
|
functor_ref_lookup(&obj->out, strdup(signal.text), signal.idx + i);
|
|
|
|
|
|
|
|
|
|
// connect the force expression, one bit.
|
|
|
|
|
inputs_connect(iobj, 1, &argv[i]);
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
#else
|
|
|
|
|
fprintf(stderr, "XXXX compile_force not implemented\n");
|
|
|
|
|
#endif
|
2001-11-01 04:00:19 +01:00
|
|
|
free(argv);
|
|
|
|
|
free(signal.text);
|
|
|
|
|
free(label);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-24 04:23:58 +02:00
|
|
|
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;
|
2001-07-22 02:04:50 +02:00
|
|
|
u->compile_table(table);
|
2001-04-28 22:24:03 +02:00
|
|
|
free(label);
|
2001-04-24 04:23:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
2001-12-06 04:31:24 +01:00
|
|
|
vvp_delay_t delay,
|
2001-04-24 04:23:58 +02:00
|
|
|
unsigned argc, struct symb_s*argv)
|
|
|
|
|
{
|
2001-10-31 05:27:46 +01:00
|
|
|
struct vvp_udp_s *u = udp_find(type);
|
|
|
|
|
assert (argc == u->nin);
|
2004-12-11 03:31:25 +01:00
|
|
|
#if 0
|
2001-10-31 05:27:46 +01:00
|
|
|
functor_t udp = new udp_functor_s(u);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
unsigned nfun = (argc+3)/4;
|
|
|
|
|
vvp_ipoint_t fdx = functor_allocate(nfun);
|
|
|
|
|
functor_define(fdx, udp);
|
|
|
|
|
define_functor_symbol(label, fdx);
|
2004-10-04 03:10:51 +02:00
|
|
|
free(label);
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
if (nfun > 1) {
|
|
|
|
|
for (unsigned i=0; i < nfun-1; i++) {
|
|
|
|
|
functor_t fu = new edge_inputs_functor_s;
|
|
|
|
|
vvp_ipoint_t ipt = ipoint_index(fdx, i+1);
|
|
|
|
|
functor_define(ipt, fu);
|
|
|
|
|
fu->out = fdx;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-10-11 20:29:21 +02:00
|
|
|
|
2001-12-06 04:31:24 +01:00
|
|
|
udp->delay = delay;
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
inputs_connect(fdx, argc, argv);
|
|
|
|
|
free(argv);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
if (u->sequ)
|
2001-12-06 04:31:24 +01:00
|
|
|
udp->put_oval(u->init, false);
|
2004-12-11 03:31:25 +01:00
|
|
|
#else
|
|
|
|
|
fprintf(stderr, "XXXX compile_udp_functor not implemented\n");
|
|
|
|
|
#endif
|
2001-04-24 04:23:58 +02:00
|
|
|
}
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
/*
|
|
|
|
|
* Take the detailed parse items from a .mem statement and generate
|
|
|
|
|
* the necessary internal structures.
|
|
|
|
|
*
|
|
|
|
|
* <label> .mem <name>, <msb>, <lsb>, <idxs...> ;
|
|
|
|
|
*
|
|
|
|
|
*/
|
2001-05-01 03:09:39 +02:00
|
|
|
void compile_memory(char *label, char *name, int msb, int lsb,
|
2005-03-03 05:33:10 +01:00
|
|
|
unsigned narg, long *args)
|
2001-05-01 03:09:39 +02:00
|
|
|
{
|
2005-03-03 05:33:10 +01:00
|
|
|
/* Create an empty memory in the symbol table. */
|
|
|
|
|
vvp_memory_t mem = memory_create(label);
|
2001-05-09 01:59:33 +02:00
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
assert( narg > 0 && narg%2 == 0 );
|
2001-05-09 01:59:33 +02:00
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
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);
|
2001-05-01 03:09:39 +02:00
|
|
|
}
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
void compile_memory_port(char *label, char *memid,
|
2001-05-01 03:09:39 +02:00
|
|
|
unsigned argc, struct symb_s *argv)
|
|
|
|
|
{
|
2005-03-09 05:52:40 +01:00
|
|
|
vvp_memory_t mem = memory_find(memid);
|
|
|
|
|
free(memid);
|
|
|
|
|
assert(mem);
|
2001-06-15 05:28:30 +02:00
|
|
|
|
2005-03-09 05:52:40 +01:00
|
|
|
vvp_net_t*ptr = new vvp_net_t;
|
|
|
|
|
vvp_fun_memport*fun = new vvp_fun_memport(mem, ptr);
|
|
|
|
|
ptr->fun = fun;
|
2001-05-01 03:09:39 +02:00
|
|
|
|
2005-03-09 05:52:40 +01:00
|
|
|
define_functor_symbol(label, ptr);
|
|
|
|
|
free(label);
|
2001-05-01 03:09:39 +02:00
|
|
|
|
2005-03-09 05:52:40 +01:00
|
|
|
inputs_connect(ptr, argc, argv);
|
|
|
|
|
free(argv);
|
2001-05-01 03:09:39 +02:00
|
|
|
}
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
/*
|
|
|
|
|
* 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)
|
2001-05-01 03:09:39 +02:00
|
|
|
{
|
2005-03-03 05:33:10 +01:00
|
|
|
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;
|
2001-05-01 03:09:39 +02:00
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
/*
|
2001-10-31 05:27:46 +01:00
|
|
|
* The parser uses this function to compile and link an executable
|
2001-03-11 01:29:38 +01:00
|
|
|
* opcode. I do this by looking up the opcode in the opcode_table. The
|
2003-02-10 00:33:26 +01:00
|
|
|
* table gives the operand structure that is acceptable, so I can
|
2001-03-11 01:29:38 +01:00
|
|
|
* 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. */
|
2004-10-04 03:10:51 +02:00
|
|
|
if (label)
|
2001-08-09 21:38:23 +02:00
|
|
|
compile_codelabel(label);
|
|
|
|
|
|
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");
|
2004-12-15 18:17:42 +01:00
|
|
|
compile_errors += 1;
|
2001-03-11 01:29:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(op);
|
|
|
|
|
|
|
|
|
|
/* Build up the code from the information about the opcode and
|
2001-08-08 03:05:06 +02:00
|
|
|
the information from the compiler. */
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t code = codespace_allocate();
|
2001-03-11 01:29:38 +01:00
|
|
|
code->opcode = op->opcode;
|
|
|
|
|
|
|
|
|
|
if (op->argc != (opa? opa->argc : 0)) {
|
|
|
|
|
yyerror("operand count");
|
2004-12-15 18:17:42 +01:00
|
|
|
compile_errors += 1;
|
2001-03-11 01:29:38 +01:00
|
|
|
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-11-01 04:00:19 +01:00
|
|
|
code->bit_idx[0] = opa->argv[idx].numb;
|
2001-03-12 00:06:49 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OA_BIT2:
|
|
|
|
|
if (opa->argv[idx].ltype != L_NUMB) {
|
|
|
|
|
yyerror("operand format");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-11-01 04:00:19 +01:00
|
|
|
code->bit_idx[1] = 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);
|
2001-08-09 21:38:23 +02:00
|
|
|
code_label_lookup(code, opa->argv[idx].symb.text);
|
2001-03-11 01:29:38 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OA_FUNC_PTR:
|
2001-06-10 19:12:51 +02:00
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
functor_ref_lookup(&code->net, opa->argv[idx].symb.text);
|
2001-03-11 01:29:38 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
case OA_FUNC_PTR2:
|
|
|
|
|
/* The operand is a functor. Resolve the label to
|
|
|
|
|
a functor pointer, or postpone the resolution
|
|
|
|
|
if it is not defined yet. */
|
|
|
|
|
if (opa->argv[idx].ltype != L_SYMB) {
|
|
|
|
|
yyerror("operand format");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
functor_ref_lookup(&code->net2, opa->argv[idx].symb.text);
|
2001-11-01 04:00:19 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
case OA_NUMBER:
|
|
|
|
|
if (opa->argv[idx].ltype != L_NUMB) {
|
|
|
|
|
yyerror("operand format");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
code->number = opa->argv[idx].numb;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-05-03 01:16:50 +02:00
|
|
|
case OA_MEM_PTR:
|
2001-05-01 03:09:39 +02:00
|
|
|
if (opa->argv[idx].ltype != L_SYMB) {
|
|
|
|
|
yyerror("operand format");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-18 04:55:18 +02:00
|
|
|
compile_mem_lookup(code, opa->argv[idx].symb.text);
|
2001-05-01 03:09:39 +02:00
|
|
|
break;
|
|
|
|
|
|
2002-08-28 19:15:06 +02:00
|
|
|
case OA_VPI_PTR:
|
|
|
|
|
/* The operand is a functor. Resolve the label to
|
|
|
|
|
a functor pointer, or postpone the resolution
|
|
|
|
|
if it is not defined yet. */
|
|
|
|
|
if (opa->argv[idx].ltype != L_SYMB) {
|
|
|
|
|
yyerror("operand format");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
compile_vpi_lookup(&code->handle, opa->argv[idx].symb.text);
|
|
|
|
|
break;
|
2001-03-11 01:29:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opa) free(opa);
|
|
|
|
|
|
|
|
|
|
free(mnem);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 08:40:44 +02:00
|
|
|
void compile_codelabel(char*label)
|
|
|
|
|
{
|
|
|
|
|
symbol_value_t val;
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t ptr = codespace_next();
|
2001-04-01 08:40:44 +02:00
|
|
|
|
2003-07-03 22:03:36 +02:00
|
|
|
val.ptr = ptr;
|
2001-04-01 08:40:44 +02:00
|
|
|
sym_set_value(sym_codespace, label, val);
|
|
|
|
|
|
|
|
|
|
free(label);
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-23 03:04:07 +02:00
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
void compile_disable(char*label, struct symb_s symb)
|
|
|
|
|
{
|
2004-10-04 03:10:51 +02:00
|
|
|
if (label)
|
2001-08-09 21:38:23 +02:00
|
|
|
compile_codelabel(label);
|
2001-04-18 06:21:23 +02:00
|
|
|
|
|
|
|
|
/* Fill in the basics of the %disable in the instruction. */
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t code = codespace_allocate();
|
2001-04-18 06:21:23 +02:00
|
|
|
code->opcode = of_DISABLE;
|
|
|
|
|
|
2001-07-11 06:43:57 +02:00
|
|
|
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)
|
|
|
|
|
{
|
2004-10-04 03:10:51 +02:00
|
|
|
if (label)
|
2001-08-09 21:38:23 +02:00
|
|
|
compile_codelabel(label);
|
2001-04-18 06:21:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fill in the basics of the %fork in the instruction. */
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t code = codespace_allocate();
|
2001-04-18 06:21:23 +02:00
|
|
|
code->opcode = of_FORK;
|
|
|
|
|
|
|
|
|
|
/* Figure out the target PC. */
|
2001-08-09 21:38:23 +02:00
|
|
|
code_label_lookup(code, dest.text);
|
2001-04-18 06:21:23 +02:00
|
|
|
|
|
|
|
|
/* Figure out the target SCOPE. */
|
2001-11-01 04:00:19 +01:00
|
|
|
compile_vpi_lookup((vpiHandle*)&code->scope, scope.text);
|
2001-04-18 06:21:23 +02:00
|
|
|
}
|
|
|
|
|
|
2001-03-18 05:35:18 +01:00
|
|
|
void compile_vpi_call(char*label, char*name, unsigned argc, vpiHandle*argv)
|
2001-03-16 02:44:34 +01:00
|
|
|
{
|
2001-08-09 21:38:23 +02:00
|
|
|
if (label)
|
|
|
|
|
compile_codelabel(label);
|
2001-03-16 02:44:34 +01:00
|
|
|
|
|
|
|
|
/* Create an instruction in the code space. */
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t code = codespace_allocate();
|
2001-03-16 02:44:34 +01:00
|
|
|
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,
|
2003-01-27 01:14:37 +01:00
|
|
|
unsigned vbit, int vwid,
|
2001-05-20 02:46:12 +02:00
|
|
|
unsigned argc, vpiHandle*argv)
|
|
|
|
|
{
|
2004-10-04 03:10:51 +02:00
|
|
|
if (label)
|
2001-08-09 21:38:23 +02:00
|
|
|
compile_codelabel(label);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-05-20 02:46:12 +02:00
|
|
|
/* Create an instruction in the code space. */
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t code = codespace_allocate();
|
2001-05-20 02:46:12 +02:00
|
|
|
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);
|
2001-03-22 23:38:13 +01:00
|
|
|
if (code->handle == 0)
|
|
|
|
|
compile_errors += 1;
|
2001-03-16 02:44:34 +01:00
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
2003-09-04 22:26:30 +02:00
|
|
|
void compile_thread(char*start_sym, char*flag)
|
2001-03-11 01:29:38 +01:00
|
|
|
{
|
2003-09-04 22:26:30 +02:00
|
|
|
bool push_flag = false;
|
|
|
|
|
|
2001-03-18 01:37:55 +01:00
|
|
|
symbol_value_t tmp = sym_get_value(sym_codespace, start_sym);
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t pc = reinterpret_cast<vvp_code_t>(tmp.ptr);
|
2001-03-11 01:29:38 +01:00
|
|
|
if (pc == 0) {
|
|
|
|
|
yyerror("unresolved address");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-04 22:26:30 +02:00
|
|
|
if (flag && (strcmp(flag,"$push") == 0))
|
|
|
|
|
push_flag = true;
|
|
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
vthread_t thr = vthread_new(pc, vpip_peek_current_scope());
|
2003-09-04 22:26:30 +02:00
|
|
|
schedule_vthread(thr, 0, push_flag);
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
free(start_sym);
|
2003-09-04 22:26:30 +02:00
|
|
|
if (flag != 0)
|
|
|
|
|
free(flag);
|
2001-03-11 01:29:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A variable is a special functor, so we allocate that functor and
|
|
|
|
|
* write the label into the symbol table.
|
|
|
|
|
*/
|
2001-04-05 03:34:26 +02:00
|
|
|
void compile_variable(char*label, char*name, int msb, int lsb,
|
2002-06-21 06:58:55 +02:00
|
|
|
char 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;
|
2001-04-28 22:24:03 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_fun_signal*vsig = new vvp_fun_signal(wid);
|
|
|
|
|
vvp_net_t*node = new vvp_net_t;
|
|
|
|
|
node->fun = vsig;
|
|
|
|
|
define_functor_symbol(label, node);
|
2001-03-20 07:16:23 +01:00
|
|
|
|
|
|
|
|
/* Make the vpiHandle for the reg. */
|
2002-06-21 06:58:55 +02:00
|
|
|
vpiHandle obj = (signed_flag > 1) ?
|
2004-12-11 03:31:25 +01:00
|
|
|
vpip_make_int(name, msb, lsb, node) :
|
|
|
|
|
vpip_make_reg(name, msb, lsb, signed_flag!=0, node);
|
2001-03-21 06:13:03 +01:00
|
|
|
compile_vpi_symbol(label, obj);
|
2001-06-10 18:47:49 +02:00
|
|
|
vpip_attach_to_current_scope(obj);
|
2001-03-21 06:13:03 +01:00
|
|
|
|
|
|
|
|
free(label);
|
2002-07-05 19:14:15 +02:00
|
|
|
free(name);
|
2001-03-11 01:29:38 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/*
|
|
|
|
|
* Here we handle .net records from the vvp source:
|
|
|
|
|
*
|
|
|
|
|
* <label> .net <name>, <msb>, <lsb>, <input> ;
|
|
|
|
|
* <label> .net/s <name>, <msb>, <lsb>, <input> ;
|
|
|
|
|
*
|
|
|
|
|
* Create a VPI handle to represent it, and fill that handle in with
|
|
|
|
|
* references into the net.
|
|
|
|
|
*/
|
2001-04-05 03:34:26 +02:00
|
|
|
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;
|
2001-04-28 22:24:03 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_t*node = new vvp_net_t;
|
2001-03-25 01:35:35 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_fun_signal*vsig = new vvp_fun_signal(wid);
|
|
|
|
|
node->fun = vsig;
|
2001-03-25 01:35:35 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/* Add the label into the functor symbol table. */
|
|
|
|
|
define_functor_symbol(label, node);
|
|
|
|
|
|
|
|
|
|
assert(argc == 1);
|
|
|
|
|
|
|
|
|
|
/* Connect the source to my input. */
|
|
|
|
|
inputs_connect(node, 1, argv);
|
2001-03-25 01:35:35 +01:00
|
|
|
|
|
|
|
|
/* Make the vpiHandle for the reg. */
|
2004-12-11 03:31:25 +01:00
|
|
|
vpiHandle obj = vpip_make_net(name, msb, lsb, signed_flag, node);
|
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);
|
2002-07-05 19:14:15 +02:00
|
|
|
free(name);
|
2001-03-25 01:35:35 +01:00
|
|
|
free(argv);
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-11 00:37:07 +01:00
|
|
|
void compile_param_string(char*label, char*name, char*str, char*value)
|
|
|
|
|
{
|
|
|
|
|
assert(strcmp(str,"string") == 0);
|
|
|
|
|
free(str);
|
|
|
|
|
|
|
|
|
|
vpiHandle obj = vpip_make_string_param(name, value);
|
|
|
|
|
compile_vpi_symbol(label, obj);
|
|
|
|
|
vpip_attach_to_current_scope(obj);
|
|
|
|
|
|
|
|
|
|
free(label);
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: compile.cc,v $
|
2005-03-22 06:18:34 +01:00
|
|
|
* Revision 1.195 2005/03/22 05:18:34 steve
|
|
|
|
|
* The indexed set can write a vector, not just a bit.
|
|
|
|
|
*
|
2005-03-19 07:23:49 +01:00
|
|
|
* Revision 1.194 2005/03/19 06:23:49 steve
|
|
|
|
|
* Handle LPM shifts.
|
|
|
|
|
*
|
2005-03-12 07:42:28 +01:00
|
|
|
* Revision 1.193 2005/03/12 06:42:28 steve
|
|
|
|
|
* Implement .arith/mod.
|
|
|
|
|
*
|
2005-03-12 05:27:42 +01:00
|
|
|
* Revision 1.192 2005/03/12 04:27:42 steve
|
|
|
|
|
* Implement VPI access to signal strengths,
|
|
|
|
|
* Fix resolution of ambiguous drive pairs,
|
|
|
|
|
* Fix spelling of scalar.
|
|
|
|
|
*
|
2005-03-09 06:52:03 +01:00
|
|
|
* Revision 1.191 2005/03/09 05:52:04 steve
|
|
|
|
|
* Handle case inequality in netlists.
|
|
|
|
|
*
|
2005-03-09 05:52:40 +01:00
|
|
|
* Revision 1.190 2005/03/09 04:52:40 steve
|
|
|
|
|
* reimplement memory ports.
|
|
|
|
|
*
|
2005-03-03 05:33:10 +01:00
|
|
|
* Revision 1.189 2005/03/03 04:33:10 steve
|
|
|
|
|
* Rearrange how memories are supported as vvp_vector4 arrays.
|
|
|
|
|
*
|
2005-02-19 02:32:52 +01:00
|
|
|
* Revision 1.188 2005/02/19 01:32:53 steve
|
|
|
|
|
* Implement .arith/div.
|
|
|
|
|
*
|
2005-02-14 02:50:23 +01:00
|
|
|
* Revision 1.187 2005/02/14 01:50:23 steve
|
|
|
|
|
* Signals may receive part vectors from %set/x0
|
|
|
|
|
* instructions. Re-implement the %set/x0 to do
|
|
|
|
|
* just that. Remove the useless %set/x0/x instruction.
|
|
|
|
|
*
|
2005-02-12 04:27:18 +01:00
|
|
|
* Revision 1.186 2005/02/12 03:27:18 steve
|
|
|
|
|
* Support C8 constants.
|
|
|
|
|
*
|
2005-01-30 06:06:49 +01:00
|
|
|
* Revision 1.185 2005/01/30 05:06:49 steve
|
|
|
|
|
* Get .arith/sub working.
|
|
|
|
|
*
|
2005-01-29 18:53:25 +01:00
|
|
|
* Revision 1.184 2005/01/29 17:53:25 steve
|
|
|
|
|
* Use scheduler to initialize constant functor inputs.
|
|
|
|
|
*
|
2005-01-28 06:34:25 +01:00
|
|
|
* Revision 1.183 2005/01/28 05:34:25 steve
|
|
|
|
|
* Add vector4 implementation of .arith/mult.
|
|
|
|
|
*
|
2005-01-22 17:21:11 +01:00
|
|
|
* Revision 1.182 2005/01/22 16:21:11 steve
|
|
|
|
|
* Implement vectored CMP_EQ and NE
|
|
|
|
|
*
|
2005-01-22 02:06:20 +01:00
|
|
|
* Revision 1.181 2005/01/22 01:06:20 steve
|
|
|
|
|
* Implement the .cmp/eeq LPM node.
|
|
|
|
|
*
|
2005-01-16 05:19:08 +01:00
|
|
|
* Revision 1.180 2005/01/16 04:19:08 steve
|
|
|
|
|
* Reimplement comparators as vvp_vector4_t nodes.
|
|
|
|
|
*
|
2004-12-31 06:54:46 +01:00
|
|
|
* Revision 1.179 2004/12/31 05:54:46 steve
|
|
|
|
|
* Fix uninitialized fun pointer for resolver nodes.
|
|
|
|
|
*
|
2004-12-17 05:47:47 +01:00
|
|
|
* Revision 1.178 2004/12/17 04:47:47 steve
|
|
|
|
|
* Replace single release with release/net and release/reg.
|
|
|
|
|
*
|
2004-12-15 18:17:42 +01:00
|
|
|
* Revision 1.177 2004/12/15 17:17:42 steve
|
|
|
|
|
* Add the force/v instruction.
|
|
|
|
|
*
|
2004-12-11 03:31:25 +01:00
|
|
|
* Revision 1.176 2004/12/11 02:31:29 steve
|
|
|
|
|
* Rework of internals to carry vectors through nexus instead
|
|
|
|
|
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
|
|
|
|
* down this path.
|
2003-05-23 05:44:34 +02:00
|
|
|
*
|
2001-03-11 01:29:38 +01:00
|
|
|
*/
|
|
|
|
|
|