Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

162 linhas
5.3KB

  1. """Tiny assembler that writes Power C object files (.o/.obj) directly.
  2. Syntax (one statement per line, ';' comments):
  3. label: local label
  4. .def NAME export NAME at this offset (def kind 1)
  5. .byte 1,2,$ff raw bytes
  6. lda #$12 lda $14 lda $0123,x lda ($14),y lda ($14,x)
  7. bne label jmp label jsr label (jmp/jsr/abs operands on local labels are relocated)
  8. jsr ext:NAME reference to an external symbol (absolute)
  9. lda ext:NAME+1 external symbol + 1
  10. ldx #<ext:NAME low byte of an external symbol (#> for the high byte)
  11. lda label,x absolute operand on a local label (relocated)
  12. """
  13. import re, sys, os
  14. sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
  15. from objfmt import Obj
  16. from pcopt import ENC, SIZE, BRANCH
  17. def num(t):
  18. t = t.strip()
  19. if t.startswith('$'):
  20. return int(t[1:], 16)
  21. return int(t, 0)
  22. def parse_operand(s):
  23. """returns (mode, value-or-label, ext) ; ext = (name, kind) for external symbols"""
  24. s = s.strip()
  25. if not s:
  26. return 'imp', None, None
  27. if s == 'a':
  28. return 'acc', None, None
  29. if s.startswith('#'):
  30. t = s[1:]
  31. part = None
  32. if t.startswith('<') or t.startswith('>'):
  33. part = t[0]
  34. t = t[1:]
  35. if t.startswith('ext:'):
  36. return 'imm', 0, (t[4:].encode(), 2 if part == '<' else 1)
  37. v = num(t)
  38. if part == '<':
  39. v &= 255
  40. elif part == '>':
  41. v = v >> 8 & 255
  42. return 'imm', v, None
  43. m = re.match(r'^\((.+),x\)$', s)
  44. if m:
  45. return 'izx', num(m.group(1)), None
  46. m = re.match(r'^\((.+)\),y$', s)
  47. if m:
  48. return 'izy', num(m.group(1)), None
  49. idx = ''
  50. m = re.match(r'^(.*),([xy])$', s)
  51. if m:
  52. s, idx = m.group(1), m.group(2)
  53. if s.startswith('ext:'):
  54. t = s[4:]
  55. kind = 0
  56. m = re.match(r'^(.*)\+1$', t)
  57. if m:
  58. t, kind = m.group(1), 4
  59. return ('abs' + idx if idx else 'abs'), 0, (t.encode(), kind)
  60. try:
  61. v = num(s)
  62. md = 'zp' if v < 256 else 'abs'
  63. return (md + idx if idx else md), v, None
  64. except ValueError:
  65. return ('abs' + idx if idx else 'abs'), s, None # local label
  66. def assemble(text, base=0):
  67. lines = []
  68. for ln in text.splitlines():
  69. ln = ln.split(';')[0].strip()
  70. m = re.match(r'^([A-Za-z_]\w*):\s*(.*)$', ln)
  71. while m:
  72. lines.append(m.group(1) + ':')
  73. ln = m.group(2).strip()
  74. m = re.match(r'^([A-Za-z_]\w*):\s*(.*)$', ln)
  75. if ln:
  76. lines.append(ln)
  77. # pass 1: sizes
  78. items = [] # ('label',name) ('def',name) ('bytes',[...]) ('ins',mn,md,val,ext)
  79. for ln in lines:
  80. if ln.endswith(':'):
  81. items.append(('label', ln[:-1]))
  82. continue
  83. if ln.startswith('.def'):
  84. items.append(('def', ln.split()[1]))
  85. continue
  86. if ln.startswith('.byte'):
  87. items.append(('bytes', [num(x) for x in ln[5:].split(',')]))
  88. continue
  89. parts = ln.split(None, 1)
  90. mn = parts[0].lower()
  91. md, val, ext = parse_operand(parts[1] if len(parts) > 1 else '')
  92. if mn in BRANCH:
  93. md = 'rel'
  94. elif mn in ('jmp', 'jsr'):
  95. md = 'abs'
  96. elif md == 'zp' and (mn, 'zp') not in ENC and (mn, 'abs') in ENC:
  97. md = 'abs'
  98. elif md == 'zpx' and (mn, 'zpx') not in ENC and (mn, 'abx') in ENC:
  99. md = 'abx'
  100. elif md == 'zpy' and (mn, 'zpy') not in ENC and (mn, 'aby') in ENC:
  101. md = 'aby'
  102. if (mn, md) not in ENC:
  103. raise ValueError('bad instruction: ' + ln)
  104. items.append(('ins', mn, md, val, ext))
  105. labels, defs = {}, []
  106. pos = base
  107. for it in items:
  108. if it[0] == 'label':
  109. labels[it[1]] = pos
  110. elif it[0] == 'def':
  111. defs.append([it[1].encode(), 1, pos])
  112. elif it[0] == 'bytes':
  113. pos += len(it[1])
  114. else:
  115. pos += SIZE[it[2]]
  116. code = bytearray()
  117. reloc, refs = [], []
  118. for it in items:
  119. if it[0] == 'bytes':
  120. code += bytes(it[1])
  121. elif it[0] == 'ins':
  122. _, mn, md, val, ext = it
  123. at = base + len(code)
  124. code.append(ENC[(mn, md)])
  125. n = SIZE[md]
  126. if md == 'rel':
  127. t = labels[val]
  128. rel = t - (at + 2)
  129. if not -128 <= rel <= 127:
  130. raise ValueError('branch out of range at %x' % at)
  131. code.append(rel & 255)
  132. elif n == 2:
  133. if ext:
  134. refs.append([ext[0], ext[1], at])
  135. val = ENC[(mn, md)]
  136. code.append(val & 255)
  137. elif n == 3:
  138. if ext:
  139. refs.append([ext[0], ext[1], at])
  140. v = ENC[(mn, md)] * 0x101
  141. elif isinstance(val, str):
  142. v = labels[val]
  143. reloc.append(at)
  144. else:
  145. v = val
  146. code += bytes((v & 255, v >> 8 & 255))
  147. o = Obj()
  148. o.code = code
  149. o.reloc = reloc
  150. o.defs = defs
  151. o.refs = sorted(refs, key=lambda r: r[2])
  152. o.res = []
  153. o.trailing = b''
  154. return o, labels

Powered by TurnKey Linux.