Volume 1 - Complex programs¶
The programs in this sections are re-using concepts and techniques that are introduced in the ref:section about the basics <vol_0>.
Implement A Stack¶
What use is a stack within a CPU? And what if a CPU doesn’t have one?
Out of the box, the Digirule2 does not have an internal stack. It is however possible, to implement one and this implementation relies heavily on the indirect copy snippet that was presented earlier.
1# Simple stack & operations
2
3# A stack is a data structure in which
4# all operations (Read & Write) take
5# place through its "head" pointer.
6
7# In ASM, it looks like an array (e.g stack[n])
8# but unlike an array, "n" IS NOT specified freely
9# but through two simple rules:
10
11# 1 - Increase n AFTER Write
12# 2 - Decrease n BEFORE Read
13
14# Thus "n" always points to the next available
15# value, at the TOP of the stack.
16# Because of this, the Read and Write ops are more
17# descriptively known as PUSH and POP.
18
19# Stacks are also known as First-In-First-Out
20# or FIFO lists.
21
22# In this demo, we demonstrate this "FIFO" logic, by
23# swapping the contents of two variables by:
24# PUSH R0
25# PUSH R1
26# POP R0
27# POP R1
28
29.EQU status_reg=252 # The status register on the Digirule2
30.EQU zero_bit=0
31
32# Initialise the stack head
33COPYLR stack stack_ptr
34
35# To push, point f_from to the variable to push to the
36# head of the stack and call f_push
37# PUSH R0
38COPYLR R0 f_from
39CALL f_push
40
41# PUSH R1
42COPYLR R1 f_from
43CALL f_push
44
45# To pop, point f_to to the variable to pop the head of
46# stack to and call f_pop.
47# POP R0
48# Which now receives the value of R1. >>FIFO<<
49COPYLR R0 f_to
50CALL f_pop
51
52# POP R1
53# Which now receives the value of R0.
54COPYLR R1 f_to
55CALL f_pop
56HALT
57
58# Pushes the value of whatever f_from points to, to
59# the top of the stack.
60f_push:
61COPYRR stack_ptr f_to
62CALL f_copy_ind
63INCR stack_ptr
64RETURN
65
66# Pops the value of the top of the stack to whatever f_to
67# points to.
68f_pop:
69COPYRA stack_ptr
70SUBLA stack
71BCRSS zero_bit status_reg # NOTE THIS CHECK. It prevents >>UNDERFLOW<<
72DECR stack_ptr
73COPYRR stack_ptr f_from
74CALL f_copy_ind
75RETURN
76
77# Memory copy by indirect addressing via self-modification.
78# We construct a suitable absolute
79# addressing copy instruction (COPYRR) and
80# execute it as a sub-routine over f_from, f_to
81f_copy_ind:
82.DB 7
83f_from:
84.DB 0
85f_to:
86.DB 0
87RETURN
88
89R0:
90.DB 0xF0
91R1:
92.DB 0x0F
93stack:
94.DB 0xF0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0x0F
95stack_ptr:
96.DB 0
Function calling conventions¶
The Digirule’s instruction set includes a CALL
operation.
It stores the value of the Program Counter (PC) to the internal stack
and transfer execution to a different point in memory. Execution
returns to the calling point once a RETURN
or RETLA
is encountered.
But, calling functions with an arbitrary number of arguments is slightly different and relies heavily on the CPUs stack.
This little demo shows a cdecl(ish) call convention to swap two numbers.
1# Function calling and call conventions
2
3# Stacks allow us to define functions with
4# many different arguments.
5
6# This brings about the question of how to load
7# and clear the stack before and after a function
8# call.
9
10# There are different ways to do this which are
11# collectively known as "Calling Conventions".
12
13# Here, we are demonstrating a cdecl inspired
14# scheme, adapted to the Digirule ASM.
15
16# In a higher level language, this demo would be
17# written as:
18# unsigned short f_add_two_numbers(unsigned short R0, unsigned short R1){
19# return R0 + R1
20# }
21# ...
22# ...
23# R0 = f_add_two_numbers(2,2)
24
25.EQU status_reg=252 # The status register on the Digirule2
26.EQU zero_bit=0
27
28# Initialise the stack head
29COPYLR stack stack_ptr
30
31COPYLR 2 R0
32COPYLR R0 f_from
33# Push 2 twice, so the function will do 2+2
34CALL f_push
35CALL f_push
36CALL f_add_two_numbers # Equivalent to: f_add_two_numbers(2,2)
37COPYAR R0
38HALT
39
40
41# Self-explanatory
42f_add_two_numbers:
43COPYLR R0 f_to
44CALL f_pop
45COPYRA R0
46CALL f_pop
47ADDRA R0
48RETURN
49
50# Pushes the value of whatever f_from points to, to
51# the top of the stack.
52f_push:
53COPYRR stack_ptr f_to
54CALL f_copy_ind
55INCR stack_ptr
56RETURN
57
58# Pops the value of the top of the stack to whatever f_to
59# points to.
60# NOTE HERE: We re-use the value of the Accumulator which
61# we may be already using in another part of the program.
62# This too is specified in the cdecl convention.
63f_pop:
64COPYAR T0 # Save the Accumulator
65COPYRA stack_ptr
66SUBLA stack
67BCRSS zero_bit status_reg # NOTE THIS CHECK. It prevents >>UNDERFLOW<<
68DECR stack_ptr
69COPYRA T0 # Restore the Accumulator
70COPYRR stack_ptr f_from
71CALL f_copy_ind
72RETURN
73
74# Memory copy by indirect addressing via self-modification.
75# We construct a suitable absolute
76# addressing copy instruction (COPYRR) and
77# execute it as a sub-routine over f_from, f_to
78f_copy_ind:
79.DB 7
80f_from:
81.DB 0
82f_to:
83.DB 0
84RETURN
85
86R0:
87.DB 0xF0
88T0:
89.DB 0xFF
90stack:
91.DB 0xF0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0x0F
92stack_ptr:
93.DB 0
Recursion¶
Being able to call functions, leads naturally to the question “Can a function call itself?”.
This is called recursion and is a very important concept in computer science (and mathematics), since it allows us to express complex iterative processes that are composed of “setup” and repetitive steps.
Having defined a stack on the #Digirule it is relatively easy to express recursion.
This is demonstrated here via the recursive evaluation of a Fibonacci series evaluation.
What is the largest Fibonacci term that the Digirule can compute out of the box?
How many steps does it take to do that?
1# Recursive Fibonacci
2
3.EQU status_reg=252 # The status register on the Digirule2
4.EQU zero_bit=0
5.EQU carry_bit=1
6
7# Initialise the stack head
8COPYLR stack stack_ptr
9
10COPYLR 7 R0
11COPYLR R0 f_from
12CALL f_push
13CALL f_fibonacci
14COPYAR R0
15HALT
16
17
18# Self-explanatory
19f_fibonacci:
20COPYLR R0 f_to
21CALL f_pop
22COPYLA 2
23SUBRA R0
24BCRSS carry_bit status_reg
25JUMP f_fibonacci_ret_num
26DECR R0
27COPYLR R0 f_from
28CALL f_push
29CALL f_push
30CALL f_fibonacci
31COPYAR T1
32COPYLR R0 f_to
33CALL f_pop
34DECR R0
35COPYLR T1 f_from
36CALL f_push
37COPYLR R0 f_from
38CALL f_push
39CALL f_fibonacci
40COPYLR T1 f_to
41CALL f_pop
42ADDRA T1
43RETURN
44
45
46f_fibonacci_ret_num:
47COPYRA R0
48RETURN
49
50COPYRA R0
51CALL f_pop
52ADDRA R0
53RETURN
54
55# Pushes the value of whatever f_from points to, to
56# the top of the stack.
57f_push:
58COPYRR stack_ptr f_to
59CALL f_copy_ind
60INCR stack_ptr
61RETURN
62
63# Pops the value of the top of the stack to whatever f_to
64# points to.
65# NOTE HERE: We re-use the value of the Accumulator which
66# we may be already using in another part of the program.
67f_pop:
68COPYAR T0 # Save the Accumulator
69COPYRA stack_ptr
70SUBLA stack
71BCRSS zero_bit status_reg # NOTE THIS CHECK. It prevents >>UNDERFLOW<<
72DECR stack_ptr
73COPYRA T0 # Restore the Accumulator
74COPYRR stack_ptr f_from
75CALL f_copy_ind
76RETURN
77
78# Memory copy by indirect addressing via self-modification.
79# We construct a suitable absolute
80# addressing copy instruction (COPYRR) and
81# execute it as a sub-routine over f_from, f_to
82f_copy_ind:
83.DB 7
84f_from:
85.DB 0
86f_to:
87.DB 0
88RETURN
89
90R0:
91.DB 0xF0
92T0:
93.DB 0xFF
94T1:
95.DB 0xFF
96stack_ptr:
97.DB 0
98stack:
99.DB 0xF0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0x0F
Find the minimum value of an array of integers¶
One of the more detailed Digirule demos presented here, is that of a very simple random number generator, using a Linear Feedback Shift Register (LFSR). This random number generator, can be used to fill an array with random numbers.
But, what can we do with a set of random numbers?
We can find its minimum (or maximum)
What modifications would this code snippet require, so that it returns the maximum value of the array?
1# Find the minimum value of an array of integers
2
3# Plain simple minimum number finder:
4# Suppose that the first number is the minimum
5# then compare it against all others. If you
6# find a number that is smaller than the initial
7# assumption, make THAT number your current "assumed"
8# min.
9
10.EQU status_reg=252 # The status register on the Digirule
11.EQU carry_bit=1 # Carry bit field of the status reg
12.EQU zero_bit=0 # Zero bit field of the status reg
13
14# R0 Is the iteration bounded var
15# R1 Is the current min value of the array
16# R2 Is the index of the current min value
17
18COPYLR 0 R0 # Locate the zero element of the array...
19COPYLA num_array
20ADDRA R0
21COPYAR f_from
22COPYLR R1 f_to # ...and make it the "current min value".
23CALL f_copy_ind
24COPYRR R0 R2
25loop_start:
26COPYLA num_array
27ADDRA R0 # Fetch the next number from the array...
28COPYAR f_from
29COPYLR R3 f_to
30CALL f_copy_ind
31
32COPYRA R3
33SUBRA R1
34BCRSC carry_bit status_reg # Is it smaller than the "current min value"?
35CALL mark_new_min # If it is, make THAT number the "current min value".
36INCR R0 # Otherwise, move to the next number to compare...
37COPYRA R0
38SUBLA 20
39BCRSS zero_bit status_reg
40JUMP loop_start # UNLESS, you have checked all N numbers (N=20 here) in
41HALT # which case, stop.
42
43mark_new_min:
44COPYRR R0 R2
45COPYRR R3 R1
46RETURN
47
48
49
50# Memory copy by indirect addressing via self-modification.
51# We construct a suitable absolute
52# addressing copy instruction (COPYRR) and
53# execute it as a sub-routine over f_from, f_to
54
55f_copy_ind:
56# memory prior to being called from the main program.
57.DB 7 # COPYRR opcode
58f_from:
59.DB 0
60f_to:
61.DB 0
62RETURN
63
64R0:
65.DB 0
66R1:
67.DB 0
68R2:
69.DB 0
70R3:
71.DB 0
72
73num_array:
74.DB 1,3,8,12,150,14,38,22,110,20,191,88,175,61,59,42,139,222,215,0
Sorting an array of integers¶
Bubble Sort, Shaker Sort, Quicksort, Merge Sort, Heap sort, Insertion sort….Delay sort!
So many different ways to enforce order to a list of items.
This is a demonstration of the simplest, most primitive and slowest algorithm that is based on finding the minimum (or maximum) element in an array: “Selection Sort”.
The algorithm is composed of two steps:
Find the minimum of an array of \(N-n\) numbers starting at position \(n\),
Move that minimum value to position \(n\)
Repeat from step 1 while \(n<N\)
As is, the agorithm sorts a list of integers in ascending order. What modifications would make the algorithm to sort in descending order?
1# Sort a list of integers using "Select Sort".
2
3# Sorting algorithms are often used to
4# demonstrate the concept of computational complexity
5# (i.e. How many steps does it take for an algorithm
6# to complete a task).
7
8# Here is a demonstration of one of the simplest,
9# most primitive and slowest algorithms to sort a
10# list of integers. It is called "Select Sort" and it
11# is basically the repetitive application of
12# finding an extreme element (min or max) and then
13# bringing it to the beginning of the list:
14
15# Find the min of ([5,12,6,1]) --> 1
16# Move it to the beginning ([1,12,6,5])
17# Find the min of (1,[12,6,5]) --> 5
18# Move it to the beginning (1,[5,12,6])
19# Find the min of (1,5,[12,6]) --> 6
20# Move it to the beginning (1,5,6,12) DONE.
21
22.EQU status_reg=252
23.EQU carry_bit=1
24.EQU zero_bit=0
25
26COPYLR 0 R4
27COPYLR 0 R5
28index_loop:
29CALL f_find_min # Find the minimum...
30
31COPYLA num_array # Move it to the beginning of the current block
32ADDRA R5
33COPYAR f_from
34COPYLR R6 f_to
35CALL f_copy_ind
36COPYAR f_to
37COPYLA num_array
38ADDRA R2
39COPYAR f_from
40CALL f_copy_ind
41COPYAR f_to
42COPYLR R6 f_from
43CALL f_copy_ind
44
45INCR R5
46INCR R4
47COPYRA R4
48SUBLA 7 # Have all elements been covered?
49BCRSS zero_bit status_reg
50JUMP index_loop # If not, repeat this sequence of steps
51HALT # Else, terminate.
52
53
54# R0 Is the iteration bounded var
55# R1 Is the current min value of the array
56# R2 Is the index of the current value
57# R3 Is the current value at the current
58# array index
59# R4 is the index of the number that is
60# currently under test.
61
62f_find_min:
63COPYRR R4 R0
64COPYLA num_array
65ADDRA R0
66COPYAR f_from
67COPYLR R1 f_to
68CALL f_copy_ind
69COPYRR R0 R2
70loop_start:
71COPYLA num_array
72ADDRA R0
73COPYAR f_from
74COPYLR R3 f_to
75CALL f_copy_ind
76
77# Now R3 has the next number at offset R0 from label num_array
78# Compare it with the currently assumed minimum
79
80COPYRA R3
81SUBRA R1
82BCRSC carry_bit status_reg
83CALL mark_new_min
84INCR R0
85COPYRA R0
86SUBLA 8
87BCRSS zero_bit status_reg
88JUMP loop_start
89RETURN
90
91mark_new_min:
92COPYRR R0 R2
93COPYRR R3 R1
94RETURN
95
96# Memory copy by indirect addressing via self-modification.
97# We construct a suitable absolute
98# addressing copy instruction (COPYRR) and
99# execute it as a sub-routine over f_from, f_to
100f_copy_ind:
101.DB 7 # COPYRR opcode
102f_from:
103.DB 0
104f_to:
105.DB 0
106RETURN
107
108R0:
109.DB 0
110R1:
111.DB 0
112R2:
113.DB 0
114R3:
115.DB 0
116R4:
117.DB 0
118R5:
119.DB 0
120R6:
121.DB 0
122
123num_array:
124.DB 10,132,8,12,150,9,1,4,192,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Longest Ripple Counter Ever¶
A ripple counter and a relatively accurate clock signal source are the basic building blocks of digital timers.
All that a ripple counter does is count clock pulses. Now, suppose we have some i
and we start counting in binary by repeatedly calling i=i+1
(or i++
for short).
The values of i
will be:
MSb LSb Decimal
bit 76543210
-------------------
00000000 0
00000001 1
00000010 2
00000011 3
00000100 4
00000101 5
00000110 6
00000111 7
........ ...
11111111 255
Bit 0, the Least Significant bit (LSb), counts \(0,1\) and then resets and “signals” bit 1, its neighbour to the left to count \(1\). Once bit 1 has counted its maximum (\(0,1\)) it will reset and “signal” bit 2, its neighbour to the left to count \(1\)….And so on, all the way to the Most Significant bit (MSb)).
From this point of view a ripple counter is just a chain of tiny little elementary counters, each one counting to its maximum and then advancing the next counter.
This continues until i
now assumes the value 255 (or 11111111
in
binary). Now, something special happens: If we try to i++
once more, i
wraps around and hits zero again.
This is a fancy way of saying i
resets and we could “catch” that event
and use it to increase another variable (j
) to start counting. This, would
now look like:
- Increase variable
i
- Once
i
wraps around increasej
- Once
j
wraps around increasek
- Once
k
wraps around increasel
Once
l
wraps around increasem
- Once
- Once
- Once
- Increase variable
And so on until we run out of memory.
In the following Digirule2 program, we use this concept to construct a ripple counter that is 224 BYTES long.
(Notice here the distinction between bit and Byte.)
A 1 byte long counter can count from \(0\) to \(2^{1 \times 8} - 1\), or \(255\).
A 224 byte long counter can count from \(0\) to \(2^{224 \times 8} - 1\) or …
279095111627852376407822673918065072905887935345660252615989519488029661278604994789701101367875859521849524793382568057369148405837577299984720398976429790087982805274893437406788716103454867635208144157749912668657006085226160261808841484862703257771979713923863820038729637520989894984676774385364934677289947762340313157123529922421738738162392233756507666339799675257002539356619747080176786496732679854783185583233878234270370065954615221443190595445898747930123678952192875629172092437548194134594886873249778512829119416327938768895
This number is big.
How Long Is Long?¶
Suppose that it takes the Digirule aproximately \(60e-6\) seconds 1 to increase the counter by 1. That is 60 microseconds.
- This means that this number, describes \(1.67457066976711425845e535\) seconds.
- Divided by 3600 seconds in an hour, it describes \(4.6515851937975396068e531\) hours.
- Divided by 24 hours in a day, it describes \(1.93816049741564150283e530\) days.
- Divided by 30 days in a month, it describes \(6.46053499138547167611e528\) months.
- Divided by 12 months in a year, it describes \(5.38377915948789306342e527\) years.
- Divided by 100 years in a century, it describes \(5.38377915948789306342e525\) centuries.
Divided by 100 centuries in a millenium, it describes \(5.38377915948789306342e523\) millenia.
That is \(\approx 5.4 \times 10^{523}\) millenia.
There is no single battery that will keep this counter going until it counts to its maximum.
There is no single lifetime (devoted to maintaining a running Digirule) within which to see its value wrap around.
And while this counter scans through each and every value between \(0\) and \(2^{1792}\) as it gallops through the millenia, it also goes through ALL the possible Digirule 2 programs that can be constructed in 224 bytes and, all the possible phrases in English 2 that can be described in 224 bytes.
1# One huge ripple counter
2
3# The main idea behind this program was to write the
4# smallest program possible, using the most memory
5# possible.
6
7# The program is making use of some self-modifying code
8# to produce an INCR indirect: An INCR instruction that
9# increases the value of a specific memory location.
10
11# The counter is initialised at a very special occasion:
12# It is about to reset itself from its maximum count back
13# down to 0. This creates a rippling effect as the reset
14# ripple travels from the Least Significant Byte (LSB) to
15# the Most Significant Byte (MSB).
16
17# This counter is 224 BYTES long and the highest number it
18# can represent is:
19
20# 27909511162785237640782267391806507290588793534566025261
21# 59895194880296612786049947897011013678758595218495247933
22# 82568057369148405837577299984720398976429790087982805274
23# 89343740678871610345486763520814415774991266865700608522
24# 61602618088414848627032577719797139238638200387296375209
25# 89894984676774385364934677289947762340313157123529922421
26# 73873816239223375650766633979967525700253935661974708017
27# 67864967326798547831855832338782342703700659546152214431
28# 90595445898747930123678952192875629172092437548194134594
29# 886873249778512829119416327938768895
30
31.EQU status_register=252 # Status register
32.EQU zero_bit=0 # Zero bit of the status reg
33
34count_again:
35COPYLR counter incr_addr # Sets the target of INCR to incr (the LSB)
36CALL incr_ind # Increases the LSB
37
38count_higher:
39BCRSS zero_bit status_register
40JUMP count_again # As soon as the LSB resets, increase
41INCR incr_addr # its most immediate MSB...
42COPYRA incr_addr
43SUBLA 253 # Check if the counter has reached its maximum
44BCRSC zero_bit status_register # addressable byte and wrap around if it has.
45JUMP count_again
46CALL incr_ind # ...and keep rippling up the orders
47JUMP count_higher # of magnitude
48
49# Indirect INCR
50# Set incr_addr then call incr_ind
51incr_ind:
52.DB 19
53incr_addr:
54.DB 0
55RETURN
56
57# Start of the counter state
58counter:
59.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
60.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
61.DB 0xFF, 0xFF, 0xFF, 0xFF
62.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
63.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
64.DB 0xFF, 0xFF, 0xFF, 0xFF
65.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
66.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
67.DB 0xFF, 0xFF, 0xFF, 0xFF
68.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
69.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
70.DB 0xFF, 0xFF, 0xFF, 0xFF
71.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
72.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
73.DB 0xFF, 0xFF, 0xFF, 0xFF
74.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
75.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
76.DB 0xFF, 0xFF, 0xFF, 0xFF
77.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
78.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
79.DB 0xFF, 0xFF, 0xFF, 0xFF
80.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
81.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
82.DB 0xFF, 0xFF, 0xFF, 0xFF
83.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
84.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
85.DB 0xFF, 0xFF, 0xFF, 0xFF
86.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
87.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
88.DB 0xFF, 0xFF, 0xFF, 0xFF
89.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
90.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
91.DB 0xFF, 0xFF, 0xFF, 0xFF
92.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
93.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
94.DB 0xFF, 0xFF, 0xFF, 0xFF
95.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
96.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
97.DB 0xFF, 0xFF, 0xFF, 0xFF
98.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
99.DB 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
100.DB 0xFF, 0xFF, 0xFF, 0xFF
Hacking the Status Register¶
Out of the 8 bits available in Digirule2’s status register, the CPU makes use of just 3:
0 Zero bit (Set when the previous operation resulted in
0
)1 Carry bit (Set when the previous operation results in a carry bit)
2 Display bit (Determines what the ADDR LEDs display)
This leaves another 5 bits “hidden” in the status register that go unused.
Are these bits accessible via Digirule2 code? And if they are, can we use them to save and recall the status register bits themselves?
Answering these questions ends up being a fantastic brainteaser, primarily because the instructions we use to manipulate the status register, also modify the status register.