In this log I'll describe a small textbook program to find N'th Fibonacci number, as implemented on my ECM-16/TTL CPU architecture, using the emulation I created recently.
Here is short video of process at 30 Hz clock rate:
-------------
Now, here is the program how it would be written in C:
int fib(N) {
if (N > 1) {
return fib(N - 1) + fib(N - 2);
}
return 1;
}
void main() {
int N = 5;
int F = fib(N);
}
It is very small and uses recursion extensively to find the N'th Fibonacci number very inefficiently. It serves only as demonstration of machine's ability to be able to call functions recursively, and this arguably a big part of Turing completeness proof of the instruction set.
Now, the program above is written in a way that does not output the result anywhere, there is no printf() or the like. I did it deliberately, as for now the emulation does not have any I/O except of rudimentary DMA that can be used to write values directly into the memory. On the other hand, all the registers and memory are visible while the emulation is running, and one of the registers can be chosen to hold output value, and thus the result could be read.
To be able to run this program, it should be compiled and assembled, and due to lack of both compiler and assembler, this is to be done manually.
First, here is C-like code that has flow which is closer to what the assembly program will look like:
void main() {
int N = 5; // r3
int F = fib(N); // r4
}
int fib(N) {
int n = N; // r0
if (n == 0) {
return 1;
}
n = n - 1;
if (n == 0) {
return 1;
}
int a = fib(n); // r6, calculating fib(N-1)
n = N - 2;
int b = fib(n); // r7, calculating fib(N-2)
return a + b; // r0 = r6 + r7
}
This is the same program, but more verbose. All the variables inside the functions are mapped to CPU registers (shown in comments), while function parameters are passed via stack.
Following is the listing of this program written in my assembly, together with machine code values obtained using this table. I added comments so the code could be followed through. After each machine word there is an address in memory where it resides (hexadecimal). All jumps are PC-relative. All data loads/stores are relative to Stack Pointer. The labels are started with underscores.
LDi SP 0x400 ;initialize stack
; 0x3a00, // 0
; 0x0400, // 2
JSR _main ;start main function
; 0x1f01, // 4
JMP -2 ;endless loop == halt execution
; 0x107f, // 6
_main: // #0x08 = 8(dec)
LDi r3 0x5 ;initialize N
; 0x3300, // 8
; 0x0005, // a
ST r3 (SP)+[-2] ;push r3, argument for _fib
; 0x73bf, // c
; 0xfffe, // e
JSR _fib ;calculate result with fib
; 0x1f04, // 10
ADDp SP 2 ;adjust SP, discarding _fib's arg
; 0x0a01, // 12
MOV r4 r0 ;save result to r4 (F)
; 0x2400, // 14
LD PC (SP)[4]+ ;pop PC, return from _main
; 0x68a8, // 16
; 0x0004, // 18
_fib: // #0x1A = 26(dec)
LD r0 (SP)[2] ;load argument into r0
; 0x6038, // 1a
; 0x0004, // 1c
ADD r0 0x0 ;test if it zero
; 0xc000, // 1e
JZ _put_one
; 0x1119, // 20
SUB r0 0x0 ;test if it is 1
; 0xc801, // 22
JZ _put_one
; 0x1117, // 24
ST r6 (SP)+[-2] ;push r6 to preserve for caller
; 0x76bf, // 26
; 0xfffe, // 28
ST r7 (SP)+[-2] ;push r7 to preserve for caller
; 0x77bf, // 2a
; 0xfffe, // 2c
ST r0 (SP)+[-2] ;push r0, arg for call
; 0x70bf, // 2e
; 0xfffe, // 30
JSR _fib ;calling fib(n-1)
; 0x1f73, // 32
ADDp SP 2 ;adjust SP, discarding _fib's arg
; 0x0a01, // 34
MOV r6 r0 ;save fib(n-1) result to r6
; 0x2600, // 36
LD r0 (SP)[8] ;load argument value
;offset is +4(stored PC)+4(stored r6,r7)=+8
; 0x6038, // 38
; 0x0008, // 3a
SUB r0 0x2 ;calculate n-2
; 0xc802, // 3c
ST r0 (SP)+[-2] ;
; 0x70bf, // 3e
; 0xfffe, // 40
JSR _fib ;calling fib(n-2)
; 0x1f6b, // 42
ADDp SP 2 ;adjust SP, discarding _fib's arg
; 0x0a01, // 44
MOV r7 r0 ;save fib(n-2) result to r7
; 0x2700, // 46
ADD r0 r6 r7 ;calculate fib(n-1) + fib(n-2)
; 0x8067, // 48
LD r7 (SP)[2]+ ;pop preserved r7
; 0x67a8, // 4a
; 0x0002, // 4c
LD r6 (SP)[2]+ ;pop preserved r6
; 0x66a8, // 4e
; 0x0002, // 50
JMP _fib_ret ;skip to return
; 0x1002, // 52
_put_one: // #0x54 = 84(dec)
LDi r0 0x1 ;put 1 to r0 - fib result for arg = 0 or 1
; 0x3000, // 54
; 0x0001, // 56
_fib_ret: // #0x58 = 88(dec)
LD PC (SP)[4]+ ;pop PC, thus returning from _fib to callee
; 0x68a8, // 58
; 0x0004, // 5a
Pavel
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.