code-info-parser.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. const {
  2. bytesToAutoText,
  3. bytesToHex,
  4. formatHexNumber,
  5. readUint16BE,
  6. readUint16LE,
  7. readUint32BE,
  8. readUint32LE,
  9. trimTrailingNullBytes
  10. } = require('../../utils/binary-utils.js')
  11. const CODE_INFO_TLV_HEADER_BYTE_LENGTH = 2
  12. const CODE_INFO_ENTRY_NAME_LENGTH_BYTE_LENGTH = 1
  13. const CODE_INFO_ENTRY_MAX_NAME_BYTE_LENGTH = 0xFF
  14. const CODE_INFO_TLV = {
  15. RAW_VARIABLE: 0x01,
  16. INT8_VARIABLE: 0x02,
  17. UINT8_VARIABLE: 0x03,
  18. INT16_VARIABLE: 0x04,
  19. UINT16_VARIABLE: 0x05,
  20. INT32_VARIABLE: 0x06,
  21. UINT32_VARIABLE: 0x07,
  22. FLOAT32_VARIABLE: 0x08,
  23. DOUBLE_VARIABLE: 0x09,
  24. INT64_VARIABLE: 0x0A,
  25. UINT64_VARIABLE: 0x0B,
  26. INT128_VARIABLE: 0x0C,
  27. UINT128_VARIABLE: 0x0D,
  28. INT256_VARIABLE: 0x0E,
  29. UINT256_VARIABLE: 0x0F,
  30. RAW_ARRAY: 0x10,
  31. INT8_ARRAY: 0x11,
  32. UINT8_ARRAY: 0x12,
  33. INT16_ARRAY: 0x13,
  34. UINT16_ARRAY: 0x14,
  35. INT32_ARRAY: 0x15,
  36. UINT32_ARRAY: 0x16,
  37. FLOAT32_ARRAY: 0x17,
  38. DOUBLE_ARRAY: 0x18,
  39. INT64_ARRAY: 0x19,
  40. UINT64_ARRAY: 0x1A,
  41. INT128_ARRAY: 0x1B,
  42. UINT128_ARRAY: 0x1C,
  43. INT256_ARRAY: 0x1D,
  44. UINT256_ARRAY: 0x1E,
  45. TEXT_ARRAY: 0x1F,
  46. ENUM_VARIABLE: 0x20,
  47. STRUCT_INSTANCE: 0x21,
  48. ENUM_ARRAY: 0x22,
  49. STRUCT_ARRAY: 0x23,
  50. CAVE_FREQ: 0x40,
  51. REF_VOLT: 0x41,
  52. AMP_GAIN: 0x42,
  53. RS_SHUNT: 0x43,
  54. BUS_DIV: 0x44,
  55. ALONG_DIV: 0x45,
  56. CHIP_MODEL: 0x46,
  57. MODEL: 0x47
  58. }
  59. const CODE_INFO_BOARD_TLV_NAMES = {
  60. [CODE_INFO_TLV.CAVE_FREQ]: 'cave_freq',
  61. [CODE_INFO_TLV.REF_VOLT]: 'ref_volt',
  62. [CODE_INFO_TLV.AMP_GAIN]: 'amp_gain',
  63. [CODE_INFO_TLV.RS_SHUNT]: 'rs_shunt',
  64. [CODE_INFO_TLV.BUS_DIV]: 'bus_div',
  65. [CODE_INFO_TLV.ALONG_DIV]: 'along_div',
  66. [CODE_INFO_TLV.CHIP_MODEL]: 'chip_model',
  67. [CODE_INFO_TLV.MODEL]: 'model'
  68. }
  69. const CODE_INFO_ENTRY_KIND = {
  70. STRUCT: 0x00,
  71. VARIABLE: 0x01,
  72. ENUM: 0x02,
  73. ARRAY: 0x03
  74. }
  75. const CODE_INFO_ENTRY_KIND_TEXT = {
  76. [CODE_INFO_ENTRY_KIND.STRUCT]: 'struct',
  77. [CODE_INFO_ENTRY_KIND.VARIABLE]: 'variable',
  78. [CODE_INFO_ENTRY_KIND.ENUM]: 'enum',
  79. [CODE_INFO_ENTRY_KIND.ARRAY]: 'array'
  80. }
  81. const CODE_INFO_ENTRY_NAME_ROLE = {
  82. DEFINITION: 'definition',
  83. INSTANCE: 'instance',
  84. VARIABLE: 'variable'
  85. }
  86. const CODE_INFO_ENTRY_TYPE_DEFINITIONS = {
  87. [CODE_INFO_TLV.RAW_VARIABLE]: {
  88. dataType: 'raw',
  89. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  90. name: 'raw_variable',
  91. valueTypeName: 'raw'
  92. },
  93. [CODE_INFO_TLV.INT8_VARIABLE]: {
  94. dataType: 'int8_t',
  95. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  96. expectedByteLength: 1,
  97. name: 'int8_variable',
  98. valueTypeName: 'int8_t'
  99. },
  100. [CODE_INFO_TLV.UINT8_VARIABLE]: {
  101. dataType: 'uint8_t',
  102. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  103. expectedByteLength: 1,
  104. name: 'uint8_variable',
  105. valueTypeName: 'uint8_t'
  106. },
  107. [CODE_INFO_TLV.INT16_VARIABLE]: {
  108. dataType: 'int16_t',
  109. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  110. expectedByteLength: 2,
  111. name: 'int16_variable',
  112. valueTypeName: 'int16_t'
  113. },
  114. [CODE_INFO_TLV.UINT16_VARIABLE]: {
  115. dataType: 'uint16_t',
  116. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  117. expectedByteLength: 2,
  118. name: 'uint16_variable',
  119. valueTypeName: 'uint16_t'
  120. },
  121. [CODE_INFO_TLV.INT32_VARIABLE]: {
  122. dataType: 'int32_t',
  123. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  124. expectedByteLength: 4,
  125. name: 'int32_variable',
  126. valueTypeName: 'int32_t'
  127. },
  128. [CODE_INFO_TLV.UINT32_VARIABLE]: {
  129. dataType: 'uint32_t',
  130. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  131. expectedByteLength: 4,
  132. name: 'uint32_variable',
  133. valueTypeName: 'uint32_t'
  134. },
  135. [CODE_INFO_TLV.FLOAT32_VARIABLE]: {
  136. dataType: 'float',
  137. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  138. expectedByteLength: 4,
  139. name: 'float32_variable',
  140. valueTypeName: 'float32'
  141. },
  142. [CODE_INFO_TLV.DOUBLE_VARIABLE]: {
  143. dataType: 'double',
  144. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  145. expectedByteLength: 8,
  146. name: 'double_variable',
  147. valueTypeName: 'double'
  148. },
  149. [CODE_INFO_TLV.INT64_VARIABLE]: {
  150. dataType: 'int64_t',
  151. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  152. expectedByteLength: 8,
  153. name: 'int64_variable',
  154. valueTypeName: 'int64_t'
  155. },
  156. [CODE_INFO_TLV.UINT64_VARIABLE]: {
  157. dataType: 'uint64_t',
  158. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  159. expectedByteLength: 8,
  160. name: 'uint64_variable',
  161. valueTypeName: 'uint64_t'
  162. },
  163. [CODE_INFO_TLV.INT128_VARIABLE]: {
  164. dataType: 'int128_t',
  165. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  166. expectedByteLength: 16,
  167. name: 'int128_variable',
  168. valueTypeName: 'int128_t'
  169. },
  170. [CODE_INFO_TLV.UINT128_VARIABLE]: {
  171. dataType: 'uint128_t',
  172. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  173. expectedByteLength: 16,
  174. name: 'uint128_variable',
  175. valueTypeName: 'uint128_t'
  176. },
  177. [CODE_INFO_TLV.INT256_VARIABLE]: {
  178. dataType: 'int256_t',
  179. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  180. expectedByteLength: 32,
  181. name: 'int256_variable',
  182. valueTypeName: 'int256_t'
  183. },
  184. [CODE_INFO_TLV.UINT256_VARIABLE]: {
  185. dataType: 'uint256_t',
  186. entryKind: CODE_INFO_ENTRY_KIND.VARIABLE,
  187. expectedByteLength: 32,
  188. name: 'uint256_variable',
  189. valueTypeName: 'uint256_t'
  190. },
  191. [CODE_INFO_TLV.ENUM_VARIABLE]: {
  192. dataType: '',
  193. entryKind: CODE_INFO_ENTRY_KIND.ENUM,
  194. name: 'enum_variable',
  195. valueTypeName: 'enum'
  196. },
  197. [CODE_INFO_TLV.STRUCT_INSTANCE]: {
  198. dataType: 'raw',
  199. entryKind: CODE_INFO_ENTRY_KIND.STRUCT,
  200. name: 'struct_instance',
  201. valueTypeName: 'struct'
  202. },
  203. [CODE_INFO_TLV.RAW_ARRAY]: {
  204. dataType: 'raw',
  205. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  206. name: 'raw_array',
  207. valueTypeName: 'raw'
  208. },
  209. [CODE_INFO_TLV.INT8_ARRAY]: {
  210. dataType: 'int8_t',
  211. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  212. expectedByteLength: 1,
  213. name: 'int8_array',
  214. valueTypeName: 'int8_t'
  215. },
  216. [CODE_INFO_TLV.UINT8_ARRAY]: {
  217. dataType: 'uint8_t',
  218. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  219. expectedByteLength: 1,
  220. name: 'uint8_array',
  221. valueTypeName: 'uint8_t'
  222. },
  223. [CODE_INFO_TLV.INT16_ARRAY]: {
  224. dataType: 'int16_t',
  225. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  226. expectedByteLength: 2,
  227. name: 'int16_array',
  228. valueTypeName: 'int16_t'
  229. },
  230. [CODE_INFO_TLV.UINT16_ARRAY]: {
  231. dataType: 'uint16_t',
  232. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  233. expectedByteLength: 2,
  234. name: 'uint16_array',
  235. valueTypeName: 'uint16_t'
  236. },
  237. [CODE_INFO_TLV.INT32_ARRAY]: {
  238. dataType: 'int32_t',
  239. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  240. expectedByteLength: 4,
  241. name: 'int32_array',
  242. valueTypeName: 'int32_t'
  243. },
  244. [CODE_INFO_TLV.UINT32_ARRAY]: {
  245. dataType: 'uint32_t',
  246. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  247. expectedByteLength: 4,
  248. name: 'uint32_array',
  249. valueTypeName: 'uint32_t'
  250. },
  251. [CODE_INFO_TLV.FLOAT32_ARRAY]: {
  252. dataType: 'float',
  253. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  254. expectedByteLength: 4,
  255. name: 'float32_array',
  256. valueTypeName: 'float32'
  257. },
  258. [CODE_INFO_TLV.DOUBLE_ARRAY]: {
  259. dataType: 'double',
  260. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  261. expectedByteLength: 8,
  262. name: 'double_array',
  263. valueTypeName: 'double'
  264. },
  265. [CODE_INFO_TLV.INT64_ARRAY]: {
  266. dataType: 'int64_t',
  267. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  268. expectedByteLength: 8,
  269. name: 'int64_array',
  270. valueTypeName: 'int64_t'
  271. },
  272. [CODE_INFO_TLV.UINT64_ARRAY]: {
  273. dataType: 'uint64_t',
  274. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  275. expectedByteLength: 8,
  276. name: 'uint64_array',
  277. valueTypeName: 'uint64_t'
  278. },
  279. [CODE_INFO_TLV.INT128_ARRAY]: {
  280. dataType: 'int128_t',
  281. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  282. expectedByteLength: 16,
  283. name: 'int128_array',
  284. valueTypeName: 'int128_t'
  285. },
  286. [CODE_INFO_TLV.UINT128_ARRAY]: {
  287. dataType: 'uint128_t',
  288. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  289. expectedByteLength: 16,
  290. name: 'uint128_array',
  291. valueTypeName: 'uint128_t'
  292. },
  293. [CODE_INFO_TLV.INT256_ARRAY]: {
  294. dataType: 'int256_t',
  295. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  296. expectedByteLength: 32,
  297. name: 'int256_array',
  298. valueTypeName: 'int256_t'
  299. },
  300. [CODE_INFO_TLV.UINT256_ARRAY]: {
  301. dataType: 'uint256_t',
  302. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  303. expectedByteLength: 32,
  304. name: 'uint256_array',
  305. valueTypeName: 'uint256_t'
  306. },
  307. [CODE_INFO_TLV.TEXT_ARRAY]: {
  308. dataType: 'text',
  309. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  310. expectedByteLength: 1,
  311. name: 'text_array',
  312. valueTypeName: 'text'
  313. },
  314. [CODE_INFO_TLV.ENUM_ARRAY]: {
  315. dataType: '',
  316. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  317. name: 'enum_array',
  318. valueTypeName: 'enum'
  319. },
  320. [CODE_INFO_TLV.STRUCT_ARRAY]: {
  321. dataType: 'raw',
  322. entryKind: CODE_INFO_ENTRY_KIND.ARRAY,
  323. name: 'struct_array',
  324. valueTypeName: 'struct'
  325. }
  326. }
  327. const CODE_INFO_MEMORY_AREA = {
  328. DATA: 0x01,
  329. IDATA: 0x02,
  330. XDATA: 0x03,
  331. CODE: 0x04,
  332. ADDR32: 0x07
  333. }
  334. const CODE_INFO_MEMORY_AREA_NAMES = {
  335. [CODE_INFO_MEMORY_AREA.DATA]: 'DATA',
  336. [CODE_INFO_MEMORY_AREA.IDATA]: 'IDATA',
  337. [CODE_INFO_MEMORY_AREA.XDATA]: 'XDATA',
  338. [CODE_INFO_MEMORY_AREA.CODE]: 'CODE',
  339. [CODE_INFO_MEMORY_AREA.ADDR32]: 'ADDR32'
  340. }
  341. const MEMORY_ENDIAN = {
  342. BIG: 'big',
  343. LITTLE: 'little'
  344. }
  345. function toBytes(bytes) {
  346. return Array.prototype.slice.call(bytes || []).map((byte) => Number(byte) & 0xFF)
  347. }
  348. function normalizeMemoryEndian(value, fallback = MEMORY_ENDIAN.LITTLE) {
  349. const text = String(value || '').trim().toLowerCase()
  350. if (text === 'little' || text === 'le' || text === '1') return MEMORY_ENDIAN.LITTLE
  351. if (text === 'big' || text === 'be' || text === '0') return MEMORY_ENDIAN.BIG
  352. return fallback
  353. }
  354. function applyMemoryEndian(bytes = [], memoryEndian = MEMORY_ENDIAN.LITTLE) {
  355. const source = Array.isArray(bytes) ? bytes.slice() : []
  356. return normalizeMemoryEndian(memoryEndian) === MEMORY_ENDIAN.LITTLE
  357. ? source.reverse()
  358. : source
  359. }
  360. function readFloat(bytes, offset, memoryEndian = MEMORY_ENDIAN.LITTLE) {
  361. if (offset + 3 >= bytes.length) return 0
  362. const buffer = new ArrayBuffer(4)
  363. const view = new DataView(buffer)
  364. const source = applyMemoryEndian(bytes.slice(offset, offset + 4), memoryEndian)
  365. for (let index = 0; index < 4; index += 1) {
  366. view.setUint8(index, source[index] || 0)
  367. }
  368. return view.getFloat32(0, false)
  369. }
  370. function readTlvText(bytes) {
  371. return bytesToAutoText(trimTrailingNullBytes(bytes)).trim()
  372. }
  373. function normalizeCodeInfoAddressWidth(value) {
  374. const numberValue = Number(value)
  375. if (numberValue === 16) return 16
  376. if (numberValue === 32) return 32
  377. throw new Error('CodeInfo 描述符地址长度必须为 16 或 32')
  378. }
  379. function formatAddress(address, addressWidth = 32) {
  380. const numberValue = Math.max(0, Math.floor(Number(address) || 0))
  381. const hexWidth = normalizeCodeInfoAddressWidth(addressWidth) === 16 ? 4 : 8
  382. return `0x${formatHexNumber(numberValue, hexWidth)}`
  383. }
  384. function normalizeTypeName(value, fallback) {
  385. const text = String(value || '').trim()
  386. return text || fallback
  387. }
  388. function getEntryKindText(entryKind) {
  389. return CODE_INFO_ENTRY_KIND_TEXT[entryKind] || 'unknown'
  390. }
  391. function getEntryTypeDefinition(type) {
  392. return CODE_INFO_ENTRY_TYPE_DEFINITIONS[Number(type) & 0xFF] || null
  393. }
  394. function getTlvName(type) {
  395. const tlvType = Number(type) & 0xFF
  396. const entryDefinition = getEntryTypeDefinition(tlvType)
  397. if (entryDefinition && entryDefinition.name) return entryDefinition.name
  398. if (CODE_INFO_BOARD_TLV_NAMES[tlvType]) return CODE_INFO_BOARD_TLV_NAMES[tlvType]
  399. return `tlv_0x${formatHexNumber(tlvType, 2)}`
  400. }
  401. function readMemoryEndianUint16(bytes, memoryEndian) {
  402. return normalizeMemoryEndian(memoryEndian) === MEMORY_ENDIAN.LITTLE
  403. ? readUint16LE(bytes, 0)
  404. : readUint16BE(bytes, 0)
  405. }
  406. function readMemoryEndianUint32(bytes, memoryEndian) {
  407. return normalizeMemoryEndian(memoryEndian) === MEMORY_ENDIAN.LITTLE
  408. ? readUint32LE(bytes, 0)
  409. : readUint32BE(bytes, 0)
  410. }
  411. function readNameField(valueBytes, offset, role) {
  412. if (offset >= valueBytes.length) {
  413. throw new Error('CodeInfo 内存入口 TLV 名称字段缺失')
  414. }
  415. const byteLength = valueBytes[offset] & 0xFF
  416. const nameOffset = offset + CODE_INFO_ENTRY_NAME_LENGTH_BYTE_LENGTH
  417. const nextOffset = nameOffset + byteLength
  418. if (byteLength > CODE_INFO_ENTRY_MAX_NAME_BYTE_LENGTH || nextOffset > valueBytes.length) {
  419. throw new Error(`CodeInfo 内存入口 TLV 名称长度无效,声明 ${byteLength} 字节,实际 ${Math.max(0, valueBytes.length - nameOffset)} 字节`)
  420. }
  421. return {
  422. field: {
  423. byteLength,
  424. role,
  425. text: readTlvText(valueBytes.slice(nameOffset, nextOffset))
  426. },
  427. nextOffset
  428. }
  429. }
  430. function ensureNoTrailingBytes(valueBytes, offset) {
  431. if (offset !== valueBytes.length) {
  432. throw new Error('CodeInfo 内存入口 TLV 长度与字段定义不一致')
  433. }
  434. }
  435. function resolveCodeInfoByteLength(sourceLength, options = {}) {
  436. const expectedLength = Number(
  437. options.codeInfoByteLength === undefined ? options.byteLength : options.codeInfoByteLength
  438. )
  439. if (!Number.isFinite(expectedLength) || expectedLength <= 0) return sourceLength
  440. if (sourceLength < expectedLength) {
  441. throw new Error('CodeInfo 数据长度小于描述符声明长度')
  442. }
  443. return Math.floor(expectedLength)
  444. }
  445. function parseEntryPrefix(valueBytes, options = {}) {
  446. const addressWidth = normalizeCodeInfoAddressWidth(options.addressWidth)
  447. const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
  448. const addressByteLength = addressWidth === 16 ? 2 : 4
  449. const minPrefixByteLength = (addressWidth === 16 ? 1 : 0) + addressByteLength + 2
  450. if (valueBytes.length < minPrefixByteLength) {
  451. throw new Error(`CodeInfo 内存入口 TLV 长度无效,至少需要 ${minPrefixByteLength} 字节`)
  452. }
  453. let cursor = 0
  454. let memoryArea = 'ADDR32'
  455. let memoryAreaCode = CODE_INFO_MEMORY_AREA.ADDR32
  456. if (addressWidth === 16) {
  457. memoryAreaCode = valueBytes[cursor] & 0xFF
  458. memoryArea = CODE_INFO_MEMORY_AREA_NAMES[memoryAreaCode] || ''
  459. if (!memoryArea || memoryAreaCode === CODE_INFO_MEMORY_AREA.ADDR32) {
  460. throw new Error('CodeInfo 16 位地址入口存储区域无效')
  461. }
  462. cursor += 1
  463. }
  464. const byteAddr = addressByteLength === 2
  465. ? readMemoryEndianUint16(valueBytes.slice(cursor, cursor + addressByteLength), memoryEndian)
  466. : readMemoryEndianUint32(valueBytes.slice(cursor, cursor + addressByteLength), memoryEndian)
  467. cursor += addressByteLength
  468. const byteLength = readMemoryEndianUint16(valueBytes.slice(cursor, cursor + 2), memoryEndian)
  469. cursor += 2
  470. return {
  471. addressByteLength,
  472. addressWidth,
  473. byteAddr,
  474. byteLength,
  475. cursor,
  476. memoryArea,
  477. memoryAreaCode
  478. }
  479. }
  480. function getEntryFallbackName(entryKindText, index) {
  481. if (entryKindText === 'enum') return `enum_${index + 1}`
  482. if (entryKindText === 'array') return `array_${index + 1}`
  483. if (entryKindText === 'variable') return `var_${index + 1}`
  484. return `struct_${index + 1}`
  485. }
  486. function createEntryBase(prefix, index, type, entryKind, names, extra = {}) {
  487. const entryKindText = getEntryKindText(entryKind)
  488. const fallbackName = getEntryFallbackName(entryKindText, index)
  489. const definitionField = names.find((name) => name.role === CODE_INFO_ENTRY_NAME_ROLE.DEFINITION)
  490. const instanceField = names.find((name) => name.role === CODE_INFO_ENTRY_NAME_ROLE.INSTANCE)
  491. || names.find((name) => name.role === CODE_INFO_ENTRY_NAME_ROLE.VARIABLE)
  492. const definitionName = normalizeTypeName(definitionField && definitionField.text, '')
  493. const instanceName = normalizeTypeName(instanceField && instanceField.text, definitionName || fallbackName)
  494. const symbolName = entryKind === CODE_INFO_ENTRY_KIND.VARIABLE
  495. ? normalizeTypeName(instanceField && instanceField.text, fallbackName)
  496. : instanceName
  497. const typeName = definitionName || extra.valueTypeName || symbolName
  498. return {
  499. addressByteLength: prefix.addressByteLength,
  500. addressWidth: prefix.addressWidth,
  501. byteAddr: prefix.byteAddr,
  502. byteLength: prefix.byteLength,
  503. definitionName,
  504. entryKind,
  505. entryKindText,
  506. index,
  507. instanceName,
  508. isArrayEntry: entryKind === CODE_INFO_ENTRY_KIND.ARRAY,
  509. isEnumEntry: entryKind === CODE_INFO_ENTRY_KIND.ENUM,
  510. isStructEntry: entryKind === CODE_INFO_ENTRY_KIND.STRUCT,
  511. isVariableEntry: entryKind === CODE_INFO_ENTRY_KIND.VARIABLE,
  512. memType: prefix.memoryAreaCode,
  513. memoryArea: prefix.memoryArea || 'UNKNOWN',
  514. nameByteLength: names.reduce((total, name) => total + Number(name.byteLength || 0), 0),
  515. nameFields: names.map((name) => ({
  516. byteLength: name.byteLength,
  517. role: name.role,
  518. text: name.text
  519. })),
  520. rawByteLength: 0,
  521. sourceAddressText: formatAddress(prefix.byteAddr, prefix.addressWidth),
  522. symbolName,
  523. tlvType: Number(type) & 0xFF,
  524. typeName,
  525. ...extra
  526. }
  527. }
  528. function validateEntryByteLength(prefix, entryDefinition, label) {
  529. const expectedByteLength = Number(entryDefinition && entryDefinition.expectedByteLength)
  530. if (!Number.isFinite(expectedByteLength) || expectedByteLength <= 0) return
  531. if (Number(prefix.byteLength) !== expectedByteLength) {
  532. throw new Error(`CodeInfo ${label} 字节长度与 TYPE 定义不一致`)
  533. }
  534. }
  535. function parseVariableEntry(valueBytes, index, type, entryDefinition, options = {}) {
  536. const prefix = parseEntryPrefix(valueBytes, options)
  537. let cursor = prefix.cursor
  538. const nameResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.VARIABLE)
  539. cursor = nameResult.nextOffset
  540. ensureNoTrailingBytes(valueBytes, cursor)
  541. validateEntryByteLength(prefix, entryDefinition, '变量入口')
  542. const entry = createEntryBase(
  543. prefix,
  544. index,
  545. type,
  546. CODE_INFO_ENTRY_KIND.VARIABLE,
  547. [nameResult.field],
  548. {
  549. dataType: entryDefinition.dataType || 'raw',
  550. valueTypeName: entryDefinition.valueTypeName || 'raw'
  551. }
  552. )
  553. return {
  554. ...entry,
  555. rawByteLength: valueBytes.length
  556. }
  557. }
  558. function parseEnumEntry(valueBytes, index, type, entryDefinition, options = {}) {
  559. const prefix = parseEntryPrefix(valueBytes, options)
  560. let cursor = prefix.cursor
  561. const definitionResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.DEFINITION)
  562. cursor = definitionResult.nextOffset
  563. const instanceResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.INSTANCE)
  564. cursor = instanceResult.nextOffset
  565. ensureNoTrailingBytes(valueBytes, cursor)
  566. const entry = createEntryBase(
  567. prefix,
  568. index,
  569. type,
  570. CODE_INFO_ENTRY_KIND.ENUM,
  571. [definitionResult.field, instanceResult.field],
  572. {
  573. dataType: entryDefinition.dataType || getIntegerDataTypeForByteLength(prefix.byteLength),
  574. valueTypeName: entryDefinition.valueTypeName || 'enum'
  575. }
  576. )
  577. return {
  578. ...entry,
  579. rawByteLength: valueBytes.length
  580. }
  581. }
  582. function parseStructEntry(valueBytes, index, type, entryDefinition, options = {}) {
  583. const prefix = parseEntryPrefix(valueBytes, options)
  584. let cursor = prefix.cursor
  585. const definitionResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.DEFINITION)
  586. cursor = definitionResult.nextOffset
  587. const instanceResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.INSTANCE)
  588. cursor = instanceResult.nextOffset
  589. ensureNoTrailingBytes(valueBytes, cursor)
  590. const entry = createEntryBase(
  591. prefix,
  592. index,
  593. type,
  594. CODE_INFO_ENTRY_KIND.STRUCT,
  595. [definitionResult.field, instanceResult.field],
  596. {
  597. dataType: entryDefinition.dataType || 'raw',
  598. valueTypeName: entryDefinition.valueTypeName || 'struct'
  599. }
  600. )
  601. return {
  602. ...entry,
  603. rawByteLength: valueBytes.length
  604. }
  605. }
  606. function readArrayDimensions(valueBytes, cursor, dimCount, memoryEndian) {
  607. const dimensions = []
  608. for (let index = 0; index < dimCount; index += 1) {
  609. if (cursor + 2 > valueBytes.length) {
  610. throw new Error('CodeInfo 数组维度字段长度无效')
  611. }
  612. const length = readMemoryEndianUint16(valueBytes.slice(cursor, cursor + 2), memoryEndian)
  613. if (!length) throw new Error('CodeInfo 数组维度长度必须大于 0')
  614. dimensions.push(length)
  615. cursor += 2
  616. }
  617. return {
  618. dimensions,
  619. nextOffset: cursor
  620. }
  621. }
  622. function parseArrayEntry(valueBytes, index, type, entryDefinition, options = {}) {
  623. const prefix = parseEntryPrefix(valueBytes, options)
  624. const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
  625. let cursor = prefix.cursor
  626. if (cursor + 5 > valueBytes.length) {
  627. throw new Error('CodeInfo 数组入口长度无效')
  628. }
  629. const elementByteLength = readMemoryEndianUint16(valueBytes.slice(cursor, cursor + 2), memoryEndian)
  630. cursor += 2
  631. const elementCount = readMemoryEndianUint16(valueBytes.slice(cursor, cursor + 2), memoryEndian)
  632. cursor += 2
  633. const dimensionCount = valueBytes[cursor] & 0xFF
  634. cursor += 1
  635. if (!elementByteLength) throw new Error('CodeInfo 数组元素字节长度必须大于 0')
  636. if (!elementCount) throw new Error('CodeInfo 数组元素数量必须大于 0')
  637. if (!dimensionCount) throw new Error('CodeInfo 数组维度数量必须大于 0')
  638. const dimensionsResult = readArrayDimensions(valueBytes, cursor, dimensionCount, memoryEndian)
  639. cursor = dimensionsResult.nextOffset
  640. const needsDefinitionName = type === CODE_INFO_TLV.ENUM_ARRAY || type === CODE_INFO_TLV.STRUCT_ARRAY
  641. let definitionResult = null
  642. if (needsDefinitionName) {
  643. definitionResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.DEFINITION)
  644. cursor = definitionResult.nextOffset
  645. }
  646. const instanceResult = readNameField(valueBytes, cursor, CODE_INFO_ENTRY_NAME_ROLE.INSTANCE)
  647. cursor = instanceResult.nextOffset
  648. ensureNoTrailingBytes(valueBytes, cursor)
  649. validateEntryByteLength({ byteLength: elementByteLength }, entryDefinition, '数组元素')
  650. const dimensionProduct = dimensionsResult.dimensions.reduce((total, value) => total * value, 1)
  651. if (dimensionProduct !== elementCount) {
  652. throw new Error('CodeInfo 数组维度乘积与元素数量不一致')
  653. }
  654. if (elementByteLength * elementCount !== prefix.byteLength) {
  655. throw new Error('CodeInfo 数组总字节长度与元素数量不一致')
  656. }
  657. const entry = createEntryBase(
  658. prefix,
  659. index,
  660. type,
  661. CODE_INFO_ENTRY_KIND.ARRAY,
  662. (definitionResult ? [definitionResult.field] : []).concat(instanceResult.field),
  663. {
  664. arrayDimensions: dimensionsResult.dimensions,
  665. arrayElementBaseIndex: 0,
  666. dataType: entryDefinition.dataType || 'raw',
  667. elementByteLength,
  668. elementCount,
  669. isEnumArrayEntry: type === CODE_INFO_TLV.ENUM_ARRAY,
  670. isStructArrayEntry: type === CODE_INFO_TLV.STRUCT_ARRAY,
  671. isTextArrayEntry: type === CODE_INFO_TLV.TEXT_ARRAY,
  672. valueTypeName: entryDefinition.valueTypeName || 'raw'
  673. }
  674. )
  675. return {
  676. ...entry,
  677. rawByteLength: valueBytes.length
  678. }
  679. }
  680. function parseMemoryEntry(valueBytes, index, type, options = {}) {
  681. const entryDefinition = getEntryTypeDefinition(type)
  682. if (!entryDefinition) return null
  683. switch (entryDefinition.entryKind) {
  684. case CODE_INFO_ENTRY_KIND.VARIABLE:
  685. return parseVariableEntry(valueBytes, index, type, entryDefinition, options)
  686. case CODE_INFO_ENTRY_KIND.ENUM:
  687. return parseEnumEntry(valueBytes, index, type, entryDefinition, options)
  688. case CODE_INFO_ENTRY_KIND.STRUCT:
  689. return parseStructEntry(valueBytes, index, type, entryDefinition, options)
  690. case CODE_INFO_ENTRY_KIND.ARRAY:
  691. return parseArrayEntry(valueBytes, index, type, entryDefinition, options)
  692. default:
  693. return null
  694. }
  695. }
  696. function applyCodeInfoTlvValue(target, type, valueBytes, options = {}) {
  697. const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
  698. switch (type) {
  699. case CODE_INFO_TLV.CAVE_FREQ:
  700. if (valueBytes.length < 1) throw new Error('CodeInfo cave_freq TLV 长度无效')
  701. target.caveFreq = valueBytes[0] & 0xFF
  702. break
  703. case CODE_INFO_TLV.REF_VOLT:
  704. if (valueBytes.length < 1) throw new Error('CodeInfo ref_volt TLV 长度无效')
  705. target.refVoltRaw = valueBytes[0] & 0xFF
  706. target.refVolt = target.refVoltRaw / 10
  707. break
  708. case CODE_INFO_TLV.AMP_GAIN:
  709. if (valueBytes.length < 1) throw new Error('CodeInfo amp_gain TLV 长度无效')
  710. target.ampGain = valueBytes[0] & 0xFF
  711. break
  712. case CODE_INFO_TLV.RS_SHUNT:
  713. if (valueBytes.length < 2) throw new Error('CodeInfo rs_shunt TLV 长度无效')
  714. target.rsShunt = readMemoryEndianUint16(valueBytes, memoryEndian)
  715. break
  716. case CODE_INFO_TLV.BUS_DIV:
  717. if (valueBytes.length < 4) throw new Error('CodeInfo bus_div TLV 长度无效')
  718. target.busDiv = readFloat(valueBytes, 0, memoryEndian)
  719. break
  720. case CODE_INFO_TLV.ALONG_DIV:
  721. if (valueBytes.length < 4) throw new Error('CodeInfo along_div TLV 长度无效')
  722. target.alongDiv = readFloat(valueBytes, 0, memoryEndian)
  723. break
  724. case CODE_INFO_TLV.CHIP_MODEL:
  725. target.chipModel = readTlvText(valueBytes)
  726. break
  727. case CODE_INFO_TLV.MODEL:
  728. target.model = readTlvText(valueBytes)
  729. break
  730. default:
  731. break
  732. }
  733. }
  734. function parseCodeInfoTlvs(bytes, options = {}) {
  735. const info = {
  736. entries: [],
  737. tlvItems: []
  738. }
  739. let offset = 0
  740. while (offset < bytes.length) {
  741. if (offset + CODE_INFO_TLV_HEADER_BYTE_LENGTH > bytes.length) {
  742. throw new Error('CodeInfo TLV 项头长度无效')
  743. }
  744. const type = bytes[offset] & 0xFF
  745. const byteLength = bytes[offset + 1] & 0xFF
  746. const valueOffset = offset + CODE_INFO_TLV_HEADER_BYTE_LENGTH
  747. const nextOffset = valueOffset + byteLength
  748. if (nextOffset > bytes.length) {
  749. throw new Error('CodeInfo TLV 项长度超出声明范围')
  750. }
  751. const valueBytes = bytes.slice(valueOffset, nextOffset)
  752. const item = {
  753. byteLength,
  754. name: getTlvName(type),
  755. rawHex: bytesToHex(valueBytes, ' '),
  756. type
  757. }
  758. info.tlvItems.push(item)
  759. const entry = parseMemoryEntry(valueBytes, info.entries.length, type, options)
  760. if (entry) {
  761. info.entries.push(entry)
  762. } else {
  763. applyCodeInfoTlvValue(info, type, valueBytes, options)
  764. }
  765. offset = nextOffset
  766. }
  767. return info
  768. }
  769. function parseCodeInfo(bytes, options = {}) {
  770. const inputBytes = toBytes(bytes)
  771. const codeInfoByteLength = resolveCodeInfoByteLength(inputBytes.length, options)
  772. const source = inputBytes.slice(0, codeInfoByteLength)
  773. const addressWidth = normalizeCodeInfoAddressWidth(options.addressWidth)
  774. const maxPacketLength = Number(options.maxPacketLength || 0) & 0xFFFF
  775. const memoryEndian = normalizeMemoryEndian(options.memoryEndian)
  776. const tlvInfo = parseCodeInfoTlvs(source, { addressWidth, memoryEndian })
  777. const entries = tlvInfo.entries
  778. const entryCount = entries.length
  779. const structCount = entries.filter((entry) => entry.isStructEntry || entry.isStructArrayEntry).length
  780. const enumCount = entries.filter((entry) => entry.isEnumEntry || entry.isEnumArrayEntry).length
  781. const variableCount = entries.filter((entry) => entry.isVariableEntry).length
  782. const arrayCount = entries.filter((entry) => entry.isArrayEntry).length
  783. const entryAddressByteLengths = entries
  784. .map((entry) => Number(entry.addressByteLength) || 0)
  785. .filter((value, index, list) => value > 0 && list.indexOf(value) === index)
  786. return {
  787. ...tlvInfo,
  788. addressWidth,
  789. addressWidthRaw: addressWidth,
  790. arrayCount,
  791. byteLength: codeInfoByteLength,
  792. entryCount,
  793. enumCount,
  794. maxPacketLength,
  795. memoryEndian,
  796. memoryEndianRaw: Number(options.memoryEndianRaw || options.memoryEndianMark || 0) & 0xFFFF,
  797. rawHex: bytesToHex(source, ' '),
  798. structEntryAddressByteLength: entryAddressByteLengths.length === 1 ? entryAddressByteLengths[0] : 0,
  799. structCount,
  800. structTable: entries,
  801. tableByteLength: entries.reduce((total, entry) => total + Number(entry.rawByteLength || 0), 0),
  802. tableCapacity: entryCount,
  803. tableRemainderByteLength: 0,
  804. tlvByteLength: source.length,
  805. truncated: false,
  806. variableCount
  807. }
  808. }
  809. function getIntegerDataTypeForByteLength(byteLength) {
  810. const length = Number(byteLength)
  811. if (length === 1) return 'uint8_t'
  812. if (length === 2) return 'uint16_t'
  813. if (length === 4) return 'uint32_t'
  814. return 'raw'
  815. }
  816. function getArrayIndexPath(linearIndex, dimensions = []) {
  817. const safeDimensions = (Array.isArray(dimensions) ? dimensions : [])
  818. .map((value) => Math.max(1, Math.floor(Number(value) || 1)))
  819. .filter((value) => value > 0)
  820. if (!safeDimensions.length) return [Math.max(0, Math.floor(Number(linearIndex) || 0))]
  821. const indexes = Array.from({ length: safeDimensions.length }, () => 0)
  822. let remaining = Math.max(0, Math.floor(Number(linearIndex) || 0))
  823. for (let index = safeDimensions.length - 1; index >= 0; index -= 1) {
  824. indexes[index] = remaining % safeDimensions[index]
  825. remaining = Math.floor(remaining / safeDimensions[index])
  826. }
  827. return indexes
  828. }
  829. function formatArrayIndexPath(indexPath = []) {
  830. return (Array.isArray(indexPath) ? indexPath : [indexPath])
  831. .map((index) => `[${Math.max(0, Math.floor(Number(index) || 0))}]`)
  832. .join('')
  833. }
  834. function createRegisterSourceMeta(entry, byteStart, byteLength, extra = {}) {
  835. const sourceAddress = entry.byteAddr + Math.max(0, Math.floor(Number(byteStart) || 0))
  836. return {
  837. sourceAddress,
  838. sourceAddressByteLength: entry.addressByteLength,
  839. sourceAddressText: formatAddress(sourceAddress, entry.addressWidth),
  840. sourceAddressWidth: entry.addressWidth,
  841. sourceArrayDimensions: entry.arrayDimensions,
  842. sourceByteLength: byteLength,
  843. sourceDefinitionName: entry.definitionName,
  844. sourceElementByteLength: entry.elementByteLength,
  845. sourceElementCount: entry.elementCount,
  846. sourceElementType: entry.valueTypeName,
  847. sourceEntryKind: entry.entryKindText,
  848. sourceInstanceName: entry.instanceName,
  849. sourceMemoryArea: entry.memoryArea,
  850. sourceMemoryClass: entry.memoryArea,
  851. sourceSymbolName: entry.symbolName,
  852. sourceSymbolType: entry.typeName,
  853. sourceValueType: entry.valueTypeName,
  854. ...extra
  855. }
  856. }
  857. function createRegistersForByteSpan(entry) {
  858. const count = Math.max(1, Number(entry.byteLength) || 1)
  859. const registers = []
  860. for (let offset = 0; offset < count; offset += 1) {
  861. registers.push({
  862. byteStart: offset,
  863. dataType: 'uint8_t',
  864. isPlaceholderByteField: true,
  865. name: offset.toString(16).toUpperCase().padStart(2, '0'),
  866. ...createRegisterSourceMeta(entry, offset, 1)
  867. })
  868. }
  869. return registers
  870. }
  871. function createScalarRegister(entry) {
  872. const dataType = entry.dataType || (entry.isEnumEntry ? getIntegerDataTypeForByteLength(entry.byteLength) : 'raw')
  873. const register = {
  874. byteStart: 0,
  875. dataType,
  876. name: entry.symbolName,
  877. ...createRegisterSourceMeta(entry, 0, entry.byteLength)
  878. }
  879. if (dataType === 'text') {
  880. register.textByteLength = String(entry.byteLength)
  881. }
  882. return [register]
  883. }
  884. function createArrayRegisters(entry) {
  885. if (entry.isStructArrayEntry) return createRegistersForByteSpan(entry)
  886. const dataType = entry.dataType || 'raw'
  887. if (dataType === 'text') {
  888. return [{
  889. byteStart: 0,
  890. dataType,
  891. name: entry.symbolName,
  892. textByteLength: String(entry.byteLength),
  893. ...createRegisterSourceMeta(entry, 0, entry.byteLength)
  894. }]
  895. }
  896. const count = Math.max(1, Number(entry.elementCount) || 1)
  897. const elementByteLength = Math.max(1, Number(entry.elementByteLength) || 1)
  898. const baseIndex = Math.max(0, Number(entry.arrayElementBaseIndex) || 0)
  899. const registers = []
  900. for (let index = 0; index < count; index += 1) {
  901. const linearIndex = baseIndex + index
  902. const indexPath = getArrayIndexPath(linearIndex, entry.arrayDimensions)
  903. const byteStart = index * elementByteLength
  904. registers.push({
  905. byteStart,
  906. dataType,
  907. name: `${entry.symbolName}${formatArrayIndexPath(indexPath)}`,
  908. ...createRegisterSourceMeta(entry, byteStart, elementByteLength, {
  909. sourceArrayIndex: linearIndex,
  910. sourceArrayIndexPath: indexPath,
  911. sourceSymbolName: `${entry.symbolName}${formatArrayIndexPath(indexPath)}`
  912. })
  913. })
  914. }
  915. return registers
  916. }
  917. function createCodeInfoContext(codeInfo = {}) {
  918. return {
  919. addressWidth: codeInfo.addressWidth,
  920. codeInfoAddressWidth: codeInfo.addressWidth,
  921. maxPacketLength: codeInfo.maxPacketLength,
  922. memoryEndian: codeInfo.memoryEndian,
  923. memoryEndianRaw: Number(codeInfo.memoryEndianRaw || 0) & 0xFFFF,
  924. storageAddressWidth: codeInfo.addressWidth
  925. }
  926. }
  927. function createSourceMeta(entry, byteLength) {
  928. return {
  929. addressUnit: 'byte',
  930. sourceAddress: entry.byteAddr,
  931. sourceAddressByteLength: entry.addressByteLength,
  932. sourceAddressText: formatAddress(entry.byteAddr, entry.addressWidth),
  933. sourceAddressWidth: entry.addressWidth,
  934. sourceArrayDimensions: entry.arrayDimensions,
  935. sourceByteLength: byteLength,
  936. sourceDefinitionName: entry.definitionName,
  937. sourceElementByteLength: entry.elementByteLength,
  938. sourceElementCount: entry.elementCount,
  939. sourceElementType: entry.valueTypeName,
  940. sourceEntryKind: entry.entryKindText,
  941. sourceInstanceName: entry.instanceName,
  942. sourceMemoryArea: entry.memoryArea,
  943. sourceMemoryClass: entry.memoryArea,
  944. sourceSymbolName: entry.symbolName,
  945. sourceSymbolType: entry.typeName,
  946. sourceValueType: entry.valueTypeName
  947. }
  948. }
  949. function createGroupFromEntry(entry, chunkLength, suffix = '', codeInfo = {}) {
  950. const isStructLike = entry.isStructEntry || entry.isStructArrayEntry
  951. const registers = isStructLike
  952. ? createRegistersForByteSpan(entry)
  953. : (entry.isArrayEntry ? createArrayRegisters(entry) : createScalarRegister(entry))
  954. return {
  955. codeInfoContext: createCodeInfoContext(codeInfo),
  956. layout: isStructLike ? 'struct' : 'register',
  957. name: `${entry.symbolName || entry.typeName}${suffix}`,
  958. quantity: registers.length,
  959. registerType: entry.memoryArea === 'CODE' ? 'input' : 'holding',
  960. registers,
  961. ...createSourceMeta(entry, chunkLength),
  962. sourceSegment: 'CodeInfo TLV',
  963. sourceSegmentModule: '',
  964. startAddress: formatAddress(entry.byteAddr, entry.addressWidth)
  965. }
  966. }
  967. function createEntryChunk(entry, offset, chunkLength) {
  968. const chunkEntry = {
  969. ...entry,
  970. byteAddr: entry.byteAddr + offset,
  971. byteLength: chunkLength
  972. }
  973. if (entry.isArrayEntry) {
  974. const elementByteLength = Math.max(1, Number(entry.elementByteLength) || 1)
  975. const elementOffset = Math.floor(offset / elementByteLength)
  976. const elementCount = Math.max(1, Math.floor(chunkLength / elementByteLength))
  977. chunkEntry.arrayElementBaseIndex = (Number(entry.arrayElementBaseIndex) || 0) + elementOffset
  978. chunkEntry.elementCount = elementCount
  979. }
  980. return chunkEntry
  981. }
  982. function getChunkStep(entry, maxRegisters) {
  983. if (!entry.isArrayEntry) return maxRegisters
  984. const elementByteLength = Math.max(1, Number(entry.elementByteLength) || 1)
  985. const elementsPerChunk = Math.max(1, Math.floor(maxRegisters / elementByteLength))
  986. return elementsPerChunk * elementByteLength
  987. }
  988. function createGroupsFromCodeInfo(codeInfo, options = {}) {
  989. const maxRegisters = Math.max(1, Number(options.maxRegistersPerGroup) || 256)
  990. const groups = []
  991. const entries = Array.isArray(codeInfo.entries) ? codeInfo.entries : codeInfo.structTable
  992. ;(Array.isArray(entries) ? entries : []).forEach((entry) => {
  993. if (!entry.byteLength || entry.memoryArea === 'UNKNOWN') return
  994. if (!entry.isStructEntry && !entry.isEnumEntry && !entry.isVariableEntry && !entry.isArrayEntry) return
  995. const chunkStep = getChunkStep(entry, maxRegisters)
  996. for (let offset = 0; offset < entry.byteLength; offset += chunkStep) {
  997. const chunkLength = Math.min(chunkStep, entry.byteLength - offset)
  998. const chunkEntry = createEntryChunk(entry, offset, chunkLength)
  999. const suffix = entry.byteLength > chunkStep ? ` #${Math.floor(offset / chunkStep) + 1}` : ''
  1000. groups.push(createGroupFromEntry(chunkEntry, chunkLength, suffix, codeInfo))
  1001. }
  1002. })
  1003. return groups
  1004. }
  1005. module.exports = {
  1006. CODE_INFO_ENTRY_KIND,
  1007. CODE_INFO_ENTRY_MAX_NAME_BYTE_LENGTH,
  1008. CODE_INFO_ENTRY_NAME_LENGTH_BYTE_LENGTH,
  1009. CODE_INFO_MEMORY_AREA,
  1010. CODE_INFO_TLV_HEADER_BYTE_LENGTH,
  1011. CODE_INFO_TLV,
  1012. MEMORY_ENDIAN,
  1013. createGroupsFromCodeInfo,
  1014. normalizeCodeInfoAddressWidth,
  1015. parseCodeInfo
  1016. }