Skip to content

Commit b2cce88

Browse files
committed
optimizations (~25%) and cleanup
Optimizations: 1. When a transistor is turned on, only add one of the nodes it controls to listout, otherwise group calculation would be done twice for this group. This simplifies recalcNodeList(). (This required the following change: Instead of adding the nodes that control transistors that have changed to listout, put the nodes that are switched by transistors on listout.) 2. The group value is calculated while collecting nodes, and the enum group_contains_value makes sure we don't check for weaker value indicators than have already been established. 3. listout is now a set, no node will be visited twice for group calculation, within one interation. 4. When setting input pins of the package to a value, only recalc the node if it actually changes. 5. Toggling a transistor is done by assigning it the group value instead of the inverse of its value. Cleanup: * Merge the concept of listin with the concept of nodes that change from the outside and trigger a recalc.
1 parent bdbe8ef commit b2cce88

File tree

2 files changed

+113
-66
lines changed

2 files changed

+113
-66
lines changed

emu.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ typedef uint8_t step_t;
1212

1313
static step_t t; /* step inside the instruction */
1414
static uint8_t ir; /* instruction register */
15-
static uint8_t operand;
1615
static uint16_t PC;
1716
static uint8_t A, X, Y, S, P;
1817
static uint8_t temp_lo, temp_hi;

perfect6502.c

Lines changed: 113 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ nodenum_t nodes_c1c2s[NODES][2*NODES];
126126
count_t nodes_gatecount[NODES];
127127
count_t nodes_c1c2count[NODES];
128128
nodenum_t nodes_dependants[NODES];
129+
nodenum_t nodes_left_dependants[NODES];
129130
nodenum_t nodes_dependant[NODES][NODES];
131+
nodenum_t nodes_left_dependant[NODES][NODES];
130132

131133
/*
132134
* The "value" propertiy of VCC and GND is never evaluated in the code,
@@ -225,6 +227,8 @@ list_t listout = {
225227
.list = list2,
226228
};
227229

230+
DECLARE_BITMAP(listout_bitmap, NODES);
231+
228232
static inline nodenum_t
229233
listin_get(count_t i)
230234
{
@@ -249,12 +253,16 @@ static inline void
249253
listout_clear()
250254
{
251255
listout.count = 0;
256+
bitmap_clear(listout_bitmap, NODES);
252257
}
253258

254259
static inline void
255260
listout_add(nodenum_t i)
256261
{
257-
listout.list[listout.count++] = i;
262+
if (!get_bitmap(listout_bitmap, i)) {
263+
listout.list[listout.count++] = i;
264+
set_bitmap(listout_bitmap, i, 1);
265+
}
258266
}
259267

260268
/************************************************************
@@ -265,7 +273,7 @@ listout_add(nodenum_t i)
265273

266274
/*
267275
* a group is a set of connected nodes, which consequently
268-
* share the same potential
276+
* share the same value
269277
*
270278
* we use an array and a count for O(1) insert and
271279
* iteration, and a redundant bitmap for O(1) lookup
@@ -312,29 +320,49 @@ group_count()
312320
*
313321
************************************************************/
314322

315-
BOOL group_contains_pullup;
316-
BOOL group_contains_pulldown;
317-
BOOL group_contains_hi;
323+
enum {
324+
contains_nothing,
325+
contains_hi,
326+
contains_pullup,
327+
contains_pulldown,
328+
contains_vcc,
329+
contains_vss
330+
} group_contains_value;
318331

