@@ -184,6 +184,8 @@ function mapOperandType(operand) {
184184 } else if ( hoverLower . includes ( 'general-purpose' ) ) {
185185 const is64bit = hoverLower . includes ( '64-bit' ) || link . startsWith ( 'x' ) ;
186186 return { type : 'reg' , size : is64bit ? 64 : 32 } ;
187+ } else if ( link . startsWith ( 'cond' ) || link === 'nzcv' ) {
188+ return { type : 'imm' } ;
187189 } else if ( link === 'imm' || link === 'amount' || link === 'shift' || link === 'extend' || link . startsWith ( 'pimm' ) || link . startsWith ( 'simm' ) || link . startsWith ( 'imm' ) ) {
188190 const match = hover . match ( / \[ ( \d + ) - ( \d + ) \] / ) ;
189191 if ( match ) {
@@ -271,6 +273,22 @@ function findVariable(inst, name) {
271273 return inst . variables . find ( v => v . name === name ) || null ;
272274}
273275
276+ /**
277+ * Parse a bitdiffs string like "sf == 1 && N == 1 && imms == 111111"
278+ * into a map { sf: 1, N: 1, imms: 63 }
279+ */
280+ function parseBitdiffs ( bitdiffs ) {
281+ if ( ! bitdiffs ) return { } ;
282+ const result = { } ;
283+ const parts = bitdiffs . split ( '&&' ) . map ( s => s . trim ( ) ) ;
284+ for ( const part of parts ) {
285+ const match = part . match ( / ^ ( \w + ) \s * = = \s * ( [ 0 1 ] + ) $ / ) ;
286+ if ( ! match ) continue ;
287+ result [ match [ 1 ] ] = parseInt ( match [ 2 ] , 2 ) ;
288+ }
289+ return result ;
290+ }
291+
274292/**
275293 * Generate a bit mask expression for a given width
276294 * @param {number } width - Bit width
@@ -1822,7 +1840,7 @@ for (const [mnemonic, variants] of Object.entries(byMnemonic)) {
18221840 output += ` }\n` ;
18231841
18241842 } else if ( format === 'reg_reg_imm' ) {
1825- const immVarNames = [ 'imm12' , 'imm9' , 'imm6' , 'imm5' , 'imm4' , 'imm3' , 'imm' ] ;
1843+ const immVarNames = [ 'imm12' , 'imm9' , 'imm6' , 'imm5' , 'imm4' , 'imm3' , 'immr' , 'cond' , 'nzcv' , ' imm'] ;
18261844 const immVarName = immVarNames . find ( name => findVariable ( inst , name ) ) ;
18271845 const immVar = immVarName ? findVariable ( inst , immVarName ) : null ;
18281846 const hasImmediateField = fields . some ( field => field && field . startsWith ( 'imm' ) ) ;
@@ -1861,6 +1879,31 @@ for (const [mnemonic, variants] of Object.entries(byMnemonic)) {
18611879 if ( useRuntimeCheck ) {
18621880 output += ` int sf = arm64_is_64bit(dst.reg) ? 1 : 0;\n` ;
18631881 output += ` instr |= (sf << 31);\n` ;
1882+
1883+ // For bitfield instructions (UBFM/SBFM), additional bits differ
1884+ // between 32-bit and 64-bit variants (e.g. N bit, imms high bit).
1885+ // Parse bitdiffs to find and apply them.
1886+ const inst32entry = variantGroup . find ( v => v . inst . bitdiffs && v . inst . bitdiffs . includes ( 'sf == 0' ) ) ;
1887+ const inst64entry = variantGroup . find ( v => v . inst . bitdiffs && v . inst . bitdiffs . includes ( 'sf == 1' ) ) ;
1888+ if ( inst32entry && inst64entry ) {
1889+ const diffs32 = parseBitdiffs ( inst32entry . inst . bitdiffs ) ;
1890+ const diffs64 = parseBitdiffs ( inst64entry . inst . bitdiffs ) ;
1891+ for ( const [ fieldName , val64 ] of Object . entries ( diffs64 ) ) {
1892+ if ( fieldName === 'sf' ) continue ;
1893+ const val32 = diffs32 [ fieldName ] ;
1894+ if ( val32 === undefined || val32 === val64 ) continue ;
1895+ const fieldVar = findVariable ( inst , fieldName ) ;
1896+ if ( ! fieldVar ) continue ;
1897+ const extraBits = val64 & ~ val32 ;
1898+ if ( extraBits ) {
1899+ output += ` if (sf) instr |= (${ extraBits } u << ${ fieldVar . lo } );\n` ;
1900+ }
1901+ const clearBits = val32 & ~ val64 ;
1902+ if ( clearBits ) {
1903+ output += ` if (sf) instr &= ~(${ clearBits } u << ${ fieldVar . lo } );\n` ;
1904+ }
1905+ }
1906+ }
18641907 } else if ( has64bit ) {
18651908 output += ` instr |= (1 << 31);\n` ;
18661909 }
@@ -1894,6 +1937,12 @@ for (const [mnemonic, variants] of Object.entries(byMnemonic)) {
18941937 output += ` instr |= ((sh & ${ bitMask ( shField . width ) } ) << ${ shField . lo } );\n` ;
18951938 }
18961939
1940+ // General immediate encoding: if immVar was found and not already
1941+ // handled by the imm12 special case, encode it into its field.
1942+ if ( immVar && immVarName !== 'imm12' ) {
1943+ output += ` instr |= ((imm & ${ bitMask ( immVar . width ) } ) << ${ immVar . lo } );\n` ;
1944+ }
1945+
18971946 output += ` cj_add_u32(ctx, instr);\n` ;
18981947 output += ` return;\n` ;
18991948 output += ` }\n` ;
@@ -2246,7 +2295,7 @@ for (const [mnemonic, variants] of Object.entries(byMnemonic)) {
22462295 output += ` return;\n` ;
22472296 output += ` }\n` ;
22482297 } else if ( format === 'reg_imm' ) {
2249- const immVarNames = [ 'imm' , 'imm12' , 'imm9' , 'imm6' , 'imm5' , 'imm4' , 'imm3' ] ;
2298+ const immVarNames = [ 'imm' , 'imm12' , 'imm9' , 'imm6' , 'imm5' , 'imm4' , 'imm3' , 'cond' , 'nzcv' ] ;
22502299 const immVarName = immVarNames . find ( name => findVariable ( inst , name ) ) ;
22512300 const immVar = immVarName ? findVariable ( inst , immVarName ) : null ;
22522301 const hasImmediateField = fields . some ( field => field && field . startsWith ( 'imm' ) ) ;
@@ -2266,7 +2315,7 @@ for (const [mnemonic, variants] of Object.entries(byMnemonic)) {
22662315 const parseFunc = isFP ? 'arm64_parse_fp_reg' : 'arm64_parse_reg' ;
22672316 const hasRdVar = ! ! findVariable ( inst , 'Rd' ) ;
22682317 const hasRnVar = ! ! findVariable ( inst , 'Rn' ) ;
2269- const immField = fields . find ( field => field && field . startsWith ( 'imm' ) ) ;
2318+ const immField = fields . find ( field => field && ( field . startsWith ( 'imm' ) || field === 'cond' || field === 'nzcv ') ) ;
22702319 const immVar = immField ? findVariable ( inst , immField ) : null ;
22712320 const hwVar = findVariable ( inst , 'hw' ) ;
22722321
0 commit comments