#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
typedef uint16_t transnum_t;
typedef uint16_t count_t;
#if 1
typedef unsigned long long bitmap_t;
#define BITMAP_SHIFT 6
#define BITMAP_MASK 63
#define ONE 1ULL
#else#endif
typedef struct {
nodenum_t *list;
count_t count;
} list_t;
typedef struct {
transnum_t transistor;
nodenum_t other_node;
} c1c2_t;
static inline c1c2_t
c1c2(transnum_t tn, nodenum_t n)
{
c1c2_t c = { tn, n };
return c;
}
typedef struct {
nodenum_t nodes;
nodenum_t transistors;
nodenum_t vss;
nodenum_t vcc;
bitmap_t *nodes_pullup;
bitmap_t *nodes_pulldown;
bitmap_t *nodes_value;
nodenum_t **nodes_gates;
c1c2_t *nodes_c1c2s;
count_t *nodes_gatecount;
count_t *nodes_c1c2offset;
nodenum_t *nodes_dependants;
nodenum_t *nodes_left_dependants;
nodenum_t **nodes_dependant;
nodenum_t **nodes_left_dependant;
nodenum_t *transistors_gate;
nodenum_t *transistors_c1;
nodenum_t *transistors_c2;
bitmap_t *transistors_on;
nodenum_t *list1;
list_t listin;
nodenum_t *list2;
list_t listout;
bitmap_t *listout_bitmap;
nodenum_t *group;
count_t groupcount;
bitmap_t *groupbitmap;
enum {
contains_nothing,
contains_hi,
contains_pullup,
contains_pulldown,
contains_vcc,
contains_vss
} group_contains_value;
} state_t;
#define INCLUDED_FROM_NETLIST_SIM_C
#include "netlist_sim.h"
#undef INCLUDED_FROM_NETLIST_SIM_C
#define WORDS_FOR_BITS(a) (a / (sizeof(bitmap_t) * 8) + 1)
static inline void
bitmap_clear(bitmap_t *bitmap, count_t count)
{
memset(bitmap, 0, WORDS_FOR_BITS(count)*sizeof(bitmap_t));
}
static inline void
set_bitmap(bitmap_t *bitmap, int index, BOOL state)
{
if (state)
bitmap[index>>BITMAP_SHIFT] |= ONE << (index & BITMAP_MASK);
else
bitmap[index>>BITMAP_SHIFT] &= ~(ONE << (index & BITMAP_MASK));
}
static inline BOOL
get_bitmap(bitmap_t *bitmap, int index)
{
return (bitmap[index>>BITMAP_SHIFT] >> (index & BITMAP_MASK)) & 1;
}
static inline void
set_nodes_pullup(state_t *state, transnum_t t, BOOL s)
{
set_bitmap(state->nodes_pullup, t, s);
}
static inline BOOL
get_nodes_pullup(state_t *state, transnum_t t)
{
return get_bitmap(state->nodes_pullup, t);
}
static inline void
set_nodes_pulldown(state_t *state, transnum_t t, BOOL s)
{
set_bitmap(state->nodes_pulldown, t, s);
}
static inline BOOL
get_nodes_pulldown(state_t *state, transnum_t t)
{
return get_bitmap(state->nodes_pulldown, t);
}
static inline void
set_nodes_value(state_t *state, transnum_t t, BOOL s)
{
set_bitmap(state->nodes_value, t, s);
}
static inline BOOL
get_nodes_value(state_t *state, transnum_t t)
{
return get_bitmap(state->nodes_value, t);
}
static inline void
set_transistors_on(state_t *state, transnum_t t, BOOL s)
{
set_bitmap(state->transistors_on, t, s);
}
static inline BOOL
get_transistors_on(state_t *state, transnum_t t)
{
return get_bitmap(state->transistors_on, t);
}
static inline nodenum_t
listin_get(state_t *state, count_t i)
{
return state->listin.list[i];
}
static inline count_t
listin_count(state_t *state)
{
return state->listin.count;
}
static inline void
lists_switch(state_t *state)
{
list_t tmp = state->listin;
state->listin = state->listout;
state->listout = tmp;
}
static inline void
listout_clear(state_t *state)
{
state->listout.count = 0;
bitmap_clear(state->listout_bitmap, state->nodes);
}
static inline void
listout_add(state_t *state, nodenum_t i)
{
if (!get_bitmap(state->listout_bitmap, i)) {
state->listout.list[state->listout.count++] = i;
set_bitmap(state->listout_bitmap, i, 1);
}
}
static inline void
group_clear(state_t *state)
{
state->groupcount = 0;
bitmap_clear(state->groupbitmap, state->nodes);
}
static inline void
group_add(state_t *state, nodenum_t i)
{
state->group[state->groupcount++] = i;
set_bitmap(state->groupbitmap, i, 1);
}
static inline nodenum_t
group_get(state_t *state, count_t n)
{
return state->group[n];
}
static inline BOOL
group_contains(state_t *state, nodenum_t el)
{
return get_bitmap(state->groupbitmap, el);
}
static inline count_t
group_count(state_t *state)
{
return state->groupcount;
}
static inline void
addNodeToGroup(state_t *state, nodenum_t n)
{
if (n == state->vss) {
state->group_contains_value = contains_vss;
return;
}
if (n == state->vcc) {
if (state->group_contains_value != contains_vss)
state->group_contains_value = contains_vcc;
return;
}
if (group_contains(state, n))
return;
group_add(state, n);
if (state->group_contains_value < contains_pulldown && get_nodes_pulldown(state, n)) {
state->group_contains_value = contains_pulldown;
}
if (state->group_contains_value < contains_pullup && get_nodes_pullup(state, n)) {
state->group_contains_value = contains_pullup;
}
if (state->group_contains_value < contains_hi && get_nodes_value(state, n)) {
state->group_contains_value = contains_hi;
}
count_t end = state->nodes_c1c2offset[n+1];
for (count_t t = state->nodes_c1c2offset[n]; t < end; t++) {
c1c2_t c = state->nodes_c1c2s[t];
if (get_transistors_on(state, c.transistor)) {
addNodeToGroup(state, c.other_node);
}
}
}
static inline void
addAllNodesToGroup(state_t *state, nodenum_t node)
{
group_clear(state);
state->group_contains_value = contains_nothing;
addNodeToGroup(state, node);
}
static inline BOOL
getGroupValue(state_t *state)
{
switch (state->group_contains_value) {
case contains_vcc:
case contains_pullup:
case contains_hi:
return YES;
case contains_vss:
case contains_pulldown:
case contains_nothing:
return NO;
}
}
static inline void
recalcNode(state_t *state, nodenum_t node)
{
addAllNodesToGroup(state, node);
BOOL newv = getGroupValue(state);
for (count_t i = 0; i < group_count(state); i++) {
nodenum_t nn = group_get(state, i);
if (get_nodes_value(state, nn) != newv) {
set_nodes_value(state, nn, newv);
for (count_t t = 0; t < state->nodes_gatecount[nn]; t++) {
transnum_t tn = state->nodes_gates[nn][t];
set_transistors_on(state, tn, newv);
}
if (newv) {
for (count_t g = 0; g < state->nodes_left_dependants[nn]; g++) {
listout_add(state, state->nodes_left_dependant[nn][g]);
}
} else {
for (count_t g = 0; g < state->nodes_dependants[nn]; g++) {
listout_add(state, state->nodes_dependant[nn][g]);
}
}
}
}
}
void
recalcNodeList(state_t *state)
{
for (int j = 0; j < 100; j++) {
lists_switch(state);
if (!listin_count(state))
break;
listout_clear(state);
for (count_t i = 0; i < listin_count(state); i++) {
nodenum_t n = listin_get(state, i);
recalcNode(state, n);
}
}
listout_clear(state);
}
static inline void
add_nodes_dependant(state_t *state, nodenum_t a, nodenum_t b)
{
for (count_t g = 0; g < state->nodes_dependants[a]; g++)
if (state->nodes_dependant[a][g] == b)
return;
state->nodes_dependant[a][state->nodes_dependants[a]++] = b;
}
static inline void
add_nodes_left_dependant(state_t *state, nodenum_t a, nodenum_t b)
{
for (count_t g = 0; g < state->nodes_left_dependants[a]; g++)
if (state->nodes_left_dependant[a][g] == b)
return;
state->nodes_left_dependant[a][state->nodes_left_dependants[a]++] = b;
}
state_t *
setupNodesAndTransistors(netlist_transdefs *transdefs, BOOL *node_is_pullup, nodenum_t nodes, nodenum_t transistors, nodenum_t vss, nodenum_t vcc)
{
state_t *state = malloc(sizeof(state_t));
state->nodes = nodes;
state->transistors = transistors;
state->vss = vss;
state->vcc = vcc;
state->nodes_pullup = calloc(WORDS_FOR_BITS(state->nodes), sizeof(*state->nodes_pullup));
state->nodes_pulldown = calloc(WORDS_FOR_BITS(state->nodes), sizeof(*state->nodes_pulldown));
state->nodes_value = calloc(WORDS_FOR_BITS(state->nodes), sizeof(*state->nodes_value));
state->nodes_gates = malloc(state->nodes * sizeof(*state->nodes_gates));
for (count_t i = 0; i < state->nodes; i++) {
state->nodes_gates[i] = calloc(state->nodes, sizeof(**state->nodes_gates));
}
state->nodes_gatecount = calloc(state->nodes, sizeof(*state->nodes_gatecount));
state->nodes_c1c2offset = calloc(state->nodes + 1, sizeof(*state->nodes_c1c2offset));
state->nodes_dependants = calloc(state->nodes, sizeof(*state->nodes_dependants));
state->nodes_left_dependants = calloc(state->nodes, sizeof(*state->nodes_left_dependants));
state->nodes_dependant = malloc(state->nodes * sizeof(*state->nodes_dependant));
for (count_t i = 0; i < state->nodes; i++) {
state->nodes_dependant[i] = calloc(state->nodes, sizeof(**state->nodes_dependant));
}
state->nodes_left_dependant = malloc(state->nodes * sizeof(*state->nodes_left_dependant));
for (count_t i = 0; i < state->nodes; i++) {
state->nodes_left_dependant[i] = calloc(state->nodes, sizeof(**state->nodes_left_dependant));
}
state->transistors_gate = calloc(state->transistors, sizeof(*state->transistors_gate));
state->transistors_c1 = calloc(state->transistors, sizeof(*state->transistors_c1));
state->transistors_c2 = calloc(state->transistors, sizeof(*state->transistors_c2));
state->transistors_on = calloc(WORDS_FOR_BITS(state->transistors), sizeof(*state->transistors_on));
state->list1 = calloc(state->nodes, sizeof(*state->list1));
state->list2 = calloc(state->nodes, sizeof(*state->list2));
state->listout_bitmap = calloc(WORDS_FOR_BITS(state->nodes), sizeof(*state->listout_bitmap));
state->group = malloc(state->nodes * sizeof(*state->group));
state->groupbitmap = calloc(WORDS_FOR_BITS(state->nodes), sizeof(*state->groupbitmap));
state->listin.list = state->list1;
state->listin.count = 0;
state->listout.list = state->list2;
state->listout.count = 0;
count_t i;
for (i = 0; i < state->nodes; i++) {
set_nodes_pullup(state, i, node_is_pullup[i]);
state->nodes_gatecount[i] = 0;
}
count_t j = 0;
for (i = 0; i < state->transistors; i++) {
nodenum_t gate = transdefs[i].gate;
nodenum_t c1 = transdefs[i].c1;
nodenum_t c2 = transdefs[i].c2;
BOOL found = NO;
for (count_t j2 = 0; j2 < j; j2++) {
if (state->transistors_gate[j2] == gate &&
((state->transistors_c1[j2] == c1 &&
state->transistors_c2[j2] == c2) ||
(state->transistors_c1[j2] == c2 &&
state->transistors_c2[j2] == c1))) {
found = YES;
}
}
if (!found) {
state->transistors_gate[j] = gate;
state->transistors_c1[j] = c1;
state->transistors_c2[j] = c2;
j++;
}
}
state->transistors = j;
count_t *c1c2count = calloc(state->nodes, sizeof(*c1c2count));
count_t c1c2total = 0;
for (i = 0; i < state->transistors; i++) {
nodenum_t gate = state->transistors_gate[i];
state->nodes_gates[gate][state->nodes_gatecount[gate]++] = i;
c1c2count[state->transistors_c1[i]]++;
c1c2count[state->transistors_c2[i]]++;
c1c2total += 2;
}
count_t c1c2offset = 0;
for (i = 0; i < state->nodes; i++) {
state->nodes_c1c2offset[i] = c1c2offset;
c1c2offset += c1c2count[i];
}
state->nodes_c1c2offset[i] = c1c2offset;
state->nodes_c1c2s = calloc(c1c2total, sizeof(*state->nodes_c1c2s));
memset(c1c2count, 0, state->nodes * sizeof(*c1c2count));
for (i = 0; i < state->transistors; i++) {
nodenum_t c1 = state->transistors_c1[i];
nodenum_t c2 = state->transistors_c2[i];
state->nodes_c1c2s[state->nodes_c1c2offset[c1] + c1c2count[c1]++] = c1c2(i, c2);
state->nodes_c1c2s[state->nodes_c1c2offset[c2] + c1c2count[c2]++] = c1c2(i, c1);
}
free(c1c2count);
for (i = 0; i < state->nodes; i++) {
state->nodes_dependants[i] = 0;
state->nodes_left_dependants[i] = 0;
for (count_t g = 0; g < state->nodes_gatecount[i]; g++) {
transnum_t t = state->nodes_gates[i][g];
nodenum_t c1 = state->transistors_c1[t];
if (c1 != vss && c1 != vcc) {
add_nodes_dependant(state, i, c1);
}
nodenum_t c2 = state->transistors_c2[t];
if (c2 != vss && c2 != vcc) {
add_nodes_dependant(state, i, c2);
}
if (c1 != vss && c1 != vcc) {
add_nodes_left_dependant(state, i, c1);
} else {
add_nodes_left_dependant(state, i, c2);
}
}
}
#if 0#endif
return state;
}
void
destroyNodesAndTransistors(state_t *state)
{
free(state->nodes_pullup);
free(state->nodes_pulldown);
free(state->nodes_value);
for (count_t i = 0; i < state->nodes; i++) {
free(state->nodes_gates[i]);
}
free(state->nodes_gates);
free(state->nodes_c1c2s);
free(state->nodes_gatecount);
free(state->nodes_c1c2offset);
free(state->nodes_dependants);
free(state->nodes_left_dependants);
for (count_t i = 0; i < state->nodes; i++) {
free(state->nodes_dependant[i]);
}
free(state->nodes_dependant);
for (count_t i = 0; i < state->nodes; i++) {
free(state->nodes_left_dependant[i]);
}
free(state->nodes_left_dependant);
free(state->transistors_gate);
free(state->transistors_c1);
free(state->transistors_c2);
free(state->transistors_on);
free(state->list1);
free(state->list2);
free(state->listout_bitmap);
free(state->group);
free(state->groupbitmap);
free(state);
}
void
stabilizeChip(state_t *state)
{
for (count_t i = 0; i < state->nodes; i++)
listout_add(state, i);
recalcNodeList(state);
}
void
setNode(state_t *state, nodenum_t nn, BOOL s)
{
set_nodes_pullup(state, nn, s);
set_nodes_pulldown(state, nn, !s);
listout_add(state, nn);
recalcNodeList(state);
}
BOOL
isNodeHigh(state_t *state, nodenum_t nn)
{
return get_nodes_value(state, nn);
}
unsigned int
readNodes(state_t *state, int count, nodenum_t *nodelist)
{
int result = 0;
for (int i = count - 1; i >= 0; i--) {
result <<= 1;
result |= isNodeHigh(state, nodelist[i]);
}
return result;
}
void
writeNodes(state_t *state, int count, nodenum_t *nodelist, int v)
{
for (int i = 0; i < 8; i++, v >>= 1)
setNode(state, nodelist[i], v & 1);
}