-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkrapetz23-1V0TzV.txt
125 lines (81 loc) · 9.57 KB
/
krapetz23-1V0TzV.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
Description of Krapets-23
For the most recent version of this document as well as the underlying source code, see: https://github.com/KedalionDaimon/1V0
Krapets-23 is an 1V0 Tz V machine.*
Built around an Attiny85-board as its "heart" and a TM1638-display as its I/O facility, this is a within its practical confines Turing-complete computer of Harvard architecture, i.e. where data and instructions reside in different memory spaces. Hence, e.g. the fifth datum and the fifth instruction have nothing whatsoever to do with each other.
Instructions are situated in the Attiny85's EEPROM space and are in the range 0-127; data are in the range 0-73. Hence, upon power-cycle, Krapets-23 will retain the program, but not the data.
All instructions are being executed in a consecutive order (unless a jump causes a redirection of execution), until either the entire instruction space has been gone through or until an adjustable maximum count of computing steps, the "runlimit", has been executed (default value of the runlimit: 3600). Unknown operands or the operation 0 are skipped over and not executed. Instruction Nr. 0 is special, as it is immediately executed, whereas all other instruction numbers wait for their execution until they have been reached by the program counter. A program is started by executing as the 0th instruction a jump to the desired entry instruction address, from where on execution continues.
Regarding the data, datum 0 is special in that it is always set to 0 and does not accept any other value; and datum 73 is special in that it sets a delay (default: 250 milliseconds) between any two instructions. During a program run, every instruction is displayed on the TM1638 display in the form AABB whereby AA is the number of the instruction being executed and BB signifies the presently executed operand, offering a "trace" of the program execution to the user. Setting datum 73 to a higher value will let the program run go slower and be more observeable, and setting datum 73 to a small value or 0 will let it run fast, but may be hard or impossible to visually comprehend. Numbers are in the range of +-2^31, however, the rightmost two positions are reserved as "places behind the decimal point" as far as multiplication and division are concerned (for addition and subtraction, this does not matter).
There are two types of interaction with the machine: setup and programming.
Regarding setup, after the prompt of 8.8.8.8.8.8.8.8., you may enter one of the following negative numbers in order to execute its corresponding function, respectively; note that negative numbers are signified by all dots lighting up (i.e. not by a "-" in front of the number), and note further that negative numbers are entered as number, then "-" to change its sign. So "-4" is entered as 4- and appears as .......4.
-1, then instruction address: show instruction at the corresponding position, in the form of AABBCCDD, where AA is the operation, and BB, CC, DD are the respective data addresses the instruction operates upon. (If any data address consists of three digits, its display will overflow into the preceding address, but its internal representation will remain unaffected; this matters particularly for instructions like JUMP or SADR mentioned below.)
-2, then datum address: display the datum stored at a data address (remember that for multiplication and division, the last two positions are considered behind the decimal point; hence 100 is 1, ....1.2.3.4. is -12.34, and so on).
-4, then datum address, then datum value: store a datum at a data address.
-5: clear (delete) all instructions.
-6: clear (delete) all data.
-9, then new runlimit: change the runlimit (from its default 3600) - make it smaller or larger.
Regarding programming, in general terms, each instruction is entered after the prompt 8.8.8.8.8.8.8.8. as five numbers:
the address of the instruction in instruction space;
the operation to be performed;
the first, second and then the third datum address which shall be involved in the operation.
Thus, e.g.:
14
9
1
2
3
would mean as 14th instruction, execute addition (9), whereby you add the numbers under the 1st and the 2nd data address and store the result in the third data address. - The third data address is commonly the target of all operations, i.e. where the result is stored. It may be the same as one of the first two addresses, too. The above example would now commonly be written as 14,9,1,2,3. The data addresses shall henceforth be denoted, for brevity, as D1, D2 and D3, and the values stored at them as V1, V2 and V3.
To remember them better, the operations have "names", but these are names only and are not expressed during interaction with the machine - all I/O is purely numeric. The operations available are as follows:
__NOOP__ 0: Do nothing. As instruction memory after clearing is filled with zeroes, this is convenient.
__JUMP__ 1: Depending on the value set by D3, and the value stored at D1, perform a jump to D2, interpreted as an instruction address, or the value stored at D2 interpreted as an instruction address, as follows:
If the value stored at D1 is equal to 0, and D3 itself is 0, or;
if the value stored at D1 is greater than 0, and D3 itself is 1, or;
if the value stored at D1 is less than 0, and D3 itself is 2, or;
if the value stored at D1 is greater than or equal to 0, and D3 itself is 3, or;
if the value stored at D1 is less than or equal to 0, and D3 itself is 4, or;
if the value stored at D1 is not equal to 0, and D3 itself is 5, or;
if D3 itself is 6 (and unconditionally regardless of the value stored at D1);
then jump to D2, where D2 is interpreted as an instruction address; or
if the value stored at D1 is equal to 0, and D3 itself is 7, or;
if the value stored at D1 is greater than 0, and D3 itself is 8, or;
if the value stored at D1 is less than 0, and D3 itself is 9, or;
if the value stored at D1 is greater than or equal to 0, and D3 itself is 10, or;
if the value stored at D1 is less than or equal to 0, and D3 itself is 11, or;
if the value stored at D1 is not equal to 0, and D3 itself is 12, or;
if D3 itself is 13 (and unconditionally regardless of the value stored at D1);
then jump to the value stored at D2, where the value stored at D2 is interpreted as an instruction address.
__IADR__ 2: Indirect addressing preparation; D1, D2 and D3 in this instruction are assumed to point to values V1, V2 and V3, respectively; these V1, V2 and V3 shall themselves serve as D1, D2 and D3 in the NEXT instruction, regardless of what D1, D2 and D3 the next instruction comes with. So, if you have:
...
11,2,1,2,3
12,9,0,0,0
...
whereby datum 1 contains 31, datum 2 contains 23 and datum 3 contains 64, then the next instruction will be executed as if it had been:
...
11,9,31,23,64
...
The use of the instruction lies in supplying indirect addressing, where the exact datum address may not be known at the time of writing the program, but may thus be computed later on and "set" for the proper instruction.
__SADR__ 5: Set address as value, essentially setting V3 to (D1*100 + D2). D1 and D2 can each have values between 0 and 511 (for D2, that means 5.11). The usefulness of the instruction lies in being able to set common constants and other housekeeping values in program space, rather than explicitly entering them as data (and thus, letting data with such setup "survive" reboots, as it will be set up properly next time the program is run, too).
__SVAL__ 6: Set V3 to V2 (ignoring D1 and V1). Like common variable assignment in other languages.
__IVAS__ 8: Indirect value assignment, where the value stored at D3 is interpreted itself as a datum address (say, "X"), and the value stored at X is set to V2. This is useful for manipulating arrays, where D3 may point to an array index, and that array index may change, but the corresponding array element under that array index will be set to V2.
__PLUS__ 9: Addition, V3 = V1 + V2.
__MINS__ 10: Subtraction, V3 = V1 - V2.
__MULS__ 11: Multiplication, V3 = V1 * V2 / 100 (due adjustment for the last two decimals).
__DIVS__ 12: Division, V3 = V1 * 100 / V2 (due adjustment for the last two decimals). Division by 0 results in 0.
In case an error is made (beyond what can corrected through immediate re-editing of a number), instructions merely need to be re-entered. Instructions need not be entered in any particular order, i.e. if you first enter the second, then the third and then the first instruction, they will still be executed in the order first, then second, then third instruction.
An example program to add the numbers from 10 to 20 in steps of 0.5 would appear as:
(Optional: -5 to clear any previous program residuals.)
1,5,0,50,1, set datum 1 to 0.5, the step
2,5,10,0,2, set datum 2 to the lower limit 10
3,5,20,0,3, set datum 3 to the higher limit 20
4,5,0,0,4, set datum 4 to zero for the initial result
5,5,1,0,5, set the difference to 1 (to be adjusted later)
6,1,5,127,2, terminate if the lower limit becomes greater than the higher limit
7,9,4,2,4, result is set to result plus lower limit
8,9,2,1,2, raise the lower limit by the step
9,10,3,2,5, find the difference between the higher and the lower limit
10,1,0,6,6 unconditionally jump to the loop check
To launch the program, do:
0,1,0,1,6
To examine the result, do:
-2, 4
The result should be revealed as 315.00.
* The Tz class signifying its code being based three operands instead of two, "V" being for a version which is reduced in its instructions, but now allowing computed GOTO in the jump instruction (modifiers 7 to 13, inclusive) as well.