diff --git a/tms320/c2x/README.md b/tms320/c2x/README.md new file mode 100644 index 0000000..b09d1a0 --- /dev/null +++ b/tms320/c2x/README.md @@ -0,0 +1,55 @@ +# TMS320C2x (legacy) test fixtures + +Fixtures for Rizin's legacy single-accumulator TMS320C2x support +(`asm.arch=tms320`, `analysis.cpu=c2x`; COFF autodetect via target id +`0x0092`). + +## Why these are hand-built + +Unlike the other TMS320 targets in this directory (`c54x`, `c55x`, `c28x`, +`c6x` — all compiled from `emulateme_nostd.c` by the TI CGT tools, see +`../compilation_cmds_ccsv5.txt`), the legacy C2x has **no available +assembler**: + +* The TI **C2000** Code Generation Tools (`cl2000`/`asm2000`) target **C28x**, + not the legacy single-accumulator C2x — a different instruction set. +* **binutils** ships `tic54x`, `tic4x` and `tic30` GAS targets, but nothing + for the legacy C2x/C25. + +So C2x machine code is produced by hand from the published instruction +encodings (the opcode bit patterns match MAME's tested `tms32025` disassembler). +The disassembly/IL expectations live in the Rizin tree, not here: + +* `test/db/asm/tms320_c2x_16` — disassembly + RzIL vectors (`d "..." `). +* `test/db/analysis/tms320.c2x_16` — op classification, reg profile, COFF open. + +## Files + +* `hello_c2x.ticoff2.coff` — a minimal TI COFF2 object (`nop; zac; lack #1; + ret`) with file magic `0x00C2` and target id `0x0092` (the first-generation + fixed-point id shared by the C1x/C2x/C5x tools), used by the COFF-open test. +* `make_c2x_coff.py` — regenerates the COFF object: + `python3 make_c2x_coff.py hello_c2x.ticoff2.coff` + +## Verification status + +These fixtures were prepared against the encoding reference and the COFF format, +but had not been round-tripped through a built `rz-asm`/loader at authoring +time. The COFF `target_id 0x0092` mapping and the F8..FF branch opcode tail in +particular should be confirmed against real C2x objects before being relied on. + +## TMS320C5x + +The C5x (C50/C51/C53) is an upward-compatible superset of the C2x and shares +the legacy first-generation COFF target id (`0x0092`), so the same fixture also +exercises the `c5x` CPU when opened with `-c c5x`: + +``` +rizin -a tms320 -c c5x hello_c2x.ticoff2.coff +``` + +Rizin decodes the C5x via the shared C2x core (which covers the C2x-compatible +instruction set that forms the bulk of real C5x code) and exposes the full C5x +register model (ACCB, PMST, TREG1/2, the circular-buffer pointers, BMAR, ...). +Real C5x objects (e.g. TMS320C5x DSK `.obj`/`.out` images) open and report +`arch=tms320, cpu=c2x, bits=16` and can be re-opened as `c5x`. diff --git a/tms320/c2x/hello_c2x.ticoff2.coff b/tms320/c2x/hello_c2x.ticoff2.coff new file mode 100644 index 0000000..9c7ef20 Binary files /dev/null and b/tms320/c2x/hello_c2x.ticoff2.coff differ diff --git a/tms320/c2x/make_c2x_coff.py b/tms320/c2x/make_c2x_coff.py new file mode 100644 index 0000000..07cd96c --- /dev/null +++ b/tms320/c2x/make_c2x_coff.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 RizinOrg +# SPDX-License-Identifier: LGPL-3.0-only +# +# Generate a minimal TI COFF2 object for the legacy TMS320C2x. No assembler +# targets the legacy C2x (neither the TI C2000 tools, which emit C28x, nor +# binutils), so this hand-assembles a tiny .text section of known C2x words and +# wraps it in a TI COFF2 container with target_id 0x0092 (the first-generation +# fixed-point id, shared by the C1x/C2x/C5x tools) so Rizin's COFF loader +# autodetects arch=tms320, cpu=c2x. Headers are little-endian (TI COFF +# convention); the C2x instruction words in .text are MSB-first. +import struct, sys + +# .text : nop ; zac ; lack #1 ; ret (MSB-first 16-bit words) +code_words = [0x5500, 0xCA00, 0xCA01, 0xCE26] +text = b"".join(struct.pack(">H", w) for w in code_words) # big-endian words + +F_MAGIC = 0x00C2 # TI COFF version 2 +TARGET_ID = 0x0092 # TMS320C1x/C2x/C5x (first-gen fixed point) +OPTHDR_SIZE = 28 +SCNHDR_SIZE = 40 +HDR_SIZE = 20 + +# layout: file hdr(20) + target_id(2) + opt hdr(28) + 1 scn hdr(40) + data +data_off = HDR_SIZE + 2 + OPTHDR_SIZE + SCNHDR_SIZE + +# file header (little-endian) +fh = struct.pack(" 1 else "hello_c2x.ticoff2.coff" +open(out, "wb").write(blob) +print("wrote %s (%d bytes), text=%d bytes" % (out, len(blob), len(text))) diff --git a/tms320/c2x_legacy/01_arithmetic.bin b/tms320/c2x_legacy/01_arithmetic.bin new file mode 100644 index 0000000..c104cff Binary files /dev/null and b/tms320/c2x_legacy/01_arithmetic.bin differ diff --git a/tms320/c2x_legacy/02_logic_shifts.bin b/tms320/c2x_legacy/02_logic_shifts.bin new file mode 100644 index 0000000..913d50c Binary files /dev/null and b/tms320/c2x_legacy/02_logic_shifts.bin differ diff --git a/tms320/c2x_legacy/03_branches_calls.bin b/tms320/c2x_legacy/03_branches_calls.bin new file mode 100644 index 0000000..0195b4b Binary files /dev/null and b/tms320/c2x_legacy/03_branches_calls.bin differ diff --git a/tms320/c2x_legacy/04_fir_filter.bin b/tms320/c2x_legacy/04_fir_filter.bin new file mode 100644 index 0000000..b01244d Binary files /dev/null and b/tms320/c2x_legacy/04_fir_filter.bin differ diff --git a/tms320/c2x_legacy/05_status_data.bin b/tms320/c2x_legacy/05_status_data.bin new file mode 100644 index 0000000..78aa770 Binary files /dev/null and b/tms320/c2x_legacy/05_status_data.bin differ diff --git a/tms320/c2x_legacy/10_full_program.bin b/tms320/c2x_legacy/10_full_program.bin new file mode 100644 index 0000000..3a14ad2 Binary files /dev/null and b/tms320/c2x_legacy/10_full_program.bin differ diff --git a/tms320/c2x_legacy/emulateme.bin b/tms320/c2x_legacy/emulateme.bin new file mode 100644 index 0000000..95267c3 Binary files /dev/null and b/tms320/c2x_legacy/emulateme.bin differ diff --git a/tms320/c2x_legacy/src/01_arithmetic.asm b/tms320/c2x_legacy/src/01_arithmetic.asm new file mode 100644 index 0000000..6e79f05 --- /dev/null +++ b/tms320/c2x_legacy/src/01_arithmetic.asm @@ -0,0 +1,68 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 01_arithmetic.asm -- TMS320C2x arithmetic and load/store coverage. +; +; Ported in spirit from the C54x coff1/01_arithmetic.s, re-expressed for the +; single-accumulator C2x: ADD/SUB with shifts and the H/S/T/C variants, the +; ADDK/SUBK/ADLK/SBLK/LALK immediates, ABS/NEG, the LT/MPY/PAC product chain +; and direct + indirect (post-modify) data addressing. +; +; Computes ((5 + 3) << 1) - |0 - 7| + (6 * 7) and leaves it in a scratch word, +; touching every arithmetic addressing form on the way. Data lives on page 4 +; (word base 0x200) to stay clear of the program image. +; + .org 0 + ldpk 4 ; DP = 4 -> data page base word 0x200 + + ; seed a few data words + lalk 7, 0 + sacl 0 ; mem[0x200] = 7 + lalk 6, 0 + sacl 1 ; mem[0x201] = 6 + lalk 0x55, 0 + sacl 2 ; mem[0x202] = 0x55 + + ; accumulator immediates and shifts + lack 5 + addk 3 ; ACC = 8 + sfl ; ACC = 16 + sacl 3 ; mem[0x203] = 16 + + ; subtract with |.| via ABS + zac + sub 0 ; ACC = -7 + abs ; ACC = 7 + neg ; ACC = -7 + abs ; ACC = 7 + sacl 4 + + ; long immediates + lalk 0x1234, 0 + adlk 0x0100, 0 ; ACC = 0x1334 + sblk 0x0034, 0 ; ACC = 0x1300 + andk 0x0F00, 0 ; ACC = 0x0300 + sacl 5 + + ; product chain: P = 6 * 7, accumulate + lt 1 ; T = 6 + mpy 0 ; P = 6 * 7 = 42 + pac ; ACC = 42 + apac ; ACC = 84 + spac ; ACC = 42 + sacl 6 + + ; indirect addressing with post-increment + larp 2 + lrlk 2, 0x210 + lack 0x11 + sacl *+, 0 ; mem[0x210] = 0x11 ; AR2 -> 0x211 + lack 0x22 + sacl *, 0 ; mem[0x211] = 0x22 + lrlk 2, 0x210 + zac + add *+, 0 ; ACC += 0x11 + add *, 0 ; ACC += 0x22 -> ACC = 0x33 + sacl 7 + + idle diff --git a/tms320/c2x_legacy/src/02_logic_shifts.asm b/tms320/c2x_legacy/src/02_logic_shifts.asm new file mode 100644 index 0000000..6b1ee4f --- /dev/null +++ b/tms320/c2x_legacy/src/02_logic_shifts.asm @@ -0,0 +1,53 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 02_logic_shifts.asm -- TMS320C2x logical and shift/rotate coverage. +; +; AND/OR/XOR with memory, the ANDK/ORK/XORK long-immediate forms, the +; SFL/SFR/ROL/ROR shifters (carry in/out), CMPL, and the T-controlled shifts +; LACT/ADDT. Builds a value through a sequence of bit operations. +; + .org 0 + ldpk 4 + + lalk 0x0F0F, 0 + sacl 0 ; mem = 0x0F0F + lalk 0x00FF, 0 + sacl 1 + lalk 0x3300, 0 + sacl 2 + + lalk 0xF0F0, 0 + and 0 ; ACC = 0xF0F0 & 0x0F0F = 0 + or 2 ; ACC = 0x3300 + xor 0 ; ACC = 0x3300 ^ 0x0F0F = 0x3C0F + sacl 3 + + ; immediate logicals + lack 0 + ork 0xFF00, 0 ; ACC = 0xFF00 + andk 0x0FF0, 0 ; ACC = 0x0F00 + xork 0x00F0, 0 ; ACC = 0x0FF0 + cmpl ; ACC = ~0x0FF0 = 0xFFFFF00F + sacl 4 + + ; shifts and rotates through carry + sc ; C = 1 + lack 1 + rol ; ACC = 3 (carry into bit0), C = 0 + rol ; ACC = 6 + sfl ; ACC = 12 + sfr ; ACC = 6 + ror ; rotate right through carry + sacl 5 + + ; T-controlled shift (LACT shifts by T[3:0]) + lalk 4, 0 + sacl 6 + lt 6 ; T = 4 + lalk 0x0003, 0 + sacl 7 + lact 7 ; ACC = mem[7] << (T & 0xf) = 3 << 4 = 0x30 + sacl 8 + + idle diff --git a/tms320/c2x_legacy/src/03_branches_calls.asm b/tms320/c2x_legacy/src/03_branches_calls.asm new file mode 100644 index 0000000..15a0d08 --- /dev/null +++ b/tms320/c2x_legacy/src/03_branches_calls.asm @@ -0,0 +1,56 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 03_branches_calls.asm -- TMS320C2x control-flow coverage. +; +; The conditional-branch set (BZ/BNZ/BGZ/BLEZ/BGEZ/BLZ/BV/BNV/BC/BNC), an +; unconditional B, and a CALL/RET pair exercising the (synthetic) stack. The +; program walks a short decision tree and a subroutine, ending with a known ACC. +; + .org 0 + ldpk 4 + + ; subroutine call: add5 adds 5 to ACC + lack 10 + call add5 ; ACC = 15 + sacl 0 + + ; conditional branch on sign + zac + sub 0 ; ACC = -15 (mem[0] = 15) + blz neg_path ; taken (ACC < 0) + lack 0xEE ; (skipped) + b done_sign +neg_path: + lack 0x42 ; ACC = 0x42 +done_sign: + sacl 1 + + ; BZ / BNZ + zac + bz was_zero ; taken + lack 0xFF +was_zero: + lack 0x7 + bnz nonzero ; taken + lack 0xFF +nonzero: + sacl 2 + + ; carry-based branch + lalk 0xFFFF, 1 ; ACC = 0xFFFE + addk 2 ; overflow into carry; ACC = 0x10000 + bc had_carry ; taken + lack 0xAA + b after_c +had_carry: + lack 0x5A +after_c: + sacl 3 + + idle + +; add5: ACC += 5 ; return +add5: + addk 5 + ret diff --git a/tms320/c2x_legacy/src/04_fir_filter.asm b/tms320/c2x_legacy/src/04_fir_filter.asm new file mode 100644 index 0000000..5d8489d --- /dev/null +++ b/tms320/c2x_legacy/src/04_fir_filter.asm @@ -0,0 +1,76 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 04_fir_filter.asm -- TMS320C2x FIR / dot-product kernel. +; +; The canonical DSP MAC chain on the single-accumulator C2x: an 8-tap dot +; product y = sum(h[i] * x[i]) computed with the LT / MPY / LTA / APAC idiom and +; indirect post-increment addressing through AR2 (samples) and AR3 (coeffs). +; +; x = {1,2,3,4,5,6,7,8}, h = {8,7,6,5,4,3,2,1} +; y = 8+14+18+20+20+18+14+8 = 120 = 0x78 +; + .org 0 + ldpk 6 ; data page base word 0x300 + + ; samples x[0..7] at 0x300..0x307 + lack 1 + sacl 0 + lack 2 + sacl 1 + lack 3 + sacl 2 + lack 4 + sacl 3 + lack 5 + sacl 4 + lack 6 + sacl 5 + lack 7 + sacl 6 + lack 8 + sacl 7 + ; coeffs h[0..7] at 0x308..0x30F + lack 8 + sacl 8 + lack 7 + sacl 9 + lack 6 + sacl 10 + lack 5 + sacl 11 + lack 4 + sacl 12 + lack 3 + sacl 13 + lack 2 + sacl 14 + lack 1 + sacl 15 + + ; dot product + larp 2 + lrlk 2, 0x300 ; AR2 -> x[] + lrlk 3, 0x308 ; AR3 -> h[] + zac + lt *+, 3 ; T = x0 ; ARP -> AR3 + mpy *+, 2 ; P = x0*h0 ; ARP -> AR2 + lta *+, 3 ; ACC += P ; T = x1 ; ARP -> AR3 + mpy *+, 2 ; P = x1*h1 + lta *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + apac ; final accumulate -> ACC = 120 + ldpk 6 + sacl 16 ; store result word + + idle diff --git a/tms320/c2x_legacy/src/05_status_data.asm b/tms320/c2x_legacy/src/05_status_data.asm new file mode 100644 index 0000000..8d6b266 --- /dev/null +++ b/tms320/c2x_legacy/src/05_status_data.asm @@ -0,0 +1,49 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 05_status_data.asm -- TMS320C2x status, data-move and table coverage. +; +; The status register save/restore pair (SST/LST and SST1/LST1), the mode bits +; (SOVM/ROVM, SSXM/RSXM, SPM, SC/RC, STC/RTC), the DMOV data shift, and the +; ZALH/ZALS/ZALR accumulator loads. Demonstrates that the modelled status bits +; round-trip through memory. +; + .org 0 + ldpk 0 ; DP = 0 so SST page-0 and LST addressing agree + + ; set a distinctive mode/flag state + sovm ; OVM = 1 + ssxm ; SXM = 1 + spm 2 ; PM = 2 + stc ; TC = 1 + larp 3 ; ARP = 3 + + sst 0x40 ; store ST0 (ARP, OVM, ...) to page-0 0x40 + sst1 0x41 ; store ST1 (TC, SXM, PM, ...) to page-0 0x41 + + ; clobber the state + rovm + rsxm + spm 0 + rtc + larp 0 + + ; restore + lst 0x40 ; ARP, OVM, DP <- mem + lst1 0x41 ; TC, SXM, PM, C, ARP <- mem + + ; accumulator high/low loads + ldpk 6 + lalk 0x1234, 0 + sacl 0 ; mem = 0x1234 + zalh 0 ; ACC = 0x1234 << 16 + zals 0 ; ACC = 0x00001234 + zalr 0 ; ACC = (0x1234<<16)|0x8000 + sach 1 + sacl 2 + + ; DMOV: mem[ea+1] = mem[ea] + lack 0x5A + sacl 3 + dmov 3 ; mem[4] = mem[3] + idle diff --git a/tms320/c2x_legacy/src/10_full_program.asm b/tms320/c2x_legacy/src/10_full_program.asm new file mode 100644 index 0000000..221f082 --- /dev/null +++ b/tms320/c2x_legacy/src/10_full_program.asm @@ -0,0 +1,72 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 10_full_program.asm -- a complete small TMS320C2x routine. +; +; Combines the categories: it sums an array (with a CALL'd helper), scales the +; sum, runs a 3-tap MAC, applies a saturating add under OVM, stores results +; through indirect addressing, and finishes at IDLE. A realistic mixed-workload +; image for the disassembler, analysis and the RzIL VM. +; + .org 0 + ldpk 6 ; data base word 0x300 + + ; build an array a[0..3] = {10,20,30,40} + lack 10 + sacl 0 + lack 20 + sacl 1 + lack 30 + sacl 2 + lack 40 + sacl 3 + + ; sum = a[0]+a[1]+a[2]+a[3] via straight adds + zac + add 0 + add 1 + add 2 + add 3 ; ACC = 100 + sacl 4 ; sum + + ; scale: sum << 1 + sfl ; ACC = 200 + sacl 5 + + ; 3-tap MAC: c={2,3,4} . a[0..2] + lack 2 + sacl 8 + lack 3 + sacl 9 + lack 4 + sacl 10 + larp 2 + lrlk 2, 0x300 ; AR2 -> a[] + lrlk 3, 0x308 ; AR3 -> c[] + zac + lt *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + lta *+, 3 + mpy *+, 2 + apac ; ACC = 2*10+3*20+4*30 = 200 + ldpk 6 + sacl 6 + + ; saturating add under OVM + sovm + lalk 0x7FFF, 16 ; ACC near +max + adlk 0x7FFF, 0 + addk 1 ; would overflow -> saturates to 0x7FFFFFFF + rovm + sach 7 ; high word of saturated result + + ; store a marker through indirect + larp 4 + lrlk 4, 0x320 + lack 0x5A + sacl *+, 0 + sach *, 0 + + idle diff --git a/tms320/c2x_legacy/src/emulateme.asm b/tms320/c2x_legacy/src/emulateme.asm new file mode 100644 index 0000000..8ca43d8 --- /dev/null +++ b/tms320/c2x_legacy/src/emulateme.asm @@ -0,0 +1,113 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; TMS320C2x RzIL emulation exerciser. +; +; A self-contained program that drives the RzIL virtual machine through loops, +; a multiply-accumulate chain, a buffer transformation, a subroutine call and +; the data/stack memory model, so the emulateme test can assert a rich final +; state rather than a single scalar. All data lives on page 6 (DP=6, word base +; 0x300) which the test reads back at byte address 0x600 onward. The program +; ends in a one-instruction self-loop so the VM settles on a stable state that +; the test reaches with "aezsu". +; +; Computed results (data page 6): +; 0x310 sum of x[] = 0x001f +; 0x311 sum of squares of x[] = 0x00ad (high word at 0x312 = 0) +; 0x313 2 * sum, via subroutine = 0x003e +; 0x314 logic/shift fold of sumsq = 0x010f +; 0x318..0x31f x[i] ^ 0x5a = 59 5b 5e 5b 5f 53 58 5c + + .org 0 +start: + ldpk 6 + +; Initialise x[0..7] = {3,1,4,1,5,9,2,6} at page offset 0 using AR1 with +; post-increment indirect stores. + lrlk 1, 0x300 + larp 1 + lack 3 + sacl *+ + lack 1 + sacl *+ + lack 4 + sacl *+ + lack 1 + sacl *+ + lack 5 + sacl *+ + lack 9 + sacl *+ + lack 2 + sacl *+ + lack 6 + sacl *+ + +; Accumulate the array with a BANZ-controlled loop. AR1 walks x[], AR4 is the +; loop counter; the running total is kept in memory at offset 0x10. + lrlk 1, 0x300 + lrlk 4, 7 + zac + sacl 0x10 +sloop: + larp 1 + lac *+, 0 + add 0x10 + sacl 0x10 + larp 4 + banz sloop, *- + +; Sum of squares through a multiply-accumulate chain: LT/MPY load the product +; register and APAC folds it into the accumulator each iteration. + lrlk 1, 0x300 + lrlk 4, 7 + zac + sacl 0x11 +qloop: + larp 1 + lt *, 0 + mpy *+ + apac + larp 4 + banz qloop, *- + sach 0x12 + sacl 0x11 + +; Buffer transform: XOR every element of x[] with 0x5a and write the result to +; a second array at offset 0x18, walking source and destination with AR1/AR2. + lrlk 1, 0x300 + lrlk 2, 0x318 + lrlk 4, 7 +xloop: + larp 1 + lac *+, 0 + xork 0x5a + larp 2 + sacl *+ + larp 4 + banz xloop, *- + +; Call a subroutine that doubles the accumulator. The call and return exercise +; the stack model, and the subroutine itself pushes and pops the accumulator. + lac 0x10, 0 + call dbl + sacl 0x13 + +; Fold the sum of squares through a chain of logical and shift operations. + lac 0x11, 0 + andk 0xff + sfl + ork 0x100 + xork 0x55 + sacl 0x14 + +; Settle on a stable state for the test to observe. +done: + b done + +; Doubling subroutine: save and restore the accumulator across a shift-left. +dbl: + push + pop + sfl + ret diff --git a/tms320/c5x_legacy/01_arithmetic.bin b/tms320/c5x_legacy/01_arithmetic.bin new file mode 100644 index 0000000..77ee510 --- /dev/null +++ b/tms320/c5x_legacy/01_arithmetic.bin @@ -0,0 +1 @@ +!!sT$ \ No newline at end of file diff --git a/tms320/c5x_legacy/02_logic_shifts.bin b/tms320/c5x_legacy/02_logic_shifts.bin new file mode 100644 index 0000000..da8994b --- /dev/null +++ b/tms320/c5x_legacy/02_logic_shifts.bin @@ -0,0 +1,2 @@ +3nml +f \ No newline at end of file diff --git a/tms320/c5x_legacy/03_branches_calls.bin b/tms320/c5x_legacy/03_branches_calls.bin new file mode 100644 index 0000000..b40c20a Binary files /dev/null and b/tms320/c5x_legacy/03_branches_calls.bin differ diff --git a/tms320/c5x_legacy/04_fir_filter.bin b/tms320/c5x_legacy/04_fir_filter.bin new file mode 100644 index 0000000..305cd50 --- /dev/null +++ b/tms320/c5x_legacy/04_fir_filter.bin @@ -0,0 +1 @@ +sTsTsTS \ No newline at end of file diff --git a/tms320/c5x_legacy/05_status_data.bin b/tms320/c5x_legacy/05_status_data.bin new file mode 100644 index 0000000..f2d5653 --- /dev/null +++ b/tms320/c5x_legacy/05_status_data.bin @@ -0,0 +1 @@ +U \ No newline at end of file diff --git a/tms320/c5x_legacy/10_full_program.bin b/tms320/c5x_legacy/10_full_program.bin new file mode 100644 index 0000000..0709990 --- /dev/null +++ b/tms320/c5x_legacy/10_full_program.bin @@ -0,0 +1 @@ +sT nml% \ No newline at end of file diff --git a/tms320/c5x_legacy/emulateme.bin b/tms320/c5x_legacy/emulateme.bin new file mode 100644 index 0000000..abbc15c Binary files /dev/null and b/tms320/c5x_legacy/emulateme.bin differ diff --git a/tms320/c5x_legacy/src/01_arithmetic.asm b/tms320/c5x_legacy/src/01_arithmetic.asm new file mode 100644 index 0000000..07031fd --- /dev/null +++ b/tms320/c5x_legacy/src/01_arithmetic.asm @@ -0,0 +1,22 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 01_arithmetic.asm -- TMS320C5x (real C5x object encoding) arithmetic and load/store (immediate/add-with-shift, LT/MPY/PAC product chain). +; +; Assembled by tms320-rs asm. Data accesses write-then-read a high page so the +; Harvard core emulator and the address-aliased Rizin RzIL VM agree. Single-word +; ops with <=8-bit immediates so the instruction count equals the word count. + + ldp #0x4 + lacl #0x21 + sacl 0x10 + lacl #0x12 + add #0x21 + sacl 0x11 + lt 0x10 + mpy 0x11 + pac + add 0x10, 4 + sub #0x5 + sacl 0x12 + lar ar2, #0x11 diff --git a/tms320/c5x_legacy/src/02_logic_shifts.asm b/tms320/c5x_legacy/src/02_logic_shifts.asm new file mode 100644 index 0000000..f9f3630 --- /dev/null +++ b/tms320/c5x_legacy/src/02_logic_shifts.asm @@ -0,0 +1,23 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 02_logic_shifts.asm -- TMS320C5x (real C5x object encoding) logical ops and shifts (AND/OR/XOR, SFL/SFR). +; +; Assembled by tms320-rs asm. Data accesses write-then-read a high page so the +; Harvard core emulator and the address-aliased Rizin RzIL VM agree. Single-word +; ops with <=8-bit immediates so the instruction count equals the word count. + + ldp #0x4 + lacl #0x33 + sacl 0x10 + lacl #0x0f + and 0x10 + sacl 0x11 + lacl #0xf0 + or 0x10 + sacl 0x12 + xor 0x11 + sfl + sfl + sfr + lar ar2, #0x66 diff --git a/tms320/c5x_legacy/src/03_branches_calls.asm b/tms320/c5x_legacy/src/03_branches_calls.asm new file mode 100644 index 0000000..30f17f3 --- /dev/null +++ b/tms320/c5x_legacy/src/03_branches_calls.asm @@ -0,0 +1,19 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 03_branches_calls.asm -- TMS320C5x (real C5x object encoding) control flow (forward B skips the dead block). +; +; Assembled by tms320-rs asm. Data accesses write-then-read a high page so the +; Harvard core emulator and the address-aliased Rizin RzIL VM agree. Single-word +; ops with <=8-bit immediates so the instruction count equals the word count. + + ldp #0x4 + lacl #0x7 + sacl 0x10 + b 0x8 + lacl #0xff + sacl 0x10 + lacl #0x3 + add 0x10 + sacl 0x11 + lar ar2, #0x40 diff --git a/tms320/c5x_legacy/src/04_fir_filter.asm b/tms320/c5x_legacy/src/04_fir_filter.asm new file mode 100644 index 0000000..3d9a9f6 --- /dev/null +++ b/tms320/c5x_legacy/src/04_fir_filter.asm @@ -0,0 +1,26 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 04_fir_filter.asm -- TMS320C5x (real C5x object encoding) FIR dot-product (MAC chain via LT/MPY/PAC/APAC). +; +; Assembled by tms320-rs asm. Data accesses write-then-read a high page so the +; Harvard core emulator and the address-aliased Rizin RzIL VM agree. Single-word +; ops with <=8-bit immediates so the instruction count equals the word count. + + ldp #0x4 + lacl #0x3 + sacl 0x10 + lacl #0x5 + sacl 0x11 + lacl #0x7 + sacl 0x12 + lt 0x10 + mpy 0x10 + pac + lt 0x11 + mpy 0x11 + apac + lt 0x12 + mpy 0x12 + apac + lar ar2, #0x53 diff --git a/tms320/c5x_legacy/src/05_status_data.asm b/tms320/c5x_legacy/src/05_status_data.asm new file mode 100644 index 0000000..04bcd25 --- /dev/null +++ b/tms320/c5x_legacy/src/05_status_data.asm @@ -0,0 +1,20 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 05_status_data.asm -- TMS320C5x (real C5x object encoding) ACCB accumulator-buffer save/restore (SACB/EXAR/LACB). +; +; Assembled by tms320-rs asm. Data accesses write-then-read a high page so the +; Harvard core emulator and the address-aliased Rizin RzIL VM agree. Single-word +; ops with <=8-bit immediates so the instruction count equals the word count. + + ldp #0x4 + lacl #0x55 + sacl 0x10 + lacl #0xaa + sacb + lacl #0x10 + exar + sacl 0x11 + lacb + sacl 0x12 + lar ar2, #0x12 diff --git a/tms320/c5x_legacy/src/10_full_program.asm b/tms320/c5x_legacy/src/10_full_program.asm new file mode 100644 index 0000000..dbb25a2 --- /dev/null +++ b/tms320/c5x_legacy/src/10_full_program.asm @@ -0,0 +1,26 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; 10_full_program.asm -- TMS320C5x (real C5x object encoding) mixed program (arithmetic + multiply + logic + shift). +; +; Assembled by tms320-rs asm. Data accesses write-then-read a high page so the +; Harvard core emulator and the address-aliased Rizin RzIL VM agree. Single-word +; ops with <=8-bit immediates so the instruction count equals the word count. + + ldp #0x4 + lacl #0x10 + sacl 0x10 + lacl #0x2 + add #0x3 + sacl 0x11 + lt 0x10 + mpy 0x11 + pac + sfl + and 0x10 + or 0x11 + sacl 0x12 + lacl #0xf + xor 0x10 + sub #0x1 + lar ar2, #0x25 diff --git a/tms320/c5x_legacy/src/emulateme.asm b/tms320/c5x_legacy/src/emulateme.asm new file mode 100644 index 0000000..d3abbfe --- /dev/null +++ b/tms320/c5x_legacy/src/emulateme.asm @@ -0,0 +1,107 @@ +; SPDX-FileCopyrightText: 2026 RizinOrg +; SPDX-License-Identifier: LGPL-3.0-only +; +; emulateme.asm -- TMS320C5x (real C5x object encoding) RzIL emulation exerciser. +; +; The C5x counterpart of the C2x exerciser: it drives the Rizin RzIL virtual +; machine through BANZ loops, a multiply-accumulate chain, a buffer transform, +; a subroutine call and the data/stack memory model. Data lives on page 6 +; (DP=6, word base 0x300), read back by the test at byte address 0x600 onward. +; Branch operands are word addresses; the loop labels are noted in comments. +; The program ends in a self-loop so the VM settles on a stable state reached +; with "aezsu". Assembled by tms320-rs assembler with label resolution. +; +; Computed results (data page 6): +; 0x310 sum of x[] = 0x001f +; 0x311 sum of squares of x[] = 0x00ad (high word at 0x312 = 0) +; 0x313 2 * sum, via subroutine = 0x003e +; 0x314 logic/shift fold of sumsq = 0x010f +; 0x318..0x31f x[i] ^ 0x5a = 59 5b 5e 5b 5f 53 58 5c + + ldp #0x6 + +; Initialise x[0..7] = {3,1,4,1,5,9,2,6} via AR1 with post-increment stores. + lar ar1, #0x300 + mar *, ar1 + lacl #0x3 + sacl *+ + lacl #0x1 + sacl *+ + lacl #0x4 + sacl *+ + lacl #0x1 + sacl *+ + lacl #0x5 + sacl *+ + lacl #0x9 + sacl *+ + lacl #0x2 + sacl *+ + lacl #0x6 + sacl *+ + +; Accumulate the array with a BANZ loop (sloop at word 0x1a). AR1 walks x[], +; AR4 counts down, the running total is kept at offset 0x10. + lar ar1, #0x300 + lar ar4, #0x7 + lacl #0x0 + sacl 0x10 + mar *, ar4 + mar *, ar1 + lacc *+ + add 0x10 + sacl 0x10 + mar *, ar4 + banz 0x1a, *- + +; Sum of squares through a multiply-accumulate chain (qloop at word 0x26): +; LT/MPY build the product and APAC folds it into the accumulator each pass. + lar ar1, #0x300 + lar ar4, #0x7 + lacl #0x0 + mar *, ar4 + mar *, ar1 + lt * + mpy *+ + apac + mar *, ar4 + banz 0x26, *- + sach 0x12 + sacl 0x11 + +; Buffer transform (xloop at word 0x35): XOR every x[] element with 0x5a and +; store the result to a second array at offset 0x18 via AR1/AR2. + lar ar1, #0x300 + lar ar2, #0x318 + lar ar4, #0x7 + mar *, ar4 + mar *, ar1 + lacc *+ + xor #0x5a + mar *, ar2 + sacl *+ + mar *, ar4 + banz 0x35, *- + +; Call a subroutine (dbl at word 0x4d) that doubles the accumulator; the call, +; the return and the push/pop inside exercise the stack model. + lacc 0x10 + call 0x4d + sacl 0x13 + +; Fold the sum of squares through logical and shift operations. + lacc 0x11 + and #0xff + sfl + or #0x100 + xor #0x55 + sacl 0x14 + +; Settle on a stable state for the test to observe (done at word 0x4b). + b 0x4b + +; Doubling subroutine: save and restore the accumulator across a shift-left. + push + pop + sfl + ret