<commit_before>
# SYNOPSIS: from asm import *

from os.path import basename, splitext
from sys import argv
import pickle # XXX this must go

#------------------------------------------------------------------------
#       Public interface
#------------------------------------------------------------------------

# These definitions allow the use of Python notation as an assembler.
# The syntax is close to assembly, but by using Python we get a
# powerful macro assembler for free.
#
# Some examples:
#       Python                  Equivalent assembly
#       ------                  -------------------
#       nop()                           nop
#       ld(1)                           ld   1
#       ld([0x30])                      ld   [$30]
#       ld([0x30], X)                   ld   [$30],x
#       ld(AC, Y)                       ld   ac,y
#       ld([Y,Xpp], OUT)                ld   [y,x++],out
#       adda(2)                         adda 2
#       adda(AC)                        adda ac
#       xora([0x30])                    xora [$30]
#       anda(0x2a)                      anda $2a
#       st([0x30])                      st   [$30]
#       st([0x30], Y)                   st   [$30],y
#       st([X])                         st   [x]
#       st([Y,1])                       st   [y,1]
#       st([Y,X])                       st   [y,x]
#       st([Y,Xpp])                     st   [y,x++]
#       st(0x2a, [Y,Xpp])               st   $2a,[y,x++]
#       label('loop')           loop:
#       bne('loop')                     bne  loop
#       bra([AC])                       bra  [ac]

X   = '__x__'
Y   = '__y__'
Xpp = '__x++__'
OUT = '__out__'
IN  = '__in__'
AC  = '__ac__'

# Mnemonics for Gigatron native 8-bit instruction set
def nop ():               _assemble(_opLD, AC)
def ld  (a, b=AC):        _assemble(_opLD,  a, b)
def anda(a, b=AC):        _assemble(_opAND, a, b)
def ora (a, b=AC):        _assemble(_opOR,  a, b)
def xora(a, b=AC):        _assemble(_opXOR, a, b)
def adda(a, b=AC):        _assemble(_opADD, a, b)
def suba(a, b=AC):        _assemble(_opSUB, a, b)
def jmpy(a):              _assemble(_opJ|_jL,  a)
def bgt (a):              _assemble(_opJ|_jGT, a)
def blt (a):              _assemble(_opJ|_jLT, a)
def bne (a):              _assemble(_opJ|_jNE, a)
def beq (a):              _assemble(_opJ|_jEQ, a)
def bge (a):              _assemble(_opJ|_jGE, a)
def ble (a):              _assemble(_opJ|_jLE, a)
def bra (a):              _assemble(_opJ|_jS,  a)
def st  (a, b=None, c=None):
  if isinstance(a, list): _assemble(_opST, AC, b, a)
  else:                   _assemble(_opST, a,  c, b)

bpl = bge # Alias
bmi = blt # Alias

def label(name):
  """Label the current address"""
  address = _romSize
  define(name, address)
  if address not in _labels:
    _labels[address] = [] # There can be more than one
  _labels[_romSize].append(name)

def C(line):
  """Insert comment to print in disassembly"""
  if line:
    address = max(0, _romSize-1)
    if address not in _comments:
      _comments[address] = []
    _comments[address].append(line)
  return None

def define(name, value):
  _symbols[name] = value

def symbol(name):
  return _symbols[name] if name in _symbols else None

def lo(name):
  _refsL.append((name, _romSize))
  return 0 # placeholder

def hi(name):
  _refsH.append((name, _romSize))
  return 0 # placeholder

def H(word):
  return word >> 8

def L(word):
   return word & 255

def align(n, chunkSize=0x10000):
  """Insert nops to align with chuck"""
  global _romSize, _maxRomSize
  _maxRomSize = 0x10000
  while _romSize % n > 0:
    nop()
  _maxRomSize = min(_maxRomSize, _romSize + chunkSize)

def wait(n):
  """Insert delay sequence of n cycles. Might clobber AC"""
  comment = 'Wait %s cycle%s' % (n, '' if n==1 else 's')
  assert n >= 0
  if n > 4:
    n -= 1
    ld(n/2 - 1)
    comment = C(comment)
    bne(_romSize & 255)
    suba(1)
    n = n % 2
  while n > 0:
    nop()
    n -= 1

