
---

# TRACE32 EEPROM 三项核心算法详解

## 一、校验和 (0xFE-0xFF)

### 算法
对 EEPROM 前 254 字节（0x00-0xFD），视为 127 个 16 位 WORD（小端序），求和后取反：

```
checksum = (-sum(all_127_words)) & 0xFFFF
```

等效于：所有 127 个 WORD 之和的低 16 位取反。

### 计算步骤

```
1. 将前254字节按小端序解析为 127 个 uint16
2. 累加所有 127 个值
3. checksum = (-total) & 0xFFFF
   或者更直观：checksum = (0x10000 - (total & 0xFFFF)) & 0xFFFF
4. 将 checksum 以小端序写入 0xFE-0xFF
```

### 示例（以原版文件为例）

```
文件 256 字节作为 127 个 WORD (LE) 计算前254字节：

WORD[0]  = 0x7070  (字节 0x00-0x01: 70 70 → 0x7070)
WORD[1]  = 0x0063  (字节 0x02-0x03: 63 00 → 0x0063)
WORD[2]  = 0x3131  (字节 0x04-0x05: 31 31 → 0x3131)
...
WORD[126]= 0x0000  (字节 0xFC-0xFD: 00 00 → 0x0000)

所有 127 个 WORD 累加 → total
checksum = (-total) & 0xFFFF

验证: 计算出的校验和必须等于 0xFE-0xFF 存储的值
```

### Python 实现

```python
import struct

def compute_checksum(data):
    """计算 256 字节 EEPROM 的校验和（前254字节）"""
    # 确保数据长度为256字节
    if len(data) < 256:
        data.extend(b'\x00' * (256 - len(data)))
    elif len(data) > 256:
        del data[256:]
    
    # 先将校验和位置置0
    data[0xFE] = 0
    data[0xFF] = 0
    
    # 计算前254字节的校验和
    # 将前254字节视为127个16位WORD（小端序）
    words = struct.unpack('<127H', bytes(data[:0xFE]))
    total = sum(words)
    checksum = (-total) & 0xFFFF
    
    # 写入校验和（小端序）
    data[0xFE] = checksum & 0xFF
    data[0xFF] = (checksum >> 8) & 0xFF
    return checksum

def verify_checksum(data):
    """验证校验和"""
    if len(data) < 256:
        return False
    
    # 读取存储的校验和
    stored_checksum = int.from_bytes(data[0xFE:0x100], 'little')
    
    # 计算前254字节的校验和
    words = struct.unpack('<127H', bytes(data[:0xFE]))
    total = sum(words)
    calculated_checksum = (-total) & 0xFFFF
    
    return stored_checksum == calculated_checksum
```

---

## 二、序列号解析 (sn_mod 计算)

### 涉及函数

**sub_1409416F0** — 序列号字符串 → 整数

```
地址: 0x1409416F0
输入: 指向 12 字节 ASCII 字符串的指针 (EEPROM offset 0x04-0x0F)
输出: 64 位整数 (序列号数值)
```

### 伪代码

```c
uint64_t sub_1409416F0(uint8_t *str) {
    uint64_t result = 0;
    
    // 跳过前导非数字字符
    if ((str[0] - '0') > 9)
        str++;  // 如 "C17080238053" → 跳过 'C'
    
    // 最多解析 11 位数字
    uint8_t *end = str + 11;
    
    while (str < end) {
        char c = *str++;
        if ((c - '0') > 9)   // 非数字则停止
            break;
        result = (c - '0') + 10 * result;  // 即 result = result * 10 + digit
    }
    
    return result;
}
```

### 计算 sn_mod

```c
sn_mod = serial_number % 100000;  // 即 serial % 0x186A0
```

### 示例

| 序列号字符串 | 解析结果 | sn_mod |
|-------------|---------|--------|
| "6186900" | 6186900 | 86900 |
| "C17080238053" | 17080238053 | 38053 |
| "06120086900" | 6120086900 | 86900 |
| "1608009000" | 1608009000 | 9000 |

注意：`06120086900` 和 `6186900` sn_mod 相同 (=86900)，所以它们可以共享同一组 hash 值。

