Puzzle: branching on the m and x flags
Puzzle: branching on the m and x flags
Here is a 65C816 puzzle I found interesting: how to copy the m or x flag into a flag that you can branch on (i.e. the n, v, z, or c flag). In fact, it can be thought of as four sub-puzzles in one, which I have arranged (roughly) in order of increasing difficulty.
The rules are:
A. BPL, BVC, BNE, or BCC must branch to the 16-bit case, i.e. n,v,z, or c is 0 when m or x is 0. (Therefore, BMI, BVS, BEQ, or BCS would branch to the 8-bit case). The other way around is not a valid solution. (From a practical standpoint, it shouldn't matter which branch instruction covers which case, but this restriction makes the puzzles slightly more challenging.)
B. It must produce a correct result no matter what the initial values of the registers and flags are. In particular, you may not assume that the DBR bank is RAM (it could be ROM); in other words, STA ABS does not necessarily store A in a RAM location (unless your code specifically sets the DBR to a RAM bank). Likewise, you may not assume that D register would reference RAM (it might reference I/O); in other words STA DP does not necessarily store in RAM location (unless your code specifically sets the D register to a RAM location). However, you may, if you wish, assume that the S register will reference RAM; in other words, you may use PHA and PLA (or LDA 1,S) if you like.
The (sub)puzzles are:
1. What is the smallest code that will copy the m flag into a flag you can branch on? For a minimal size solution, what is the fewest number of flags, registers, and RAM locations that must be overwritten?
2. Same as #1 (both questions), except copying the x flag instead of the m flag.
3. Same as #1 (both questions), except that all registers (except the P register), all RAM locations, and all flags that can't be branched on (i.e. the m, x, b, d, i, and e flags) must be preserved; in other words, if you are copying the m flag to the v flag you may overwrite the n, z, and c flags, but you must preserve the d flag.
4. Same as #3, except copying the x flag instead of the m flag.
There are multiple answers for each (sub)puzzle. The best I could do was 3 bytes for #1, and #2, and 4 bytes for #3 and #4. (Note that this byte count does not include any subsequent BCC etc. instruction.)
The rules are:
A. BPL, BVC, BNE, or BCC must branch to the 16-bit case, i.e. n,v,z, or c is 0 when m or x is 0. (Therefore, BMI, BVS, BEQ, or BCS would branch to the 8-bit case). The other way around is not a valid solution. (From a practical standpoint, it shouldn't matter which branch instruction covers which case, but this restriction makes the puzzles slightly more challenging.)
B. It must produce a correct result no matter what the initial values of the registers and flags are. In particular, you may not assume that the DBR bank is RAM (it could be ROM); in other words, STA ABS does not necessarily store A in a RAM location (unless your code specifically sets the DBR to a RAM bank). Likewise, you may not assume that D register would reference RAM (it might reference I/O); in other words STA DP does not necessarily store in RAM location (unless your code specifically sets the D register to a RAM location). However, you may, if you wish, assume that the S register will reference RAM; in other words, you may use PHA and PLA (or LDA 1,S) if you like.
The (sub)puzzles are:
1. What is the smallest code that will copy the m flag into a flag you can branch on? For a minimal size solution, what is the fewest number of flags, registers, and RAM locations that must be overwritten?
2. Same as #1 (both questions), except copying the x flag instead of the m flag.
3. Same as #1 (both questions), except that all registers (except the P register), all RAM locations, and all flags that can't be branched on (i.e. the m, x, b, d, i, and e flags) must be preserved; in other words, if you are copying the m flag to the v flag you may overwrite the n, z, and c flags, but you must preserve the d flag.
4. Same as #3, except copying the x flag instead of the m flag.
There are multiple answers for each (sub)puzzle. The best I could do was 3 bytes for #1, and #2, and 4 bytes for #3 and #4. (Note that this byte count does not include any subsequent BCC etc. instruction.)
Re: Puzzle: branching on the m and x flags
Bit of a challenge! Quick recap from your doc:
As a starting point, I'd probably think of
but then of course the PLP has restored everything, as opposed to 'everything else' - and I've used quite a few bytes.
Quote:
The P register contains 9 (yes, 9) of the flags.
- P register bit 7: n flag
P register bit 6: v flag
P register bit 5: m flag (native mode)
P register bit 4: x flag (native mode), b flag (emulation mode)
P register bit 3: d flag
P register bit 2: i flag
P register bit 1: z flag
P register bit 0: c flag
Code: Select all
PHP
PHP
PLA
<something>
PLP
- BitWise
- In Memoriam
- Posts: 996
- Joined: 02 Mar 2004
- Location: Berkshire, UK
- Contact:
Re: Puzzle: branching on the m and x flags
The sequence PHP/PLA is dangerous as P always 8 bits and A may be either 8 or 16. Any BIT or AND instruction could fail unless you set M to known state as part of the test.
So you probably need to do something like:
So you probably need to do something like:
Code: Select all
PHP ; Save MX
.longa off
SEP #$20 ; Ensure A is 8-bits
PHA ; Save A
LDA 2,S ; Fetch Flags
LSR A ; Shift MX down to ZC bits
LSR A
LSR A
LSR A
EOR 2,S ; Difference with current P
AND #$03 ; Limit to ZC bits
EOR 2,S ; And update P
STA 2,S
PLA ; Restore A
PLP ; Restore flags with MX in ZC
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
-
White Flame
- Posts: 704
- Joined: 24 Jul 2012
Re: Puzzle: branching on the m and x flags
Code: Select all
ldx #$ea00In 16-bit index mode, that's ldx #$ea00, so /Z and N.
Switch to lda to test the m bit. Blows a register, though.
Re: Puzzle: branching on the m and x flags
Aha! Testing the behaviour, not the flags themselves. Neat!
-
White Flame
- Posts: 704
- Joined: 24 Jul 2012
Re: Puzzle: branching on the m and x flags
Hmm, I've never actually programmed the 816 before, but if BIT # does 16-bit immediates, then a similar trick could be used as well, without sacrificing the accumulator, if the high 2 bits of the immediate value get shoved into N and V. Ruins Z, though.
Re: Puzzle: branching on the m and x flags
White Flame wrote:
Code: Select all
ldx #$ea00In 16-bit index mode, that's ldx #$ea00, so /Z and N.
Switch to lda to test the m bit. Blows a register, though.
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Puzzle: branching on the m and x flags
White Flame wrote:
Code: Select all
ldx #$ea00In 16-bit index mode, that's ldx #$ea00, so /Z and N.
Switch to lda to test the m bit. Blows a register, though.
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Re: Puzzle: branching on the m and x flags
White Flame wrote:
Code: Select all
ldx #$ea00The first solution I stumbled upon was A9 00 3A which copies m to n. But since DEX is CA and DEY is 88, I didn't immediately get a solution for the x flag, unlike your solution which makes the solution for both obvious. I wasn't able to find any 3 byte solution that overwrote less than 1 register and 2 flags.
For #3 and #4, as mentioned above, 4 bytes is the smallest solution I found when preserving the A and X (or Y) registers. However, the minimum number of flags overwritten was different for the m flag solutions and x flag solutions I found.
-
White Flame
- Posts: 704
- Joined: 24 Jul 2012
Re: Puzzle: branching on the m and x flags
m -> c, clobbers z:
x -> c, clobbers n & z
Code: Select all
clc
bit #$3800 ; sec hidden in 16-bit modeCode: Select all
e0 00 24 18
; when x flag = 1
cpx #$00 ; always sets carry, clobbers n & z
bit #$18 ; clobbers z
; when x flag = 0
cpx #$2400 ; clobbers n, z, c
clc ; always clears c - barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Puzzle: branching on the m and x flags
Ah! I somehow knew that the shortest solutions would use BIT# and CPX#, but I lacked the raw talent to connect the last few dots on my own!
Very impressive.
Mike B.
Very impressive.
Mike B.
-
White Flame
- Posts: 704
- Joined: 24 Jul 2012
Re: Puzzle: branching on the m and x flags
I was actually trying to mask a SEP/REP instruction to directly fiddle one of the branchable status bits, but that always ended up 1 byte longer. Having cpx #$00 set the carry was the key, combining in flag behavior that wouldn't be clobbered easily by the next instructions, as opposed to N or Z.
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Puzzle: branching on the m and x flags
Code: Select all
e0 00 24 18
; when x flag = 1
cpx #$00 ; always sets carry, clobbers n & z
bit #$18 ; clobbers z
; when x flag = 0
cpx #$2400 ; clobbers n, z, c
clc ; always clears c Mike B.
Re: Puzzle: branching on the m and x flags
Technically, using BIT DP is a correct solution. However, recall rule B:
So there is the possibility of a side effect since BIT DP could access an I/O location. A solution without any side effects exists. (And it's faster too.) BIT # is not correct as it assumes m=1 when x=1.
Quote:
...Likewise, you may not assume that D register would reference RAM (it might reference I/O); in other words STA DP does not necessarily store in RAM location (unless your code specifically sets the D register to a RAM location)...
-
White Flame
- Posts: 704
- Joined: 24 Jul 2012
Re: Puzzle: branching on the m and x flags
Yeah, I goofed on that. I originally had BIT dp, but remembered about the I/O clause, flipping it to immediate, and didn't have a lot of time to prove it before posting. Again, I've never coded for the 65816 yet, so this is fun to learn anyway. 
Now, let's see, one reference I saw had WDM without any parameters, but now I see it could be a 2-byte no-op instruction. If it's the latter, then that would be a good substitution for the BIT. Not sure how many cycles it would be.
Now, let's see, one reference I saw had WDM without any parameters, but now I see it could be a 2-byte no-op instruction. If it's the latter, then that would be a good substitution for the BIT. Not sure how many cycles it would be.