# TRACE32 EEPROM 三项核心算法详解

## 一、校验和 (0xFE-0xFF)

### 算法
对 EEPROM 全部 256 字节，视为 128 个 16 位 WORD（小端序），求和后取反：

```
checksum = (-sum(all_128_words)) & 0xFFFF
```

等效于：所有 128 个 WORD 之和的低 16 位 = 0。

### 计算步骤

```
1. 将 256 字节按小端序解析为 128 个 uint16
2. 累加所有 128 个值
3. checksum = (-total) & 0xFFFF
   或者更直观：checksum = (0x10000 - (total & 0xFFFF)) & 0xFFFF
```

### 示例（以原版文件为例）

```
文件 256 字节作为 128 个 WORD (LE):

WORD[0]  = 0x7261  (字节 0x00-0x01: 61 72 → 0x7261)
WORD[1]  = 0x006D  (字节 0x02-0x03: 6D 00 → 0x006D)
WORD[2]  = 0x3731  (字节 0x04-0x05: 31 37 → 0x3731)
...
WORD[126]= 0x01    (字节 0xFC-0xFD: 01 → 0x0001，不含校验和自身)
WORD[127]= 0x0000  (字节 0xFE-0xFF: 校验和位置，计算时视为 0)

所有 128 个 WORD 累加 → total
checksum = (-total) & 0xFFFF

验证: 重新累加含校验和的 128 个 WORD → 低 16 位必须为 0
```

### Python 实现

```python
import struct

def compute_checksum(data):
    """计算 256 字节 EEPROM 的校验和"""
    data[0xFE] = 0
    data[0xFF] = 0
    words = struct.unpack('<128H', bytes(data))
    total = sum(words)
    checksum = (-total) & 0xFFFF
    data[0xFE] = checksum & 0xFF
    data[0xFF] = (checksum >> 8) & 0xFF
    return checksum

def verify_checksum(data):
    """验证校验和"""
    words = struct.unpack('<128H', bytes(data))
    return (sum(words) & 0xFFFF) == 0
```

---

## 二、序列号解析 (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
    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)
```

### 全部 11 个 ARM 架构 (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 |

### 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
    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 校验和"""
    data[0xFE] = 0
    data[0xFF] = 0
    words = struct.unpack('<128H', bytes(data))
    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
```