def pc():
  return _romSize

def zpByte(len=1):
  """Allocate one or more bytes from the zero page"""
  global _zpSize
  s = _zpSize
  if s <= 0x80 and 0x80 < s + len:
   s = 0x81 # Keep 0x80 reserved
  _zpSize = s+len
  assert _zpSize <= 0x100
  return s

def zpReset(startFrom=1):
  global _zpSize
  _zpSize = startFrom

def trampoline():
  """Read 1 byte from ROM page"""
  while L(pc()) < 256-5:
    nop()
  bra(AC)                       #13
  """
     It is possible to make this section 2 bytes shorter
     and 1 cycle faster by entering directly wih "jmp y,ac"
     instead of "jmp y,251". However, this will cost two
     words at 'LUP' in vCPU and space is expensive there.
  """
  C('+-----------------------------------+')
  bra(253)                      #14
  C('|                                   |')
  ld(hi('lupReturn'), Y)        #15
  C('| Trampoline for page $%04x lookups |' % (pc()&~255))
  jmpy(lo('lupReturn'))         #17
  C('|                                   |')
  st([lo('vAC')])               #18
  C('+-----------------------------------+')

def end():
  errors = 0

  for name, where in _refsL:
    if name in _symbols:
      _rom1[where] ^= _symbols[name] & 255 # xor allows some label tricks
    else:
      print 'Error: Undefined symbol %s' % repr(name)
      errors += 1

  for name, where in _refsH:
    if name in _symbols:
      _rom1[where] += _symbols[name] >> 8
    else:
      print 'Error: Undefined symbol %s' % repr(name)
      errors += 1

  if errors:
    print '%d error(s)' % errors
    exit()

#------------------------------------------------------------------------
#       Behind the scenes
#------------------------------------------------------------------------
<commit_msg>Update comments<commit_after>
# SYNOPSIS: from asm import *

from os.path import basename, splitext
from sys import argv
import pickle # XXX this must go

#------------------------------------------------------------------------
#       Public interface
#------------------------------------------------------------------------

# These definitions allow the use of Python notation as an assembler.
# The syntax is close to assembly, but by using Python we get a
# powerful macro assembler for free.
#
# Some examples:
#       Python                  Equivalent assembly
#       ------                  -------------------
#       nop()                           nop
#       ld(1)                           ld   1
#       ld([0x30])                      ld   [$30]
#       ld([0x30], X)                   ld   [$30],x
#       ld(AC, Y)                       ld   ac,y
#       ld([Y,Xpp], OUT)                ld   [y,x++],out
#       adda(2)                         adda 2
#       adda(AC)                        adda ac
#       xora([0x30])                    xora [$30]
#       anda(0x2a)                      anda $2a
#       st([0x30])                      st   [$30]
#       st([0x30], Y)                   st   [$30],y
#       st([X])                         st   [x]
#       st([Y,1])                       st   [y,1]
#       st([Y,X])                       st   [y,x]
#       st([Y,Xpp])                     st   [y,x++]
#       st(0x2a, [Y,Xpp])               st   $2a,[y,x++]
#       label('loop')           loop:
#       bne('loop')                     bne  loop
#       bra([AC])                       bra  [ac]

X   = '__x__'
Y   = '__y__'
Xpp = '__x++__'
OUT = '__out__'
IN  = '__in__'
AC  = '__ac__'

# Mnemonics for Gigatron native 8-bit instruction set
def nop ():               _assemble(_opLD, AC)
def ld  (a, b=AC):        _assemble(_opLD,  a, b)
def anda(a, b=AC):        _assemble(_opAND, a, b)
def ora (a, b=AC):        _assemble(_opOR,  a, b)
def xora(a, b=AC):        _assemble(_opXOR, a, b)
def adda(a, b=AC):        _assemble(_opADD, a, b)
def suba(a, b=AC):        _assemble(_opSUB, a, b)
def jmpy(a):              _assemble(_opJ|_jL,  a)
def bgt (a):              _assemble(_opJ|_jGT, a)
def blt (a):              _assemble(_opJ|_jLT, a)
def bne (a):              _assemble(_opJ|_jNE, a)
def beq (a):              _assemble(_opJ|_jEQ, a)
def bge (a):              _assemble(_opJ|_jGE, a)
def ble (a):              _assemble(_opJ|_jLE, a)
def bra (a):              _assemble(_opJ|_jS,  a)
def st  (a, b=None, c=None):
  if isinstance(a, list): _assemble(_opST, AC, b, a)
  else:                   _assemble(_opST, a,  c, b)

