• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Keine Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Emily's Z80 assembler for the Gameboy.


Commit MetaInfo

Revision3200946f5bd923585df0f1804c507c39e7e9d4e5 (tree)
Zeit2021-03-02 17:22:04
AutorAlaskanEmily <emily@alas...>
CommiterAlaskanEmily

Log Message

Add ROM bank support with !bank <num>. Defaults to bank 0.

Ändern Zusammenfassung

Diff

--- a/em_gb_asm.py
+++ b/em_gb_asm.py
@@ -52,6 +52,7 @@ class Block:
5252 self.name = name
5353 self.current_label = None
5454 self.base = None
55+ self.bank = None
5556 self.has_error = False
5657 self.data = bytearray()
5758 self.symbols = {}
@@ -618,10 +619,26 @@ def assemble(block, mnemonic, operands=()):
618619 # print(str(mnemonic) + " " + str(operands))
619620 mnemonic = mnemonic.lower()
620621
622+ if mnemonic.startswith("!bank"):
623+ if block.bank != None:
624+ block.error("!bank specified more than once")
625+ return
626+
627+ if len(operands) != 1:
628+ block.error("!bank must have one integer argument")
629+ return
630+
631+ try:
632+ bank = int(operands[0], 0)
633+ except:
634+ block.error("Invalid bank value " + operands[0])
635+ return
636+ block.bank = bank
637+
621638 # TODO: We should really split blocks with origin, not jam it in here.
622639 if mnemonic.startswith("!orig"):
623640 if block.base != None:
624- block.error("Origin specified more than once")
641+ block.error(mnemonic + " specified more than once")
625642
626643 if len(operands) != 1:
627644 block.error(mnemonic + " must have one integer argument")
@@ -732,7 +749,7 @@ def assemble(block, mnemonic, operands=()):
732749 raise
733750 finally:
734751 included_names.remove(o)
735- return+
752+ return
736753
737754 if mnemonic == "!incbin":
738755 for o in operands:
@@ -831,12 +848,33 @@ for p in sys.argv[1:]:
831848 if len(blocks) == 0:
832849 sys.exit(0)
833850
851+max_bank = 0
852+for b in blocks:
853+ if b.bank == None:
854+ b.bank = 0
855+ else:
856+ if b.bank > max_bank:
857+ max_bank = b.bank
858+ if b.base == None:
859+ b.error("!bank specified, but no !orig")
860+ else:
861+ if b.bank == 0 and b.base >= 0x4000:
862+ b.error("Invalid base for bank 0")
863+ elif b.bank == 0 and b.base + len(b.data) >= 0x4000:
864+ b.error("Block is too large to fit into bank 0")
865+ if b.bank != 0 and (b.base < 0x4000 or b.base >= 0x8000):
866+ b.error("Invalid base for bank " + str(b.bank))
867+ elif b.bank == 0 and b.base + len(b.data) >= 0x8000:
868+ b.error("Block is too large to fit into bank " + str(b.bank))
869+
870+bank_spans=[[]] * (max_bank + 1)
871+
834872 # First, place all already originated blocks.
835-spans=[]
836873 for b in blocks:
837874 if b.base == None:
838875 continue
839876 b_len = len(b.data)
877+ spans = bank_spans[b.bank]
840878 for s in spans:
841879 if s[0] <= b.base + b_len and s[0] + s[1] >= b.base:
842880 b.error("Conflicting origin")
@@ -845,11 +883,12 @@ for b in blocks:
845883 if not b.has_error:
846884 spans.append((b.base, b_len))
847885
848-if len(spans) == 0:
849- blocks[0].base = 0
850- spans = [(0, len(blocks[0].data))]
851-else:
852- spans.sort(key=lambda a:a[0])
886+for spans in bank_spans:
887+ if len(spans) == 0:
888+ blocks[0].base = 0
889+ spans.append((0, len(blocks[0].data)))
890+ else:
891+ spans.sort(key=lambda a:a[0])
853892
854893 blocks.sort(key=lambda b:len(b.data))
855894 # Place all remaining blocks where there is room.
@@ -860,6 +899,7 @@ for b in blocks:
860899 continue
861900 b_len = len(b.data)
862901 i = 0
902+ spans = bank_spans[b.bank]
863903 while i + 1 < len(spans):
864904 if spans[i+1][0] - (spans[i][0] + spans[i][1]) > b_len:
865905 break
@@ -869,21 +909,31 @@ for b in blocks:
869909 spans.append(obj)
870910 spans.sort(key=lambda s:s[0])
871911
872-blocks.sort(key=lambda b:b.base)
912+blocks.sort(key=lambda b: b.base + (b.bank << 16))
873913 out = open("a.gb", "wb")
874914 debug = open("a.sym", "w")
875915 debug.write("; Emily's Assembler symbol info\n")
876916 at = 0
877917 zero = bytearray([0])
878918 zero16 = bytearray([0] * 16)
919+
920+# Resolve all relocs.
879921 for b in blocks:
880922 if b.has_error:
881923 continue
882924 b.resolveRelocs(blocks)
883- while at + 16 <= b.base:
925+
926+# Adjust base addresses for banks.
927+for b in blocks:
928+ if b.has_error:
929+ continue
930+ base = b.base + (0x4000 * b.bank)
931+
932+ # This is just to make writing a little faster
933+ while at + 16 <= base:
884934 out.write(zero16)
885935 at += 16
886- while at < b.base:
936+ while at < base:
887937 out.write(zero)
888938 at += 1
889939
@@ -891,6 +941,7 @@ for b in blocks:
891941 out.write(b.data)
892942 at += len(b.data)
893943 # Write the debug symbol info
944+ bank_name = hex(b.bank)[2:].upper().rjust(2, '0')
894945 for sym in b.symbols:
895946 if sym[0] == '.':
896947 continue
@@ -899,10 +950,12 @@ for b in blocks:
899950 else:
900951 name = sym
901952 addr = hex(b.symbols[sym] + b.base)[2:].upper().rjust(4, '0')
902- debug.write("00:" + addr + " " + name.replace('.', '_') + "\n")
953+ debug.write(bank_name + ":" + addr + " " + name.replace('.', '_') + "\n")
954+
903955 for a in b.ascii:
904956 addr = hex(a[0] + b.base)[2:].upper().rjust(4, '0')
905- debug.write("00:" + addr + " .asc:" + hex(a[1])[2:].upper().rjust(4, '0') + "\n")
957+ asc = hex(a[1])[2:].upper().rjust(4, '0')
958+ debug.write(bank_name + ":" + addr + " .asc:" + asc + "\n")
906959
907960 while at < 0x7FF0:
908961 out.write(zero16)