After the previous logs 7. Programming the YGREC8 and 15. Assembly language and syntax, this log shows a few basic programming idioms and explains how to use the YGREC8 architecture.
Conditional execution
Most instructions can be predicated (be executed if a certain condition is met) except IN and OUT (they really stand out, I know). A condition can be given if the SRC operand is a register or a short immediate (imm3), giving a range of -4 to +3. Due to this very narrow range, the ADD opcode will add 1 to imm3 if it ranges from 0 to 3. This extends the range from -4 to +4, thus skipping the value 0 because ADD R1 0 does nothing.
There are three main cases :
- The instruction to conditionally execute is only one opcode and uses only registers, or a imm3 value : the condition is appended to the instruction.
ADD R1 1 IFC ; increments R1 if carry bit set
That's the best, and simplest case. - There is a sequence of two or three instructions to conditionally execute : a conditional short jump will do the trick
ADD PC 4 IFC ; skip 3 instructions if carry bit set MOV R1 R2 MOV R2 R3 ; exchange R2 and R2 MOV R3 R1 ; resume here :
- When 4 or more instructions must be jumped over, a long jump is required but this type of instruction can't have a condition. There are two methods :
- Preload the target address in a register, then conditionally MOV it to PCMOV R1 42h MOV PC R1 IFC
- Invert the condition to perform a short jump, over a long jump to the targetADD PC 1 IFNC MOV PC 42h
The first method requires an additional register so the second is often preferred.
All these methods apply for CALL as well as loops. In particular, the first method of 3 might be used to hold the starting address of a loop and save one instruction cycle.
Call and return
The instruction CALL acts like a MOV but the core swaps NPC and RESULT so the result value is written to PC and the NPC is written to the selected register.
There is no return instruction, this is simply a MOV to PC.
There is no dedicated stack or "link register". Conventions can be drafted but 7 registers are equally possible and they can be optimised easily. CALL to PC however makes no sense and amounts to a MOV (or jump) {this could be used as a special function code or something later}.
- Terminal calls (that don't call anything else) can store the caller's address in any register, be it R or A (D has more side effects).
CALL R1 MyFunc MyFunc: ; do something here ; like, well, actual work ? MOV PC R1 ; return
In the above example, R1 is the "link register" and this leaves R2, R3, A1 and A2 for passing arguments.
- Nested calls must save NPC on the stack. There are two memory spaces and registers : A1/D1 and A2/D2 so it's a matter of internal convention. In this case, CALL goes to D1 or D2, and the callee must increment and decrement the stack pointer :
CALL D1 Nested ... Nested: ADD A1 1 ; push ; do some actual work, like CALL D1 Nested2 ; another non-leaf function ADD A1 -1 ; pop MOV PC D1
Of course, if the function is a leaf, there is no need to increment or decrement the stack pointer.
In all cases, it's important to be sure of the calling convention for each function.
Access to memory is pretty limited (with only 2 ports) so the stack pointer must often be saved and restored if one pointer is not enough to access the required data...
Example
The following listing uses both looping and function call/return to compute the sum of all the integers up to R1 :
; max register value is 256 so it overflows over sqrt(2×256)
MOV R1 22
CALL R2 SUM
; display result here,
; expect (22×22)/2 = 242
INV
SUM:
MOV R3 0 ; clear the accumulator
SUM_LOOP:
ADD R3 R1 ; accumulate
ADD R1 -1 ; decrement the counter
ADD PC -2 IFNC ; loop back to SUM_LOOP if carry not set
; (could have been IFNS if R1 argument
; is guaranteed > 0, saving one iteration)
; result of accumulation in R3
MOV PC R2 ; return
So the YGREC8 core is not very powerful but just enough to do some useful work in an unusual yet not too awkward way.
Stack
As previously seen, there is no stack-specific mechanism or opcode. The stack can be mapped to A1/D1 or A2/D2. Or both. They can grow up or down. No stack overflow is provided.
Push and pop are software-defined and amount to incrementing or decrementing the relevant A register.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
This log is 5 years old and the coding conventions have changed since.... Destination is at the end now.
Are you sure? yes | no