[resolved][puzzle] tight spot
kuroneko
Posts: 3,623
The (broken) code fragment below is from a VGA renderer, the first N-1 back porch lines need carry clear while the last one requires carry to be set (as an extra parameter so to speak).
'-----------------------------------------------
[COLOR="orange"]mov ecnt, #29 -1[/COLOR]
[COLOR="orange"]call #blank[/COLOR] ' back porch
[COLOR="orange"]djnz ecnt, #$-1[/COLOR]
[COLOR="blue"]call #blank[/COLOR] ' last blank line done manually
'-----------------------------------------------
blank ...
blank_ret ret
The entry condition for the fragment is carry clear, the blank subroutine returns with carry clear. How can the objective be achieved by only changing code between the lines but not adding extra instructions and/or data? Extra points for keeping the total runtime to a minimum. 
Comments
'----------------------------------------------- [COLOR=orange]mov ecnt, #29[/COLOR] cmp ecnt, #2 wc [COLOR=orange]call #blank[/COLOR] ' back porch [COLOR=orange]djnz ecnt, #$-2[/COLOR] '----------------------------------------------- blank ... blank_ret ret'----------------------------------------------- [COLOR=orange]muxnc ecnt, #29-1 wz [/COLOR] [COLOR=orange]call #blank[/COLOR] ' back porch if_nz [COLOR=orange]djnz ecnt, #$-1 wz,wc [/COLOR] if_z_and_nc jmp #$-3 wc '----------------------------------------------But I can't quite get it to work... preventing the final jmp from happening more than once is the issue.
' ecnt zero, C clear on entry, Z preserved over a call to blank muxnc ecnt, #29-1 wz call #blank ' back porch if_nz djnz ecnt, #$-1 if_nz jmpret ecnt, #$-3 nr,wcBut it's not the solution I'm after, interesting approach though.mov ecnt, #29 -1 call #blank ' back porch djnz ecnt, #$-1 call #blank [color=red]wc[/color] ' last blank line done manuallyFrom the manual: The C flag is set (1) unless PC+1 equals 0; very unlikely since it would require the CALL to be executed from the top of cog RAM ($1FF; special purpose register VSCL).'----------------------------------------------- mov ecnt, #29-1 wc call #blank ' back porch djnz ecnt, #$-1 call #blank wc ' last blank line done manually '----------------------------------------------- blank_ret ret blank ... jmp blank_retblank_ret nop blank ... jmp blank_ret-Phil
-Phil
-Phil
'----------------------------------------------- mov ecnt, #29 -1 ' carry is clear on entry - sets ecnt to 28 call #blank ' call back porch - returns with carry clear djnz ecnt, #$-1 wc ' decrement ecnt and jump to current location - 1 if not 0 (call #blank) ' set carry if ecnt is zero and jump is not taken call #blank ' last blank line done manually '----------------------------------------------- blank ... blank_ret retYeah, I know that. The question is what gets compared with the contents of the return statement in the case of a non-immediate jmpret: the 9-bit literal in the jmpret instruction or the value fetched from the address it points to? I'm betting the latter, since that's the "source" value, not the 9-bit value encoded in the instruction itself.
-Phil
@kwinn, that won't work because the C flag is set only if the count is -1.
BTW, kwinn, if there were an ijnz instruction, your method would work, since incrementing from -1 to zero would cause an unsigned carry.
-Phil
Strictly speaking that's incorrect. The comparison is between destination and source operand. The latter is not always the same as the jump target.
-Phil
'----------------------------------------------- mov ecnt, #29-1 call #blank cmp ecnt, #2 wc djnz ecnt, #blank '-----------------------------------------------Nice one! I like it!
-Phil
mov ecnt, #$18 '27 zeros then 2 ones call #blank :loop shl ecnt, #1 wz,wc if_nz jmp #blankAfter shifting out the first 1 (into carry flag, thus calling with carry) the next shift leaves register zero, terminating loop
'----------------------------------------------- mov ecnt, #29 call #blank cmp ecnt, #3 wc djnz ecnt, #blank '-----------------------------------------------