319332
static void
320333
addNodeToGroup(nodenum_t n)
321334
{
335+
/*
336+
* We need to stop at vss and vcc, otherwise we'll revisit other groups
337+
* with the same value - just because they all derive their value from
338+
* the fact that they are connected to vcc or vss.
339+
*/
340+
if (n == vss) {
341+
group_contains_value = contains_vss;
342+
return;
343+
}
344+
if (n == vcc) {
345+
if (group_contains_value != contains_vss)
346+
group_contains_value = contains_vcc;
347+
return;
348+
}
349+
322350
if (group_contains(n))
323351
return;
324352

325353
group_add(n);
326354

327-
if (get_nodes_pullup(n))
328-
group_contains_pullup = YES;
329-
if (get_nodes_pulldown(n))
330-
group_contains_pulldown = YES;
331-
if (get_nodes_value(n))
332-
group_contains_hi = YES;
333-
334-
if (n == vss || n == vcc)
335-
return;
355+
if (group_contains_value < contains_pulldown && get_nodes_pulldown(n)) {
356+
group_contains_value = contains_pulldown;
357+
}
358+
if (group_contains_value < contains_pullup && get_nodes_pullup(n)) {
359+
group_contains_value = contains_pullup;
360+
}
361+
if (group_contains_value < contains_hi && get_nodes_value(n)) {
362+
group_contains_value = contains_hi;
363+
}
336364

337-
/* revisit all transistors that are controlled by this node */
365+
/* revisit all transistors that control this node */
338366
for (count_t t = 0; t < nodes_c1c2count[n]; t++) {
339367
transnum_t tn = nodes_c1c2s[n][t];
340368
/* if the transistor connects c1 and c2... */
@@ -353,29 +381,24 @@ addAllNodesToGroup(node)
353381
{
354382
group_clear();
355383

356-
group_contains_pullup = NO;
357-
group_contains_pulldown = NO;
358-
group_contains_hi = NO;
384+
group_contains_value = contains_nothing;
359385

360386
addNodeToGroup(node);
361387
}
362388

363389
static inline BOOL
364390
getGroupValue()
365391
{
366-
if (group_contains(vss))
367-
return NO;
368-
369-
if (group_contains(vcc))
370-
return YES;
371-
372-
if (group_contains_pulldown)
373-
return NO;
374-
375-
if (group_contains_pullup)
376-
return YES;
377-
378-
return group_contains_hi;
392+
switch (group_contains_value) {
393+
case contains_vcc:
394+
case contains_pullup:
395+
case contains_hi:
396+
return YES;
397+
case contains_vss:
398+
case contains_pulldown:
399+
case contains_nothing:
400+
return NO;
401+
}
379402
}
380403

381404
void
@@ -402,24 +425,33 @@ recalcNode(nodenum_t node)
402425
set_nodes_value(nn, newv);
403426
for (count_t t = 0; t < nodes_gatecount[nn]; t++) {
404427
transnum_t tn = nodes_gates[nn][t];
405-
set_transistors_on(tn, !get_transistors_on(tn));
428+
set_transistors_on(tn, newv);
429+
}
430+
431+
if (newv) {
432+
for (count_t g = 0; g < nodes_left_dependants[nn]; g++) {
433+
listout_add(nodes_left_dependant[nn][g]);
434+
}
435+
} else {
436+
for (count_t g = 0; g < nodes_dependants[nn]; g++) {
437+
listout_add(nodes_dependant[nn][g]);
438+
}
406439
}
407-
listout_add(nn);
408440
}
409441
}
410442
}
411443

412444
void
413-
recalcNodeList(const nodenum_t *source, count_t count)
445+
recalcNodeList()
414446
{
415-
listout_clear();
416-
417-
for (count_t i = 0; i < count; i++)
418-
recalcNode(source[i]);
419-
420-
lists_switch();
421-
422447
for (int j = 0; j < 100; j++) { /* loop limiter */
448+
/*
449+
* make the secondary list our primary list, use
450+
* the data storage of the primary list as the
451+
* secondary list
452+
*/
453+
lists_switch();
454+
423455
if (!listin_count())
424456
break;
425457

@@ -434,25 +466,10 @@ recalcNodeList(const nodenum_t *source, count_t count)
434466
*/
435467
for (count_t i = 0; i < listin_count(); i++) {
436468
nodenum_t n = listin_get(i);
437-
for (count_t g = 0; g < nodes_dependants[n]; g++)
438-
recalcNode(nodes_dependant[n][g]);
469+
recalcNode(n);
439470
}
440-
/*
441-
* make the secondary list our primary list, use
442-
* the data storage of the primary list as the
443-
* secondary list
444-
*/
445-
lists_switch();
446471
}
447-
}
448-
449-
void
450-
recalcAllNodes()
451-
{
452-
nodenum_t temp[NODES];
453-
for (count_t i = 0; i < NODES; i++)
454-
temp[i] = i;
455-
recalcNodeList(temp, NODES);
472+
listout_clear();
456473
}
457474

