327 lines
7.9 KiB
C++
327 lines
7.9 KiB
C++
/*
|
|
* Copyright (c) 2006-2010 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 "compile.h"
|
|
# include "functor.h"
|
|
# include "symbols.h"
|
|
# include <stdlib.h>
|
|
#ifdef HAVE_MALLOC_H
|
|
# include <malloc.h>
|
|
#endif
|
|
# include <limits.h>
|
|
# include <assert.h>
|
|
|
|
struct vvp_decode_adr_s;
|
|
struct vvp_decode_en_s;
|
|
|
|
static symbol_table_t decoder_table = 0;
|
|
|
|
static struct vvp_decode_adr_s* decoder_find(char *label)
|
|
{
|
|
if (decoder_table == 0)
|
|
return 0;
|
|
|
|
symbol_value_t v = sym_get_value(decoder_table, label);
|
|
return (vvp_decode_adr_s*)v.ptr;
|
|
}
|
|
|
|
static void decoder_save(char*label, struct vvp_decode_adr_s*obj)
|
|
{
|
|
if (! decoder_table)
|
|
decoder_table = new_symbol_table();
|
|
|
|
assert(! decoder_find(label));
|
|
|
|
symbol_value_t v;
|
|
v.ptr = obj;
|
|
sym_set_value(decoder_table, label, v);
|
|
}
|
|
|
|
/*
|
|
* This structure represents a decoder address object. We receive the
|
|
* value changes of address bits, and accumulate the current address value.
|
|
*/
|
|
struct vvp_decode_adr_s : public functor_s {
|
|
|
|
vvp_decode_adr_s(vvp_ipoint_t i, unsigned w);
|
|
|
|
void set(vvp_ipoint_t i, bool push, unsigned val, unsigned str);
|
|
|
|
// functor index for this node, for finding all the input
|
|
// functors related to me.
|
|
vvp_ipoint_t ix;
|
|
const unsigned width;
|
|
// Keep a list of decode_en objects that reference me.
|
|
struct vvp_decodable_s* enable_list;
|
|
};
|
|
|
|
/*
|
|
* A vvp_decodeable_s object may receive results from an address
|
|
* decoder. The propagate_decoder_address virtual method is called by
|
|
* the address decoder for all the associated decodable objects.
|
|
*/
|
|
struct vvp_decodable_s {
|
|
vvp_decodable_s(vvp_decode_adr_s*dec, unsigned s)
|
|
: decoder(dec), self(s)
|
|
{
|
|
enable_next = decoder->enable_list;
|
|
decoder->enable_list = this;
|
|
}
|
|
|
|
virtual void propagate_decoder_address(unsigned adr) =0;
|
|
|
|
struct vvp_decode_adr_s*decoder;
|
|
const unsigned self;
|
|
|
|
struct vvp_decodable_s* enable_next;
|
|
};
|
|
|
|
/*
|
|
*/
|
|
struct vvp_decode_en_s : public functor_s, public vvp_decodable_s {
|
|
|
|
vvp_decode_en_s(vvp_decode_adr_s*dec, unsigned s);
|
|
|
|
void set(vvp_ipoint_t i, bool push, unsigned val, unsigned str);
|
|
|
|
void propagate_decoder_address(unsigned adr);
|
|
|
|
// This is the enable calculated from the decoder
|
|
bool decode_en;
|
|
// This is the enable that arrives from the extra input.
|
|
bool extra_en;
|
|
// This is the mass-enable that enables independent of address
|
|
bool mass_en;
|
|
};
|
|
|
|
struct vvp_demux_s : public functor_s, public vvp_decodable_s {
|
|
|
|
vvp_demux_s(vvp_decode_adr_s*dec, unsigned s);
|
|
|
|
void set(vvp_ipoint_t i, bool push, unsigned val, unsigned str);
|
|
|
|
void propagate_decoder_address(unsigned adr);
|
|
|
|
unsigned char sel_val;
|
|
unsigned char not_val;
|
|
bool decode_en;
|
|
};
|
|
|
|
vvp_decode_adr_s::vvp_decode_adr_s(vvp_ipoint_t me, unsigned w)
|
|
: ix(me), width(w), enable_list(0)
|
|
{
|
|
}
|
|
|
|
void vvp_decode_adr_s::set(vvp_ipoint_t i, bool push,
|
|
unsigned val, unsigned str)
|
|
{
|
|
functor_t ifu = functor_index(i);
|
|
ifu->put(i, val);
|
|
unsigned cur_adr = 0;
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
|
int abval = functor_get_input(ix + idx);
|
|
unsigned mask = 1 << idx;
|
|
if (abval > 1)
|
|
cur_adr |= UINT_MAX;
|
|
else if (abval == 1)
|
|
cur_adr |= mask;
|
|
|
|
}
|
|
|
|
for (vvp_decodable_s*cur = enable_list ; cur ; cur = cur->enable_next)
|
|
cur->propagate_decoder_address(cur_adr);
|
|
}
|
|
|
|
vvp_decode_en_s::vvp_decode_en_s(vvp_decode_adr_s*dec, unsigned s)
|
|
: vvp_decodable_s(dec, s)
|
|
{
|
|
decode_en = false;
|
|
extra_en = true;
|
|
mass_en = false;
|
|
|
|
}
|
|
|
|
void vvp_decode_en_s::set(vvp_ipoint_t i, bool push,
|
|
unsigned val, unsigned str)
|
|
{
|
|
functor_t ifu = functor_index(i);
|
|
ifu->put(i, val);
|
|
|
|
int abval = functor_get_input(i);
|
|
unsigned port = ipoint_port(i);
|
|
switch (port) {
|
|
case 0: // regular enable
|
|
if (abval == 1) {
|
|
extra_en = true;
|
|
} else {
|
|
extra_en = false;
|
|
}
|
|
break;
|
|
case 1: // mass enable
|
|
if (abval == 1) {
|
|
mass_en = true;
|
|
} else {
|
|
mass_en = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((extra_en && decode_en) || mass_en)
|
|
put_oval(1, true);
|
|
else
|
|
put_oval(0, true);
|
|
}
|
|
|
|
void vvp_decode_en_s::propagate_decoder_address(unsigned adr)
|
|
{
|
|
if (adr == self) {
|
|
decode_en = true;
|
|
} else {
|
|
decode_en = false;
|
|
}
|
|
|
|
if (extra_en && decode_en)
|
|
put_oval(1, true);
|
|
else
|
|
put_oval(0, true);
|
|
}
|
|
|
|
vvp_demux_s::vvp_demux_s(vvp_decode_adr_s*dec, unsigned s)
|
|
: vvp_decodable_s(dec, s)
|
|
{
|
|
decode_en = false;
|
|
sel_val = StX;
|
|
not_val = StX;
|
|
}
|
|
|
|
void vvp_demux_s::set(vvp_ipoint_t i, bool push,
|
|
unsigned val, unsigned str)
|
|
{
|
|
functor_t ifu = functor_index(i);
|
|
ifu->put(i, val);
|
|
|
|
unsigned port = ipoint_port(i);
|
|
switch (port) {
|
|
case 0: // not-selected input
|
|
not_val = val;
|
|
break;
|
|
case 1: // is-selected input
|
|
sel_val = val;
|
|
break;
|
|
}
|
|
|
|
if (decode_en)
|
|
put_oval(sel_val, true);
|
|
else
|
|
put_oval(not_val, true);
|
|
}
|
|
|
|
void vvp_demux_s::propagate_decoder_address(unsigned adr)
|
|
{
|
|
if (adr == self) {
|
|
decode_en = true;
|
|
} else {
|
|
decode_en = false;
|
|
}
|
|
|
|
if (decode_en)
|
|
put_oval(sel_val, true);
|
|
else
|
|
put_oval(not_val, true);
|
|
}
|
|
|
|
void compile_decode_adr(char*label, unsigned argc, struct symb_s*argv)
|
|
{
|
|
unsigned nfun = (argc + 3)/4;
|
|
vvp_ipoint_t ix = functor_allocate(nfun);
|
|
|
|
vvp_decode_adr_s*a = new struct vvp_decode_adr_s(ix, argc);
|
|
|
|
functor_define(ix, a);
|
|
|
|
if (nfun > 0) {
|
|
extra_ports_functor_s *fu = new extra_ports_functor_s[nfun-1];
|
|
for (unsigned idx = 1 ; idx < nfun ; idx += 1) {
|
|
fu[idx-1].base_ = ix;
|
|
functor_define(ipoint_index(ix, idx), fu+idx-1);
|
|
}
|
|
}
|
|
|
|
inputs_connect(ix, argc, argv);
|
|
free(argv);
|
|
|
|
decoder_save(label, a);
|
|
free(label);
|
|
}
|
|
|
|
void compile_decode_en(char*label, char*decoder, int slice,
|
|
struct symb_s enable,
|
|
struct symb_s mass_enable)
|
|
{
|
|
vvp_decode_adr_s*adr = decoder_find(decoder);
|
|
vvp_decode_en_s*a = new struct vvp_decode_en_s(adr, slice);
|
|
|
|
vvp_ipoint_t ix = functor_allocate(1);
|
|
functor_define(ix, a);
|
|
|
|
symb_s argv[2];
|
|
argv[0] = enable;
|
|
argv[1] = mass_enable;
|
|
inputs_connect(ix, 2, argv);
|
|
|
|
define_functor_symbol(label, ix);
|
|
free(label);
|
|
}
|
|
|
|
void compile_demux(char*label, char*decoder, int slice,
|
|
struct symb_s not_selected,
|
|
struct symb_s selected)
|
|
{
|
|
vvp_decode_adr_s*adr = decoder_find(decoder);
|
|
vvp_demux_s*a = new struct vvp_demux_s(adr, slice);
|
|
|
|
vvp_ipoint_t ix = functor_allocate(1);
|
|
functor_define(ix, a);
|
|
|
|
symb_s argv[2];
|
|
argv[0] = not_selected;
|
|
argv[1] = selected;
|
|
inputs_connect(ix, 2, argv);
|
|
|
|
define_functor_symbol(label, ix);
|
|
free(label);
|
|
}
|
|
|
|
/*
|
|
* $Log: decoder.cc,v $
|
|
* Revision 1.1.2.4 2006/11/02 17:47:52 steve
|
|
* Fix compile on Mac OS X
|
|
*
|
|
* Revision 1.1.2.3 2006/03/26 23:09:00 steve
|
|
* Add the .demux device.
|
|
*
|
|
* Revision 1.1.2.2 2006/03/12 07:34:21 steve
|
|
* Fix the memsynth1 case.
|
|
*
|
|
* Revision 1.1.2.1 2006/02/19 00:11:36 steve
|
|
* Handle synthesis of FF vectors with l-value decoder.
|
|
*
|
|
*/
|
|
|