### Python 实现

```python
def parse_serial(serial_str):
    """模拟 sub_1409416F0"""
    s = serial_str.strip()
    if s and not s[0].isdigit():
        s = s[1:]  # 跳过前导非数字
    result = 0
    for c in s[:11]:
        if not c.isdigit():
            break
        result = result * 10 + int(c)
    return result

serial = parse_serial("C17080238053")  # → 17080238053
sn_mod = serial % 100000               # → 38053
```

---

## 三、有效期激活码 (License String 中的 hex code)

### 涉及函数

**sub_140941DD0** — License 行解析与激活码验证

```
地址: 0x140941DD0
License String 格式: "SN MM/YYYY ACTIVATION_CODE"
例: "C17080238053 10/2022 17DD0CD690E2E267"
```

### 算法

```
输入:
  serial  = sub_1409416F0 解析后的序列号整数
  month   = 日期中的月份 (如 10)
  year    = 日期中的年份 (如 2022)

计算:
  v29 = 100003 × serial × (month + 12 × year)

  hash1 = sub_140151110( HI_DWORD(v29) )  ← 高 32 位
  hash2 = sub_140151110( LO_DWORD(v29) )  ← 低 32 位

  activation_code = LE_BYTES(hash1) + LE_BYTES(hash2)
                  = 8 字节 (16 个 hex 字符)
```

### 完整演示

```
序列号: C17080238053 → serial = 17080238053
日期:   10/2022

v29 = 100003 × 17080238053 × (10 + 12 × 2022)
    = 100003 × 17080238053 × 24274
    = 41,461,813,666,947,695,566
    = 0x023F65F3DB21DA83CE

HI_DWORD = 0x3F65F3DB       LO_DWORD = 0x21DA83CE
    ↓                              ↓
sub_140151110(0x3F65F3DB)   sub_140151110(0x21DA83CE)
    = 0xD60CDD17                 = 0x67E2E290

LE 字节: 17 DD 0C D6       LE 字节: 90 E2 E2 67

拼接: 17 DD 0C D6 90 E2 E2 67 = "17DD0CD690E2E267"  ✓
```

### Python 实现

```python
def compute_activation_code(serial_str, month, year):
    """计算有效期激活码"""
    serial = parse_serial(serial_str)
    v29 = 100003 * serial * (month + 12 * year)
    hi = (v29 >> 32) & 0xFFFFFFFF
    lo = v29 & 0xFFFFFFFF
    hash1 = hash_140151110(hi)
    hash2 = hash_140151110(lo)
    code = hash1.to_bytes(4, 'little') + hash2.to_bytes(4, 'little')
    return code.hex().upper()

# 验证
code = compute_activation_code("C17080238053", 10, 2022)
print(code)  # → 17DD0CD690E2E267
```

### 更换有效期方法

要延期 License，只需：
1. 设定新的 month/year
2. 用以上公式计算新的激活码
3. 更新 EEPROM 0xC0-0xEF 中的 License String

```python
# 延期到 2099年12月
new_code = compute_activation_code("C17080238053", 12, 2099)
# → 332C9814A6099F18
new_license = "C17080238053 12/2099 " + new_code
```

---

## 四、架构授权 Hash 计算

### 涉及函数

**sub_140151110** — License Hash 函数

```
地址: 0x140151110
输入: ECX = sn_mod × char_sum(filename)
输出: EAX = 32-bit hash
```

### 反汇编

```asm
sub_140151110:
    lea  rax, table_start     ; 乘数/加数表起始
    lea  rdx, table_end       ; 表结束
loop:
    imul ecx, [rax-4]         ; ecx *= multiplier
    add  ecx, [rax]           ; ecx += adder
    add  rax, 8               ; 前进 8 字节
    cmp  rax, rdx
    jl   loop
    mov  eax, ecx
    ret
```

### 表数据 (0x141DE91C0, 80 字节 = 10 对)

```
乘数: [17, 37,  7,  5, 37, 19, 47, 41, 53, 17]
加数: [11,  3, 11, 31, 13, 23, 31, 43, 59, 19]
```

