=========================== 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 `. .. _stack_imp: 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. .. literalinclude:: ../../dg_asm_examples/stack/stack.dsf :language: DigiruleASM :linenos: 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. .. literalinclude:: ../../dg_asm_examples/stack/funcall.dsf :language: DigiruleASM :linenos: 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?* .. literalinclude:: ../../dg_asm_examples/recfibo/recfibo.dsf :language: DigiruleASM :linenos: 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 :ref:`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?* .. literalinclude:: ../../dg_asm_examples/findmin/findmin.dsf :language: DigiruleASM :linenos: 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: 1. Find the minimum of an array of :math:`N-n` numbers starting at position :math:`n`, 2. Move that minimum value to position :math:`n` 3. Repeat from step 1 while :math:`n3) and then try to read them back. If their state has been preserved, then they can be considered "accessible". Here is the code: .. literalinclude:: ../../dg_asm_examples/statusreghack/statusreghack.dsf :language: DigiruleASM :linenos: Keying this in to the Digirule2 confirms the result. It is indeed possible to write and read to those "hidden" bits. Using the "hidden" bits to save and restore the status register --------------------------------------------------------------- This all comes down to saving bits 0,1 to higher bits (say for example 4 and 5). The straightforward way to do this would be to store the status register, shift it left by 3,ORit with the saved value and then store that result back to the status register. To restore it we can simply shift right by 3 positions and have the status register set to the stored values. The following code is indeed along those lines but with minor differences since: 1. Logic operations such as ``OR`` go through the Accumulator but ``SHIFT**`` operations can be applied to numeric registers directly. Shifting and ORing to save the status register bits to higher bits would require an extra memory location. Which would then beg the question: Why not just save the status register to memory and move on? (But that is not what we are trying to do here). 1. The ``SHIFT**`` instructions are through the carry bit. Therefore, to just do SHIFT on the Digirule2, it has to be preceded by an instruction that clears the carry bit. 2. The ``COPYRR`` instruction modifies the zero bit. For these reasons, saving and loading the values of the status register is carried out by plain simple bit operations. The code is almost identical which means that it can possibly be reduced and optimised even further (e.g. use the same function for saving and loading). Here is the code: .. literalinclude:: ../../dg_asm_examples/statusreghack/statusreghack3.dsf :language: DigiruleASM :linenos: .. [1] Brent Hauser responded with all the details about the Digirule2's timings on the Discord server. The 60 micro second estimate is a conservative estimate of the Digirule's timing to execute the counter program. If the hardware counts a bit slower than that, then the millenia will keep piling up. Even if the Digirule was made to run 1 order of mangitude faster, that would only knock off one order of magnitude from that :math:`...e51`. It would still be, a big number. .. [2] "...phrases in English" is the quicker thing to describe here, since the ASCII table contains direct correspondences of numbers to English characters. If the memory was interpreted as Unicode, all languages would be possible but in that case, the maximum number of letters described by 224 bytes would varry.