@@ -231,6 +231,39 @@ static unsigned long long read_imm_64(m68k_info *info)
231231 return value & 0xffffffffffffffff ;
232232}
233233
234+ /* Read a 12-byte Motorola extended-precision immediate: sign+exponent word,
235+ * reserved word, and 64-bit significand. */
236+ static bool imm_bytes_available (const m68k_info * info , size_t size )
237+ {
238+ const uint64_t addr = (info -> pc - info -> baseAddress ) &
239+ info -> address_mask ;
240+ return addr <= info -> code_len && info -> code_len - addr >= size ;
241+ }
242+
243+ static bool read_imm_extended (m68k_info * info , m68k_op_fp_extended * value )
244+ {
245+ if (!imm_bytes_available (info , 12 ))
246+ return false;
247+
248+ memset (value , 0 , sizeof (* value ));
249+ value -> sign_exp = (uint16_t )read_imm_16 (info );
250+ value -> reserved = (uint16_t )read_imm_16 (info );
251+ value -> significand = read_imm_64 (info );
252+ return true;
253+ }
254+
255+ /* Read a 12-byte Motorola packed-decimal immediate. */
256+ static bool read_imm_packed (m68k_info * info , m68k_op_fp_packed * value )
257+ {
258+ if (!imm_bytes_available (info , 12 ))
259+ return false;
260+
261+ memset (value , 0 , sizeof (* value ));
262+ value -> header = read_imm_32 (info );
263+ value -> fraction = read_imm_64 (info );
264+ return true;
265+ }
266+
234267/* 100% portable signed int generators */
235268static int make_int_8 (int value )
236269{
@@ -2906,8 +2939,11 @@ static void d68020_cpgen(m68k_info *info)
29062939 cs_m68k_op * op0 ;
29072940 cs_m68k_op * op1 ;
29082941 bool supports_single_op ;
2942+ bool is_fmove ;
2943+ bool packed_destination ;
2944+ bool ea_operand ;
29092945 uint32_t next ;
2910- int rm , src , dst , opmode ;
2946+ int command_type , src , dst , opmode ;
29112947
29122948 LIMIT_FEATURE (info , M68020_PLUS | CS_MODE_M68K_CF_FPU );
29132949
@@ -2929,15 +2965,20 @@ static void d68020_cpgen(m68k_info *info)
29292965 * operations (type 0-1); fmove_fpcr/fmovem types are dispatched
29302966 * separately and never reach the SD path. */
29312967 uint32_t peeked = peek_imm_16 (info );
2932- if (M68K_FEXT_TYPE (peeked ) <= 1 && M68K_FEXT_SD_FLAG (peeked ))
2968+ if (M68K_FEXT_TYPE (peeked ) <= M68K_FEXT_TYPE_GENERAL_MAX &&
2969+ M68K_FEXT_SD_FLAG (peeked ))
29332970 LIMIT_FEATURE (info , M68040_PLUS | CS_MODE_M68K_CF_FPU );
29342971
29352972 next = read_imm_16 (info );
29362973
2937- rm = M68K_FEXT_RM (next );
2974+ ea_operand = M68K_FEXT_RM (next ) != 0 ;
2975+ command_type = M68K_FEXT_TYPE (next );
29382976 src = M68K_FEXT_SRC (next );
29392977 dst = M68K_FEXT_DST (next );
29402978 opmode = M68K_FEXT_OPMODE (next );
2979+ packed_destination = command_type == M68K_FEXT_TYPE_FMOVE_TO_EA &&
2980+ (src == M68K_FPDST_PACKED_STATIC ||
2981+ src == M68K_FPDST_PACKED_DYNAMIC );
29412982
29422983 if (BITFIELD (info -> ir , 5 , 0 ) == 0 && M68K_FEXT_IS_FMOVECR (next )) {
29432984 ext = build_init_op (info , M68K_INS_FMOVECR , 2 , 0 );
@@ -2954,20 +2995,28 @@ static void d68020_cpgen(m68k_info *info)
29542995 return ;
29552996 }
29562997
2957- switch (M68K_FEXT_TYPE ( next ) ) {
2958- case 0x4 :
2959- case 0x5 :
2998+ switch (command_type ) {
2999+ case M68K_FEXT_TYPE_FPCR_FROM_EA :
3000+ case M68K_FEXT_TYPE_FPCR_TO_EA :
29603001 fmove_fpcr (info , next );
29613002 return ;
29623003
2963- case 0x6 :
2964- case 0x7 :
3004+ case M68K_FEXT_TYPE_FMOVEM_FROM_EA :
3005+ case M68K_FEXT_TYPE_FMOVEM_TO_EA :
29653006 fmovem (info , next );
29663007 return ;
29673008 default :
29683009 break ;
29693010 }
29703011
3012+ /* In a packed register-to-memory FMOVE, bits 6:0 encode the static
3013+ * k-factor or dynamic Dn selector rather than an arithmetic opmode. */
3014+ if (packed_destination ) {
3015+ MCInst_setOpcode (info -> inst , M68K_INS_FMOVE );
3016+ supports_single_op = false;
3017+ goto fpu_operands ;
3018+ }
3019+
29713020 if (M68K_FEXT_SD_FLAG (next )) {
29723021 if (opmode == M68K_FPOP_FSSQRT_RAW ) {
29733022 MCInst_setOpcode (info -> inst , M68K_INS_FSSQRT );
@@ -3112,26 +3161,54 @@ static void d68020_cpgen(m68k_info *info)
31123161
31133162fpu_operands :
31143163 ext = & info -> extension ;
3164+ is_fmove = MCInst_getOpcode (info -> inst ) == M68K_INS_FMOVE ;
31153165
31163166 ext -> op_count = 2 ;
31173167 ext -> op_size .type = M68K_SIZE_TYPE_CPU ;
31183168 ext -> op_size .cpu_size = 0 ;
31193169
3120- if ((opmode == 0x00 ) && M68K_FEXT_DIR (next ) != 0 ) {
3170+ if ((opmode == 0x00 || packed_destination ) &&
3171+ M68K_FEXT_DIR (next ) != 0 ) {
31213172 op0 = & ext -> operands [1 ];
31223173 op1 = & ext -> operands [0 ];
31233174 } else {
31243175 op0 = & ext -> operands [0 ];
31253176 op1 = & ext -> operands [1 ];
31263177 }
31273178
3128- if (rm == 0 && supports_single_op && src == dst ) {
3179+ if (! ea_operand && supports_single_op && src == dst ) {
31293180 ext -> op_count = 1 ;
31303181 op0 -> reg = M68K_REG_FP0 + dst ;
31313182 return ;
31323183 }
31333184
3134- if (rm == 1 ) {
3185+ if (packed_destination ) {
3186+ cs_m68k_op * op_k = & ext -> operands [2 ];
3187+ ext -> op_size .type = M68K_SIZE_TYPE_FPU ;
3188+ ext -> op_size .fpu_size = M68K_FPU_SIZE_PACKED ;
3189+ if (!get_ea_mode_op (info , op0 , info -> ir , 12 )) {
3190+ invalid_insn (info );
3191+ return ;
3192+ }
3193+
3194+ ext -> op_count = 3 ;
3195+ if (src == M68K_FPDST_PACKED_STATIC ) {
3196+ int k_factor = next & 0x7f ;
3197+ if (k_factor & 0x40 )
3198+ k_factor -= 0x80 ;
3199+ op_k -> address_mode = M68K_AM_IMMEDIATE ;
3200+ op_k -> type = M68K_OP_IMM ;
3201+ op_k -> imm = (uint64_t )(int64_t )k_factor ;
3202+ } else {
3203+ op_k -> address_mode = M68K_AM_NONE ;
3204+ op_k -> type = M68K_OP_REG ;
3205+ op_k -> reg = M68K_REG_D0 + ((next >> 4 ) & 7 );
3206+ }
3207+ op1 -> reg = M68K_REG_FP0 + dst ;
3208+ return ;
3209+ }
3210+
3211+ if (ea_operand ) {
31353212 switch (src ) {
31363213 case M68K_FPSRC_LONG :
31373214 ext -> op_size .cpu_size = M68K_CPU_SIZE_LONG ;
@@ -3184,7 +3261,15 @@ static void d68020_cpgen(m68k_info *info)
31843261 case M68K_FPSRC_EXTENDED :
31853262 ext -> op_size .type = M68K_SIZE_TYPE_FPU ;
31863263 ext -> op_size .fpu_size = M68K_FPU_SIZE_EXTENDED ;
3187- if (!get_ea_mode_op (info , op0 , info -> ir , 12 )) {
3264+ if (is_fmove && m68k_ea_is_immediate (info -> ir )) {
3265+ if (!read_imm_extended (info ,
3266+ & op0 -> fp_extended )) {
3267+ invalid_insn (info );
3268+ return ;
3269+ }
3270+ op0 -> address_mode = M68K_AM_IMMEDIATE ;
3271+ op0 -> type = M68K_OP_FP_EXTENDED ;
3272+ } else if (!get_ea_mode_op (info , op0 , info -> ir , 12 )) {
31883273 invalid_insn (info );
31893274 return ;
31903275 }
@@ -3193,7 +3278,16 @@ static void d68020_cpgen(m68k_info *info)
31933278 case M68K_FPSRC_PACKED :
31943279 ext -> op_size .type = M68K_SIZE_TYPE_FPU ;
31953280 ext -> op_size .fpu_size = M68K_FPU_SIZE_EXTENDED ;
3196- if (!get_ea_mode_op (info , op0 , info -> ir , 12 )) {
3281+ if (is_fmove )
3282+ ext -> op_size .fpu_size = M68K_FPU_SIZE_PACKED ;
3283+ if (is_fmove && m68k_ea_is_immediate (info -> ir )) {
3284+ if (!read_imm_packed (info , & op0 -> fp_packed )) {
3285+ invalid_insn (info );
3286+ return ;
3287+ }
3288+ op0 -> address_mode = M68K_AM_IMMEDIATE ;
3289+ op0 -> type = M68K_OP_FP_PACKED ;
3290+ } else if (!get_ea_mode_op (info , op0 , info -> ir , 12 )) {
31973291 invalid_insn (info );
31983292 return ;
31993293 }
@@ -5322,6 +5416,18 @@ static void build_regs_read_write_counts(m68k_info *info)
53225416
53235417 if (!info -> extension .op_count )
53245418 return ;
5419+ if (MCInst_getOpcode (info -> inst ) == M68K_INS_FMOVE &&
5420+ info -> extension .op_size .type == M68K_SIZE_TYPE_FPU &&
5421+ info -> extension .op_size .fpu_size == M68K_FPU_SIZE_PACKED &&
5422+ info -> extension .op_count == 3 ) {
5423+ /* Packed register-to-memory FMOVE reads both the FP source and
5424+ * its static/dynamic k-factor; only the memory operand is a
5425+ * destination. */
5426+ update_op_reg_list (info , & info -> extension .operands [0 ], 0 );
5427+ update_op_reg_list (info , & info -> extension .operands [1 ], 1 );
5428+ update_op_reg_list (info , & info -> extension .operands [2 ], 0 );
5429+ return ;
5430+ }
53255431 if (info -> inst -> Opcode == M68K_INS_FMOVEM &&
53265432 info -> extension .op_count == 2 &&
53275433 info -> extension .operands [1 ].type == M68K_OP_REG ) {
0 commit comments