Add missing TI TMS320C6x archtiectures - C62x, C66x, C67x.#6603
Draft
notxvilka wants to merge 8 commits into
Draft
Add missing TI TMS320C6x archtiectures - C62x, C66x, C67x.#6603notxvilka wants to merge 8 commits into
notxvilka wants to merge 8 commits into
Conversation
TI C6000 relocatable COFF objects carry symbol relocations that Rizin ignored: the relocation path keyed on the PE machine word and read fixed 10-byte entries, but TI COFF2 records its target in a separate field and uses 12-byte entries. MVKL/MVKH address halves and data pointers were left at zero, so nothing referencing a symbol resolved. TI encodes each relocation as an RPN expression evaluated by a small stack machine (SPRAAO8): RE_PUSH* load a symbol value or a constant, the arithmetic operators fold the two top stack entries, and the RE_*STFLD operators store the result into the bit field the reloc's symbol-index word describes. Evaluate that per section, together with the classic direct RELBYTE/WORD/LONG data relocations, and emit one patch per store so both the reloc list and the patched buffer show the resolved address. Co-authored-by agent: Claude/claude-opus-4-8
ELF EM_TI_C6000 objects were falling through to x86; map the machine to the tms320 arch and default the cpu to c674x (the EABI does not record the variant, so use the unified C64x+/C67x+ superset the ABI targets). Convert the full EABI relocation set: the data relocations (ABS8/16/32) resolve to a flat symbol value, the instruction-field relocations (the MVKL/MVKH ABS_L16/H16 halves and the static-base SBR_* and PC-relative PCR_* displacements) patch a bit field inside a 32-bit opcode and so carry their width but no directly resolvable value, and the framing/attribute entries (ALIGN/FPHEAD/NOCMP) patch nothing. A C6000 object that previously resolved no relocations now resolves its full set with symbol names. Co-authored-by agent: Claude/claude-opus-4-8
The C64x support was a thin Capstone wrapper: it only covered C64x, carried no analysis of its own, and could not grow to the rest of the C6000 line. Replace it with one native engine for the whole VLIW family (c62x/c64x/c64x+/c67x/c674x/c66x), structured like the c54x/c55 engines so RzIL and pseudo output can be layered on later. The engine is a pure decoder feeding stateless consumers: decode.c produces a C6xInsn (unit, operands, predicate, parallel bit, op-type) and format.c / analysis.c render text and fill RzAnalysisOp from it. A single opcode table drives every cpu; floating-point and SIMD rows are gated by per-cpu feature flags, so mpysp and the C64x+ integer extensions (mvd, mpyli, mpy32u, andn, ...) decode only where they exist. Double-precision and 40-bit long results render as register pairs (a1:a0). Real C64x+/C674x code is dominated by compact 16-bit instructions: a fetch packet may end in a header word (.fphead) whose layout field repacks the other seven words as pairs of 16-bit opcodes and supplies the register set, saturation, and parallel bit. A fixed 32-bit decoder misaligns the bulk of such code, so the decoder reads the header ahead of the packet and sizes each slot as two or four bytes. Every compact format the corpus exercises is expanded: nop/mv/mvk, the .L ALU and compare-against-constant forms, the .D word/byte/half and doubleword loads/stores in all addressing modes (including the B15 stack forms), the .S shift/field/mvc/mvk forms, and the branches, all carrying the packet-relative displacement. Control flow the Capstone path never produced: B/BNOP displacements to jmp/cjmp with resolved targets, B to a register to rjmp, the BDEC/BPOS loop back-edges, and the ABI return (B .S2 B3) to ret -- in both the 32-bit and compact forms -- so function boundaries and the software-pipelined loop fall out of the graph. CALLP is recognised as a call: it is encoded as an otherwise-meaningless unconditional branch with the z bit set (creg == 0, bits 31:28 == 0001), so a real predicated branch there is unaffected. Branch offsets are relative to the fetch-packet base (PCE1), and BNOP is half-word-scaled so it can reach compact slots; the compact branch encodings are always BNOP, even with a zero NOP count. The whole set is validated byte-exact against TI dis6x (c6000 v7.4.4, run under Wine): all eight emulateme objects (every variant, COFF and ELF, ccsv5 and ccsv7) and 9480 unique instruction words (6047 C64x, 1381 C67x, 2052 C674x) disassemble with zero invalids and zero mismatches. That includes the assembler idioms dis6x prints and the underlying decode already implied -- MV (or/add against 0), NEG, NOT (xor -1), ZERO (a register subtracted from itself), and the negative-constant SUB spelled as an add -- now rendered the same way on the .L, .S, and .D units, whose differing operand orders the earlier code got wrong for the .D forms. The sweeps also corrected a scrambled .S shift table and a set of 40-bit (slong) SUB/ADD forms whose pair destination had been read as a single. The register profile gains the C6000 EABI stack/frame roles (B15 is SP, A15 the frame pointer), the CSR status alias, and the corrected generic-argument mapping (the fourth argument register is B6, not a second A6). Analysis fills op->family (FPU for the floating-point ops), op->val for an immediate operand, and op->stackptr for an add/sub writing the stack pointer, so prologue/epilogue stack motion is visible. The Capstone backend stays reachable as the c64x-capstone cpu for the pseudo output the native engine lacks; the tests asserting Capstone-specific opex are pointed at it, while the shared register profile is exercised through native c64x. The C64x+/C66x packed-SIMD set is filled in across .M, .S, and .L: the packed multiplies and dot products, GMPY4, ROTL, the XPND/SHFL/DEAL/BITC/ BITR shuffles, MPY32(U/SU/US), the packed add/sub/min/max and pack/unpack forms, and MPY(SP2)DP -- derived from the TI asm6x assembler and checked byte-exact against dis6x, cross-path forms included. The C66x complex and matrix multiplies (CMPY*, GMPY, XORMPY, DDOTP*, the 4H dot products) decode in the z=1/creg=0 corner of the same space -- always unconditional, which is exactly what tells them apart from the C64x+ op sharing each slot -- gated so CMPY is invalid on C64x/C67x and DOTP4H on C674x. The 128-bit C66x quad/matrix multiplies (QMPY32, QMPYSP, QSMPY32R1, DMPYSP, CMATMPY/CMATMPYR1) decode too, via a new register- quad operand (a7:a6:a5:a4). Analysis (RzAnalysisOp) covers every added instruction: the packed and complex multiplies are MUL (MPYSPDP/ MPYSP2DP in the FPU family), packed add/sub/compare/shift map to their integer types, SPLOOP is NULL and IDLE is NOP; predication is keyed on creg alone so the unconditional z=1 ops are not mistaken for CJMPs. The software- pipelined loop-buffer ops (SPLOOP/SPLOOPD/SPMASK) and IDLE decode too. The register profile is narrowed per cpu: C62x/C67x expose 16 registers per side and no C64x+ control-register file, C64x and later the full 32 plus that file. Finally the || parallel prefix follows the TI convention -- it marks an instruction that runs in parallel with the *previous* one, carried across the stateless decode calls by a one-word look-back that a fetch-packet header passes through transparently. Co-authored-by agent: Claude/claude-opus-4-8
Lift the decoded C6xInsn to RzIL through op->il_op, with a per-cpu IL config: a 32-bit PC bound as pce1 (the name the c6x profile uses), byte- addressed memory, the 16- or 32-register general set matching the profile (c62x/c67x expose only a0-a15/b0-b15), and the control registers MVC reaches -- the set common to every C6000 plus the C64x+ extension bound only on the wide variants, so IL-VM setup never references a register the profile omits. The scalar core is covered: the MV/MVK/MVKL/MVKH/MVD moves and MVC control-register moves; the register and immediate ALU (ADD, SUB, ADDK, AND, ANDN, OR, XOR, NEG, NOT, ABS with INT_MIN saturation); the shifts (SHL, SHR arithmetic, SHRU logical); the 16x16 multiplies (MPY, MPYH), the two-way dot products (DOTP2 = lo*lo + hi*hi, DOTPN2 = hi*hi - lo*lo), and the four-way byte dot products (DOTPU4 unsigned, DOTPSU4 signed x unsigned); the single- and double-precision float arithmetic (ADDSP/SUBSP/MPYSP and ADDDP/SUBDP/MPYDP over register pairs) and the int-to-float and single-to-int conversions (INTSP, SPINT round to nearest, INTDP, SPDP), lifted through the RzIL floating-point ops as IEEE-754 binary32/binary64 rounding to nearest even (SPINT's decode is added alongside in the disassembler commit); the packed add/sub (ADD2/SUB2 over two halfwords, ADD4/SUB4 over four bytes, each lane independent) and their signed-saturating forms (SADD2/SSUB2, each lane clamped to the signed 16-bit range); the packed min/max (MIN2/MAX2 signed halfwords, MINU4/MAXU4 unsigned bytes) and packed absolute value (ABS2, per halfword with 0x8000 -> 0x7fff saturation); the halfword packs (PACK2/PACKH2/PACKLH2/PACKHL2), the signed 32->16 saturating pack (SPACK2), and the byte unpacks (UNPKLU4/UNPKHU4); the scalar compares (CMPEQ, CMPGT/CMPGTU, CMPLT/CMPLTU, result 1 or 0) and the packed compares (CMPEQ2/CMPGT2 halfwords, CMPEQ4/CMPGTU4 bytes, one result bit per lane); field extracts (EXT, EXTU) and ZERO; the byte/half/word loads and stores and the 64-bit doubleword pair loads and stores (LDDW/STDW and the non-aligned LDNDW/STNDW, whose even register holds the low word at the lower address); and the control transfers -- the B/BNOP branches (register, control-register or PC-relative target), the protected call CALLP (which also records the return address), and the PC-relative address computation ADDKPC. All memory forms cover every addressing mode, including pre/post base write-back. MVC is a plain register copy, so status-register side effects are not modelled. A predicated instruction wraps its effect in a BRANCH on the creg register with the z sense, which for a branch yields a conditional jump. Every lifted form is checked in the c6x asm tests, where rz-asm -I both renders and validates the IL, matching the rest of tms320. One VLIW trait bounds emulation, deliberately for this pass: instructions in one execute packet read the register file as of the packet start (all reads before all writes), which the sequential RzIL VM does not model as a parallel register swap. Branches carry five delay slots; as in the other delay-slot lifters, the IL emits the transfer directly, so the sequential VM takes a branch at once rather than after five execute packets -- but the branch target, and CALLP's return address, are exact. The cont/parallel flags and op->delay carry what a packet- and delay-slot- aware pass would need. The byte-saturating ops, the packed shifts, the saturating/complex multiplies, and the float-to-int conversions (decoder-gated) are not yet lifted. Co-authored-by agent: Claude/claude-opus-4-8
The native c6x engine now decodes, analyzes, and lifts the whole C64x/ C64x+ instruction set (verified byte-exact against the assembler and with zero invalids over the emulateme corpus), so the optional Capstone-based c64x path is redundant. Drop the `c64x-capstone` cpu, its wrapper, and the plugin plumbing; C64x is now native-only. Co-authored-by agent: Claude/claude-opus-4-8
Restore the aoma/aom mnemonic listing that the Capstone path used to provide, now driven by the native decoder. c6x_mnemonics() gathers the printed mnemonic of every decode-table row plus the forms the decoder emits directly (loads, stores, moves, branches, the nop/idle family), sorted and de-duplicated. The asm plugin mnemonics callback serves it for the native c6x cpus and returns nothing for the C5000/C54x front-ends, which expose no such table. Co-authored-by agent: Claude/claude-opus-4-8
The shared cc-tms320-32 sdb only carried the C5000 convention, so C6000 functions fell back to it (ar0-ar3), registers the C6000 file does not have. Add the C6000 EABI (SPRAB89) convention -- arguments in A4/B4/A6/B6/A8/B8/A10/B10/A12/B12, return in A4 -- and point the analysis default at it for the c6x cpus, restoring c55x when a C5000 cpu is selected. Together with the wider reg-profile-to-cc derivation this makes arcc report the full ten-argument convention. Co-authored-by agent: Claude/claude-opus-4-8
Add a module README describing the current state of the c6x native disassembler, analysis, and RzIL uplift: the decoder/consumer split, the VLIW packet and compact-fetch-packet handling, the decoded instruction coverage across the family, and what the RzIL lifter models. Co-authored-by agent: Claude/claude-opus-4-8
| } | ||
| RzILOpPure *off = reg_off | ||
| ? (scale > 1 ? MUL(VARG(c6x_reg_name(m->base_side, m->off_reg)), U32(scale)) : VARG(c6x_reg_name(m->base_side, m->off_reg))) | ||
| : U32(m->off_cst * scale); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Your checklist for this pull request
RZ_APIfunction and struct this PR changes.RZ_API).Detailed description
We had the TMS320C64 support via Capstone, but the capstone implementation is incomplete, also by creating a sharing infrastructure like TMS320C5x series already does and reuse some of the already existing TMS320 infrastructure in Rizin, we can reuse common code (and uplifting to RzIL) between all of the TMS320C6x architectures.
Test plan
CI is green
Closing issues
Closes rizinorg/ideas#64