### 完整公式

```
char_sum(filename) = sum(ord(c) for c in filename)

value = sn_mod × char_sum

hash = sub_140151110(value)
     = ((((((((((value × 17 + 11) × 37 + 3) × 7 + 11) × 5 + 31)
           × 37 + 13) × 19 + 23) × 47 + 31) × 41 + 43)
           × 53 + 59) × 17 + 19) & 0xFFFFFFFF
```

### 完整演示：Cortex-M (0x75CE9244)

```
文件名: scccortexm.t32
char_sum = s+c+c+c+o+r+t+e+x+m+.+t+3+2
        = 115+99+99+99+111+114+116+101+120+109+46+116+51+50
        = 1346

sn_mod  = 38053  (序列号 C17080238053)
value   = 38053 × 1346 = 51,219,338 = 0x030D8B8A

迭代 0: (0x030D8B8A × 17 + 11) → 0x33E64435
迭代 1: (0x33E64435 × 37 +  3) → 0x8047DBAC
迭代 2: (0x8047DBAC ×  7 + 11) → 0x81F701BF
迭代 3: (0x81F701BF ×  5 + 31) → 0x89D308DA
迭代 4: (0x89D308DA × 37 + 13) → 0xEB80478F
迭代 5: (0xEB80478F × 19 + 23) → 0x7A854FB4
迭代 6: (0x7A854FB4 × 47 + 31) → 0x7E79A22B
迭代 7: (0x7E79A22B × 41 + 43) → 0x417AF90E
迭代 8: (0x417AF90E × 53 + 59) → 0x8E759021
迭代 9: (0x8E759021 × 17 + 19) → 0x75CE9244

最终 hash = 0x75CE9244
LE 字节序 = 44 92 CE 75  (写入 EEPROM 0x10-0x13)
```

### Python 完整实现（三项算法）

```python
_MULTS = [17, 37, 7, 5, 37, 19, 47, 41, 53, 17]
_ADDS  = [11, 3, 11, 31, 13, 23, 31, 43, 59, 19]

def hash_140151110(value):
    """（算法3）10轮 LCG hash — 用于架构授权和激活码"""
    v = value & 0xFFFFFFFF
    for i in range(10):
        v = (v * _MULTS[i] + _ADDS[i]) & 0xFFFFFFFF
    return v

def parse_serial(serial_str):
    """（算法2）sub_1409416F0: 序列号解析"""
    s = serial_str.strip()
    if s and not s[0].isdigit():
        s = s[1:]
    result = 0
    for c in s[:11]:
        if not c.isdigit():
            break
        result = result * 10 + int(c)
    return result

def compute_hash(serial_str, filename):
    """（算法3）计算单个架构的授权 hash"""
    serial = parse_serial(serial_str)
    sn_mod = serial % 100000
    csum = sum(ord(c) for c in filename)
    value = sn_mod * csum
    return hash_140151110(value)

def compute_activation_code(serial_str, month, year):
    """（算法2）计算有效期激活码"""
    serial = parse_serial(serial_str)
    v29 = 100003 * serial * (month + 12 * year)
    hi = (v29 >> 32) & 0xFFFFFFFF
    lo = v29 & 0xFFFFFFFF
    hash1 = hash_140151110(hi)
    hash2 = hash_140151110(lo)
    code = hash1.to_bytes(4, 'little') + hash2.to_bytes(4, 'little')
    return code.hex().upper()

def compute_checksum(data):
    """（算法1）计算 EEPROM 校验和（前254字节）"""
    # 确保数据长度为256字节
    if len(data) < 256:
        data.extend(b'\x00' * (256 - len(data)))
    elif len(data) > 256:
        del data[256:]
    
    # 先将校验和位置置0
    data[0xFE] = 0
    data[0xFF] = 0
    
    # 计算前254字节的校验和
    words = struct.unpack('<127H', bytes(data[:0xFE]))
    total = sum(words)
    checksum = (-total) & 0xFFFF
    
    # 写入校验和（小端序）
    data[0xFE] = checksum & 0xFF
    data[0xFF] = (checksum >> 8) & 0xFF

# 使用示例
h = compute_hash("C17080238053", "scccortexm.t32")
print(f"Cortex-M hash = 0x{h:08X}")  # → 0x75CE9244

code = compute_activation_code("C17080238053", 12, 2099)
print(f"激活码 = {code}")  # → 332C9814A6099F18
```

