Emily's Z80 assembler for the Gameboy.
Revision | 3200946f5bd923585df0f1804c507c39e7e9d4e5 (tree) |
---|---|
Zeit | 2021-03-02 17:22:04 |
Autor | AlaskanEmily <emily@alas...> |
Commiter | AlaskanEmily |
Add ROM bank support with !bank <num>. Defaults to bank 0.
@@ -52,6 +52,7 @@ class Block: | ||
52 | 52 | self.name = name |
53 | 53 | self.current_label = None |
54 | 54 | self.base = None |
55 | + self.bank = None | |
55 | 56 | self.has_error = False |
56 | 57 | self.data = bytearray() |
57 | 58 | self.symbols = {} |
@@ -618,10 +619,26 @@ def assemble(block, mnemonic, operands=()): | ||
618 | 619 | # print(str(mnemonic) + " " + str(operands)) |
619 | 620 | mnemonic = mnemonic.lower() |
620 | 621 | |
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 | + | |
621 | 638 | # TODO: We should really split blocks with origin, not jam it in here. |
622 | 639 | if mnemonic.startswith("!orig"): |
623 | 640 | if block.base != None: |
624 | - block.error("Origin specified more than once") | |
641 | + block.error(mnemonic + " specified more than once") | |
625 | 642 | |
626 | 643 | if len(operands) != 1: |
627 | 644 | block.error(mnemonic + " must have one integer argument") |
@@ -732,7 +749,7 @@ def assemble(block, mnemonic, operands=()): | ||
732 | 749 | raise |
733 | 750 | finally: |
734 | 751 | included_names.remove(o) |
735 | - return+ | |
752 | + return | |
736 | 753 | |
737 | 754 | if mnemonic == "!incbin": |
738 | 755 | for o in operands: |
@@ -831,12 +848,33 @@ for p in sys.argv[1:]: | ||
831 | 848 | if len(blocks) == 0: |
832 | 849 | sys.exit(0) |
833 | 850 | |
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 | + | |
834 | 872 | # First, place all already originated blocks. |
835 | -spans=[] | |
836 | 873 | for b in blocks: |
837 | 874 | if b.base == None: |
838 | 875 | continue |
839 | 876 | b_len = len(b.data) |
877 | + spans = bank_spans[b.bank] | |
840 | 878 | for s in spans: |
841 | 879 | if s[0] <= b.base + b_len and s[0] + s[1] >= b.base: |
842 | 880 | b.error("Conflicting origin") |
@@ -845,11 +883,12 @@ for b in blocks: | ||
845 | 883 | if not b.has_error: |
846 | 884 | spans.append((b.base, b_len)) |
847 | 885 | |
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]) | |
853 | 892 | |
854 | 893 | blocks.sort(key=lambda b:len(b.data)) |
855 | 894 | # Place all remaining blocks where there is room. |
@@ -860,6 +899,7 @@ for b in blocks: | ||
860 | 899 | continue |
861 | 900 | b_len = len(b.data) |
862 | 901 | i = 0 |
902 | + spans = bank_spans[b.bank] | |
863 | 903 | while i + 1 < len(spans): |
864 | 904 | if spans[i+1][0] - (spans[i][0] + spans[i][1]) > b_len: |
865 | 905 | break |
@@ -869,21 +909,31 @@ for b in blocks: | ||
869 | 909 | spans.append(obj) |
870 | 910 | spans.sort(key=lambda s:s[0]) |
871 | 911 | |
872 | -blocks.sort(key=lambda b:b.base) | |
912 | +blocks.sort(key=lambda b: b.base + (b.bank << 16)) | |
873 | 913 | out = open("a.gb", "wb") |
874 | 914 | debug = open("a.sym", "w") |
875 | 915 | debug.write("; Emily's Assembler symbol info\n") |
876 | 916 | at = 0 |
877 | 917 | zero = bytearray([0]) |
878 | 918 | zero16 = bytearray([0] * 16) |
919 | + | |
920 | +# Resolve all relocs. | |
879 | 921 | for b in blocks: |
880 | 922 | if b.has_error: |
881 | 923 | continue |
882 | 924 | 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: | |
884 | 934 | out.write(zero16) |
885 | 935 | at += 16 |
886 | - while at < b.base: | |
936 | + while at < base: | |
887 | 937 | out.write(zero) |
888 | 938 | at += 1 |
889 | 939 |
@@ -891,6 +941,7 @@ for b in blocks: | ||
891 | 941 | out.write(b.data) |
892 | 942 | at += len(b.data) |
893 | 943 | # Write the debug symbol info |
944 | + bank_name = hex(b.bank)[2:].upper().rjust(2, '0') | |
894 | 945 | for sym in b.symbols: |
895 | 946 | if sym[0] == '.': |
896 | 947 | continue |
@@ -899,10 +950,12 @@ for b in blocks: | ||
899 | 950 | else: |
900 | 951 | name = sym |
901 | 952 | 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 | + | |
903 | 955 | for a in b.ascii: |
904 | 956 | 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") | |
906 | 959 | |
907 | 960 | while at < 0x7FF0: |
908 | 961 | out.write(zero16) |