@gaialabs/core 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -131,6 +131,148 @@ var RomDataReader = class {
131
131
  }
132
132
  };
133
133
 
134
+ //#endregion
135
+ //#region src/types/constants.ts
136
+ /**
137
+ * ROM processing constants
138
+ * Converted from GaiaLib/Types/RomProcessingConstants.cs
139
+ */
140
+ var RomProcessingConstants = class RomProcessingConstants {
141
+ static PAGE_SIZE = 32768;
142
+ static SNES_HEADER_SIZE = 80;
143
+ static DICTIONARIES = ["dictionary_01EBA8", "dictionary_01F54D"];
144
+ static DICT_COMMANDS = [214, 215];
145
+ static END_CHARS = [
146
+ 192,
147
+ 202,
148
+ 209
149
+ ];
150
+ static WHITESPACE = [" ", " "];
151
+ static OPERATORS = ["-", "+"];
152
+ static COMMA_SPACE = [
153
+ ",",
154
+ " ",
155
+ " "
156
+ ];
157
+ static ADDRESS_SPACE = [
158
+ "@",
159
+ "&",
160
+ "^",
161
+ "#",
162
+ "$",
163
+ "%",
164
+ "*"
165
+ ];
166
+ static SYMBOL_SPACE = [
167
+ ",",
168
+ " ",
169
+ " ",
170
+ "<",
171
+ ">",
172
+ "(",
173
+ ")",
174
+ ":",
175
+ "[",
176
+ "]",
177
+ "{",
178
+ "}",
179
+ "`",
180
+ "~",
181
+ "|"
182
+ ];
183
+ static LABEL_SPACE = [
184
+ "[",
185
+ "{",
186
+ "#",
187
+ "`",
188
+ "~",
189
+ "|",
190
+ ":"
191
+ ];
192
+ static OBJECT_SPACE = ["<", "["];
193
+ static COP_SPLIT_CHARS = [
194
+ " ",
195
+ " ",
196
+ ",",
197
+ "(",
198
+ ")",
199
+ "[",
200
+ "]",
201
+ "$",
202
+ "#"
203
+ ];
204
+ static WHITESPACE_REGEX = /[ \t]/;
205
+ static COMMA_SPACE_REGEX = /[, \t]/;
206
+ static SYMBOL_SPACE_REGEX = /[, \t<>()\:\[\]{}`~|]/;
207
+ static LABEL_SPACE_REGEX = /[\[{#`~|:]/;
208
+ static OBJECT_SPACE_REGEX = /[<\[]/;
209
+ static ADDRESS_SPACE_REGEX = /[@&^#$%*]/;
210
+ static COP_SPLIT_REGEX = /[ \t,()[\]$#]/;
211
+ static COMMA_SPACE_TRIM_REGEX = /^[, \t]+|[, \t]+$/g;
212
+ /**
213
+ * Gets the size of an object for processing purposes
214
+ * @param obj The object to get the size for
215
+ * @returns Size in bytes
216
+ * @throws Error when unable to determine size
217
+ */
218
+ static getSize(obj) {
219
+ if (obj === void 0 || obj === null) return 0;
220
+ switch (typeof obj) {
221
+ case "object":
222
+ if (Array.isArray(obj)) return obj.reduce((acc, x) => acc + RomProcessingConstants.getSize(x), 0);
223
+ if ("size" in obj) return obj.size;
224
+ if ("length" in obj) return obj.length;
225
+ if ("_tag" in obj) switch (obj._tag) {
226
+ case "Byte": return 1;
227
+ case "Word": return 2;
228
+ }
229
+ break;
230
+ case "number":
231
+ if (obj <= 255) return 1;
232
+ if (obj <= 65535) return 2;
233
+ if (obj <= 16777215) return 3;
234
+ return 4;
235
+ case "string":
236
+ if (!obj.length) return 0;
237
+ switch (obj[0]) {
238
+ case "@":
239
+ case "%": return 3;
240
+ case "*":
241
+ case "&": return 2;
242
+ case "^": return 1;
243
+ }
244
+ switch (obj) {
245
+ case "Byte": return 1;
246
+ case "Word": return 2;
247
+ case "Offset": return 2;
248
+ case "Address": return 3;
249
+ }
250
+ return obj.length;
251
+ }
252
+ return 0;
253
+ }
254
+ };
255
+ /**
256
+ * BlockReader specific constants
257
+ */
258
+ var BlockReaderConstants = class {
259
+ static REF_SEARCH_MAX_RANGE = 416;
260
+ static BANK_MASK_CHECK = 64;
261
+ static BYTE_DELIMITER_THRESHOLD = 256;
262
+ static BANK_HIGH_MEMORY_1 = 126;
263
+ static BANK_HIGH_MEMORY_2 = 127;
264
+ static POINTER_CHARACTERS = ["&", "@"];
265
+ static WIDE_STRING_TYPE = "WideString";
266
+ static BINARY_TYPE = "Binary";
267
+ static CODE_TYPE = "Code";
268
+ static LOCATION_FORMAT = "loc_{0:X6}";
269
+ static TYPE_NAME_FORMAT = "{0}_{1:X6}";
270
+ static OFFSET_FORMAT = "+{0:X}";
271
+ static MARKER_FORMAT = "+M";
272
+ static NEGATIVE_OFFSET_FORMAT = "-{0:X}";
273
+ static NEGATIVE_MARKER_FORMAT = "-M";
274
+ };
275
+
134
276
  //#endregion
135
277
  //#region src/types/addressing.ts
136
278
  /**
@@ -144,6 +286,7 @@ let AddressType = /* @__PURE__ */ function(AddressType) {
144
286
  AddressType["Address"] = "Address";
145
287
  AddressType["WBank"] = "WBank";
146
288
  AddressType["Relative"] = "Relative";
289
+ AddressType["WRelative"] = "WRelative";
147
290
  AddressType["Location"] = "Location";
148
291
  return AddressType;
149
292
  }({});
@@ -165,6 +308,11 @@ let MemoryMapMode = /* @__PURE__ */ function(MemoryMapMode) {
165
308
  MemoryMapMode["ExHi"] = "ExHi";
166
309
  return MemoryMapMode;
167
310
  }({});
311
+ let CpuMode = /* @__PURE__ */ function(CpuMode) {
312
+ CpuMode["Slow"] = "Slow";
313
+ CpuMode["Fast"] = "Fast";
314
+ return CpuMode;
315
+ }({});
168
316
  /**
169
317
  * SNES address structure
170
318
  * Converted from GaiaLib/Types/Address.cs
@@ -193,14 +341,19 @@ var Address = class Address {
193
341
  get isCodeBank() {
194
342
  return (this.bank & Address.DATA_BANK_FLAG) === 0;
195
343
  }
196
- toInt() {
344
+ toLocation() {
197
345
  if (this.mode === MemoryMapMode.Lo) return (this.bank & 63) << 15 | this.offset & 32767;
198
346
  if (this.mode === MemoryMapMode.Hi || this.bank & Address.FAST_BANK_FLAG) return (this.bank & 63) << 16 | this.offset & 65535;
199
347
  return this.bank === 62 ? this.offset + 20774912 : this.bank === 63 ? this.offset + 20840448 : ((this.bank & 63) << 16 | this.offset & 65535) + 16777216;
200
348
  }
201
- static fromInt(value, mode) {
202
- if (mode === MemoryMapMode.Lo) return new Address(value >> 15 & 255, value & 32767 | 32768, mode);
203
- if (mode === MemoryMapMode.Hi || value & Address.FAST_BANK_FLAG) return new Address(value >> 16 & 255, value & 65535, mode);
349
+ static fromLocation(value, mode, cpuMode) {
350
+ let bankFlag = cpuMode === CpuMode.Fast ? Address.FAST_BANK_FLAG : 0;
351
+ if (mode === MemoryMapMode.Lo) return new Address(value >> 15 & 127 | bankFlag, value & 32767 | 32768, mode);
352
+ if (mode === MemoryMapMode.Hi) {
353
+ if ((value & RomProcessingConstants.PAGE_SIZE) === 0) bankFlag = 192;
354
+ return new Address(value >> 16 & 127 | bankFlag, value & 65535, mode);
355
+ }
356
+ if (value & Address.FAST_BANK_FLAG) return new Address(value >> 16 & 255, value & 65535, mode);
204
357
  if (value >= 20774912 && value < 20840448) return new Address(62, value - 20774912, mode);
205
358
  if (value >= 20840448 && value < 20905984) return new Address(63, value - 20840448, mode);
206
359
  return new Address(value >> 16 & 127, value & 65535, mode);
@@ -212,8 +365,11 @@ var Address = class Address {
212
365
  if (value >= 20840448 && value < 20905984) return 63;
213
366
  return value >> 16 & 127;
214
367
  }
368
+ toInt() {
369
+ return this.bank << 16 | this.offset;
370
+ }
215
371
  toString() {
216
- return (this.bank << 16 | this.offset).toString(16).toUpperCase().padStart(6, "0");
372
+ return this.toInt().toString(16).toUpperCase().padStart(6, "0");
217
373
  }
218
374
  static typeFromCode(code) {
219
375
  switch (code) {
@@ -346,12 +502,12 @@ let BinType = /* @__PURE__ */ function(BinType) {
346
502
  BinType["Palette"] = "Palette";
347
503
  BinType["Sound"] = "Sound";
348
504
  BinType["Music"] = "Music";
349
- BinType["Unknown"] = "Unknown";
350
505
  BinType["Meta17"] = "Meta17";
351
506
  BinType["Spritemap"] = "Spritemap";
352
507
  BinType["Assembly"] = "Assembly";
353
508
  BinType["Patch"] = "Patch";
354
509
  BinType["Transform"] = "Transform";
510
+ BinType["Binary"] = "Binary";
355
511
  return BinType;
356
512
  }({});
357
513
 
@@ -649,148 +805,6 @@ var CompressionRegistry = class {
649
805
  }
650
806
  };
651
807
 
652
- //#endregion
653
- //#region src/types/constants.ts
654
- /**
655
- * ROM processing constants
656
- * Converted from GaiaLib/Types/RomProcessingConstants.cs
657
- */
658
- var RomProcessingConstants = class RomProcessingConstants {
659
- static PAGE_SIZE = 32768;
660
- static SNES_HEADER_SIZE = 80;
661
- static DICTIONARIES = ["dictionary_01EBA8", "dictionary_01F54D"];
662
- static DICT_COMMANDS = [214, 215];
663
- static END_CHARS = [
664
- 192,
665
- 202,
666
- 209
667
- ];
668
- static WHITESPACE = [" ", " "];
669
- static OPERATORS = ["-", "+"];
670
- static COMMA_SPACE = [
671
- ",",
672
- " ",
673
- " "
674
- ];
675
- static ADDRESS_SPACE = [
676
- "@",
677
- "&",
678
- "^",
679
- "#",
680
- "$",
681
- "%",
682
- "*"
683
- ];
684
- static SYMBOL_SPACE = [
685
- ",",
686
- " ",
687
- " ",
688
- "<",
689
- ">",
690
- "(",
691
- ")",
692
- ":",
693
- "[",
694
- "]",
695
- "{",
696
- "}",
697
- "`",
698
- "~",
699
- "|"
700
- ];
701
- static LABEL_SPACE = [
702
- "[",
703
- "{",
704
- "#",
705
- "`",
706
- "~",
707
- "|",
708
- ":"
709
- ];
710
- static OBJECT_SPACE = ["<", "["];
711
- static COP_SPLIT_CHARS = [
712
- " ",
713
- " ",
714
- ",",
715
- "(",
716
- ")",
717
- "[",
718
- "]",
719
- "$",
720
- "#"
721
- ];
722
- static WHITESPACE_REGEX = /[ \t]/;
723
- static COMMA_SPACE_REGEX = /[, \t]/;
724
- static SYMBOL_SPACE_REGEX = /[, \t<>()\:\[\]{}`~|]/;
725
- static LABEL_SPACE_REGEX = /[\[{#`~|:]/;
726
- static OBJECT_SPACE_REGEX = /[<\[]/;
727
- static ADDRESS_SPACE_REGEX = /[@&^#$%*]/;
728
- static COP_SPLIT_REGEX = /[ \t,()[\]$#]/;
729
- static COMMA_SPACE_TRIM_REGEX = /^[, \t]+|[, \t]+$/g;
730
- /**
731
- * Gets the size of an object for processing purposes
732
- * @param obj The object to get the size for
733
- * @returns Size in bytes
734
- * @throws Error when unable to determine size
735
- */
736
- static getSize(obj) {
737
- if (obj === void 0 || obj === null) return 0;
738
- switch (typeof obj) {
739
- case "object":
740
- if (Array.isArray(obj)) return obj.reduce((acc, x) => acc + RomProcessingConstants.getSize(x), 0);
741
- if ("size" in obj) return obj.size;
742
- if ("length" in obj) return obj.length;
743
- if ("_tag" in obj) switch (obj._tag) {
744
- case "Byte": return 1;
745
- case "Word": return 2;
746
- }
747
- break;
748
- case "number":
749
- if (obj <= 255) return 1;
750
- if (obj <= 65535) return 2;
751
- if (obj <= 16777215) return 3;
752
- return 4;
753
- case "string":
754
- if (!obj.length) return 0;
755
- switch (obj[0]) {
756
- case "@":
757
- case "%": return 3;
758
- case "*":
759
- case "&": return 2;
760
- case "^": return 1;
761
- }
762
- switch (obj) {
763
- case "Byte": return 1;
764
- case "Word": return 2;
765
- case "Offset": return 2;
766
- case "Address": return 3;
767
- }
768
- return obj.length;
769
- }
770
- return 0;
771
- }
772
- };
773
- /**
774
- * BlockReader specific constants
775
- */
776
- var BlockReaderConstants = class {
777
- static REF_SEARCH_MAX_RANGE = 416;
778
- static BANK_MASK_CHECK = 64;
779
- static BYTE_DELIMITER_THRESHOLD = 256;
780
- static BANK_HIGH_MEMORY_1 = 126;
781
- static BANK_HIGH_MEMORY_2 = 127;
782
- static POINTER_CHARACTERS = ["&", "@"];
783
- static WIDE_STRING_TYPE = "WideString";
784
- static BINARY_TYPE = "Binary";
785
- static CODE_TYPE = "Code";
786
- static LOCATION_FORMAT = "loc_{0:X6}";
787
- static TYPE_NAME_FORMAT = "{0}_{1:X6}";
788
- static OFFSET_FORMAT = "+{0:X}";
789
- static MARKER_FORMAT = "+M";
790
- static NEGATIVE_OFFSET_FORMAT = "-{0:X}";
791
- static NEGATIVE_MARKER_FORMAT = "-M";
792
- };
793
-
794
808
  //#endregion
795
809
  //#region src/types/files.ts
796
810
  /**
@@ -850,11 +864,11 @@ function createChunkFileFromDbFile(rom, compression, dbFile, fileType) {
850
864
  enrichWithRawDataFromDbFile(rom, chunkFile, compression, dbFile, fileType);
851
865
  return chunkFile;
852
866
  }
853
- function createChunkFileFromDbBlock(block, fileType) {
867
+ function createChunkFileFromDbBlock(block, fileType, memoryMode) {
854
868
  const chunkFile = new ChunkFile(block.name, 0, 0, fileType);
855
869
  chunkFile.group = block.group;
856
870
  chunkFile.scene = block.scene;
857
- enrichWithPartsFromDbBlock(chunkFile, block);
871
+ enrichWithPartsFromDbBlock(chunkFile, block, memoryMode);
858
872
  return chunkFile;
859
873
  }
860
874
  function combineHeader(data, position, length, header, type) {
@@ -899,12 +913,12 @@ function enrichWithRawDataFromDbFile(rom, chunkFile, compression, dbFile, fileTy
899
913
  /**
900
914
  * Enriches ChunkFile with AsmBlock parts from DbBlock
901
915
  */
902
- function enrichWithPartsFromDbBlock(chunkFile, block) {
916
+ function enrichWithPartsFromDbBlock(chunkFile, block, memoryMode) {
903
917
  chunkFile.parts = [];
904
918
  chunkFile.size = 0;
905
919
  if (!block.parts?.length) throw new Error(`Block ${block.name} has no parts`);
906
920
  chunkFile.location = block.parts[0].start;
907
- chunkFile.bank = block.movable ? void 0 : chunkFile.location >> 16;
921
+ chunkFile.bank = block.movable ? void 0 : memoryMode === MemoryMapMode.Lo ? chunkFile.location >> 15 : chunkFile.location >> 16;
908
922
  chunkFile.transforms = block.transforms;
909
923
  chunkFile.postProcess = block.postProcess;
910
924
  for (const part of block.parts) {
@@ -936,8 +950,12 @@ var ChunkFileUtils = class {
936
950
  */
937
951
  static calculateSize(chunkFile) {
938
952
  if (!chunkFile.parts) {
939
- if (typeof chunkFile.compressed === "boolean" || chunkFile.type.header === -2) chunkFile.size += 2;
940
- return chunkFile.size;
953
+ let size$1 = chunkFile.rawData?.length ?? chunkFile.size;
954
+ if (chunkFile.type.header === -2 || chunkFile.compressed === false) {
955
+ size$1 += 2;
956
+ chunkFile.size = size$1;
957
+ }
958
+ return size$1;
941
959
  }
942
960
  let size = 0;
943
961
  for (let x = 0; x < chunkFile.parts.length; x++) {
@@ -1367,7 +1385,7 @@ var CopCommandProcessor = class {
1367
1385
  if (bank === null && offset === 0) return new Word(offset);
1368
1386
  const addr = new Address(bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode), offset, this._blockReader._root.config.memoryMode);
1369
1387
  if (addr.isROM) {
1370
- const location = addr.toInt();
1388
+ const location = addr.toLocation();
1371
1389
  if (partStr !== "Address" && isPtr && !this._blockReader._root.rewrites[location]) this._blockReader.noteType(location, otherStr, true);
1372
1390
  if (type === AddressType.Unknown) type = this.tryParseAddressType(partStr) ?? AddressType.Unknown;
1373
1391
  return new LocationWrapper(location, type);
@@ -1501,7 +1519,7 @@ var AddressingModeHandler = class {
1501
1519
  const refLoc = this._dataReader.readUShort();
1502
1520
  const address = new Address(this._dataReader.readByte(), refLoc, reg.mode);
1503
1521
  if (address.isROM) {
1504
- const wrapper = new LocationWrapper(address.toInt(), AddressType.Address);
1522
+ const wrapper = new LocationWrapper(address.toLocation(), AddressType.Address);
1505
1523
  if (this.isJumpInstruction(mnemonic)) this._blockReader.noteType(wrapper.location, "Code", false, reg);
1506
1524
  operands.push(wrapper);
1507
1525
  } else operands.push(address);
@@ -1517,7 +1535,7 @@ var AddressingModeHandler = class {
1517
1535
  handlePCRelativeMode(operands, nextAddress, reg, isLong) {
1518
1536
  const relative = isLong ? nextAddress + this._dataReader.readShort() : nextAddress + this._dataReader.readSByte();
1519
1537
  this._blockReader.updateRegisterState(relative, reg);
1520
- operands.push(new LocationWrapper(relative, AddressType.Relative));
1538
+ operands.push(new LocationWrapper(relative, isLong ? AddressType.WRelative : AddressType.Relative));
1521
1539
  }
1522
1540
  handleStackRelativeMode(operands) {
1523
1541
  operands.push(new Byte(this._dataReader.readByte()));
@@ -1542,7 +1560,7 @@ var AddressingModeHandler = class {
1542
1560
  const isJump = isPush || isIndexedIndirect || this.isJumpInstruction(mnemonic);
1543
1561
  const addr = new Address(xBank1 ?? (isJump ? Address.resolveBank(this._dataReader.position, registers.mode) : dataBank) ?? 129, refLoc, registers.mode);
1544
1562
  if (addr.isROM) {
1545
- const wrapper = new LocationWrapper(addr.toInt(), AddressType.Offset);
1563
+ const wrapper = new LocationWrapper(addr.toLocation(), AddressType.Offset);
1546
1564
  if (isJump) {
1547
1565
  const type = isIndexedIndirect ? "&Code" : "Code";
1548
1566
  const name = this._blockReader.noteType(wrapper.location, type, isPush, registers);
@@ -1607,16 +1625,7 @@ var TransformProcessor = class TransformProcessor {
1607
1625
  }
1608
1626
  applyDefaultTransform(operandIndex, operands, bank) {
1609
1627
  const opnd = operands[operandIndex];
1610
- const adrs = new Address(bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode), opnd && "value" in opnd ? opnd["value"] : opnd, this._blockReader._root.config.memoryMode);
1611
- const loc = adrs.toInt();
1612
- const nameResult = this._referenceManager.tryGetName(loc);
1613
- let referenceName;
1614
- if (!nameResult.found) {
1615
- referenceName = `loc_${adrs.toString()}`;
1616
- this._referenceManager.tryAddName(loc, referenceName);
1617
- } else referenceName = nameResult.referenceName;
1618
- this._blockReader.resolveInclude(loc, false);
1619
- operands[operandIndex] = `&${referenceName}`;
1628
+ operands[operandIndex] = new LocationWrapper(new Address(bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode), opnd && "value" in opnd ? opnd["value"] : opnd, this._blockReader._root.config.memoryMode).toLocation(), AddressType.Offset);
1620
1629
  }
1621
1630
  cleanTransformName(transform) {
1622
1631
  let name = transform;
@@ -1790,7 +1799,6 @@ var DbStringDictionary = class {
1790
1799
  range;
1791
1800
  command;
1792
1801
  name;
1793
- suffix;
1794
1802
  entries;
1795
1803
  constructor(data) {
1796
1804
  this.base = data.base ?? void 0;
@@ -1798,7 +1806,6 @@ var DbStringDictionary = class {
1798
1806
  this.command = data.command ?? void 0;
1799
1807
  this.name = data.name ?? "";
1800
1808
  this.entries = data.entries ?? void 0;
1801
- this.suffix = data.suffix ?? "";
1802
1809
  if (this.base === void 0 && this.command === void 0) throw new Error("Base or command is required");
1803
1810
  if (!this.name) throw new Error("Name is required");
1804
1811
  if (!this.entries) throw new Error("Entries is required");
@@ -2624,13 +2631,13 @@ var QuintetLZ = class QuintetLZ {
2624
2631
  * @param srcData Source data to compress
2625
2632
  * @returns Compressed data
2626
2633
  */
2627
- compact(srcData) {
2634
+ compact(srcData, srcPosition, srcLen) {
2628
2635
  const dictionary = new Uint8Array(QuintetLZ.DICTIONARY_SIZE);
2629
2636
  dictionary.fill(QuintetLZ.DICTIONARY_INIT);
2630
2637
  let offset = QuintetLZ.DICTIONARY_OFFSET;
2631
- let srcIx = 0;
2638
+ let srcIx = srcPosition ?? 0;
2632
2639
  let dstIx = 0;
2633
- const srcLen = srcData.length;
2640
+ if (!srcLen) srcLen = srcData.length - srcIx;
2634
2641
  const outputBuffer = new Uint8Array(srcLen * 2);
2635
2642
  outputBuffer[dstIx++] = srcLen & 255;
2636
2643
  outputBuffer[dstIx++] = srcLen >> 8 & 255;
@@ -2897,7 +2904,7 @@ var BlockWriter = class {
2897
2904
  if (typeof obj === "number") return ObjectType.Number;
2898
2905
  return ObjectType.String;
2899
2906
  }
2900
- writeObject(obj, depth, isBranch = false) {
2907
+ writeObject(obj, depth, isBranch = false, isArray = false) {
2901
2908
  const lines = [];
2902
2909
  const objType = this.getObjectType(obj);
2903
2910
  let objLines;
@@ -2915,7 +2922,7 @@ var BlockWriter = class {
2915
2922
  objLines = [this._blockReader.resolveName(obj.location, obj.type, isBranch)];
2916
2923
  break;
2917
2924
  case ObjectType.Address:
2918
- objLines = [`$${obj.toString()}`];
2925
+ objLines = isArray ? [`$#${obj.offset.toString(16).toUpperCase().padStart(4, "0")}`] : [`$${obj.toString()}`];
2919
2926
  break;
2920
2927
  case ObjectType.ByteArray:
2921
2928
  objLines = [`#${Array.from(obj).map((b) => b.toString(16).toUpperCase().padStart(2, "0")).join("")}`];
@@ -3028,13 +3035,13 @@ var BlockWriter = class {
3028
3035
  const hexStr = str.substring(ix + 1, ix + 7);
3029
3036
  const rawAddr = parseInt(hexStr, 16);
3030
3037
  const adrs = new Address(rawAddr >> 16 & 255, rawAddr & 65535, this._blockReader._root.config.memoryMode);
3031
- if (adrs.isROM) {
3032
- const addressType = char === "^" ? AddressType.Offset : AddressType.Address;
3033
- const location = adrs.toInt();
3034
- const name = this._blockReader.resolveName(location, addressType, false);
3035
- str = str.replace(str.substring(ix, ix + 7), name);
3036
- }
3037
- ix = str.indexOf(char, ix + 7);
3038
+ const addressType = char === "^" ? AddressType.Offset : AddressType.Address;
3039
+ let name = "";
3040
+ if (adrs.isROM) name = this._blockReader.resolveName(adrs.toLocation(), addressType, false);
3041
+ else if (addressType === AddressType.Offset) name = adrs.offset.toString(16).toUpperCase().padStart(4, "0");
3042
+ else name = adrs.toString();
3043
+ str = str.replace(str.substring(ix, ix + 7), name);
3044
+ ix = str.indexOf(char);
3038
3045
  }
3039
3046
  }
3040
3047
  const refChar = stringObj.type.delimiter;
@@ -3085,7 +3092,7 @@ var BlockWriter = class {
3085
3092
  lines.push("[");
3086
3093
  this._isInline = false;
3087
3094
  for (let i = 0; i < arr.length; i++) {
3088
- const objLines = this.writeObject(arr[i], depth + 1);
3095
+ const objLines = this.writeObject(arr[i], depth + 1, false, true);
3089
3096
  for (const line of objLines) lines.push(indent + " " + line);
3090
3097
  lines[lines.length - 1] += ` ;${i.toString(16).toUpperCase().padStart(2, "0")}`;
3091
3098
  }
@@ -3297,19 +3304,19 @@ var TypeParser = class {
3297
3304
  }
3298
3305
  const stringType = this._stringTypes[fixedTypeName];
3299
3306
  if (stringType) return this._stringReader.parseString(stringType, fixedSize);
3300
- const mType = this.tryParseMemberType(typeName);
3307
+ const mType = this.tryParseMemberType(fixedTypeName);
3301
3308
  if (mType !== null) switch (mType) {
3302
3309
  case MemberType.Byte: return new Byte(this._romDataReader.readByte());
3303
3310
  case MemberType.Word: return new Word(this.parseWordSafe());
3304
3311
  case MemberType.Offset: return this.parseLocation(this._romDataReader.readUShort(), bank, null, AddressType.Offset);
3305
3312
  case MemberType.Address: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Address);
3306
3313
  case MemberType.Location: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Location);
3307
- case MemberType.Binary: return this.parseBinary();
3314
+ case MemberType.Binary: return this.parseBinary(fixedSize);
3308
3315
  case MemberType.Code: return this.parseCode(reg);
3309
3316
  default: throw new Error("Invalid member type");
3310
3317
  }
3311
- const parentType = this._blockReader._root.structs[typeName];
3312
- if (!parentType) throw new Error(`Unknown type: ${typeName}`);
3318
+ const parentType = this._blockReader._root.structs[fixedTypeName];
3319
+ if (!parentType) throw new Error(`Unknown type: ${fixedTypeName}`);
3313
3320
  const delimiter = parentType.delimiter;
3314
3321
  const discOffset = parentType.discriminator;
3315
3322
  const objects = [];
@@ -3321,7 +3328,7 @@ var TypeParser = class {
3321
3328
  const discPosition = this._romDataReader.position + discOffset;
3322
3329
  const desc = this._romDataReader.romData[discPosition];
3323
3330
  if (discOffset === 0) this._romDataReader.position++;
3324
- targetType = Object.values(this._blockReader._root.structs).find((x) => x.parent === typeName && x.discriminator === desc) || parentType;
3331
+ targetType = Object.values(this._blockReader._root.structs).find((x) => x.parent === fixedTypeName && x.discriminator === desc) || parentType;
3325
3332
  }
3326
3333
  const types = targetType.types;
3327
3334
  if (types && types.length > 0) {
@@ -3354,12 +3361,13 @@ var TypeParser = class {
3354
3361
  parseWordSafe() {
3355
3362
  return this._referenceManager.containsStruct(this._romDataReader.position + 1) ? this._romDataReader.readByte() : this._romDataReader.readUShort();
3356
3363
  }
3357
- parseBinary() {
3364
+ parseBinary(size) {
3358
3365
  const startPosition = this._romDataReader.position;
3359
- do
3366
+ let len = 0;
3367
+ do {
3360
3368
  this._romDataReader.position++;
3361
- while (this._blockReader.partCanContinue());
3362
- const len = this._romDataReader.position - startPosition;
3369
+ len++;
3370
+ } while (len !== size && this._blockReader.partCanContinue());
3363
3371
  const outBuffer = new Uint8Array(len);
3364
3372
  for (let i = 0; i < len; i++) outBuffer[i] = this._romDataReader.romData[startPosition + i];
3365
3373
  return outBuffer;
@@ -3372,7 +3380,7 @@ var TypeParser = class {
3372
3380
  else {
3373
3381
  adrs = new Address(bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode), offset, this._blockReader._root.config.memoryMode);
3374
3382
  if (!adrs.isROM) return adrs;
3375
- loc = adrs.toInt();
3383
+ loc = adrs.toLocation();
3376
3384
  }
3377
3385
  if (typeName && !this._blockReader._root.rewrites[loc]) {
3378
3386
  this._referenceManager.tryAddStruct(loc, typeName);
@@ -3617,26 +3625,40 @@ var BlockReader = class {
3617
3625
  */
3618
3626
  createChunkFilesFromSfx() {
3619
3627
  let pos = this._root.config.sfxLocation;
3628
+ let offset = 0;
3620
3629
  const count = this._root.config.sfxCount;
3621
3630
  const romData = this._romDataReader.romData;
3622
3631
  const fileType = Object.values(this._root.fileTypes).find((x) => x.type === BinType.Sound);
3623
- const getSize = () => romData[pos++] | romData[pos++] << 8;
3624
- for (let i = 0; i < count; i++) {
3625
- const size = getSize();
3626
- const startPos = pos;
3627
- let remaining = size;
3628
- let end = pos + remaining;
3632
+ const getByte = this._root.config.sfxType === "Striped" ? () => {
3633
+ const byte = romData[pos + offset++];
3634
+ if (offset & RomProcessingConstants.PAGE_SIZE) offset += RomProcessingConstants.PAGE_SIZE;
3635
+ return byte;
3636
+ } : () => romData[pos + offset++];
3637
+ const getSize = () => getByte() | getByte() << 8;
3638
+ const getBytes = this._root.config.sfxType === "Striped" ? (size) => {
3639
+ let end = offset + size;
3629
3640
  let data;
3630
3641
  if (end & RomProcessingConstants.PAGE_SIZE) {
3631
3642
  const endLen = end & 32767;
3632
- remaining -= endLen;
3633
- data = romData.slice(pos, pos + remaining);
3634
- pos += remaining + RomProcessingConstants.PAGE_SIZE;
3635
- end = pos + endLen;
3636
- const data2 = romData.slice(pos, end);
3643
+ size -= endLen;
3644
+ data = romData.slice(pos + offset, pos + offset + size);
3645
+ offset += size + RomProcessingConstants.PAGE_SIZE;
3646
+ end = offset + endLen;
3647
+ const data2 = romData.slice(pos + offset, pos + end);
3637
3648
  data = new Uint8Array([...data, ...data2]);
3638
- } else data = romData.slice(pos, end);
3639
- pos = end;
3649
+ } else data = romData.slice(pos + offset, pos + end);
3650
+ offset = end;
3651
+ return data;
3652
+ } : (size) => {
3653
+ const end = offset + size;
3654
+ const data = romData.slice(pos + offset, pos + end);
3655
+ offset = end;
3656
+ return data;
3657
+ };
3658
+ for (let i = 0; i < count; i++) {
3659
+ const size = getSize();
3660
+ const startPos = pos + offset;
3661
+ const data = getBytes(size);
3640
3662
  const chunk = new ChunkFile(`sfx${i.toString(16).toUpperCase().padStart(2, "0")}`, size, startPos, fileType);
3641
3663
  chunk.rawData = data;
3642
3664
  chunk.group = "sfx";
@@ -3657,7 +3679,7 @@ var BlockReader = class {
3657
3679
  */
3658
3680
  createChunkFilesFromDbBlocks() {
3659
3681
  for (const block of this._root.blocks) {
3660
- const chunkFile = createChunkFileFromDbBlock(block, Object.values(this._root.fileTypes).find((x) => x.isBlock));
3682
+ const chunkFile = createChunkFileFromDbBlock(block, Object.values(this._root.fileTypes).find((x) => x.isBlock), this._root.config.memoryMode);
3661
3683
  this._enrichedChunks.push(chunkFile);
3662
3684
  }
3663
3685
  }
@@ -3763,8 +3785,18 @@ var RomLayout = class RomLayout {
3763
3785
  bestDepth = 0;
3764
3786
  bestOffset = 0;
3765
3787
  bestRemain = 0;
3766
- constructor(files) {
3767
- this.unmatchedFiles = Array.from(files).filter((x) => (x.size || 0) > 0).sort((a, b) => {
3788
+ root;
3789
+ config;
3790
+ sfxPackType;
3791
+ sfxFiles = [];
3792
+ constructor(files, root) {
3793
+ this.root = root;
3794
+ this.config = root.config;
3795
+ this.sfxPackType = root.config.sfxPack ?? root.config.sfxType;
3796
+ this.sfxFiles = this.sfxPackType !== "Individual" ? files.filter((x) => x.type.type === "Sound").sort((a, b) => {
3797
+ return parseInt(a.name.substring(a.name.length - 2, a.name.length), 16) - parseInt(b.name.substring(b.name.length - 2, b.name.length), 16);
3798
+ }) : [];
3799
+ this.unmatchedFiles = files.filter((x) => (x.size || 0) > 0).filter((x) => this.sfxPackType === "Individual" || x.type.type !== "Sound").sort((a, b) => {
3768
3800
  const aAsm = a.parts ? 0 : 1;
3769
3801
  const bAsm = b.parts ? 0 : 1;
3770
3802
  if (aAsm !== bAsm) return aAsm - bAsm;
@@ -3774,16 +3806,67 @@ var RomLayout = class RomLayout {
3774
3806
  });
3775
3807
  }
3776
3808
  organize() {
3777
- for (let page = 0; page < 128; page++) {
3809
+ let stripeSfx = false;
3810
+ let page;
3811
+ const maxPages = this.config.memoryMode === MemoryMapMode.Hi ? 128 : this.config.memoryMode === MemoryMapMode.ExHi ? 256 : 64;
3812
+ for (page = 0; page < maxPages; page++) {
3778
3813
  if (this.unmatchedFiles.length === 0) break;
3814
+ let start = page << 15;
3779
3815
  let remain = RomProcessingConstants.PAGE_SIZE;
3780
- if (page === 1) remain -= RomProcessingConstants.SNES_HEADER_SIZE;
3781
- this.currentUpper = (page & 1) !== 0;
3782
- this.currentBank = page >> 1;
3816
+ if (start <= this.config.sfxLocation && start + remain > this.config.sfxLocation) {
3817
+ this.config.sfxLocation - start;
3818
+ if (this.sfxPackType === "Sequential") {
3819
+ let offset = 0;
3820
+ for (const file of this.sfxFiles) {
3821
+ file.location = start + offset;
3822
+ console.log(` ${file.location.toString(16).toUpperCase().padStart(6, "0")}: ${file.name}`);
3823
+ offset += file.size;
3824
+ if (offset & RomProcessingConstants.PAGE_SIZE) {
3825
+ offset &= 32767;
3826
+ console.log(`Page ${start.toString(16).toUpperCase().padStart(6, "0")} matched with SFX files 0 remaining`);
3827
+ start += RomProcessingConstants.PAGE_SIZE;
3828
+ page++;
3829
+ }
3830
+ }
3831
+ console.log(`Page ${start.toString(16).toUpperCase().padStart(6, "0")} matched with SFX files ${remain} remaining`);
3832
+ start += offset;
3833
+ remain = RomProcessingConstants.PAGE_SIZE - offset;
3834
+ } else if (this.sfxPackType === "Striped") stripeSfx = true;
3835
+ }
3836
+ if (page === 0 && this.config.memoryMode === MemoryMapMode.Lo || page === 1 && this.config.memoryMode === MemoryMapMode.Hi) remain -= RomProcessingConstants.SNES_HEADER_SIZE;
3837
+ if (stripeSfx) {
3838
+ let offset = 0;
3839
+ while (remain > 0 && this.sfxFiles.length) {
3840
+ const file = this.sfxFiles.shift();
3841
+ file.location = start + offset;
3842
+ console.log(` ${file.location.toString(16).toUpperCase().padStart(6, "0")}: ${file.name}`);
3843
+ offset += file.size;
3844
+ if (offset & RomProcessingConstants.PAGE_SIZE) {
3845
+ offset &= 32767;
3846
+ console.log(`Page ${start.toString(16).toUpperCase().padStart(6, "0")} matched with SFX files 0 remaining`);
3847
+ start += RomProcessingConstants.PAGE_SIZE;
3848
+ page++;
3849
+ if (offset) {
3850
+ const newFile = new ChunkFile(file.name + "_2", file.size, file.location, Object.values(this.root.fileTypes).find((x) => x.type === BinType.Binary));
3851
+ const end = file.rawData.length - offset;
3852
+ newFile.rawData = file.rawData.slice(end);
3853
+ newFile.size = newFile.rawData.length;
3854
+ this.sfxFiles.unshift(newFile);
3855
+ file.rawData = file.rawData.slice(0, end);
3856
+ file.size -= offset;
3857
+ }
3858
+ remain = 0;
3859
+ break;
3860
+ } else remain -= file.size;
3861
+ }
3862
+ start += offset;
3863
+ if (!this.sfxFiles.length) stripeSfx = false;
3864
+ }
3865
+ this.currentUpper = this.config.memoryMode === MemoryMapMode.Lo || (page & 1) !== 0;
3866
+ this.currentBank = this.config.memoryMode === MemoryMapMode.Lo ? page : page >> 1;
3783
3867
  this.bestDepth = 0;
3784
3868
  this.bestRemain = remain;
3785
3869
  this.bestOffset = 0;
3786
- const start = page << 15;
3787
3870
  this.testDepth(0, 0, remain, this.currentUpper);
3788
3871
  if (this.currentUpper) {
3789
3872
  this.bestOffset = this.bestDepth;
@@ -3794,7 +3877,7 @@ var RomLayout = class RomLayout {
3794
3877
  const file = this.unmatchedFiles[this.bestResult[i++]];
3795
3878
  file.location = position;
3796
3879
  console.log(` ${position.toString(16).toUpperCase().padStart(6, "0")}: ${file.name}`);
3797
- position += file.size || 0;
3880
+ position += file.size;
3798
3881
  }
3799
3882
  console.log(`Page ${start.toString(16).toUpperCase().padStart(6, "0")} matched with ${this.bestDepth} files ${this.bestRemain} remaining`);
3800
3883
  this.commitPage();
@@ -3803,6 +3886,7 @@ var RomLayout = class RomLayout {
3803
3886
  const names = this.unmatchedFiles.map((x) => x.name).join("\r\n");
3804
3887
  throw new Error(`Unable to match ${this.unmatchedFiles.length} files\r\n${names}`);
3805
3888
  }
3889
+ return page;
3806
3890
  }
3807
3891
  testDepth(startIndex, depth, remain, asmMode) {
3808
3892
  for (let fileIndex = startIndex; fileIndex < this.unmatchedFiles.length; fileIndex++) {
@@ -3868,7 +3952,16 @@ var RomProcessor = class RomProcessor {
3868
3952
  const asmFiles = [];
3869
3953
  for (const file of allFiles) {
3870
3954
  if (file.type.type === "Patch") patches.push(file);
3871
- else if (file.type.type !== "Assembly") continue;
3955
+ else if (file.type.type !== "Assembly") {
3956
+ if (file.compressed === true) if (this.writer.root.config.uncompress) file.compressed = false;
3957
+ else {
3958
+ let newData = this.writer.root.compression.compact(file.rawData, file.type.header);
3959
+ if (file.type.header) newData = new Uint8Array([...file.rawData.slice(0, file.type.header), ...newData]);
3960
+ file.rawData = newData;
3961
+ file.size = newData.length;
3962
+ }
3963
+ continue;
3964
+ }
3872
3965
  asmFiles.push(file);
3873
3966
  if (!file.parts) {
3874
3967
  const { blocks, includes, reqBank } = new Assembler(this.writer.root, file.textData).parseAssembly();
@@ -3879,7 +3972,7 @@ var RomProcessor = class RomProcessor {
3879
3972
  }
3880
3973
  RomProcessor.applyPatches(asmFiles, patches);
3881
3974
  for (const file of allFiles) ChunkFileUtils.calculateSize(file);
3882
- new RomLayout(allFiles).organize();
3975
+ const pages = new RomLayout(allFiles, this.writer.root).organize();
3883
3976
  for (const file of asmFiles) ChunkFileUtils.rebase(file);
3884
3977
  for (const f of asmFiles) {
3885
3978
  const includeBlocks = asmFiles.filter((x) => f.includes?.has(x.name.toUpperCase())).flatMap((x) => x.parts).filter((b) => !!b.label);
@@ -3889,6 +3982,7 @@ var RomProcessor = class RomProcessor {
3889
3982
  }
3890
3983
  const blockLookup = /* @__PURE__ */ new Map();
3891
3984
  for (const f of allFiles) blockLookup.set(f.name.toUpperCase(), f.location);
3985
+ this.writer.allocate(pages);
3892
3986
  for (const file of allFiles) await this.writer.writeFile(file, blockLookup);
3893
3987
  }
3894
3988
  static applyPatches(asmFiles, patches) {
@@ -3934,6 +4028,7 @@ var RomProcessor = class RomProcessor {
3934
4028
  var RomWriter = class {
3935
4029
  bpsPath;
3936
4030
  outBuffer;
4031
+ romSize;
3937
4032
  cartName;
3938
4033
  makerCode;
3939
4034
  root;
@@ -3941,7 +4036,6 @@ var RomWriter = class {
3941
4036
  this.cartName = cartName;
3942
4037
  this.makerCode = makerCode;
3943
4038
  this.root = root;
3944
- this.outBuffer = new Uint8Array(4194304);
3945
4039
  }
3946
4040
  async repack(files) {
3947
4041
  await new RomProcessor(this).repack(files);
@@ -3950,35 +4044,47 @@ var RomWriter = class {
3950
4044
  this.writeChecksum();
3951
4045
  return this.outBuffer;
3952
4046
  }
4047
+ allocate(pages) {
4048
+ const size = pages * RomProcessingConstants.PAGE_SIZE;
4049
+ let bits = 0;
4050
+ let target = 1024;
4051
+ while (target < size) {
4052
+ target <<= 1;
4053
+ bits++;
4054
+ }
4055
+ this.romSize = bits;
4056
+ this.outBuffer = new Uint8Array(target);
4057
+ }
3953
4058
  writeHeader() {
3954
4059
  const buf = this.outBuffer;
3955
- let pos = 65456;
4060
+ let pos = this.root.config.memoryMode === MemoryMapMode.Lo ? 32688 : 65456;
3956
4061
  this.writeAscii(this.makerCode.padEnd(6, " "), pos);
3957
4062
  pos += 6;
3958
4063
  for (let i = 0; i < 10; i++) buf[pos++] = 0;
3959
4064
  this.writeAscii(this.cartName.toUpperCase().padEnd(21, " "), pos);
3960
4065
  pos += 21;
3961
- buf[pos++] = 49;
3962
- buf[pos++] = 2;
3963
- buf[pos++] = 12;
3964
- buf[pos++] = 3;
4066
+ buf[pos++] = 32 | (this.root.config.cpuMode === CpuMode.Fast ? 16 : 0) | (this.root.config.memoryMode === MemoryMapMode.Hi ? 1 : this.root.config.memoryMode === MemoryMapMode.ExHi ? 5 : 0);
4067
+ buf[pos++] = this.root.config.chipset;
4068
+ buf[pos++] = this.romSize;
4069
+ buf[pos++] = this.root.config.ramSize;
3965
4070
  buf[pos++] = 1;
3966
4071
  buf[pos++] = 51;
3967
4072
  buf[pos++] = 0;
3968
4073
  }
3969
4074
  writeChecksum() {
3970
4075
  const buf = this.outBuffer;
3971
- buf[65500] = 255;
3972
- buf[65501] = 255;
3973
- buf[65502] = 0;
3974
- buf[65503] = 0;
4076
+ let pos = this.root.config.memoryMode === MemoryMapMode.Lo ? 32732 : 65500;
4077
+ buf[pos] = 255;
4078
+ buf[pos + 1] = 255;
4079
+ buf[pos + 2] = 0;
4080
+ buf[pos + 3] = 0;
3975
4081
  let sum = 0;
3976
4082
  for (let i = 0; i < buf.length; i++) sum += buf[i];
3977
- buf[65502] = sum & 255;
3978
- buf[65503] = sum >> 8 & 255;
4083
+ buf[pos + 2] = sum & 255;
4084
+ buf[pos + 3] = sum >> 8 & 255;
3979
4085
  const comp = ~sum;
3980
- buf[65500] = comp & 255;
3981
- buf[65501] = comp >> 8 & 255;
4086
+ buf[pos] = comp & 255;
4087
+ buf[pos + 1] = comp >> 8 & 255;
3982
4088
  }
3983
4089
  writeEntryPoints(asmFiles) {
3984
4090
  const buf = this.outBuffer;
@@ -3986,8 +4092,10 @@ var RomWriter = class {
3986
4092
  for (const ep of this.root.config.entryPoints) {
3987
4093
  const match = entryBlocks.find((b) => b.label === ep.name);
3988
4094
  if (match) {
3989
- buf[ep.location] = match.location & 255;
3990
- buf[ep.location + 1] = match.location >> 8 & 255;
4095
+ let location = match.location;
4096
+ if (this.root.config.memoryMode === MemoryMapMode.Lo) location += RomProcessingConstants.PAGE_SIZE;
4097
+ buf[ep.location] = location & 255;
4098
+ buf[ep.location + 1] = location >> 8 & 255;
3991
4099
  }
3992
4100
  }
3993
4101
  }
@@ -3999,19 +4107,21 @@ var RomWriter = class {
3999
4107
  const data = file.rawData;
4000
4108
  let remain = file.size;
4001
4109
  let srcPos = 0;
4002
- if (file.type.header === -2) {
4003
- remain -= 2;
4004
- buf[pos++] = remain & 255;
4005
- buf[pos++] = remain >> 8 & 255;
4006
- } else if (file.type.header > 0) {
4007
- remain -= file.type.header;
4008
- for (let i = 0; i < file.type.header; i++) buf[pos++] = data[srcPos++];
4110
+ if (file.compressed !== true) {
4111
+ if (file.type.header === -2) {
4112
+ remain -= 2;
4113
+ buf[pos++] = remain & 255;
4114
+ buf[pos++] = remain >> 8 & 255;
4115
+ } else if (file.type.header > 0) {
4116
+ remain -= file.type.header;
4117
+ for (let i = 0; i < file.type.header; i++) buf[pos++] = data[srcPos++];
4118
+ }
4009
4119
  }
4010
- if (file.compressed !== void 0) {
4120
+ if (file.compressed === false) {
4011
4121
  remain -= 2;
4012
- const inverse = 0 - remain & 65535;
4013
- buf[pos++] = inverse & 255;
4014
- buf[pos++] = inverse >> 8 & 255;
4122
+ const size = 0 - remain & 65535;
4123
+ buf[pos++] = size & 255;
4124
+ buf[pos++] = size >> 8 & 255;
4015
4125
  }
4016
4126
  while (remain > 0) {
4017
4127
  buf[pos++] = data[srcPos++];
@@ -4105,7 +4215,7 @@ var RomWriter = class {
4105
4215
  default: throw new Error(`Invalid operand '${label}'`);
4106
4216
  }
4107
4217
  }
4108
- let type = Address.typeFromCode(str[0]);
4218
+ let type = isRelative ? parentOp?.size === 3 ? AddressType.WRelative : AddressType.Relative : Address.typeFromCode(str[0]);
4109
4219
  if (type === AddressType.Unknown) type = parentOp?.size === 4 ? AddressType.Address : parentOp?.size === 2 ? AddressType.Unknown : AddressType.Offset;
4110
4220
  if (isRelative) {
4111
4221
  loc -= block.location + opos;
@@ -4119,22 +4229,24 @@ var RomWriter = class {
4119
4229
  break;
4120
4230
  } else markerOffset += RomProcessingConstants.getSize(part);
4121
4231
  }
4232
+ if (!isRelative && type !== AddressType.Location) loc = Address.fromLocation(loc, this.root.config.memoryMode, this.root.config.cpuMode).toInt();
4122
4233
  switch (type) {
4123
4234
  case AddressType.Offset:
4235
+ case AddressType.WRelative:
4124
4236
  currentObj = new Word(loc);
4125
4237
  continue;
4126
4238
  case AddressType.Bank:
4127
- currentObj = new Byte(loc >> 16 | ((loc & 65535) >= 32768 ? 128 : 192));
4239
+ currentObj = new Byte(loc >> 16);
4128
4240
  continue;
4129
4241
  case AddressType.WBank:
4130
- currentObj = new Word(loc >> 16 | ((loc & 65535) >= 32768 ? 128 : 192));
4242
+ currentObj = new Word(loc >> 16);
4131
4243
  continue;
4132
4244
  case AddressType.Address:
4133
- currentObj = new Long(loc | ((loc & 65535) >= 32768 ? 8388608 : 12582912));
4134
- continue;
4135
4245
  case AddressType.Location:
4136
4246
  currentObj = new Long(loc);
4137
4247
  continue;
4248
+ case AddressType.Unknown:
4249
+ case AddressType.Relative:
4138
4250
  default:
4139
4251
  currentObj = new Byte(loc);
4140
4252
  continue;
@@ -4549,7 +4661,7 @@ var StringReader = class StringReader {
4549
4661
  } else {
4550
4662
  let found = false;
4551
4663
  for (const dictionary of Object.values(dictionaries)) if (c >= dictionary.base && c <= dictionary.range) {
4552
- builder.push(dictionary.entries[c - dictionary.base] + dictionary.suffix);
4664
+ builder.push(dictionary.entries[c - dictionary.base]);
4553
4665
  found = true;
4554
4666
  break;
4555
4667
  }
@@ -4668,24 +4780,38 @@ var StringProcessor = class {
4668
4780
  }
4669
4781
  }
4670
4782
  processString(str, stringType) {
4671
- const dict = stringType.commands;
4783
+ const cmdLookup = stringType.commands;
4784
+ const dictLookup = stringType.dictionaries;
4672
4785
  let lastCmd = null;
4786
+ for (const dictionary of Object.values(dictLookup)) for (let ix = 0; ix < dictionary.entries.length; ix++) {
4787
+ const entry = dictionary.entries[ix];
4788
+ if (str.indexOf(entry) >= 0) if (dictionary.command !== void 0) str = str.replace(entry, `[${dictionary.command}:${(ix + dictionary.base).toString(16).toUpperCase()}]`);
4789
+ else str = str.replace(entry, `[${(ix + dictionary.base).toString(16).toUpperCase()}]`);
4790
+ }
4673
4791
  for (let x = 0; x < str.length; x++) {
4674
4792
  const c = str[x];
4675
4793
  if (c === "[") {
4676
4794
  const endIx = str.indexOf("]", x + 1);
4677
- const parts = str.substring(x + 1, endIx).split(/* @__PURE__ */ new RegExp(`[${[
4795
+ const splitChars = [
4678
4796
  ":",
4679
4797
  ",",
4680
4798
  " "
4681
- ].join("")}]`)).filter((p) => p.length > 0);
4799
+ ];
4800
+ const subStr = str.substring(x + 1, endIx);
4801
+ let ix = subStr.length === 2 ? parseInt(subStr, 16) : NaN;
4802
+ if (!isNaN(ix)) {
4803
+ this.memBuffer.push(ix);
4804
+ x = endIx;
4805
+ continue;
4806
+ }
4807
+ const parts = str.substring(x + 1, endIx).split(/* @__PURE__ */ new RegExp(`[${splitChars.join("")}]`)).filter((p) => p.length > 0);
4682
4808
  x = endIx;
4683
4809
  if (parts.length === 0) {
4684
4810
  this.flushBuffer(stringType, true);
4685
4811
  this.context.currentBlock.objList.push({ offset: this.context.currentBlock.size });
4686
4812
  continue;
4687
4813
  }
4688
- const cmd = dict[parts[0]];
4814
+ const cmd = cmdLookup[parts[0]];
4689
4815
  if (cmd) {
4690
4816
  lastCmd = cmd;
4691
4817
  this.memBuffer.push(cmd.id);
@@ -6157,12 +6283,12 @@ var RomGenerator = class {
6157
6283
  this.assembleCodeFromText(asmFiles);
6158
6284
  RomProcessor.applyPatches(asmFiles, patchFiles);
6159
6285
  for (const asm of chunkFiles) ChunkFileUtils.calculateSize(asm);
6160
- new RomLayout(chunkFiles).organize();
6286
+ const pages = new RomLayout(chunkFiles, this.dbRoot).organize();
6161
6287
  for (const file of asmFiles) ChunkFileUtils.rebase(file);
6162
6288
  this.generateAsmIncludeLookups(asmFiles);
6163
6289
  const blockLookup = /* @__PURE__ */ new Map();
6164
6290
  for (const f of chunkFiles) blockLookup.set(f.name.toUpperCase(), f.location);
6165
- return await this.writeRom(blockLookup, chunkFiles, asmFiles);
6291
+ return await this.writeRom(blockLookup, chunkFiles, asmFiles, pages);
6166
6292
  }
6167
6293
  applyProjectInit(chunkFiles, asmFiles, patchFiles) {
6168
6294
  const moduleLookup = /* @__PURE__ */ new Map();
@@ -6207,8 +6333,9 @@ var RomGenerator = class {
6207
6333
  existing.size = chunkFile.size;
6208
6334
  } else chunkFiles.push(chunkFile);
6209
6335
  }
6210
- async writeRom(blockLookup, chunkFiles, asmFiles) {
6336
+ async writeRom(blockLookup, chunkFiles, asmFiles, pages) {
6211
6337
  const romWriter = new RomWriter(this.dbRoot, "GAIALABS", "01JG ");
6338
+ romWriter.allocate(pages);
6212
6339
  for (const file of chunkFiles) await romWriter.writeFile(file, blockLookup);
6213
6340
  romWriter.writeHeader();
6214
6341
  romWriter.writeEntryPoints(asmFiles);
@@ -6492,6 +6619,7 @@ exports.CompressionAlgorithms = CompressionAlgorithms;
6492
6619
  exports.CompressionRegistry = CompressionRegistry;
6493
6620
  exports.CopCommandProcessor = CopCommandProcessor;
6494
6621
  exports.CopDef = CopDef;
6622
+ exports.CpuMode = CpuMode;
6495
6623
  exports.DbAddressingMode = DbAddressingMode;
6496
6624
  exports.DbBlock = DbBlock;
6497
6625
  exports.DbFile = DbFile;