Implement supply->strong strength reduction for non-resistive switches.

As specified in 1364-2005 section 7.11.
This commit is contained in:
Martin Whitaker 2018-02-23 22:07:59 +00:00
parent 69d80839a5
commit 36eef5154f
5 changed files with 71 additions and 52 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2018 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
@ -45,14 +45,14 @@ struct vvp_island_branch_tran : public vvp_island_branch {
vvp_island_branch_tran(vvp_net_t*en__, bool active_high__,
unsigned width__, unsigned part__,
unsigned offset__);
unsigned offset__, bool resistive__);
bool run_test_enabled();
void run_resolution();
void run_output();
vvp_net_t*en;
unsigned width, part, offset;
bool active_high;
bool active_high, resistive;
tran_state_t state;
};
@ -60,9 +60,10 @@ vvp_island_branch_tran::vvp_island_branch_tran(vvp_net_t*en__,
bool active_high__,
unsigned width__,
unsigned part__,
unsigned offset__)
unsigned offset__,
bool resistive__)
: en(en__), width(width__), part(part__), offset(offset__),
active_high(active_high__)
active_high(active_high__), resistive(resistive__)
{
state = en__ ? tran_disabled : tran_enabled;
}
@ -235,7 +236,8 @@ bool vvp_island_branch_tran::run_test_enabled()
// input is 'x' or 'z'. We use the rules that are given for MOS switches.
inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a,
const vvp_vector8_t&b,
tran_state_t state)
tran_state_t state,
unsigned str_map[8])
{
assert(a.size() == b.size());
vvp_vector8_t out (a.size());
@ -243,6 +245,9 @@ inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a,
for (unsigned idx = 0 ; idx < out.size() ; idx += 1) {
vvp_scalar_t a_bit = a.value(idx);
vvp_scalar_t b_bit = b.value(idx);
b_bit = vvp_scalar_t(b_bit.value(),
str_map[b_bit.strength0()],
str_map[b_bit.strength1()]);
if (state == tran_unknown) {
switch (b_bit.value()) {
case BIT4_0:
@ -293,8 +298,8 @@ static void push_value_through_branch(const vvp_vector8_t&val,
// previously collected (and resolved) for the port.
if (branch->width == 0) {
// There are no part selects.
dst_port->value = resolve_ambiguous(dst_port->value, val,
branch->state);
dst_port->value = resolve_ambiguous(dst_port->value, val, branch->state,
vvp_switch_strength_map[branch->resistive]);
} else if (dst_ab == 1) {
// The other side is a strict subset (part select)
@ -413,7 +418,7 @@ void compile_island_tranif(int sense, char*island, char*pa, char*pb, char*pe)
vvp_island_branch_tran*br = new vvp_island_branch_tran(en,
sense ? true :
false,
0, 0, 0);
0, 0, 0, false);
use_island->add_branch(br, pa, pb);
@ -430,7 +435,7 @@ void compile_island_tranvp(char*island, char*pa, char*pb,
free(island);
vvp_island_branch_tran*br = new vvp_island_branch_tran(NULL, false,
wid, par, off);
wid, par, off, false);
use_island->add_branch(br, pa, pb);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2018 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
@ -19,9 +19,10 @@
# include "npmos.h"
vvp_fun_pmos_::vvp_fun_pmos_(bool enable_invert)
vvp_fun_pmos_::vvp_fun_pmos_(bool enable_invert, bool resistive)
{
inv_en_ = enable_invert;
resistive_ = resistive;
}
@ -58,12 +59,18 @@ void vvp_fun_pmos_::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
void vvp_fun_pmos_::generate_output_(vvp_net_ptr_t ptr)
{
const unsigned*strength_map = vvp_switch_strength_map[resistive_];
vvp_vector8_t out (bit_.size());
for (unsigned idx = 0 ; idx < out.size() ; idx += 1) {
vvp_bit4_t b_en = en_.value(idx);
vvp_scalar_t b_bit = bit_.value(idx);
b_bit = vvp_scalar_t(b_bit.value(),
strength_map[b_bit.strength0()],
strength_map[b_bit.strength1()]);
switch (b_en) {
case BIT4_0:
out.set_bit(idx, b_bit);
@ -93,7 +100,7 @@ void vvp_fun_pmos_::generate_output_(vvp_net_ptr_t ptr)
vvp_fun_pmos::vvp_fun_pmos(bool enable_invert)
: vvp_fun_pmos_(enable_invert)
: vvp_fun_pmos_(enable_invert, false)
{
}
@ -112,7 +119,7 @@ void vvp_fun_pmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
}
vvp_fun_rpmos::vvp_fun_rpmos(bool enable_invert)
: vvp_fun_pmos_(enable_invert)
: vvp_fun_pmos_(enable_invert, true)
{
}
@ -126,7 +133,7 @@ void vvp_fun_rpmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
if (ptr.port() != 0)
return;
bit_ = resistive_reduction(bit);
bit_ = bit;
generate_output_(ptr);
}
@ -135,8 +142,9 @@ void vvp_fun_rpmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
* CMOS primitive.
*/
vvp_fun_cmos_::vvp_fun_cmos_()
vvp_fun_cmos_::vvp_fun_cmos_(bool resistive)
{
resistive_ = resistive;
}
void vvp_fun_cmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t &bit,
@ -175,6 +183,8 @@ void vvp_fun_cmos_::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
void vvp_fun_cmos_::generate_output_(vvp_net_ptr_t ptr)
{
const unsigned*strength_map = vvp_switch_strength_map[resistive_];
vvp_vector8_t out (bit_.size());
for (unsigned idx = 0 ; idx < out.size() ; idx += 1) {
@ -182,6 +192,10 @@ void vvp_fun_cmos_::generate_output_(vvp_net_ptr_t ptr)
vvp_bit4_t b_p_en = p_en_.value(idx);
vvp_scalar_t b_bit = bit_.value(idx);
b_bit = vvp_scalar_t(b_bit.value(),
strength_map[b_bit.strength0()],
strength_map[b_bit.strength1()]);
if (b_n_en == BIT4_1 || b_p_en == BIT4_0) {
out.set_bit(idx, b_bit);
} else if (b_n_en == BIT4_0 && b_p_en == BIT4_1) {
@ -206,7 +220,7 @@ void vvp_fun_cmos_::generate_output_(vvp_net_ptr_t ptr)
}
vvp_fun_cmos::vvp_fun_cmos()
: vvp_fun_cmos_()
: vvp_fun_cmos_(false)
{
}
@ -225,7 +239,7 @@ void vvp_fun_cmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
}
vvp_fun_rcmos::vvp_fun_rcmos()
: vvp_fun_cmos_()
: vvp_fun_cmos_(true)
{
}
@ -239,6 +253,6 @@ void vvp_fun_rcmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
if (ptr.port() != 0)
return;
bit_ = resistive_reduction(bit);
bit_ = bit;
generate_output_(ptr);
}

View File

@ -1,7 +1,7 @@
#ifndef IVL_npmos_H
#define IVL_npmos_H
/*
* Copyright (c) 2005-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2018 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
@ -46,7 +46,7 @@
class vvp_fun_pmos_ : public vvp_net_fun_t {
public:
explicit vvp_fun_pmos_(bool enable_invert);
explicit vvp_fun_pmos_(bool enable_invert, bool resistive);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
@ -62,7 +62,7 @@ class vvp_fun_pmos_ : public vvp_net_fun_t {
vvp_vector8_t bit_;
vvp_vector4_t en_;
bool inv_en_;
bool inv_en_, resistive_;
};
class vvp_fun_pmos : public vvp_fun_pmos_ {
@ -109,7 +109,7 @@ class vvp_fun_rpmos : public vvp_fun_pmos_ {
class vvp_fun_cmos_ : public vvp_net_fun_t {
public:
explicit vvp_fun_cmos_();
explicit vvp_fun_cmos_(bool resistive);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t &bit,
vvp_context_t);
@ -126,6 +126,7 @@ class vvp_fun_cmos_ : public vvp_net_fun_t {
vvp_vector8_t bit_;
vvp_vector4_t n_en_;
vvp_vector4_t p_en_;
bool resistive_;
};
class vvp_fun_cmos : public vvp_fun_cmos_ {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2004-2018 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
@ -3686,32 +3686,29 @@ vvp_scalar_t fully_featured_resolv_(vvp_scalar_t a, vvp_scalar_t b)
return res;
}
vvp_vector8_t resistive_reduction(const vvp_vector8_t&that)
{
static unsigned rstr[8] = {
0, /* Hi-Z --> Hi-Z */
1, /* Small capacitance --> Small capacitance */
1, /* Medium capacitance --> Small capacitance */
2, /* Weak drive --> Medium capacitance */
2, /* Large capacitance --> Medium capacitance */
unsigned vvp_switch_strength_map[2][8] = {
{ // non-resistive
0, /* High impedance --> High impedance */
1, /* Small capacitor --> Small capacitor */
2, /* Medium capacitor --> Medium capacitor */
3, /* Weak drive --> Weak drive */
4, /* Large capacitor --> Large capacitor */
5, /* Pull drive --> Pull drive */
6, /* Strong drive --> Strong drive */
6 /* Supply drive --> Strong drive */
},
{ // resistive
0, /* High impedance --> High impedance */
1, /* Small capacitor --> Small capacitor */
1, /* Medium capacitor --> Small capacitor */
2, /* Weak drive --> Medium capacitor */
2, /* Large capacitor --> Medium capacitor */
3, /* Pull drive --> Weak drive */
5, /* Strong drive --> Pull drive */
5 /* Supply drive --> Pull drive */
}
};
vvp_vector8_t res (that.size());
for (unsigned idx = 0 ; idx < res.size() ; idx += 1) {
vvp_scalar_t bit = that.value(idx);
bit = vvp_scalar_t(bit.value(),
rstr[bit.strength0()],
rstr[bit.strength1()]);
res.set_bit(idx, bit);
}
return res;
}
vvp_vector4_t reduce4(const vvp_vector8_t&that)
{
vvp_vector4_t out (that.size());

View File

@ -1,7 +1,7 @@
#ifndef IVL_vvp_net_H
#define IVL_vvp_net_H
/*
* Copyright (c) 2004-2016 Stephen Williams (steve@icarus.com)
* Copyright (c) 2004-2018 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
@ -954,9 +954,11 @@ inline vvp_vector8_t resolve(const vvp_vector8_t&a, const vvp_vector8_t&b)
return out;
}
/* This function implements the strength reduction implied by
Verilog standard resistive devices. */
extern vvp_vector8_t resistive_reduction(const vvp_vector8_t&a);
/* This lookup tabke implements the strength reduction implied by
Verilog standard switch devices. The major dimension selects
between non-resistive and resistive devices. */
extern unsigned vvp_switch_strength_map[2][8];
/* The reduce4 function converts a vector8 to a vector4, losing
strength information in the process. */
extern vvp_vector4_t reduce4(const vvp_vector8_t&that);