Bring switch information out to the ivl_target API.

This involves defining the API for switches and cleaning up the
elaborated form to match the defined ivl_target API. Also add t-dll
code to support the ivl_switch_t functions, and add stub code that
checks the results.
This commit is contained in:
Stephen Williams 2008-05-23 20:53:10 -07:00
parent 88313670c0
commit ca756f3ec3
13 changed files with 342 additions and 21 deletions

View File

@ -88,6 +88,31 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
return o;
}
ostream& operator << (ostream&o, ivl_switch_type_t val)
{
switch (val) {
case IVL_SW_TRAN:
o << "tran";
break;
case IVL_SW_TRANIF0:
o << "tranif0";
break;
case IVL_SW_TRANIF1:
o << "tranif1";
break;
case IVL_SW_RTRAN:
o << "rtran";
break;
case IVL_SW_RTRANIF0:
o << "rtranif0";
break;
case IVL_SW_RTRANIF1:
o << "rtranif1";
break;
}
return o;
}
static inline void dump_scope_path(ostream&o, const NetScope*scope)
{
if (const NetScope*parent = scope->parent()) {
@ -613,11 +638,7 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
void NetTran::dump_node(ostream&o, unsigned ind) const
{
const char*r = resistive_? "r" : "";
const char*ifx = enable_==0? "" : enable_>0? "if1" : "if0";
o << setw(ind) << "" << r << "tran" << ifx << " " << name() << endl;
o << setw(ind) << "" << type_ << " " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}

View File

@ -666,7 +666,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, false, 0);
cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN);
}
break;
case RTRAN:
@ -676,7 +676,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, true, 0);
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN);
return;
}
break;
@ -687,7 +687,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, false, -1);
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0);
}
break;
case RTRANIF0:
@ -697,7 +697,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, true, -1);
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0);
}
break;
case TRANIF1:
@ -707,7 +707,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, false, 1);
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1);
}
break;
case RTRANIF1:
@ -717,7 +717,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
} else {
cur[idx] = new NetTran(scope, inm, true, 1);
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1);
}
break;
default:

11
ivl.def
View File

@ -152,6 +152,8 @@ ivl_scope_port
ivl_scope_ports
ivl_scope_sigs
ivl_scope_sig
ivl_scope_switch
ivl_scope_switches
ivl_scope_time_precision
ivl_scope_time_units
ivl_scope_type
@ -216,6 +218,15 @@ ivl_stmt_parm_count
ivl_stmt_rval
ivl_stmt_sub_stmt
ivl_switch_a
ivl_switch_b
ivl_switch_basename
ivl_switch_enable
ivl_switch_scope
ivl_switch_type
ivl_switch_attr_cnt;
ivl_switch_attr_val;
ivl_udp_init
ivl_udp_name
ivl_udp_nin

View File

