Clarification on P2 OpCode Identification.

in Propeller 2
I'm trying to better understand the P2ASM OpCodes and am confused by the block on lines #35-42 and #43-50
Picking one example:
EEEE 0100000 CZI DDDDDDDDD SSSSSSSSS TESTB D,{#}S WC/WZ Test bit S[4:0] of D, write to C/Z. C/Z = D[S[4:0]].
vs
EEEE 0100000 CZI DDDDDDDDD SSSSSSSSS BITL D,{#}S {WCZ} Bit S[4:0] of D = 0, C,Z = D[S[4:0]].
How does one differentiate between the two before performing the action in Column F of the spreadsheet?
Thanks,
Red
Picking one example:
EEEE 0100000 CZI DDDDDDDDD SSSSSSSSS TESTB D,{#}S WC/WZ Test bit S[4:0] of D, write to C/Z. C/Z = D[S[4:0]].
vs
EEEE 0100000 CZI DDDDDDDDD SSSSSSSSS BITL D,{#}S {WCZ} Bit S[4:0] of D = 0, C,Z = D[S[4:0]].
How does one differentiate between the two before performing the action in Column F of the spreadsheet?
Thanks,
Red
Comments
This table might help.
EEEE 0100000 00I DDDDDDDDD SSSSSSSSS BITL D,S/# EEEE 0100000 01I DDDDDDDDD SSSSSSSSS TESTB D,S/# WZ EEEE 0100000 10I DDDDDDDDD SSSSSSSSS TESTB D,S/# WC EEEE 0100000 11I DDDDDDDDD SSSSSSSSS BITL D,S/# WCZ EEEE 0100001 00I DDDDDDDDD SSSSSSSSS BITH D,S/# EEEE 0100001 01I DDDDDDDDD SSSSSSSSS TESTBN D,S/# WZ EEEE 0100001 10I DDDDDDDDD SSSSSSSSS TESTBN D,S/# WC EEEE 0100001 11I DDDDDDDDD SSSSSSSSS BITH D,S/# WCZ EEEE 0100010 00I DDDDDDDDD SSSSSSSSS BITC D,S/# EEEE 0100010 01I DDDDDDDDD SSSSSSSSS TESTB D,S/# ANDZ EEEE 0100010 10I DDDDDDDDD SSSSSSSSS TESTB D,S/# ANDC EEEE 0100010 11I DDDDDDDDD SSSSSSSSS BITC D,S/# WCZ EEEE 0100011 00I DDDDDDDDD SSSSSSSSS BITNC D,S/# EEEE 0100011 01I DDDDDDDDD SSSSSSSSS TESTBN D,S/# ANDZ EEEE 0100011 10I DDDDDDDDD SSSSSSSSS TESTBN D,S/# ANDC EEEE 0100011 11I DDDDDDDDD SSSSSSSSS BITNC D,S/# WCZ EEEE 0100100 00I DDDDDDDDD SSSSSSSSS BITZ D,S/# EEEE 0100100 01I DDDDDDDDD SSSSSSSSS TESTB D,S/# ORZ EEEE 0100100 10I DDDDDDDDD SSSSSSSSS TESTB D,S/# ORC EEEE 0100100 11I DDDDDDDDD SSSSSSSSS BITZ D,S/# WCZ EEEE 0100101 00I DDDDDDDDD SSSSSSSSS BITNZ D,S/# EEEE 0100101 01I DDDDDDDDD SSSSSSSSS TESTBN D,S/# ORZ EEEE 0100101 10I DDDDDDDDD SSSSSSSSS TESTBN D,S/# ORC EEEE 0100101 11I DDDDDDDDD SSSSSSSSS BITNZ D,S/# WCZ EEEE 0100110 00I DDDDDDDDD SSSSSSSSS BITRND D,S/# EEEE 0100110 01I DDDDDDDDD SSSSSSSSS TESTB D,S/# XORZ EEEE 0100110 10I DDDDDDDDD SSSSSSSSS TESTB D,S/# XORC EEEE 0100110 11I DDDDDDDDD SSSSSSSSS BITRND D,S/# WCZ EEEE 0100111 00I DDDDDDDDD SSSSSSSSS BITNOT D,S/# EEEE 0100111 01I DDDDDDDDD SSSSSSSSS TESTBN D,S/# XORZ EEEE 0100111 10I DDDDDDDDD SSSSSSSSS TESTBN D,S/# XORC EEEE 0100111 11I DDDDDDDDD SSSSSSSSS BITNOT D,S/# WCZ EEEE 1101011 00L DDDDDDDDD 001000000 DIRL D/# EEEE 1101011 01L DDDDDDDDD 001000000 TESTP D/# WZ EEEE 1101011 10L DDDDDDDDD 001000000 TESTP D/# WC EEEE 1101011 11L DDDDDDDDD 001000000 DIRL D/# WCZ EEEE 1101011 00L DDDDDDDDD 001000001 DIRH D/# EEEE 1101011 01L DDDDDDDDD 001000001 TESTPN D/# WZ EEEE 1101011 10L DDDDDDDDD 001000001 TESTPN D/# WC EEEE 1101011 11L DDDDDDDDD 001000001 DIRH D/# WCZ EEEE 1101011 00L DDDDDDDDD 001000010 DIRC D/# EEEE 1101011 01L DDDDDDDDD 001000010 TESTP D/# ANDZ EEEE 1101011 10L DDDDDDDDD 001000010 TESTP D/# ANDC EEEE 1101011 11L DDDDDDDDD 001000010 DIRC D/# WCZ EEEE 1101011 00L DDDDDDDDD 001000011 DIRNC D/# {WCZ} EEEE 1101011 01L DDDDDDDDD 001000011 TESTPN D/# ANDZ EEEE 1101011 10L DDDDDDDDD 001000011 TESTPN D/# ANDC EEEE 1101011 11L DDDDDDDDD 001000011 DIRNC D/# {WCZ} EEEE 1101011 00L DDDDDDDDD 001000100 DIRZ D/# EEEE 1101011 01L DDDDDDDDD 001000100 TESTP D/# ORZ EEEE 1101011 10L DDDDDDDDD 001000100 TESTP D/# ORC EEEE 1101011 11L DDDDDDDDD 001000100 DIRZ D/# WCZ EEEE 1101011 00L DDDDDDDDD 001000101 DIRNZ D/# EEEE 1101011 01L DDDDDDDDD 001000101 TESTPN D/# ORZ EEEE 1101011 10L DDDDDDDDD 001000101 TESTPN D/# ORC EEEE 1101011 11L DDDDDDDDD 001000101 DIRNZ D/# WCZ EEEE 1101011 00L DDDDDDDDD 001000110 DIRRND D/# EEEE 1101011 01L DDDDDDDDD 001000110 TESTP D/# XORZ EEEE 1101011 10L DDDDDDDDD 001000110 TESTP D/# XORC EEEE 1101011 11L DDDDDDDDD 001000110 DIRRND D/# WCZ EEEE 1101011 00L DDDDDDDDD 001000111 DIRNOT D/# EEEE 1101011 01L DDDDDDDDD 001000111 TESTPN D/# XORZ EEEE 1101011 10L DDDDDDDDD 001000111 TESTPN D/# XORC EEEE 1101011 11L DDDDDDDDD 001000111 DIRNOT D/# WCZ
(Oh, I guess it could be logic puzzle implied by saying you won't have a test without storing the result or a bitl that stores to only one of them.)
Thanks ozpropdev!
Helps a ton.
I should have something to share soonish I hope which people may be amused by.
Glad it was helpful.
http://forums.parallax.com/discussion/comment/1448159/#Comment_1448159
EEEE 0110001 CZ 0 DDDDDDDDD DDDDDDDDD NOT D {WC/WZ/WCZ} EEEE 0110001 CZ I DDDDDDDDD SSSSSSSSS NOT D,{#}S {WC/WZ/WCZ}
Typically the I flag would determine if the # was present or not.
How can I decode the difference between D, S and D, #S?
The difference is when an immediate source is used, I = 1.
For the first case here of NOT D {wc,wz,wcz} the compiler will actually use S=D and I=0
ie NOT D,D {wc,wz ,wcz}
. Math and Logic EEEE 0110001 CZI DDDDDDDDD SSSSSSSSS NOT D,{#}S {WC/WZ/WCZ} Get !S into D. D = !S. C = !S[31]. * alias Math and Logic EEEE 0110001 CZ0 DDDDDDDDD DDDDDDDDD NOT D {WC/WZ/WCZ} Get !D into D. D = !D. C = !D[31]. *
My best guess is it's when S==D, hence the weird register naming.So if I = 0, NOT D. That's clear.
It's the difference between
NOT D, S
and
NOT D, #S
Maybe it's my understanding of the DDDDDDDDD DDDDDDDDD?
I thought that meant an 18 bit number. Is there an implication that that should be two 9 bit numbers that are always equal?
If so, what happens if I=1 and they are not?
S represents the 9 bit address of a cog register which stores the 32 bit number, and the I bit = 0.
It's all one instruction. The alias mnemonic is just tidy way of showing register D being both source and destination. The extra 9 D's is a representative illusion, it's still 9 S's but with duplicate register number. The reason for the I=0 is because that specific case can only be true for register direct addressing.
My last check was 79% coverage this morning so making good progress.
My current peculiarity is decoding jmp/call/calld arguments and trying to end up with the same result as p2dump.
I read the docs so I understand that cog ram addresses as longs and hub ram as bytes and that apparently I have to increment PC by 1 (or 4) when doing relative calls.
I have about 5% of them ending up with results in the wilderness so I just need to apply more time to the problem.
My validation is literal text comparison between the two tools so every whitespace is special. (The disadvantage of this approach is that if there are any bugs in p2dump I will be explicitly replicating them)
I de-lurked my project on Twitter yesterday for those following me there. Right now all my code is in a testing namespace.
I'll post a project thread when I'm near 100% coverage and moved into a real namespace.
If you look in the util/verify directory you will see a few files that I use to do the verification. The script runall tests 33 different spin2 files, and runrand tests 10 Mbytes of random data. BTW, when the disassembler encounters data that produces invalid or ambiguous instructions it will just generate a LONG value with the original data.
I'm impatiently waiting for the end of the work day so I can try and get to 100%
I'm doing my development on a Chromebook which adds a second level of fun to the builds.
p2dump | disasm ------------------------------------------------------------------------------------------------ 0130 ad900010 if_z jmp #$+5 | 0130 ad900010 if_z jmp #$+$14 0150 5d900008 if_nz jmp #$+3 | 0150 5d900008 if_nz jmp #$+$c 0430 fd900000 jmp #$+4 0430 fd900000 jmp #$+4 0454 fd63ec2c jmp $1f6 0454 fd63ec2c jmp $1f6 0534 fd63ec2c jmp $1f6 0534 fd63ec2c jmp $1f6 073c fd90013c jmp #$+$140 073c fd90013c jmp #$+$140
Yup - confirmed. Apparently the algorithm for converting from numbers to addresses differs under 0x400 which makes sense as that's where the cog RAM / hub RAM boundary is.
So, cogram ($200 longs) + lutram (another $200 longs) = 4 kB, but $400 bytes in hubram addressing is only 1 kB.
Therefore, hubexec operates from 1 kB up. cogexec below that.
I see this in the output:
07b4 fb041d28 long $fb041d28 | 07b4 fb041d28 rdlong $e, #$128 07e0 fb041d2c long $fb041d2c | 07e0 fb041d2c rdlong $e, #$12c 0824 fb041d30 long $fb041d30 | 0824 fb041d30 rdlong $e, #$130 0890 fb041b34 long $fb041b34 | 0890 fb041b34 rdlong $d, #$134
I'm not saying mine is correct (it's likely not), but I'm not sure what to make of the results from p2dump either.
In the end, the most complicated part of working out that equation was whether or not the opcode needed you to increase the PC or not when you did the divide. Some did, some didn't.
I use the same disassembler code in spinsim, and it will generate a "rdlong $e, ptra[8]" because it uses more relaxed rules. However, I should flag the instruction as questionable in spinsim.
By default, p2dump assumes that the first $400 bytes run in cog memory, and anything after that runs in hub RAM. This boundary can be adjusted using the -hub option. If you run p2dump without the -data option it will generate DAT, ORG and ORGH instructions, which allow the output file to be assembled by p2asm.
I see that PTRA and PTRB are defined as pointers in HUB RAM.
I also see that cog RAM maps 0x1EF is COG Register, 0x200-0x3F0 COG LUT, 0x400-0xFFFFF is HUB RAM.
What happens if I try to jmp to ptra and ptra < 0x400?
0x200-0x3FF is LUT
0x00000-0x00FFF is HUB but code cannot execute from here (HUB is addressed as bytes)
0x01000-0xFFFFF is HUB where code (hubexec) can be executed from
Note in the current P2 silicon HUB is only 512KB and the top 16KB is also mapped to the top of the 1MB address range
hubexec starts at $400
EEEE 1101011 00L DDDDDDDDD 000000111 LOCKREL D/# {WC}
We can't check for C if we mandate that C is zero? right?