---

## 已知架构 Hash 表 (sn_mod=38053)

| 文件名 | 架构 | csum | sn_mod×csum | Hash |
|--------|------|------|-------------|------|
| sccarm70.t32 | ARM7 | 999 | 0x02440FE3 | 0x229E902F |
| sccarm90.t32 | ARM9 | 1001 | 0x0245392D | 0x89A57ACD |
| sccarm10.t32 | ARM10 | 993 | 0x02409405 | 0xED89D055 |
| sccarm11.t32 | ARM11 | 994 | 0x024128AA | 0xA10D45A4 |
| sccmci.t32 | MCI | 889 | 0x020430FD | 0x0022283D |
| sccarmsa.t32 | ARM SA | 1108 | 0x02835A24 | 0x919782D2 |
| scccortexm.t32 | Cortex-M | 1346 | 0x030D8B8A | 0x75CE9244 |
| scccortex.t32 | Cortex-A/R | 1237 | 0x02CE4149 | 0x06D59FA1 |
| sccARMv8.t32 | ARMv8/v9 | 974 | 0x02358BC6 | 0x9AC81B78 |
| sccjanus.t32 | JANUS | 1121 | 0x028AE685 | 0xAF4477D5 |
| sccetb.t32 | ETB Trace | 891 | 0x02055A47 | 0x672912DB |
| sccavr.t32 | AVR | - | - | 0x7D1B2675 |
| sccavr8.t32 | AVR8 | - | - | 0x7D1B2675 |
| scc68k.t32 | 68K | - | - | 0xAED62A9D |
| scc166nb.t32 | C166 | - | - | 0x44E3D185 |
| scc166sv2.t32 | C166S | - | - | 0x44E3D185 |
| scc322800.t32 | C2000 | - | - | 0x5F6E3172 |
| scc32540.t32 | C5400 | - | - | 0x95F8A889 |
| scc32550.t32 | C5500 | - | - | 0x1789F314 |
| sccmips.t32 | MIPS | - | - | 0xC1DCCFBD |
| sccmsp430.t32 | MSP430 | - | - | 0x037BE3EF |
| sccppc4200.t32 | PPC4200 | - | - | 0x229E902F |
| sccppc5500.t32 | PPC5500 | - | - | 0x57B35009 |
| sccppc40.t32 | PPC40x | - | - | 0x08827D7A |
| sccppc44.t32 | PPC44x | - | - | 0x08827D7A |
| sccppc50.t32 | PPC50x | - | - | 0x08827D7A |
| sccppc60.t32 | PPC60x | - | - | 0x08827D7A |
| sccppc74.t32 | PPC74x | - | - | 0x49EA6B10 |
| sccppc82.t32 | PPC82x | - | - | 0x49EA6B10 |
| sccppc85.t32 | PPC85x | - | - | 0xCE9E4AB1 |
| sccppc86.t32 | PPC86x | - | - | 0xCE9E4AB1 |
| sccs08.t32 | HCS08 | - | - | 0x1AAC882A |
| sccs12.t32 | HCS12 | - | - | 0x991B3D9F |
| sccs12x.t32 | HCS12X | - | - | 0x991B3D9F |
| sccms12z.t32 | HCS12Z | - | - | 0x991B3D9F |
| sccRH850.t32 | V850 | - | - | 0x991B3D9F |
| sccxtensa.t32 | XTENSA | - | - | 0x991B3D9F |
| scchsdp.t32 | HSDP | - | - | 0x991B3D9F |
| sccRISCV.t32 | RISCV | - | - | 0x991B3D9F |
| sccRISCV_32.t32 | RISCV32 | - | - | 0x991B3D9F |
| sccRISCV_64.t32 | RISCV64 | - | - | 0x991B3D9F |

---

*文档版本：1.0*
*最后更新：2024年*

---