bpl = bge # Alias
bmi = blt # Alias

def label(name):
  """Label the current address"""
  address = _romSize
  define(name, address)
  if address not in _labels:
    _labels[address] = [] # There can be more than one
  _labels[_romSize].append(name)

def C(line):
  """Insert comment to print in disassembly"""
  if line:
    address = max(0, _romSize-1)
    if address not in _comments:
      _comments[address] = []
    _comments[address].append(line)
  return None

def define(name, value):
  _symbols[name] = value

def symbol(name):
  return _symbols[name] if name in _symbols else None

def lo(name):
  _refsL.append((name, _romSize))
  return 0 # placeholder

def hi(name):
  _refsH.append((name, _romSize))
  return 0 # placeholder

def H(word):
  return word >> 8

def L(word):
   return word & 255

def align(n, chunkSize=0x10000):
  """Insert nops to align with chunk boundary"""
  global _romSize, _maxRomSize
  _maxRomSize = 0x10000
  while _romSize % n > 0:
    nop()
  _maxRomSize = min(_maxRomSize, _romSize + chunkSize)

def wait(n):
  """Insert delay sequence of n cycles. Might clobber AC"""
  comment = 'Wait %s cycle%s' % (n, '' if n==1 else 's')
  assert n >= 0
  if n > 4:
    n -= 1
    ld(n/2 - 1)
    comment = C(comment)
    bne(_romSize & 255)
    suba(1)
    n = n % 2
  while n > 0:
    nop()
    n -= 1

def pc():
  """Current ROM address"""
  return _romSize

def zpByte(len=1):
  """Allocate one or more bytes from the zero-page"""
  global _zpSize
  s = _zpSize
  if s <= 0x80 and 0x80 < s + len:
   s = 0x81 # Keep 0x80 reserved
  _zpSize = s+len
  assert _zpSize <= 0x100
  return s

def zpReset(startFrom=1):
  """Reset zero-page allocation"""
  global _zpSize
  _zpSize = startFrom

def trampoline():
  """Read 1 byte from ROM page"""
  while L(pc()) < 256-5:
    nop()
  bra(AC)                       #13
  """
     It is possible to make this section 2 bytes shorter
     and 1 cycle faster by entering directly wih "jmp y,ac"
     instead of "jmp y,251". However, this will cost two
     words at 'LUP' in vCPU and space is expensive there.
  """
  C('+-----------------------------------+')
  bra(253)                      #14
  C('|                                   |')
  ld(hi('lupReturn'), Y)        #15
  C('| Trampoline for page $%04x lookups |' % (pc()&~255))
  jmpy(lo('lupReturn'))         #17
  C('|                                   |')
  st([lo('vAC')])               #18
  C('+-----------------------------------+')

def end():
  """Resolve symbols and write output"""
  errors = 0

  for name, where in _refsL:
    if name in _symbols:
      _rom1[where] ^= _symbols[name] & 255 # xor allows some label tricks
    else:
      print 'Error: Undefined symbol %s' % repr(name)
      errors += 1

  for name, where in _refsH:
    if name in _symbols:
      _rom1[where] += _symbols[name] >> 8
    else:
      print 'Error: Undefined symbol %s' % repr(name)
      errors += 1

  if errors:
    print '%d error(s)' % errors
    exit()

#------------------------------------------------------------------------
#       Behind the scenes
#------------------------------------------------------------------------

{'fraction_non_alphanumeric': 0.18837431575288904, 'fraction_numerical': 0.022069684594665046, 'mean_word_length': 1.48649816375027, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7335827', 'n_tokens_mistral': 4100, 'n_tokens_neox': 3805, 'n_words': 1154}