@@ -682,46 +682,89 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction)
682682 var imm12 = ( instruction >> 10 ) & 0b1111_1111_1111 ; //Bits 10-21
683683 var rn = ( int ) ( instruction >> 5 ) & 0b11111 ; //Bits 5-9
684684 var rt = ( int ) ( instruction & 0b11111 ) ; //Bits 0-4
685+
686+ //Zero extend imm12 to 64-bit
687+ var immediate = ( long ) imm12 ;
688+ immediate <<= ( int ) size ; //Shift left by the size... apparently?
689+
690+ Arm64Register baseReg ;
691+ Arm64Mnemonic mnemonic ;
692+
693+ if ( isVector )
694+ {
695+ //For once, SIMD/FP is the simple path. It's always LDR or STR, and for all but the 128-bit version, the register depends on size
696+ //Let's get the 128-bit check out first
697+ if ( opc is 0b10 or 0b11 )
698+ {
699+ //128-bit. Ensure size is 00
700+ if ( size != 0 )
701+ throw new Arm64UndefinedInstructionException ( "Load/store register from immediate (unsigned): opc 0b10/0b11 unallocated for size > 0" ) ;
702+
703+ mnemonic = opc == 0b10 ? Arm64Mnemonic . STR : Arm64Mnemonic . LDR ;
704+ baseReg = Arm64Register . V0 ; //128-bit variant
705+ }
706+ else
707+ {
708+ mnemonic = opc == 0b00 ? Arm64Mnemonic . STR : Arm64Mnemonic . LDR ;
709+ baseReg = size switch
710+ {
711+ 0b00 => Arm64Register . B0 , //8-bit variant
712+ 0b01 => Arm64Register . H0 , //16-bit variant
713+ 0b10 => Arm64Register . S0 , //32-bit variant
714+ 0b11 => Arm64Register . D0 , //64-bit variant
715+ _ => throw new ( "Impossible size" )
716+ } ;
717+ }
718+
719+ return new ( )
720+ {
721+ Mnemonic = mnemonic ,
722+ Op0Kind = Arm64OperandKind . Register ,
723+ Op1Kind = Arm64OperandKind . Memory ,
724+ Op0Reg = baseReg + rt ,
725+ MemBase = Arm64Register . X0 + rn ,
726+ MemOffset = immediate ,
727+ MemIndexMode = Arm64MemoryIndexMode . Offset ,
728+ MnemonicCategory = Arm64MnemonicCategory . MemoryToOrFromRegister ,
729+ } ;
730+ }
731+
732+ //Now we have to deal with the non-SIMD/FP case.
685733
686734 //This is considerably less clean than it perhaps could be because they don't stick to patterns and
687735 //the mnemonics are different for different sizes.
688736 //Example - in general, even opc is a store, odd is a load. But opc == 11 && !v && size = 0 => LDRSB. :(
689- var mnemonic = opc switch
737+ mnemonic = opc switch
690738 {
691739 0b00 => size switch
692740 {
693- 0b00 when ! isVector => Arm64Mnemonic . STRB ,
694- 0b01 when ! isVector => Arm64Mnemonic . STRH ,
695- 0b10 or 0b11 when ! isVector => Arm64Mnemonic . STR ,
696- _ when isVector => Arm64Mnemonic . STR ,
741+ 0b00 => Arm64Mnemonic . STRB ,
742+ 0b01 => Arm64Mnemonic . STRH ,
743+ 0b10 or 0b11 => Arm64Mnemonic . STR , //32 or 64-bit
697744 _ => throw new ( $ "Impossible size: { size } ")
698745 } ,
699746 0b01 => size switch
700747 {
701- 0b00 when ! isVector => Arm64Mnemonic . LDRB ,
702- 0b01 when ! isVector => Arm64Mnemonic . LDRH ,
703- 0b10 or 0b11 when ! isVector => Arm64Mnemonic . LDR ,
704- _ when isVector => Arm64Mnemonic . LDR ,
748+ 0b00 => Arm64Mnemonic . LDRB ,
749+ 0b01 => Arm64Mnemonic . LDRH ,
750+ 0b10 or 0b11 => Arm64Mnemonic . LDR , //32 or 64-bit
705751 _ => throw new ( $ "Impossible size: { size } ")
706752 } ,
707753 0b10 => size switch
708754 {
709- 0b00 when ! isVector => Arm64Mnemonic . LDRSB , //64-bit variant
710- 0b01 when ! isVector => Arm64Mnemonic . LDRSH , //64-bit variant
711- 0b10 when ! isVector => Arm64Mnemonic . LDRSW ,
712- 0b00 when isVector => Arm64Mnemonic . STR , //128-bit store
755+ //These all break the rules, they are loads but they are even opc
756+ 0b00 => Arm64Mnemonic . LDRSB , //64-bit variant
757+ 0b01 => Arm64Mnemonic . LDRSH , //64-bit variant
758+ 0b10 => Arm64Mnemonic . LDRSW ,
713759 0b11 => throw new Arm64UndefinedInstructionException ( "Load/store register from immediate (unsigned): opc 0b10 unallocated for size 0b11" ) ,
714- _ when isVector => throw new Arm64UndefinedInstructionException ( "Load/store register from immediate (unsigned): opc 0b10 unallocated for vectors when size > 0" ) ,
715760 _ => throw new ( $ "Impossible size: { size } ")
716761 } ,
717762 0b11 => size switch
718763 {
719- 0b00 when ! isVector => Arm64Mnemonic . LDRSB , //32-bit variant
720- 0b01 when ! isVector => Arm64Mnemonic . LDRSH , //32-bit variant
721- 0b10 when ! isVector => Arm64Mnemonic . PRFM , //TODO?
722- 0b00 when isVector => Arm64Mnemonic . LDR , //128-bit load
764+ 0b00 => Arm64Mnemonic . LDRSB , //32-bit variant
765+ 0b01 => Arm64Mnemonic . LDRSH , //32-bit variant
766+ 0b10 => Arm64Mnemonic . PRFM , //TODO?
723767 0b11 => throw new Arm64UndefinedInstructionException ( "Load/store register from immediate (unsigned): opc 0b11 unallocated for size 0b11" ) ,
724- _ when isVector => throw new Arm64UndefinedInstructionException ( "Load/store register from immediate (unsigned): opc 0b11 unallocated for vectors when size > 0" ) ,
725768 _ => throw new ( $ "Impossible size: { size } ")
726769 } ,
727770 _ => throw new ( "Impossible opc value" )
@@ -730,17 +773,8 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction)
730773 if ( mnemonic == Arm64Mnemonic . PRFM )
731774 throw new NotImplementedException ( "If you're seeing this, reach out, because PRFM is not implemented." ) ;
732775
733- var baseReg = mnemonic switch
776+ baseReg = mnemonic switch
734777 {
735- Arm64Mnemonic . STR or Arm64Mnemonic . LDR when isVector && opc is 0 => size switch
736- {
737- 0 => Arm64Register . B0 ,
738- 1 => Arm64Register . H0 ,
739- 2 => Arm64Register . S0 ,
740- 3 => Arm64Register . D0 ,
741- _ => throw new ( "Impossible size" )
742- } ,
743- Arm64Mnemonic . STR or Arm64Mnemonic . LDR when isVector => Arm64Register . V0 , //128-bit vector
744778 Arm64Mnemonic . STRB or Arm64Mnemonic . LDRB or Arm64Mnemonic . STRH or Arm64Mnemonic . LDRH => Arm64Register . W0 ,
745779 Arm64Mnemonic . STR or Arm64Mnemonic . LDR when size is 0b10 => Arm64Register . W0 ,
746780 Arm64Mnemonic . STR or Arm64Mnemonic . LDR => Arm64Register . X0 ,
@@ -749,21 +783,14 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction)
749783 Arm64Mnemonic . LDRSW => Arm64Register . X0 ,
750784 _ => throw new ( "Impossible mnemonic" )
751785 } ;
752-
753- var regT = baseReg + rt ;
754- var regN = Arm64Register . X0 + rn ;
755-
756- //Zero extend imm12 to 64-bit
757- var immediate = ( long ) imm12 ;
758- immediate <<= ( int ) size ; //Shift left by the size... apparently?
759-
786+
760787 return new ( )
761788 {
762789 Mnemonic = mnemonic ,
763790 Op0Kind = Arm64OperandKind . Register ,
764791 Op1Kind = Arm64OperandKind . Memory ,
765- Op0Reg = regT ,
766- MemBase = regN ,
792+ Op0Reg = baseReg + rt ,
793+ MemBase = Arm64Register . X0 + rn ,
767794 MemOffset = immediate ,
768795 MemIndexMode = Arm64MemoryIndexMode . Offset ,
769796 MnemonicCategory = Arm64MnemonicCategory . MemoryToOrFromRegister ,
0 commit comments