458475
/************************************************************
@@ -464,9 +481,12 @@ recalcAllNodes()
464481
static inline void
465482
setNode(nodenum_t nn, BOOL state)
466483
{
467-
set_nodes_pullup(nn, state);
468-
set_nodes_pulldown(nn, !state);
469-
recalcNodeList(&nn, 1);
484+
BOOL oldstate = get_nodes_pullup(nn);
485+
if (state != oldstate) {
486+
set_nodes_pullup(nn, state);
487+
set_nodes_pulldown(nn, !state);
488+
listout_add(nn);
489+
}
470490
}
471491

472492
static inline BOOL
@@ -593,11 +613,12 @@ chipStatus()
593613
readP(),
594614
readIR());
595615

596-
if (clk)
616+
if (clk) {
597617
if (r_w)
598618
printf(" R$%04X=$%02X", a, memory[a]);
599619
else
600620
printf(" W$%04X=$%02X", a, d);
621+
}
601622
printf("\n");
602623
}
603624

@@ -642,6 +663,7 @@ step()
642663

643664
/* invert clock */
644665
setNode(clk0, !clk);
666+
recalcNodeList();
645667

646668
/* handle memory reads and writes */
647669
if (!clk)
@@ -668,6 +690,16 @@ add_nodes_dependant(nodenum_t a, nodenum_t b)
668690
nodes_dependant[a][nodes_dependants[a]++] = b;
669691
}
670692

693+
static inline void
694+
add_nodes_left_dependant(nodenum_t a, nodenum_t b)
695+
{
696+
for (count_t g = 0; g < nodes_left_dependants[a]; g++)
697+
if (nodes_left_dependant[a][g] == b)
698+
return;
699+
700+
nodes_left_dependant[a][nodes_left_dependants[a]++] = b;
701+
}
702+
671703
void
672704
setupNodesAndTransistors()
673705
{
@@ -722,10 +754,22 @@ setupNodesAndTransistors()
722754

723755
for (i = 0; i < NODES; i++) {
724756
nodes_dependants[i] = 0;
757+
nodes_left_dependants[i] = 0;
725758
for (count_t g = 0; g < nodes_gatecount[i]; g++) {
726759
transnum_t t = nodes_gates[i][g];
727-
add_nodes_dependant(i, transistors_c1[t]);
728-
add_nodes_dependant(i, transistors_c2[t]);
760+
nodenum_t c1 = transistors_c1[t];
761+
if (c1 != vss && c1 != vcc) {
762+
add_nodes_dependant(i, c1);
763+
}
764+
nodenum_t c2 = transistors_c2[t];
765+
if (c2 != vss && c2 != vcc) {
766+
add_nodes_dependant(i, c2);
767+
}
768+
if (c1 != vss && c1 != vcc) {
769+
add_nodes_left_dependant(i, c1);
770+
} else {
771+
add_nodes_left_dependant(i, c2);
772+
}
729773
}
730774
}
731775
}
@@ -748,14 +792,18 @@ resetChip()
748792
setNode(irq, 1);
749793
setNode(nmi, 1);
750794

751-
recalcAllNodes();
795+
for (count_t i = 0; i < NODES; i++)
796+
listout_add(i);
797+
798+
recalcNodeList();
752799

753800
/* hold RESET for 8 cycles */
754801
for (int i = 0; i < 16; i++)
755802
step();
756803

757804
/* release RESET */
758805
setNode(res, 1);
806+
recalcNodeList();
759807

760808
cycle = 0;
761809
}

0 commit comments

Comments
 (0)