@ -123,6 +123,9 @@ _BEGIN_DECL
* ivl_process_t object holds one of these, but a statement may in
* turn contain other statements.
*
* ivl_switch_t
* Switches are the tran/tranif devices in the design.
*
* -- A Note About Bit Sets --
* Some objects hold a value as an array of bits. In these cases there
* is some method that retrieves the width of the value and another
@ -155,6 +158,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_switch_s *ivl_switch_t;
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
typedef struct ivl_statement_s*ivl_statement_t;
@ -226,6 +230,16 @@ typedef enum ivl_logic_e {
IVL_LO_UDP = 21
} ivl_logic_t;
/* This is the type of a ivl_switch_t object */
typedef enum ivl_switch_type_e {
IVL_SW_TRAN = 0,
IVL_SW_TRANIF0 = 1,
IVL_SW_TRANIF1 = 2,
IVL_SW_RTRAN = 3,
IVL_SW_RTRANIF0 = 4,
IVL_SW_RTRANIF1 = 5
} ivl_switch_type_t;
/* This is the type of an LPM object. */
typedef enum ivl_lpm_type_e {
IVL_LPM_ABS = 32,
@ -1501,6 +1515,8 @@ extern unsigned ivl_scope_ports(ivl_scope_t net);
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_sigs(ivl_scope_t net);
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_switches(ivl_scope_t net);
extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx);
extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net);
extern const char* ivl_scope_tname(ivl_scope_t net);
extern int ivl_scope_time_precision(ivl_scope_t net);
@ -1826,6 +1842,42 @@ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
IVL_ST_WAIT, IVL_ST_WHILE */
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
/* SWITCHES
*
* The switches represent the tran devices in the design.
*
* FUNCTION SUMMARY
*
* ivl_switch_type
* Return the enumerated value that is the type of the switch.
*
* ivl_switch_basename
* This is the name given to the device in the source code.
*
* ivl_switch_scope
* The scope where the switch device appears.
*
* ivl_switch_a
* ivl_switch_b
* The a and b ports are the two ports of the switch.
*
* ivl_switch_enable
* If the device has an enable (tranifX) then this is the enable
* port.
*
* SEMANTIC NOTES
* The a/b ports can be any type, but the types must exactly
* match. The enable must be a scalar.
*/
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
extern const char*ivl_switch_basename(ivl_switch_t net);
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_a(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
#if defined(__MINGW32__) || defined (__CYGWIN32__)
# define DLLEXPORT __declspec(dllexport)

View File

@ -28,12 +28,25 @@
# include "netmisc.h"
# include "ivl_assert.h"
NetTran::NetTran(NetScope*scope, perm_string n, bool resistive, int enable)
: NetNode(scope, n, enable? 3 : 2)
static bool has_enable(ivl_switch_type_t tt)
{
switch (tt) {
case IVL_SW_TRANIF0:
case IVL_SW_TRANIF1:
case IVL_SW_RTRANIF0:
case IVL_SW_RTRANIF1:
return true;
default:
return false;
}
}
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
: NetNode(scope, n, has_enable(tt)? 3 : 2)
{
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
if (enable) {
if (pin_count() == 3) {
pin(2).set_dir(Link::INPUT);
pin(2).set_name(perm_string::literal("E"), 0);
}

View File

@ -1362,15 +1362,16 @@ class NetSysFunc : public NetNode {
class NetTran : public NetNode {
public:
NetTran(NetScope*scope, perm_string n, bool resistive, int enable);
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
~NetTran();
ivl_switch_type_t type() const { return type_; }
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
bool resistive_;
bool enable_;
ivl_switch_type_t type_;
};
/* =========

View File

@ -1627,6 +1627,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
return net->sigs_[idx];
}
extern "C" unsigned ivl_scope_switches(ivl_scope_t net)
{
assert(net);
return net->switches.size();
}
extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx)
{
assert(net);
assert(idx < net->switches.size());
return net->switches[idx];
}
extern "C" int ivl_scope_time_precision(ivl_scope_t net)
{
assert(net);
@ -2143,3 +2156,28 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
return 0;
}
extern "C" const char*ivl_switch_basename(ivl_switch_t net)
{
return net->name;
}
extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net)
{
return net->type;
}
extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net)
{
return net->pins[0];
}
extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net)
{
return net->pins[1];
}
extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
{
return net->pins[2];
}

View File

@ -380,6 +380,19 @@ static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
nex->ptrs_[top-1].l.lpm= net;
}
static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin)
{
unsigned top = nex->nptr_ + 1;
nex->ptrs_ = (struct ivl_nexus_ptr_s*)
realloc(nex->ptrs_, top*sizeof(struct ivl_nexus_ptr_s));
nex->nptr_ = top;
nex->ptrs_[top-1].type_= __NEXUS_PTR_SWI;
nex->ptrs_[top-1].drive0 = IVL_DR_HiZ;
nex->ptrs_[top-1].drive1 = IVL_DR_HiZ;
nex->ptrs_[top-1].pin_ = pin;
nex->ptrs_[top-1].l.swi= net;
}
void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
{
@ -431,6 +444,11 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
}
}
static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net)
{
scope->switches.push_back(net);
}
ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
const char*name)
{
@ -621,6 +639,13 @@ int dll_target::end_design(const Design*)
return rc;
}
void dll_target::switch_attributes(struct ivl_switch_s *obj,
const NetNode*net)
{
obj->nattr = net->attr_cnt();
obj->attr = fill_in_attributes(net);
}
void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
const NetNode*net)
{
@ -1010,9 +1035,38 @@ void dll_target::logic(const NetLogic*net)
bool dll_target::tran(const NetTran*net)
{
cerr << net->get_fileline() << ": sorry: "
<< "trans devices not supported." << endl;
return false;
struct ivl_switch_s*obj = new struct ivl_switch_s;
obj->type = net->type();
obj->name = net->name();
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->pins[0] = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->pins[1] = nex->t_cookie();
nexus_switch_add(obj->pins[0], obj, 0);
nexus_switch_add(obj->pins[1], obj, 1);
if (net->pin_count() > 2) {
nex = net->pin(2).nexus();
assert(nex->t_cookie());
obj->pins[2] = nex->t_cookie();
nexus_switch_add(obj->pins[2], obj, 2);
} else {
obj->pins[2] = 0;
}
switch_attributes(obj, net);
scope_add_switch(obj->scope, obj);
return true;
}
bool dll_target::sign_extend(const NetSignExtend*net)

25
t-dll.h
View File

@ -23,6 +23,7 @@
# include "ivl_target.h"
# include "StringHeap.h"
# include "netlist.h"
# include <vector>
#if defined(__MINGW32__)
#include <windows.h>
@ -147,6 +148,7 @@ struct dll_target : public target_t, public expr_scan_t {
ivl_scope_t lookup_scope_(const NetScope*scope);
ivl_attribute_s* fill_in_attributes(const Attrib*net);
void switch_attributes(struct ivl_switch_s *obj, const NetNode*net);
void logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net);
private:
@ -446,6 +448,19 @@ struct ivl_net_logic_s {
ivl_expr_t delay[3];
};
struct ivl_switch_s {
ivl_switch_type_t type;
perm_string name;
ivl_scope_t scope;
struct ivl_attribute_s*attr;
unsigned nattr;
ivl_nexus_t pins[3];
perm_string file;
unsigned lineno;
};
/*
* UDP definition.
@ -482,12 +497,14 @@ struct ivl_nexus_ptr_s {
ivl_net_logic_t log; /* type 1 */
ivl_net_const_t con; /* type 2 */
ivl_lpm_t lpm; /* type 3 */
ivl_switch_t swi; /* type 4 */
} l;
};
# define __NEXUS_PTR_SIG 0
# define __NEXUS_PTR_LOG 1
# define __NEXUS_PTR_CON 2
# define __NEXUS_PTR_LPM 3
# define __NEXUS_PTR_SWI 4
/*
* NOTE: ONLY allocate ivl_nexus_s objects with the included "new" operator.
@ -568,6 +585,8 @@ struct ivl_scope_s {
unsigned ports;
ivl_signal_t*port;
std::vector<ivl_switch_t>switches;
signed int time_precision :8;
signed int time_units :8;
@ -731,4 +750,10 @@ static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info)
scope->def_lineno = info->get_def_lineno();
}
static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info)
{
net->file = info->get_file();
net->lineno = info->get_lineno();
}
#endif

View File

@ -51,7 +51,7 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = stub.o expression.o statement.o
O = stub.o expression.o statement.o switches.o
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl

View File

@ -35,6 +35,15 @@ extern FILE*out;
*/
extern int stub_errors;
/*
* This function finds the vector width of a signal. It relies on the
* assumption that all the signal inputs to the nexus have the same
* width. The ivl_target API should assert that condition.
*/
extern unsigned width_of_nexus(ivl_nexus_t nex);
extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex);
/*
* Show the details of the expression.
*/
@ -45,6 +54,8 @@ extern void show_expression(ivl_expr_t net, unsigned ind);
*/
extern void show_statement(ivl_statement_t net, unsigned ind);
extern void show_switch(ivl_switch_t net);
/*
*/
extern const char*data_type_string(ivl_variable_type_t vtype);

View File

@ -1478,6 +1478,9 @@ static int show_scope(ivl_scope_t net, void*x)
for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1)
show_lpm(ivl_scope_lpm(net, idx));
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1)
show_switch(ivl_scope_switch(net, idx));
switch (ivl_scope_type(net)) {
case IVL_SCT_FUNCTION:
case IVL_SCT_TASK:

92
tgt-stub/switches.c Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2008 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
*/
# include "config.h"
# include "priv.h"
# include <stdlib.h>
# include <inttypes.h>
# include <assert.h>
void show_switch(ivl_switch_t net)
{
const char*name = ivl_switch_basename(net);
int has_enable = 0;
switch (ivl_switch_type(net)) {
case IVL_SW_TRAN:
fprintf(out, " tran %s", name);
break;
case IVL_SW_RTRAN:
fprintf(out, " rtran %s", name);
break;
case IVL_SW_TRANIF0:
fprintf(out, " tranif0 %s", name);
has_enable = 1;
break;
case IVL_SW_RTRANIF0:
fprintf(out, " rtranif0 %s", name);
has_enable = 1;
break;
case IVL_SW_TRANIF1:
fprintf(out, " tranif1 %s", name);
has_enable = 1;
break;
case IVL_SW_RTRANIF1:
fprintf(out, " rtranif1 %s", name);
has_enable = 1;
break;
}
fprintf(out, "\n");
ivl_nexus_t nex = ivl_switch_a(net);
const char*nex_name = nex? ivl_nexus_name(nex) : "";
ivl_variable_type_t nex_type_a = nex? type_of_nexus(nex) : IVL_VT_NO_TYPE;
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
nex = ivl_switch_b(net);
nex_name = nex? ivl_nexus_name(nex) : "";
ivl_variable_type_t nex_type_b = nex? type_of_nexus(nex) : IVL_VT_NO_TYPE;
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
/* The A/B pins of the switch must be present, and must match. */
if (nex_type_a == IVL_VT_NO_TYPE) {
fprintf(out, " A: ERROR: Type missing for pin A\n");
stub_errors += 1;
}
if (nex_type_b == IVL_VT_NO_TYPE) {
fprintf(out, " B: ERROR: Type missing for pin B\n");
stub_errors += 1;
}
if (nex_type_a != nex_type_b) {
fprintf(out, " A/B: ERROR: Type mismatch between pins A and B\n");
stub_errors += 1;
}
if (has_enable) {
nex = ivl_switch_enable(net);
nex_name = nex? ivl_nexus_name(nex) : "";
fprintf(out, " E: %s\n", nex_name);
if (width_of_nexus(nex) != 1) {
fprintf(out, " E: ERROR: Nexus width is %u\n",
width_of_nexus(nex));
}
}
}