2010-09-22 07:35:22 +00:00
|
|
|
//#define DEBUG
|
2010-09-22 15:25:34 +00:00
|
|
|
int verbose = 0;
|
2010-09-22 05:14:57 +00:00
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
typedef unsigned char uint8_t;
|
2010-09-22 05:14:57 +00:00
|
|
|
typedef unsigned short uint16_t;
|
2010-09-22 01:51:38 +00:00
|
|
|
typedef int BOOL;
|
|
|
|
|
2010-09-22 22:57:00 +00:00
|
|
|
typedef uint16_t nodenum_t;
|
2010-09-22 23:02:36 +00:00
|
|
|
typedef uint16_t transnum_t;
|
|
|
|
typedef uint16_t count_t;
|
|
|
|
typedef uint8_t state_t;
|
2010-09-22 22:57:00 +00:00
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
#define NO 0
|
|
|
|
#define YES 1
|
|
|
|
|
|
|
|
#include "segdefs.h"
|
|
|
|
#include "transdefs.h"
|
|
|
|
#include "nodenames.h"
|
|
|
|
|
|
|
|
#define ngnd vss
|
|
|
|
#define npwr vcc
|
|
|
|
|
|
|
|
enum {
|
|
|
|
STATE_VCC,
|
2010-09-22 17:37:35 +00:00
|
|
|
STATE_PU,
|
2010-09-22 01:51:38 +00:00
|
|
|
STATE_FH,
|
2010-09-22 17:37:35 +00:00
|
|
|
STATE_GND,
|
|
|
|
STATE_FL,
|
2010-09-22 01:51:38 +00:00
|
|
|
STATE_PD,
|
|
|
|
};
|
|
|
|
|
2010-09-22 17:37:35 +00:00
|
|
|
#define MAX_HIGH STATE_FH /* VCC, PU and FH are considered high */
|
|
|
|
|
2010-09-22 07:35:22 +00:00
|
|
|
#define NODES 1725
|
|
|
|
#define TRANSISTORS 3510
|
|
|
|
|
2010-09-23 00:38:06 +00:00
|
|
|
BOOL nodes_pullup[NODES];//XXX no idea why this array overflows!!
|
|
|
|
BOOL nodes_pulldown[NODES];
|
|
|
|
state_t nodes_state[NODES];
|
|
|
|
nodenum_t nodes_gates[NODES][NODES];
|
|
|
|
nodenum_t nodes_c1c2s[NODES][2*NODES];
|
|
|
|
count_t nodes_gatecount[NODES];
|
|
|
|
count_t nodes_c1c2count[NODES];
|
2010-09-22 01:51:38 +00:00
|
|
|
|
2010-09-23 00:38:06 +00:00
|
|
|
transnum_t transistors_name[TRANSISTORS];
|
|
|
|
nodenum_t transistors_gate[TRANSISTORS];
|
|
|
|
nodenum_t transistors_c1[TRANSISTORS];
|
|
|
|
nodenum_t transistors_c2[TRANSISTORS];
|
2010-09-22 05:14:57 +00:00
|
|
|
|
2010-09-23 00:38:06 +00:00
|
|
|
int transistors_on[TRANSISTORS/sizeof(int)+1];
|
2010-09-22 23:14:18 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
set_transistors_on(transnum_t t, BOOL state)
|
|
|
|
{
|
|
|
|
if (state)
|
|
|
|
transistors_on[t>>5] |= 1 << (t & 31);
|
|
|
|
else
|
|
|
|
transistors_on[t>>5] &= ~(1 << (t & 31));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
get_transistors_on(transnum_t t)
|
|
|
|
{
|
|
|
|
return (transistors_on[t>>5] >> (t & 31)) & 1;
|
|
|
|
}
|
2010-09-22 01:51:38 +00:00
|
|
|
|
|
|
|
uint8_t memory[65536];
|
|
|
|
int cycle;
|
|
|
|
|
2010-09-22 10:05:49 +00:00
|
|
|
uint8_t A, X, Y, S, P;
|
|
|
|
uint16_t PC;
|
|
|
|
BOOL N, Z, C;
|
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
void
|
2010-09-23 00:38:06 +00:00
|
|
|
setupNodesAndTransistors()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-22 23:02:36 +00:00
|
|
|
count_t i;
|
2010-09-22 01:51:38 +00:00
|
|
|
for (i = 0; i < sizeof(segdefs)/sizeof(*segdefs); i++) {
|
2010-09-23 00:38:06 +00:00
|
|
|
nodes_pullup[i] = segdefs[i];
|
|
|
|
nodes_gatecount[i] = 0;
|
|
|
|
nodes_c1c2count[i] = 0;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < sizeof(transdefs)/sizeof(*transdefs); i++) {
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t gate = transdefs[i].gate;
|
|
|
|
nodenum_t c1 = transdefs[i].c1;
|
|
|
|
nodenum_t c2 = transdefs[i].c2;
|
2010-09-23 00:38:06 +00:00
|
|
|
transistors_name[i] = i;
|
|
|
|
transistors_gate[i] = gate;
|
|
|
|
transistors_c1[i] = c1;
|
|
|
|
transistors_c2[i] = c2;
|
|
|
|
nodes_gates[gate][nodes_gatecount[gate]++] = i;
|
|
|
|
nodes_c1c2s[c1][nodes_c1c2count[c1]++] = i;
|
|
|
|
nodes_c1c2s[c2][nodes_c1c2count[c2]++] = i;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
2010-09-23 08:06:26 +00:00
|
|
|
nodes_state[ngnd] = STATE_GND;
|
|
|
|
nodes_state[npwr] = STATE_VCC;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 05:14:57 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
2010-09-22 23:02:36 +00:00
|
|
|
printarray(nodenum_t *array, count_t count)
|
2010-09-22 05:14:57 +00:00
|
|
|
{
|
2010-09-22 23:02:36 +00:00
|
|
|
count_t i;
|
2010-09-22 05:14:57 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
printf("%d ", array[i]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t group[NODES];
|
2010-09-22 23:02:36 +00:00
|
|
|
count_t groupcount;
|
2010-09-23 00:38:06 +00:00
|
|
|
int groupbitmap[NODES/sizeof(int)+1];
|
2010-09-22 22:38:56 +00:00
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
BOOL
|
2010-09-23 02:53:11 +00:00
|
|
|
groupContains(nodenum_t el)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-22 22:51:14 +00:00
|
|
|
return (groupbitmap[el>>5] >> (el & 31)) & 1;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 18:00:45 +00:00
|
|
|
typedef struct {
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t *list;
|
2010-09-22 23:02:36 +00:00
|
|
|
count_t count;
|
2010-09-23 02:35:50 +00:00
|
|
|
int *bitmap;
|
2010-09-22 18:00:45 +00:00
|
|
|
} list_t;
|
|
|
|
|
|
|
|
list_t recalc;
|
|
|
|
|
|
|
|
BOOL
|
2010-09-22 22:57:00 +00:00
|
|
|
recalcListContains(nodenum_t el)
|
2010-09-22 18:00:45 +00:00
|
|
|
{
|
2010-09-23 02:35:50 +00:00
|
|
|
return (recalc.bitmap[el>>5] >> (el & 31)) & 1;
|
2010-09-22 18:00:45 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 22:57:00 +00:00
|
|
|
void addNodeToGroup(nodenum_t i);
|
2010-09-22 01:51:38 +00:00
|
|
|
|
|
|
|
void
|
2010-09-22 23:02:36 +00:00
|
|
|
addNodeTransistor(nodenum_t node, transnum_t t)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 03:21:13 +00:00
|
|
|
/* if the transistor does not connect c1 and c2, we stop here */
|
2010-09-22 23:14:18 +00:00
|
|
|
if (!get_transistors_on(t))
|
2010-09-22 01:51:38 +00:00
|
|
|
return;
|
2010-09-23 00:38:06 +00:00
|
|
|
|
|
|
|
if (transistors_c1[t] == node)
|
2010-09-23 03:21:13 +00:00
|
|
|
addNodeToGroup(transistors_c2[t]);
|
|
|
|
else
|
|
|
|
addNodeToGroup(transistors_c1[t]);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-22 22:57:00 +00:00
|
|
|
addNodeToGroup(nodenum_t i)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 02:53:11 +00:00
|
|
|
if (groupContains(i))
|
2010-09-22 01:51:38 +00:00
|
|
|
return;
|
2010-09-23 03:21:13 +00:00
|
|
|
|
2010-09-22 18:06:15 +00:00
|
|
|
group[groupcount++] = i;
|
2010-09-22 22:51:14 +00:00
|
|
|
groupbitmap[i>>5] |= 1 << (i & 31);
|
2010-09-23 03:21:13 +00:00
|
|
|
|
|
|
|
if (i == ngnd || i == npwr)
|
2010-09-22 01:51:38 +00:00
|
|
|
return;
|
2010-09-23 03:21:13 +00:00
|
|
|
|
|
|
|
for (count_t t = 0; t < nodes_c1c2count[i]; t++)
|
2010-09-23 00:38:06 +00:00
|
|
|
addNodeTransistor(i, nodes_c1c2s[i][t]);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 02:59:33 +00:00
|
|
|
// 1. if there is a pullup node, it's STATE_PU
|
|
|
|
// 2. if there is a pulldown node, it's STATE_PD
|
|
|
|
// (if both 1 and 2 are true, the first pullup or pulldown wins, with
|
|
|
|
// a statistical advantage towards STATE_PU
|
|
|
|
// 3. otherwise, if there is an FH node, it's STATE_FH
|
|
|
|
// 4. otherwise, it's STATE_FL (if there is an FL node, which is always the case)
|
2010-09-22 23:02:36 +00:00
|
|
|
state_t
|
2010-09-22 18:06:15 +00:00
|
|
|
getNodeValue()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 02:53:11 +00:00
|
|
|
if (groupContains(ngnd))
|
2010-09-22 01:51:38 +00:00
|
|
|
return STATE_GND;
|
2010-09-23 02:53:11 +00:00
|
|
|
if (groupContains(npwr))
|
2010-09-22 01:51:38 +00:00
|
|
|
return STATE_VCC;
|
2010-09-23 02:59:33 +00:00
|
|
|
state_t flstate = STATE_FL;
|
|
|
|
for (count_t i = 0; i < groupcount; i++) {
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t nn = group[i];
|
2010-09-23 00:38:06 +00:00
|
|
|
if (nodes_pullup[nn])
|
2010-09-22 01:51:38 +00:00
|
|
|
return STATE_PU;
|
2010-09-23 00:38:06 +00:00
|
|
|
if (nodes_pulldown[nn])
|
2010-09-22 01:51:38 +00:00
|
|
|
return STATE_PD;
|
2010-09-23 00:38:06 +00:00
|
|
|
if (nodes_state[nn] == STATE_FH)
|
2010-09-22 01:51:38 +00:00
|
|
|
flstate = STATE_FH;
|
|
|
|
}
|
|
|
|
return flstate;
|
|
|
|
}
|
|
|
|
|
2010-09-22 05:14:57 +00:00
|
|
|
void
|
2010-09-22 22:57:00 +00:00
|
|
|
addRecalcNode(nodenum_t nn)
|
2010-09-22 05:14:57 +00:00
|
|
|
{
|
2010-09-23 06:44:32 +00:00
|
|
|
/* no need to analyze VCC or GND */
|
2010-09-22 18:00:45 +00:00
|
|
|
if (nn == ngnd || nn == npwr)
|
2010-09-22 05:14:57 +00:00
|
|
|
return;
|
2010-09-23 06:44:32 +00:00
|
|
|
|
|
|
|
/* we already know about this node */
|
2010-09-22 18:00:45 +00:00
|
|
|
if (recalcListContains(nn))
|
2010-09-22 05:14:57 +00:00
|
|
|
return;
|
2010-09-23 06:44:32 +00:00
|
|
|
|
|
|
|
/* add node to list */
|
2010-09-22 18:06:15 +00:00
|
|
|
recalc.list[recalc.count++] = nn;
|
2010-09-23 02:35:50 +00:00
|
|
|
recalc.bitmap[nn>>5] |= 1 << (nn & 31);
|
2010-09-22 05:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-22 22:57:00 +00:00
|
|
|
floatnode(nodenum_t nn)
|
2010-09-22 05:14:57 +00:00
|
|
|
{
|
2010-09-23 06:44:32 +00:00
|
|
|
/* VCC and GND are constant */
|
2010-09-22 17:37:35 +00:00
|
|
|
if (nn == ngnd || nn == npwr)
|
2010-09-22 05:14:57 +00:00
|
|
|
return;
|
2010-09-23 06:44:32 +00:00
|
|
|
|
2010-09-23 00:38:06 +00:00
|
|
|
state_t state = nodes_state[nn];
|
2010-09-23 06:44:32 +00:00
|
|
|
|
2010-09-22 17:37:35 +00:00
|
|
|
if (state == STATE_GND || state == STATE_PD)
|
2010-09-23 00:38:06 +00:00
|
|
|
nodes_state[nn] = STATE_FL;
|
2010-09-23 06:44:32 +00:00
|
|
|
|
2010-09-22 17:37:35 +00:00
|
|
|
if (state == STATE_VCC || state == STATE_PU)
|
2010-09-23 00:38:06 +00:00
|
|
|
nodes_state[nn] = STATE_FH;
|
2010-09-22 05:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
2010-09-22 22:57:00 +00:00
|
|
|
isNodeHigh(nodenum_t nn)
|
2010-09-22 05:14:57 +00:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2010-09-22 07:25:32 +00:00
|
|
|
printf("%s nn=%d state=%d\n", __func__, nn, nodes[nn].state);
|
2010-09-22 17:37:35 +00:00
|
|
|
printf("%s nn=%d res=%d\n", __func__, nn, nodes[nn].state <= MAX_HIGH);
|
2010-09-22 05:14:57 +00:00
|
|
|
#endif
|
2010-09-23 00:38:06 +00:00
|
|
|
return nodes_state[nn] <= MAX_HIGH;
|
2010-09-22 05:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-22 23:02:36 +00:00
|
|
|
recalcTransistor(transnum_t tn)
|
2010-09-22 05:14:57 +00:00
|
|
|
{
|
2010-09-23 06:44:32 +00:00
|
|
|
/* if the gate is high, the transistor should be on */
|
2010-09-23 00:38:06 +00:00
|
|
|
BOOL on = isNodeHigh(transistors_gate[tn]);
|
2010-09-23 06:44:32 +00:00
|
|
|
|
|
|
|
/* no change? nothing to do! */
|
2010-09-22 23:14:18 +00:00
|
|
|
if (on == get_transistors_on(tn))
|
2010-09-22 17:00:22 +00:00
|
|
|
return;
|
2010-09-23 06:44:32 +00:00
|
|
|
|
2010-09-22 23:14:18 +00:00
|
|
|
set_transistors_on(tn, on);
|
2010-09-23 06:44:32 +00:00
|
|
|
|
|
|
|
/* if the transistor is off, both nodes are floating */
|
2010-09-22 17:00:22 +00:00
|
|
|
if (!on) {
|
2010-09-23 00:38:06 +00:00
|
|
|
floatnode(transistors_c1[tn]);
|
|
|
|
floatnode(transistors_c2[tn]);
|
2010-09-22 17:00:22 +00:00
|
|
|
}
|
2010-09-23 06:44:32 +00:00
|
|
|
|
|
|
|
/* next time, we'll have to look at both nodes behind the transistor */
|
2010-09-23 00:38:06 +00:00
|
|
|
addRecalcNode(transistors_c1[tn]);
|
|
|
|
addRecalcNode(transistors_c2[tn]);
|
2010-09-22 05:14:57 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
void
|
2010-09-22 22:57:00 +00:00
|
|
|
recalcNode(nodenum_t node)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-22 18:06:15 +00:00
|
|
|
if (node == ngnd || node == npwr)
|
2010-09-22 01:51:38 +00:00
|
|
|
return;
|
|
|
|
|
2010-09-22 18:06:15 +00:00
|
|
|
groupcount = 0;
|
2010-09-22 22:46:11 +00:00
|
|
|
bzero(groupbitmap, sizeof(groupbitmap));
|
2010-09-23 03:28:00 +00:00
|
|
|
/*
|
|
|
|
* get all nodes that are connected through
|
|
|
|
* transistors, starting with this one
|
|
|
|
*/
|
2010-09-22 18:06:15 +00:00
|
|
|
addNodeToGroup(node);
|
2010-09-22 01:51:38 +00:00
|
|
|
|
2010-09-23 03:28:00 +00:00
|
|
|
/* get the state of the group */
|
2010-09-22 23:02:36 +00:00
|
|
|
state_t newv = getNodeValue();
|
2010-09-23 03:21:13 +00:00
|
|
|
|
2010-09-23 03:28:00 +00:00
|
|
|
/*
|
|
|
|
* now all nodes in this group are in this state,
|
2010-09-23 06:44:32 +00:00
|
|
|
* - all transistors switched by nodes the group
|
|
|
|
* need to be recalculated
|
|
|
|
* - all nodes behind the transistor are collected
|
|
|
|
* and must be looked at in the next run
|
2010-09-23 03:28:00 +00:00
|
|
|
*/
|
2010-09-23 03:21:13 +00:00
|
|
|
for (count_t i = 0; i < groupcount; i++) {
|
2010-09-23 00:38:06 +00:00
|
|
|
nodes_state[group[i]] = newv;
|
2010-09-23 03:28:00 +00:00
|
|
|
for (count_t t = 0; t < nodes_gatecount[group[i]]; t++)
|
2010-09-23 00:38:06 +00:00
|
|
|
recalcTransistor(nodes_gates[group[i]][t]);
|
2010-09-22 05:14:57 +00:00
|
|
|
}
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/*
|
|
|
|
* NOTE: "list" as provided by the caller must
|
|
|
|
* at least be able to hold NODES elements!
|
|
|
|
*/
|
2010-09-22 01:51:38 +00:00
|
|
|
void
|
2010-09-22 23:02:36 +00:00
|
|
|
recalcNodeList(nodenum_t *list, count_t count)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 06:44:32 +00:00
|
|
|
/* storage for secondary list and two sets of bitmaps */
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t list1[NODES];
|
2010-09-23 02:35:50 +00:00
|
|
|
int bitmap1[NODES/sizeof(int)+1];
|
|
|
|
int bitmap2[NODES/sizeof(int)+1];
|
2010-09-22 18:00:45 +00:00
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/* the nodes we are working with */
|
2010-09-22 18:00:45 +00:00
|
|
|
list_t current;
|
|
|
|
current.list = list;
|
|
|
|
current.count = count;
|
|
|
|
current.bitmap = bitmap2;
|
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/* the nodes we are collecting for the next run */
|
2010-09-22 18:00:45 +00:00
|
|
|
recalc.list = list1;
|
|
|
|
recalc.bitmap = bitmap1;
|
|
|
|
|
2010-09-23 02:53:11 +00:00
|
|
|
for (int j = 0; j < 100; j++) { // loop limiter
|
|
|
|
if (!current.count)
|
|
|
|
return;
|
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/* clear secondary list */
|
2010-09-23 02:41:12 +00:00
|
|
|
bzero(recalc.bitmap, sizeof(*recalc.bitmap)*NODES/sizeof(int));
|
|
|
|
recalc.count = 0;
|
2010-09-22 18:00:45 +00:00
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/*
|
|
|
|
* for all nodes, follow their paths through
|
|
|
|
* turned-on transistors, find the state of the
|
|
|
|
* path and assign it to all nodes, and re-evaluate
|
|
|
|
* all transistors controlled by this path, collecting
|
|
|
|
* all nodes that changed because of it for the next run
|
|
|
|
*/
|
2010-09-23 02:53:11 +00:00
|
|
|
for (count_t i = 0; i < current.count; i++)
|
2010-09-22 18:00:45 +00:00
|
|
|
recalcNode(current.list[i]);
|
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/*
|
|
|
|
* make the secondary list our primary list, use
|
|
|
|
* the data storage of the primary list as the
|
|
|
|
* secondary list
|
|
|
|
*/
|
2010-09-23 02:53:11 +00:00
|
|
|
list_t tmp = current;
|
|
|
|
current = recalc;
|
|
|
|
recalc = tmp;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
recalcAllNodes()
|
|
|
|
{
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t list[NODES];
|
2010-09-23 06:44:32 +00:00
|
|
|
for (count_t i = 0; i < NODES; i++)
|
2010-09-22 05:14:57 +00:00
|
|
|
list[i] = i;
|
2010-09-22 07:35:22 +00:00
|
|
|
recalcNodeList(list, NODES);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 02:41:12 +00:00
|
|
|
static inline void
|
|
|
|
setNode(nodenum_t nn, BOOL state)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 02:41:12 +00:00
|
|
|
nodes_pullup[nn] = state;
|
|
|
|
nodes_pulldown[nn] = !state;
|
2010-09-22 22:57:00 +00:00
|
|
|
nodenum_t list[NODES];
|
2010-09-22 07:35:22 +00:00
|
|
|
list[0] = nn;
|
|
|
|
recalcNodeList(list, 1);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-23 02:41:12 +00:00
|
|
|
setLow(nodenum_t nn)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 02:41:12 +00:00
|
|
|
setNode(nn, 0);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 15:25:34 +00:00
|
|
|
void
|
2010-09-23 02:41:12 +00:00
|
|
|
setHigh(nodenum_t nn)
|
2010-09-22 15:25:34 +00:00
|
|
|
{
|
2010-09-23 02:41:12 +00:00
|
|
|
setNode(nn, 1);
|
2010-09-22 15:25:34 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 06:56:23 +00:00
|
|
|
/************************************************************
|
|
|
|
*
|
|
|
|
* Address Bus and Data Bus Interface
|
|
|
|
*
|
|
|
|
************************************************************/
|
|
|
|
|
2010-09-23 06:44:32 +00:00
|
|
|
/* the nodes that make the data bus */
|
|
|
|
const nodenum_t dbnodes[8] = { db0, db1, db2, db3, db4, db5, db6, db7 };
|
2010-09-23 02:47:31 +00:00
|
|
|
|
2010-09-22 05:14:57 +00:00
|
|
|
void
|
|
|
|
writeDataBus(uint8_t x)
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 02:47:31 +00:00
|
|
|
for (int i = 0; i < 8; i++) {
|
2010-09-23 06:44:32 +00:00
|
|
|
nodenum_t nn = dbnodes[i];
|
2010-09-23 02:47:31 +00:00
|
|
|
nodes_pulldown[nn] = !(x & 1);
|
|
|
|
nodes_pullup[nn] = x & 1;
|
2010-09-22 05:14:57 +00:00
|
|
|
x >>= 1;
|
|
|
|
}
|
2010-09-23 06:44:32 +00:00
|
|
|
|
2010-09-23 06:56:23 +00:00
|
|
|
/* recalc all nodes connected starting from the data bus */
|
2010-09-23 06:44:32 +00:00
|
|
|
nodenum_t list[NODES];
|
|
|
|
bcopy(dbnodes, list, sizeof(dbnodes));
|
|
|
|
recalcNodeList(list, 8);
|
2010-09-22 05:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t mRead(uint16_t a)
|
|
|
|
{
|
2010-09-22 15:25:34 +00:00
|
|
|
if (verbose)
|
|
|
|
printf("PEEK($%04X) = $%02X\n", a, memory[a]);
|
2010-09-22 05:14:57 +00:00
|
|
|
return memory[a];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
readAddressBus()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(ab0) << 0) |
|
|
|
|
(isNodeHigh(ab1) << 1) |
|
|
|
|
(isNodeHigh(ab2) << 2) |
|
|
|
|
(isNodeHigh(ab3) << 3) |
|
|
|
|
(isNodeHigh(ab4) << 4) |
|
|
|
|
(isNodeHigh(ab5) << 5) |
|
|
|
|
(isNodeHigh(ab6) << 6) |
|
|
|
|
(isNodeHigh(ab7) << 7) |
|
|
|
|
(isNodeHigh(ab8) << 8) |
|
|
|
|
(isNodeHigh(ab9) << 9) |
|
|
|
|
(isNodeHigh(ab10) << 10) |
|
|
|
|
(isNodeHigh(ab11) << 11) |
|
|
|
|
(isNodeHigh(ab12) << 12) |
|
|
|
|
(isNodeHigh(ab13) << 13) |
|
|
|
|
(isNodeHigh(ab14) << 14) |
|
|
|
|
(isNodeHigh(ab15) << 15);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-22 05:14:57 +00:00
|
|
|
uint8_t
|
|
|
|
readDataBus()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(db0) << 0) |
|
|
|
|
(isNodeHigh(db1) << 1) |
|
|
|
|
(isNodeHigh(db2) << 2) |
|
|
|
|
(isNodeHigh(db3) << 3) |
|
|
|
|
(isNodeHigh(db4) << 4) |
|
|
|
|
(isNodeHigh(db5) << 5) |
|
|
|
|
(isNodeHigh(db6) << 6) |
|
|
|
|
(isNodeHigh(db7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mWrite(uint16_t a, uint8_t d)
|
|
|
|
{
|
2010-09-22 15:25:34 +00:00
|
|
|
if (verbose)
|
|
|
|
printf("POKE $%04X, $%02X\n", a, d);
|
2010-09-22 05:14:57 +00:00
|
|
|
memory[a] = d;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 06:56:23 +00:00
|
|
|
/************************************************************
|
|
|
|
*
|
|
|
|
* Tracing/Debugging
|
|
|
|
*
|
|
|
|
************************************************************/
|
|
|
|
|
2010-09-22 05:14:57 +00:00
|
|
|
uint8_t
|
|
|
|
readA()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(a0) << 0) |
|
|
|
|
(isNodeHigh(a1) << 1) |
|
|
|
|
(isNodeHigh(a2) << 2) |
|
|
|
|
(isNodeHigh(a3) << 3) |
|
|
|
|
(isNodeHigh(a4) << 4) |
|
|
|
|
(isNodeHigh(a5) << 5) |
|
|
|
|
(isNodeHigh(a6) << 6) |
|
|
|
|
(isNodeHigh(a7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
readX()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(x0) << 0) |
|
|
|
|
(isNodeHigh(x1) << 1) |
|
|
|
|
(isNodeHigh(x2) << 2) |
|
|
|
|
(isNodeHigh(x3) << 3) |
|
|
|
|
(isNodeHigh(x4) << 4) |
|
|
|
|
(isNodeHigh(x5) << 5) |
|
|
|
|
(isNodeHigh(x6) << 6) |
|
|
|
|
(isNodeHigh(x7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
readY()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(y0) << 0) |
|
|
|
|
(isNodeHigh(y1) << 1) |
|
|
|
|
(isNodeHigh(y2) << 2) |
|
|
|
|
(isNodeHigh(y3) << 3) |
|
|
|
|
(isNodeHigh(y4) << 4) |
|
|
|
|
(isNodeHigh(y5) << 5) |
|
|
|
|
(isNodeHigh(y6) << 6) |
|
|
|
|
(isNodeHigh(y7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
readP()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(p0) << 0) |
|
|
|
|
(isNodeHigh(p1) << 1) |
|
|
|
|
(isNodeHigh(p2) << 2) |
|
|
|
|
(isNodeHigh(p3) << 3) |
|
|
|
|
(isNodeHigh(p4) << 4) |
|
|
|
|
(isNodeHigh(p5) << 5) |
|
|
|
|
(isNodeHigh(p6) << 6) |
|
|
|
|
(isNodeHigh(p7) << 7);
|
|
|
|
}
|
|
|
|
|
2010-09-22 15:25:34 +00:00
|
|
|
uint8_t
|
|
|
|
readNOTIR()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(notir0) << 0) |
|
|
|
|
(isNodeHigh(notir1) << 1) |
|
|
|
|
(isNodeHigh(notir2) << 2) |
|
|
|
|
(isNodeHigh(notir3) << 3) |
|
|
|
|
(isNodeHigh(notir4) << 4) |
|
|
|
|
(isNodeHigh(notir5) << 5) |
|
|
|
|
(isNodeHigh(notir6) << 6) |
|
|
|
|
(isNodeHigh(notir7) << 7);
|
|
|
|
}
|
|
|
|
|
2010-09-22 05:14:57 +00:00
|
|
|
uint8_t
|
|
|
|
readSP()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(s0) << 0) |
|
|
|
|
(isNodeHigh(s1) << 1) |
|
|
|
|
(isNodeHigh(s2) << 2) |
|
|
|
|
(isNodeHigh(s3) << 3) |
|
|
|
|
(isNodeHigh(s4) << 4) |
|
|
|
|
(isNodeHigh(s5) << 5) |
|
|
|
|
(isNodeHigh(s6) << 6) |
|
|
|
|
(isNodeHigh(s7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
readPCL()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(pcl0) << 0) |
|
|
|
|
(isNodeHigh(pcl1) << 1) |
|
|
|
|
(isNodeHigh(pcl2) << 2) |
|
|
|
|
(isNodeHigh(pcl3) << 3) |
|
|
|
|
(isNodeHigh(pcl4) << 4) |
|
|
|
|
(isNodeHigh(pcl5) << 5) |
|
|
|
|
(isNodeHigh(pcl6) << 6) |
|
|
|
|
(isNodeHigh(pcl7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
readPCH()
|
|
|
|
{
|
|
|
|
return (isNodeHigh(pch0) << 0) |
|
|
|
|
(isNodeHigh(pch1) << 1) |
|
|
|
|
(isNodeHigh(pch2) << 2) |
|
|
|
|
(isNodeHigh(pch3) << 3) |
|
|
|
|
(isNodeHigh(pch4) << 4) |
|
|
|
|
(isNodeHigh(pch5) << 5) |
|
|
|
|
(isNodeHigh(pch6) << 6) |
|
|
|
|
(isNodeHigh(pch7) << 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
readPC()
|
|
|
|
{
|
|
|
|
return (readPCH() << 8) | readPCL();
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
chipStatus()
|
|
|
|
{
|
2010-09-22 15:25:34 +00:00
|
|
|
printf("halfcyc:%d phi0:%d AB:%04X D:%02X RnW:%d PC:%04X A:%02X X:%02X Y:%02X SP:%02X P:%02X IR:%02X\n",
|
2010-09-22 05:14:57 +00:00
|
|
|
cycle,
|
|
|
|
isNodeHigh(clk0),
|
|
|
|
readAddressBus(),
|
|
|
|
readDataBus(),
|
|
|
|
isNodeHigh(rw),
|
|
|
|
readPC(),
|
|
|
|
readA(),
|
|
|
|
readX(),
|
|
|
|
readY(),
|
|
|
|
readSP(),
|
2010-09-22 15:25:34 +00:00
|
|
|
readP(),
|
|
|
|
readNOTIR() ^ 0xFF);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 06:56:23 +00:00
|
|
|
/************************************************************
|
|
|
|
*
|
2010-09-23 07:45:42 +00:00
|
|
|
* Interface to OS Library Code / Monitor
|
2010-09-23 06:56:23 +00:00
|
|
|
*
|
|
|
|
************************************************************/
|
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
void
|
2010-09-23 07:45:42 +00:00
|
|
|
init_monitor()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 07:45:42 +00:00
|
|
|
FILE *f;
|
|
|
|
f = fopen("cbmbasic.bin", "r");
|
|
|
|
fread(memory + 0xA000, 1, 17591, f);
|
|
|
|
fclose(f);
|
2010-09-23 08:06:26 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* fill the KERNAL jumptable with JMP $F800;
|
|
|
|
* we will put code there later that loads
|
|
|
|
* the CPU state and returns
|
|
|
|
*/
|
2010-09-23 07:45:42 +00:00
|
|
|
for (uint16_t addr = 0xFF90; addr < 0xFFF3; addr += 3) {
|
|
|
|
memory[addr+0] = 0x4C;
|
|
|
|
memory[addr+1] = 0x00;
|
|
|
|
memory[addr+2] = 0xF8;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
/*
|
|
|
|
* cbmbasic scribbles over 0x01FE/0x1FF, so we can't start
|
|
|
|
* with a stackpointer of 0 (which seems to be the state
|
|
|
|
* after a RESET), so RESET jumps to 0xF000, which contains
|
|
|
|
* a JSR to the actual start of cbmbasic
|
|
|
|
*/
|
2010-09-23 07:45:42 +00:00
|
|
|
memory[0xf000] = 0x20;
|
|
|
|
memory[0xf001] = 0x94;
|
|
|
|
memory[0xf002] = 0xE3;
|
|
|
|
|
|
|
|
memory[0xfffc] = 0x00;
|
|
|
|
memory[0xfffd] = 0xF0;
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-23 07:45:42 +00:00
|
|
|
handle_monitor()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-22 15:25:34 +00:00
|
|
|
PC = readPC();
|
2010-09-23 08:06:26 +00:00
|
|
|
|
2010-09-22 15:40:26 +00:00
|
|
|
if (PC >= 0xFF90 && ((PC - 0xFF90) % 3 == 0) && isNodeHigh(clk0)) {
|
2010-09-23 08:06:26 +00:00
|
|
|
/* get register status out of 6502 */
|
2010-09-22 15:25:34 +00:00
|
|
|
A = readA();
|
|
|
|
X = readX();
|
|
|
|
Y = readY();
|
|
|
|
S = readSP();
|
|
|
|
P = readP();
|
|
|
|
N = P >> 7;
|
|
|
|
Z = (P >> 1) & 1;
|
|
|
|
C = P & 1;
|
|
|
|
|
|
|
|
kernal_dispatch();
|
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
/* encode processor status */
|
2010-09-23 02:35:50 +00:00
|
|
|
P &= 0x7C; // clear N, Z, C
|
|
|
|
P |= (N << 7) | (Z << 1) | C;
|
|
|
|
|
2010-09-22 15:25:34 +00:00
|
|
|
/*
|
2010-09-23 08:06:26 +00:00
|
|
|
* all KERNAL calls make the 6502 jump to $F800, so we
|
|
|
|
* put code there that loads the return state of the
|
|
|
|
* KERNAL function and returns to the caller
|
|
|
|
*/
|
|
|
|
memory[0xf800] = 0xA9; /* LDA #P */
|
2010-09-22 15:25:34 +00:00
|
|
|
memory[0xf801] = P;
|
2010-09-23 08:06:26 +00:00
|
|
|
memory[0xf802] = 0x48; /* PHA */
|
|
|
|
memory[0xf803] = 0xA9; /* LHA #A */
|
2010-09-22 15:25:34 +00:00
|
|
|
memory[0xf804] = A;
|
2010-09-23 08:06:26 +00:00
|
|
|
memory[0xf805] = 0xA2; /* LDX #X */
|
2010-09-22 15:25:34 +00:00
|
|
|
memory[0xf806] = X;
|
2010-09-23 08:06:26 +00:00
|
|
|
memory[0xf807] = 0xA0; /* LDY #Y */
|
2010-09-22 15:25:34 +00:00
|
|
|
memory[0xf808] = Y;
|
2010-09-23 08:06:26 +00:00
|
|
|
memory[0xf809] = 0x28; /* PLP */
|
|
|
|
memory[0xf80a] = 0x60; /* RTS */
|
|
|
|
/*
|
|
|
|
* XXX we could do RTI instead of PLP/RTS, but RTI seems to be
|
|
|
|
* XXX broken in the chip dump - after the KERNAL call at 0xFF90,
|
|
|
|
* XXX the 6502 gets heavily confused about its program counter
|
|
|
|
* XXX and executes garbage instructions
|
|
|
|
*/
|
2010-09-22 15:25:34 +00:00
|
|
|
}
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 07:45:42 +00:00
|
|
|
/************************************************************
|
|
|
|
*
|
2010-09-23 08:06:26 +00:00
|
|
|
* Main Clock Loop
|
2010-09-23 07:45:42 +00:00
|
|
|
*
|
|
|
|
************************************************************/
|
|
|
|
|
2010-09-22 01:51:38 +00:00
|
|
|
void
|
2010-09-23 08:06:26 +00:00
|
|
|
halfStep()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 08:06:26 +00:00
|
|
|
BOOL clk = isNodeHigh(clk0);
|
2010-09-23 07:45:42 +00:00
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
/* invert clock */
|
|
|
|
setNode(clk0, !clk);
|
2010-09-23 07:45:42 +00:00
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
/* handle memory reads and writes */
|
|
|
|
if (clk && isNodeHigh(rw))
|
|
|
|
writeDataBus(mRead(readAddressBus()));
|
|
|
|
if (!clk && !isNodeHigh(rw))
|
|
|
|
mWrite(readAddressBus(), readDataBus());
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-23 07:45:42 +00:00
|
|
|
step()
|
|
|
|
{
|
|
|
|
halfStep();
|
|
|
|
cycle++;
|
|
|
|
if (verbose)
|
|
|
|
chipStatus();
|
|
|
|
|
|
|
|
handle_monitor();
|
|
|
|
}
|
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
/************************************************************
|
|
|
|
*
|
|
|
|
* Initialization
|
|
|
|
*
|
|
|
|
************************************************************/
|
|
|
|
|
2010-09-23 07:45:42 +00:00
|
|
|
void
|
2010-09-23 08:06:26 +00:00
|
|
|
initChip()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 08:06:26 +00:00
|
|
|
/* all nodes are floating */
|
|
|
|
for (nodenum_t nn = 0; nn < NODES; nn++)
|
|
|
|
nodes_state[nn] = STATE_FL;
|
|
|
|
/* all transistors are off */
|
|
|
|
for (transnum_t tn = 0; tn < TRANSISTORS; tn++)
|
|
|
|
set_transistors_on(tn, NO);
|
|
|
|
|
|
|
|
cycle = 0;
|
|
|
|
|
|
|
|
setLow(res);
|
|
|
|
setLow(clk0);
|
|
|
|
setHigh(rdy);
|
|
|
|
setLow(so);
|
|
|
|
setHigh(irq);
|
|
|
|
setHigh(nmi);
|
|
|
|
|
|
|
|
recalcAllNodes();
|
|
|
|
|
|
|
|
/* hold RESET for 8 cycles */
|
|
|
|
for (int i = 0; i < 16; i++)
|
2010-09-23 07:45:42 +00:00
|
|
|
step();
|
2010-09-23 08:06:26 +00:00
|
|
|
|
|
|
|
/* release RESET */
|
|
|
|
setHigh(res);
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
int
|
|
|
|
main()
|
2010-09-22 01:51:38 +00:00
|
|
|
{
|
2010-09-23 08:06:26 +00:00
|
|
|
/* set up data structures for efficient emulation */
|
2010-09-23 00:38:06 +00:00
|
|
|
setupNodesAndTransistors();
|
2010-09-23 08:06:26 +00:00
|
|
|
/* set initial state of nodes, transistors, inputs; RESET chip */
|
2010-09-22 01:51:38 +00:00
|
|
|
initChip();
|
2010-09-23 08:06:26 +00:00
|
|
|
/* set up memory for user program */
|
2010-09-23 07:45:42 +00:00
|
|
|
init_monitor();
|
|
|
|
|
2010-09-23 08:06:26 +00:00
|
|
|
/* emulate the 6502! */
|
|
|
|
for (;;)
|
|
|
|
step();
|
2010-09-22 01:51:38 +00:00
|
|
|
}
|