diff --git a/arch/__init__.py b/arch/__init__.py deleted file mode 100755 index 2b4e715b0..000000000 --- a/arch/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# vim:ts=4:et:sw=4: - -import importlib - - -__all__ = [ - 'zx48k', - 'zxnext' -] - -AVAILABLE_ARCHITECTURES = __all__ -target = None - - -def set_target_arch(target_arch: str): - global target - assert target_arch in AVAILABLE_ARCHITECTURES - target = importlib.import_module(f'.{target_arch}', 'arch') - - -set_target_arch(AVAILABLE_ARCHITECTURES[0]) diff --git a/arch/zx48k/__init__.py b/arch/zx48k/__init__.py deleted file mode 100755 index edbfacaf7..000000000 --- a/arch/zx48k/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# vim:ts=4:et:sw=4: - -from . import beep -from .translator import * # noqa - -import src.api.global_ -from src.api.constants import TYPE - - -__all__ = [ - 'beep', -] - - -# ----------------------------------------- -# Arch initialization setup -# ----------------------------------------- -src.api.global_.PARAM_ALIGN = 2 # Z80 param align -src.api.global_.BOUND_TYPE = TYPE.uinteger -src.api.global_.SIZE_TYPE = TYPE.ubyte -src.api.global_.PTR_TYPE = TYPE.uinteger -src.api.global_.STR_INDEX_TYPE = TYPE.uinteger -src.api.global_.MIN_STRSLICE_IDX = 0 # Min. string slicing position -src.api.global_.MAX_STRSLICE_IDX = 65534 # Max. string slicing position diff --git a/arch/zx48k/backend/__16bit.py b/arch/zx48k/backend/__16bit.py deleted file mode 100644 index f13c50daa..000000000 --- a/arch/zx48k/backend/__16bit.py +++ /dev/null @@ -1,1006 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# -------------------------------------------------------------- -# Copyleft (k) 2008, by Jose M. Rodriguez-Rosa -# (a.k.a. Boriel, http://www.boriel.com) -# -# This module contains 8 bit boolean, arithmetic and -# comparation intermediate-code traductions -# -------------------------------------------------------------- - -from .__common import REQUIRES, is_int, log2, is_2n, _int_ops, tmp_label -from .__8bit import _8bit_oper - - -# ----------------------------------------------------- -# 16 bits operands -# ----------------------------------------------------- -def int16(op): - ''' Returns a 16 bit operand converted to 16 bits unsigned int. - Negative numbers are returned in 2 complement. - ''' - return int(op) & 0xFFFF - - -def _16bit_oper(op1, op2=None, reversed=False): - ''' Returns pop sequence for 16 bits operands - 1st operand in HL, 2nd operand in DE - - For subtraction, division, etc. you can swap operators extraction order - by setting reversed to True - ''' - output = [] - - if op1 is not None: - op1 = str(op1) # always to str - - if op2 is not None: - op2 = str(op2) # always to str - - if op2 is not None and reversed: - op1, op2 = op2, op1 - - op = op1 - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - if is_int(op): - op = int(op) - - if indirect: - output.append('ld hl, (%i)' % op) - else: - output.append('ld hl, %i' % int16(op)) - else: - if immediate: - if indirect: - output.append('ld hl, (%s)' % op) - else: - output.append('ld hl, %s' % op) - else: - if op[0] == '_': - output.append('ld hl, (%s)' % op) - else: - output.append('pop hl') - - if indirect: - output.append('ld a, (hl)') - output.append('inc hl') - output.append('ld h, (hl)') - output.append('ld l, a') - - if op2 is None: - return output - - if not reversed: - tmp = output - output = [] - - op = op2 - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - if is_int(op): - op = int(op) - - if indirect: - output.append('ld de, (%i)' % op) - else: - output.append('ld de, %i' % int16(op)) - else: - if immediate: - output.append('ld de, %s' % op) - else: - if op[0] == '_': - output.append('ld de, (%s)' % op) - else: - output.append('pop de') - - if indirect: - output.append('call __LOAD_DE_DE') # DE = (DE) - REQUIRES.add('lddede.asm') - - if not reversed: - output.extend(tmp) - - return output - - -# ----------------------------------------------------- -# Arithmetic operations -# ----------------------------------------------------- - -def _add16(ins): - ''' Pops last 2 bytes from the stack and adds them. - Then push the result onto the stack. - - - Optimizations: - * If any of the operands is ZERO, - then do NOTHING: A + 0 = 0 + A = A - - * If any of the operands is < 4, then - INC is used - - * If any of the operands is > (65531) (-4), then - DEC is used - ''' - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - op2 = int16(op2) - output = _16bit_oper(op1) - - if op2 == 0: - output.append('push hl') - return output # ADD HL, 0 => NOTHING - - if op2 < 4: - output.extend(['inc hl'] * op2) # ADD HL, 2 ==> inc hl; inc hl - output.append('push hl') - return output - - if op2 > 65531: # (between -4 and 0) - output.extend(['dec hl'] * (0x10000 - op2)) - output.append('push hl') - return output - - output.append('ld de, %i' % op2) - output.append('add hl, de') - output.append('push hl') - return output - - if op2[0] == '_': # stack optimization - op1, op2 = op2, op1 - - output = _16bit_oper(op1, op2) - output.append('add hl, de') - output.append('push hl') - return output - - -def _sub16(ins): - ''' Pops last 2 words from the stack and subtract them. - Then push the result onto the stack. Top of the stack is - subtracted Top -1 - - Optimizations: - * If 2nd op is ZERO, - then do NOTHING: A - 0 = A - - * If any of the operands is < 4, then - DEC is used - - * If any of the operands is > 65531 (-4..-1), then - INC is used - ''' - op1, op2 = tuple(ins.quad[2:4]) - - if is_int(op2): - op = int16(op2) - output = _16bit_oper(op1) - - if op == 0: - output.append('push hl') - return output - - if op < 4: - output.extend(['dec hl'] * op) - output.append('push hl') - return output - - if op > 65531: - output.extend(['inc hl'] * (0x10000 - op)) - output.append('push hl') - return output - - output.append('ld de, -%i' % op) - output.append('add hl, de') - output.append('push hl') - return output - - if op2[0] == '_': # Optimization when 2nd operand is an id - rev = True - op1, op2 = op2, op1 - else: - rev = False - - output = _16bit_oper(op1, op2, rev) - output.append('or a') - output.append('sbc hl, de') - output.append('push hl') - return output - - -def _mul16(ins): - ''' Multiplies tow last 16bit values on top of the stack and - and returns the value on top of the stack - - Optimizations: - * If any of the ops is ZERO, - then do A = 0 ==> XOR A, cause A * 0 = 0 * A = 0 - - * If any ot the ops is ONE, do NOTHING - A * 1 = 1 * A = A - - * If B is 2^n and B < 16 => Shift Right n - ''' - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: # If any of the operands is constant - op1, op2 = _int_ops(op1, op2) # put the constant one the 2nd - output = _16bit_oper(op1) - - if op2 == 0: # A * 0 = 0 * A = 0 - if op1[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - output.append('ld hl, 0') - output.append('push hl') - return output - - if op2 == 1: # A * 1 = 1 * A == A => Do nothing - output.append('push hl') - return output - - if op2 == 0xFFFF: # This is the same as (-1) - output.append('call __NEGHL') - output.append('push hl') - REQUIRES.add('neg16.asm') - return output - - if is_2n(op2) and log2(op2) < 4: - output.extend(['add hl, hl'] * int(log2(op2))) - output.append('push hl') - return output - - output.append('ld de, %i' % op2) - else: - if op2[0] == '_': # stack optimization - op1, op2 = op2, op1 - - output = _16bit_oper(op1, op2) - - output.append('call __MUL16_FAST') # Inmmediate - output.append('push hl') - REQUIRES.add('mul16.asm') - return output - - -def _divu16(ins): - ''' Divides 2 16bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 1 then - do nothing - - * If 2nd op is 2 then - Shift Right Logical - ''' - op1, op2 = tuple(ins.quad[2:]) - if is_int(op1) and int(op1) == 0: # 0 / A = 0 - if op2[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - else: - output = _16bit_oper(op2) # Normalize stack - - output.append('ld hl, 0') - output.append('push hl') - return output - - if is_int(op2): - op = int16(op2) - output = _16bit_oper(op1) - - if op2 == 0: # A * 0 = 0 * A = 0 - if op1[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - output.append('ld hl, 0') - output.append('push hl') - return output - - if op == 1: - output.append('push hl') - return output - - if op == 2: - output.append('srl h') - output.append('rr l') - output.append('push hl') - return output - - output.append('ld de, %i' % op) - else: - if op2[0] == '_': # Optimization when 2nd operand is an id - rev = True - op1, op2 = op2, op1 - else: - rev = False - output = _16bit_oper(op1, op2, rev) - - output.append('call __DIVU16') - output.append('push hl') - REQUIRES.add('div16.asm') - return output - - -def _divi16(ins): - ''' Divides 2 16bit signed integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 1 then - do nothing - - * If 2nd op is -1 then - do NEG - - * If 2nd op is 2 then - Shift Right Arithmetic - ''' - op1, op2 = tuple(ins.quad[2:]) - if is_int(op1) and int(op1) == 0: # 0 / A = 0 - if op2[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - else: - output = _16bit_oper(op2) # Normalize stack - - output.append('ld hl, 0') - output.append('push hl') - return output - - if is_int(op2): - op = int16(op2) - output = _16bit_oper(op1) - - if op == 1: - output.append('push hl') - return output - - if op == -1: - output.append('call __NEGHL') - output.append('push hl') - REQUIRES.add('neg16.asm') - return output - - if op == 2: - output.append('sra h') - output.append('rr l') - output.append('push hl') - return output - - output.append('ld de, %i' % op) - else: - if op2[0] == '_': # Optimization when 2nd operand is an id - rev = True - op1, op2 = op2, op1 - else: - rev = False - output = _16bit_oper(op1, op2, rev) - - output.append('call __DIVI16') - output.append('push hl') - REQUIRES.add('div16.asm') - return output - - -def _modu16(ins): - ''' Reminder of div. 2 16bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd operand is 1 => Return 0 - * If 2nd operand = 2^n => do AND (2^n - 1) - ''' - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - op2 = int16(op2) - output = _16bit_oper(op1) - - if op2 == 1: - if op2[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - - output.append('ld hl, 0') - output.append('push hl') - return output - - if is_2n(op2): - k = op2 - 1 - if op2 > 255: # only affects H - output.append('ld a, h') - output.append('and %i' % (k >> 8)) - output.append('ld h, a') - else: - output.append('ld h, 0') # High part goes 0 - output.append('ld a, l') - output.append('and %i' % (k % 0xFF)) - output.append('ld l, a') - - output.append('push hl') - return output - - output.append('ld de, %i' % op2) - else: - output = _16bit_oper(op1, op2) - - output.append('call __MODU16') - output.append('push hl') - REQUIRES.add('div16.asm') - return output - - -def _modi16(ins): - ''' Reminder of div 2 16bit signed integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd operand is 1 => Return 0 - * If 2nd operand = 2^n => do AND (2^n - 1) - ''' - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - op2 = int16(op2) - output = _16bit_oper(op1) - - if op2 == 1: - if op2[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - - output.append('ld hl, 0') - output.append('push hl') - return output - - if is_2n(op2): - k = op2 - 1 - if op2 > 255: # only affects H - output.append('ld a, h') - output.append('and %i' % (k >> 8)) - output.append('ld h, a') - else: - output.append('ld h, 0') # High part goes 0 - output.append('ld a, l') - output.append('and %i' % (k % 0xFF)) - output.append('ld l, a') - - output.append('push hl') - return output - - output.append('ld de, %i' % op2) - else: - output = _16bit_oper(op1, op2) - - output.append('call __MODI16') - output.append('push hl') - REQUIRES.add('div16.asm') - return output - - -def _ltu16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit unsigned version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('or a') - output.append('sbc hl, de') - output.append('sbc a, a') - output.append('push af') - return output - - -def _lti16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit signed version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('call __LTI16') - output.append('push af') - REQUIRES.add('lti16.asm') - return output - - -def _gtu16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit unsigned version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3], reversed=True) - output.append('or a') - output.append('sbc hl, de') - output.append('sbc a, a') - output.append('push af') - return output - - -def _gti16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit signed version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3], reversed=True) - output.append('call __LTI16') - output.append('push af') - REQUIRES.add('lti16.asm') - return output - - -def _leu16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit unsigned version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3], reversed=True) - output.append('or a') - output.append('sbc hl, de') # Carry if A > B - output.append('ccf') # Negates the result => Carry if A <= B - output.append('sbc a, a') - output.append('push af') - return output - - -def _lei16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit signed version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('call __LEI16') - output.append('push af') - REQUIRES.add('lei16.asm') - return output - - -def _geu16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit unsigned version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('or a') - output.append('sbc hl, de') - output.append('ccf') - output.append('sbc a, a') - output.append('push af') - return output - - -def _gei16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit signed version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3], reversed=True) - output.append('call __LEI16') - output.append('push af') - REQUIRES.add('lei16.asm') - return output - - -def _eq16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand == 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit un/signed version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('call __EQ16') - output.append('push af') - REQUIRES.add('eq16.asm') - - return output - - -def _ne16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand != 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 16 bit un/signed version - ''' - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('or a') # Resets carry flag - output.append('sbc hl, de') - output.append('ld a, h') - output.append('or l') - output.append('push af') - - return output - - -def _or16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand OR (logical) 2nd operand (top of the stack), - pushes 0 if False, 1 if True. - - 16 bit un/signed version - - Optimizations: - - If any of the operators are constants: Returns either 0 or - the other operand - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - if op2 == 0: - output = _16bit_oper(op1) - output.append('ld a, h') - output.append('or l') # Convert x to Boolean - output.append('push af') - return output # X or False = X - - output = _16bit_oper(op1) - output.append('ld a, 0FFh') # X or True = True - output.append('push af') - return output - - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('ld a, h') - output.append('or l') - output.append('or d') - output.append('or e') - output.append('push af') - return output - - -def _bor16(ins): - ''' Pops top 2 operands out of the stack, and performs - 1st operand OR (bitwise) 2nd operand (top of the stack), - pushes result (16 bit in HL). - - 16 bit un/signed version - - Optimizations: - - If any of the operators are constants: Returns either 0 or - the other operand - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _16bit_oper(op1) - if op2 == 0: # X | 0 = X - output.append('push hl') - return output - - if op2 == 0xFFFF: # X & 0xFFFF = 0xFFFF - output.append('ld hl, 0FFFFh') - output.append('push hl') - return output - - output = _16bit_oper(op1, op2) - output.append('call __BOR16') - output.append('push hl') - REQUIRES.add('bor16.asm') - return output - - -def _xor16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand XOR (logical) 2nd operand (top of the stack), - pushes 0 if False, 1 if True. - - 16 bit un/signed version - - Optimizations: - - If any of the operators are constants: Returns either 0 or - the other operand - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - output = _16bit_oper(op1) - - if op2 == 0: # X xor False = X - output.append('ld a, h') - output.append('or l') - output.append('push af') - return output - - # X xor True = NOT X - output.append('ld a, h') - output.append('or l') - output.append('sub 1') - output.append('sbc a, a') - output.append('push af') - return output - - output = _16bit_oper(ins.quad[2], ins.quad[3]) - output.append('call __XOR16') - output.append('push af') - REQUIRES.add('xor16.asm') - return output - - -def _bxor16(ins): - ''' Pops top 2 operands out of the stack, and performs - 1st operand XOR (bitwise) 2nd operand (top of the stack), - pushes result (16 bit in HL). - - 16 bit un/signed version - - Optimizations: - - If any of the operators are constants: Returns either 0 or - the other operand - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _16bit_oper(op1) - if op2 == 0: # X ^ 0 = X - output.append('push hl') - return output - - if op2 == 0xFFFF: # X ^ 0xFFFF = bNOT X - output.append('call __NEGHL') - output.append('push hl') - REQUIRES.add('neg16.asm') - return output - - output = _16bit_oper(op1, op2) - output.append('call __BXOR16') - output.append('push hl') - REQUIRES.add('bxor16.asm') - return output - - -def _and16(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand AND (logical) 2nd operand (top of the stack), - pushes 0 if False, 1 if True. - - 16 bit un/signed version - - Optimizations: - - If any of the operators are constants: Returns either 0 or - the other operand - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _16bit_oper(op1) - if op2 != 0: - output.append('ld a, h') - output.append('or l') - output.append('push af') - return output # X and True = X - - output = _16bit_oper(op1) - output.append('xor a') # X and False = False - output.append('push af') - return output - - output = _16bit_oper(op1, op2) - output.append('call __AND16') - output.append('push af') - REQUIRES.add('and16.asm') - return output - - -def _band16(ins): - ''' Pops top 2 operands out of the stack, and performs - 1st operand AND (bitwise) 2nd operand (top of the stack), - pushes result (16 bit in HL). - - 16 bit un/signed version - - Optimizations: - - If any of the operators are constants: Returns either 0 or - the other operand - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - if op2 == 0xFFFF: # X & 0xFFFF = X - return [] - - if op2 == 0: # X & 0 = 0 - output = _16bit_oper(op1) - output.append('ld hl, 0') - output.append('push hl') - return output - - output = _16bit_oper(op1, op2) - output.append('call __BAND16') - output.append('push hl') - REQUIRES.add('band16.asm') - return output - - -def _not16(ins): - ''' Negates top (Logical NOT) of the stack (16 bits in HL) - ''' - output = _16bit_oper(ins.quad[2]) - output.append('ld a, h') - output.append('or l') - output.append('sub 1') - output.append('sbc a, a') - output.append('push af') - return output - - -def _bnot16(ins): - ''' Negates top (Bitwise NOT) of the stack (16 bits in HL) - ''' - output = _16bit_oper(ins.quad[2]) - output.append('call __BNOT16') - output.append('push hl') - REQUIRES.add('bnot16.asm') - return output - - -def _neg16(ins): - ''' Negates top of the stack (16 bits in HL) - ''' - output = _16bit_oper(ins.quad[2]) - output.append('call __NEGHL') - output.append('push hl') - REQUIRES.add('neg16.asm') - return output - - -def _abs16(ins): - ''' Absolute value of top of the stack (16 bits in HL) - ''' - output = _16bit_oper(ins.quad[2]) - output.append('call __ABS16') - output.append('push hl') - REQUIRES.add('abs16.asm') - return output - - -def _shru16(ins): - ''' Logical right shift 16bit unsigned integer. - The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 0 then - do nothing - - * If 2nd op is 1 - Shift Right Arithmetic - ''' - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op = int16(op2) - if op == 0: - return [] - - output = _16bit_oper(op1) - if op == 1: - output.append('srl h') - output.append('rr l') - output.append('push hl') - return output - - output.append('ld b, %i' % op) - else: - output = _8bit_oper(op2) - output.append('ld b, a') - output.extend(_16bit_oper(op1)) - - label = tmp_label() - output.append('%s:' % label) - output.append('srl h') - output.append('rr l') - output.append('djnz %s' % label) - output.append('push hl') - return output - - -def _shri16(ins): - ''' Arithmetical right shift 16bit signed integer. - The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 0 then - do nothing - - * If 2nd op is 1 - Shift Right Arithmetic - ''' - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op = int16(op2) - if op == 0: - return [] - - output = _16bit_oper(op1) - if op == 1: - output.append('srl h') - output.append('rr l') - output.append('push hl') - return output - - output.append('ld b, %i' % op) - else: - output = _8bit_oper(op2) - output.append('ld b, a') - output.extend(_16bit_oper(op1)) - - label = tmp_label() - output.append('%s:' % label) - output.append('sra h') - output.append('rr l') - output.append('djnz %s' % label) - output.append('push hl') - return output - - -def _shl16(ins): - ''' Logical/aritmetical left shift 16bit (un)signed integer. - The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 0 then - do nothing - - * If 2nd op is lower than 6 - unroll lop - ''' - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op = int16(op2) - if op == 0: - return [] - - output = _16bit_oper(op1) - if op < 6: - output.extend(['add hl, hl'] * op) - output.append('push hl') - return output - - output.append('ld b, %i' % op) - else: - output = _8bit_oper(op2) - output.append('ld b, a') - output.extend(_16bit_oper(op1)) - - label = tmp_label() - output.append('%s:' % label) - output.append('add hl, hl') - output.append('djnz %s' % label) - output.append('push hl') - return output diff --git a/arch/zx48k/backend/__32bit.py b/arch/zx48k/backend/__32bit.py deleted file mode 100644 index 1a81f803e..000000000 --- a/arch/zx48k/backend/__32bit.py +++ /dev/null @@ -1,868 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim:ts=4:et:sw=4: - -# -------------------------------------------------------------- -# Copyleft (k) 2008, by Jose M. Rodriguez-Rosa -# (a.k.a. Boriel, http://www.boriel.com) -# -# This module contains 8 bit boolean, arithmetic and -# comparation intermediate-code traductions -# -------------------------------------------------------------- - -from .__common import REQUIRES, is_int, _int_ops, tmp_label -from .__8bit import _8bit_oper - - -# ----------------------------------------------------- -# 32 bits operands -# ----------------------------------------------------- - - -def int32(op): - """ Returns a 32 bit operand converted to 32 bits unsigned int. - Negative numbers are returned in 2 complement. - - The result is returned in a tuple (DE, HL) => High16, Low16 - """ - result = int(op) & 0xFFFFFFFF - return (result >> 16, result & 0xFFFF) - - -def _32bit_oper(op1, op2=None, reversed=False, preserveHL=False): - """ Returns pop sequence for 32 bits operands - 1st operand in HLDE, 2nd operand remains in the stack - - Now it does support operands inversion calling __SWAP32. - - However, if 1st operand is integer (immediate) or indirect, the stack - will be rearranged, so it contains a 32 bit pushed parameter value for the - subroutine to be called. - - If preserveHL is True, then BC will be used instead of HL for lower part - for the 1st operand. - """ - output = [] - - if op1 is not None: - op1 = str(op1) - - if op2 is not None: - op2 = str(op2) - - op = op2 if op2 is not None else op1 - - int1 = False # whether op1 (2nd operand) is integer - - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - hl = 'hl' if not preserveHL and not indirect else 'bc' - - if is_int(op): - int1 = True - op = int(op) - - if indirect: - if immediate: - output.append('ld hl, %i' % op) - else: - output.append('ld hl, (%i)' % op) - - output.append('call __ILOAD32') - REQUIRES.add('iload32.asm') - - if preserveHL: - output.append('ld b, h') - output.append('ld c, l') - else: - DE, HL = int32(op) - output.append('ld de, %i' % DE) - output.append('ld %s, %i' % (hl, HL)) - else: - if op[0] == '_': - if immediate: - output.append('ld %s, %s' % (hl, op)) - else: - output.append('ld %s, (%s)' % (hl, op)) - else: - if immediate: - output.append('ld %s, (%s) & 0xFFFF' % (hl, op)) - else: - output.append('pop %s' % hl) - - if indirect: - output.append('call __ILOAD32') - REQUIRES.add('iload32.asm') - - if preserveHL: - output.append('ld b, h') - output.append('ld c, l') - else: - if op[0] == '_': - output.append('ld de, (%s + 2)' % op) - else: - if immediate: - output.append('ld de, (%s) >> 16' % op) - else: - output.append('pop de') - - if op2 is not None: - op = op1 - - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - if is_int(op): - op = int(op) - - if indirect: - output.append('exx') - if immediate: - output.append('ld hl, %i' % (op & 0xFFFF)) - else: - output.append('ld hl, (%i)' % (op & 0xFFFF)) - - output.append('call __ILOAD32') - output.append('push de') - output.append('push hl') - output.append('exx') - REQUIRES.add('iload32.asm') - else: - DE, HL = int32(op) - output.append('ld bc, %i' % DE) - output.append('push bc') - output.append('ld bc, %i' % HL) - output.append('push bc') - else: - if indirect: - output.append('exx') # uses alternate set to put it on the stack - if op[0] == '_': - if immediate: - output.append('ld hl, %s' % op) - else: - output.append('ld hl, (%s)' % op) - else: - output.append('pop hl') # Pointers are only 16 bits *** - - output.append('call __ILOAD32') - output.append('push de') - output.append('push hl') - output.append('exx') - REQUIRES.add('iload32.asm') - elif immediate: - output.append('ld bc, (%s) >> 16' % op) - output.append('push bc') - output.append('ld bc, (%s) & 0xFFFF' % op) - output.append('push bc') - elif op[0] == '_': # an address - if int1 or op1[0] == '_': # If previous op was integer, we can use hl in advance - tmp = output - output = [] - output.append('ld hl, (%s + 2)' % op) - output.append('push hl') - output.append('ld hl, (%s)' % op) - output.append('push hl') - output.extend(tmp) - else: - output.append('ld bc, (%s + 2)' % op) - output.append('push bc') - output.append('ld bc, (%s)' % op) - output.append('push bc') - else: - pass # 2nd operand remains in the stack - - if op2 is not None and reversed: - output.append('call __SWAP32') - REQUIRES.add('swap32.asm') - - return output - - -# ----------------------------------------------------- -# Arithmetic operations -# ----------------------------------------------------- - -def _add32(ins): - """ Pops last 2 bytes from the stack and adds them. - Then push the result onto the stack. - - Optimizations: - * If any of the operands is ZERO, - then do NOTHING: A + 0 = 0 + A = A - """ - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2) is not None: - o1, o2 = _int_ops(op1, op2) - - if int(o2) == 0: # A + 0 = 0 + A = A => Do Nothing - output = _32bit_oper(o1) - output.append('push de') - output.append('push hl') - return output - - if op1[0] == '_' and op2[0] != '_': - op1, op2 = op2, op1 # swap them - - if op2[0] == '_': - output = _32bit_oper(op1) - output.append('ld bc, (%s)' % op2) - output.append('add hl, bc') - output.append('ex de, hl') - output.append('ld bc, (%s + 2)' % op2) - output.append('adc hl, bc') - output.append('push hl') - output.append('push de') - return output - - output = _32bit_oper(op1, op2) - output.append('pop bc') - output.append('add hl, bc') - output.append('ex de, hl') - output.append('pop bc') - output.append('adc hl, bc') - output.append('push hl') # High and low parts are reversed - output.append('push de') - - return output - - -def _sub32(ins): - """ Pops last 2 dwords from the stack and subtract them. - Then push the result onto the stack. - NOTE: The operation is TOP[0] = TOP[-1] - TOP[0] - - If TOP[0] is 0, nothing is done - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - if int(op2) == 0: # A - 0 = A => Do Nothing - output = _32bit_oper(op1) - output.append('push de') - output.append('push hl') - return output - - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - - output = _32bit_oper(op1, op2, rev) - output.append('call __SUB32') - output.append('push de') - output.append('push hl') - REQUIRES.add('sub32.asm') - return output - - -def _mul32(ins): - """ Multiplies two last 32bit values on top of the stack and - and returns the value on top of the stack - - Optimizations done: - - * If any operand is 1, do nothing - * If any operand is 0, push 0 - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2): - op1, op2 = _int_ops(op1, op2) - output = _32bit_oper(op1) - - if op2 == 1: - output.append('push de') - output.append('push hl') - return output # A * 1 = Nothing - - if op2 == 0: - output.append('ld hl, 0') - output.append('push hl') - output.append('push hl') - return output - - output = _32bit_oper(op1, op2) - output.append('call __MUL32') # Inmmediate - output.append('push de') - output.append('push hl') - REQUIRES.add('mul32.asm') - return output - - -def _divu32(ins): - """ Divides 2 32bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - - * If 2nd operand is 1, do nothing - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - if int(op2) == 1: - output = _32bit_oper(op1) - output.append('push de') - output.append('push hl') - return output - - rev = is_int(op1) or op1[0] == 't' or op2[0] != 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __DIVU32') - output.append('push de') - output.append('push hl') - REQUIRES.add('div32.asm') - return output - - -def _divi32(ins): - """ Divides 2 32bit signed integers. The result is pushed onto the stack. - - Optimizations: - - * If 2nd operand is 1, do nothing - * If 2nd operand is -1, do NEG32 - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - if int(op2) == 1: - output = _32bit_oper(op1) - output.append('push de') - output.append('push hl') - return output - - if int(op2) == -1: - return _neg32(ins) - - rev = is_int(op1) or op1[0] == 't' or op2[0] != 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __DIVI32') - output.append('push de') - output.append('push hl') - REQUIRES.add('div32.asm') - return output - - -def _modu32(ins): - """ Reminder of div. 2 32bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - - * If 2nd op is 1. Returns 0 - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - if int(op2) == 1: - output = _32bit_oper(op1) - output.append('ld hl, 0') - output.append('push hl') - output.append('push hl') - return output - - rev = is_int(op1) or op1[0] == 't' or op2[0] != 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __MODU32') - output.append('push de') - output.append('push hl') - REQUIRES.add('div32.asm') - return output - - -def _modi32(ins): - """ Reminder of div. 2 32bit signed integers. The result is pushed onto the stack. - - Optimizations: - - * If 2nd op is 1. Returns 0 - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - if int(op2) == 1: - output = _32bit_oper(op1) - output.append('ld hl, 0') - output.append('push hl') - output.append('push hl') - return output - - rev = is_int(op1) or op1[0] == 't' or op2[0] != 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __MODI32') - output.append('push de') - output.append('push hl') - REQUIRES.add('div32.asm') - return output - - -def _ltu32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit unsigned version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __SUB32') - output.append('sbc a, a') - output.append('push af') - REQUIRES.add('sub32.asm') - return output - - -def _lti32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit signed version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __LTI32') - output.append('push af') - REQUIRES.add('lti32.asm') - return output - - -def _gtu32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit unsigned version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('pop bc') - output.append('or a') - output.append('sbc hl, bc') - output.append('ex de, hl') - output.append('pop de') - output.append('sbc hl, de') - output.append('sbc a, a') - output.append('push af') - return output - - -def _gti32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit signed version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __LEI32') # Checks A <= B ? - output.append('sub 1') # Carry if A = 0 (False) - output.append('sbc a, a') # Negates => A > B ? - output.append('push af') - REQUIRES.add('lei32.asm') - return output - - -def _leu32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit unsigned version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('pop bc') - output.append('or a') - output.append('sbc hl, bc') - output.append('ex de, hl') - output.append('pop de') - output.append('sbc hl, de') # Carry if A > B - output.append('ccf') # Negates result => Carry if A <= B - output.append('sbc a, a') - output.append('push af') - return output - - -def _lei32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit signed version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __LEI32') - output.append('push af') - REQUIRES.add('lei32.asm') - return output - - -def _geu32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit unsigned version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __SUB32') # Carry if A < B - output.append('ccf') # Negates result => Carry if A >= B - output.append('sbc a, a') - output.append('push af') - REQUIRES.add('sub32.asm') - return output - - -def _gei32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit signed version - """ - op1, op2 = tuple(ins.quad[2:]) - rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't' - output = _32bit_oper(op1, op2, rev) - output.append('call __LTI32') # A = (a < b) - output.append('sub 1') # Carry if !(a < b) - output.append('sbc a, a') # A = !(a < b) = (a >= b) - output.append('push af') - REQUIRES.add('lti32.asm') - return output - - -def _eq32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand == 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __EQ32') - output.append('push af') - REQUIRES.add('eq32.asm') - return output - - -def _ne32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand != 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __EQ32') - output.append('sub 1') # Carry if A = 0 (False) - output.append('sbc a, a') # Negates => A > B ? - output.append('push af') - REQUIRES.add('eq32.asm') - return output - - -def _or32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand OR (Logical) 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __OR32') - output.append('push af') - REQUIRES.add('or32.asm') - return output - - -def _bor32(ins): - """ Pops top 2 operands out of the stack, and checks - if the 1st operand OR (Bitwise) 2nd operand (top of the stack). - Pushes result DE (high) HL (low) - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __BOR32') - output.append('push de') - output.append('push hl') - REQUIRES.add('bor32.asm') - return output - - -def _xor32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand XOR (Logical) 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __XOR32') - output.append('push af') - REQUIRES.add('xor32.asm') - return output - - -def _bxor32(ins): - """ Pops top 2 operands out of the stack, and checks - if the 1st operand XOR (Bitwise) 2nd operand (top of the stack). - Pushes result DE (high) HL (low) - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __BXOR32') - output.append('push de') - output.append('push hl') - REQUIRES.add('bxor32.asm') - return output - - -def _and32(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand AND (Logical) 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - - if _int_ops(op1, op2): - op1, op2 = _int_ops(op1, op2) - - if op2 == 0: # X and False = False - if str(op1)[0] == 't': # a temporary term (stack) - output = _32bit_oper(op1) # Remove op1 from the stack - else: - output = [] - output.append('xor a') - output.append('push af') - return output - - # For X and TRUE = X we do nothing as we have to convert it to boolean - # which is a rather expensive instruction - - output = _32bit_oper(op1, op2) - output.append('call __AND32') - output.append('push af') - REQUIRES.add('and32.asm') - return output - - -def _band32(ins): - """ Pops top 2 operands out of the stack, and checks - if the 1st operand AND (Bitwise) 2nd operand (top of the stack). - Pushes result DE (high) HL (low) - - 32 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - output = _32bit_oper(op1, op2) - output.append('call __BAND32') - output.append('push de') - output.append('push hl') - REQUIRES.add('band32.asm') - return output - - -def _not32(ins): - """ Negates top (Logical NOT) of the stack (32 bits in DEHL) - """ - output = _32bit_oper(ins.quad[2]) - output.append('call __NOT32') - output.append('push af') - REQUIRES.add('not32.asm') - return output - - -def _bnot32(ins): - """ Negates top (Bitwise NOT) of the stack (32 bits in DEHL) - """ - output = _32bit_oper(ins.quad[2]) - output.append('call __BNOT32') - output.append('push de') - output.append('push hl') - REQUIRES.add('bnot32.asm') - return output - - -def _neg32(ins): - """ Negates top of the stack (32 bits in DEHL) - """ - output = _32bit_oper(ins.quad[2]) - output.append('call __NEG32') - output.append('push de') - output.append('push hl') - REQUIRES.add('neg32.asm') - return output - - -def _abs32(ins): - """ Absolute value of top of the stack (32 bits in DEHL) - """ - output = _32bit_oper(ins.quad[2]) - output.append('call __ABS32') - output.append('push de') - output.append('push hl') - REQUIRES.add('abs32.asm') - return output - - -def _shru32(ins): - """ Logical Right shift 32bit unsigned integers. - The result is pushed onto the stack. - - Optimizations: - - * If 2nd operand is 0, do nothing - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - output = _32bit_oper(op1) - - if int(op2) == 0: - output.append('push de') - output.append('push hl') - return output - - if int(op2) > 1: - label = tmp_label() - output.append('ld b, %s' % op2) - output.append('%s:' % label) - output.append('call __SHRL32') - output.append('djnz %s' % label) - else: - output.append('call __SHRL32') - - output.append('push de') - output.append('push hl') - REQUIRES.add('shrl32.asm') - return output - - output = _8bit_oper(op2) - output.append('ld b, a') - output.extend(_32bit_oper(op1)) - label = tmp_label() - output.append('%s:' % label) - output.append('call __SHRL32') - output.append('djnz %s' % label) - output.append('push de') - output.append('push hl') - REQUIRES.add('shrl32.asm') - return output - - -def _shri32(ins): - """ Logical Right shift 32bit unsigned integers. - The result is pushed onto the stack. - - Optimizations: - - * If 2nd operand is 0, do nothing - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - output = _32bit_oper(op1) - - if int(op2) == 0: - output.append('push de') - output.append('push hl') - return output - - if int(op2) > 1: - label = tmp_label() - output.append('ld b, %s' % op2) - output.append('%s:' % label) - output.append('call __SHRA32') - output.append('djnz %s' % label) - else: - output.append('call __SHRA32') - - output.append('push de') - output.append('push hl') - REQUIRES.add('shra32.asm') - return output - - output = _8bit_oper(op2) - output.append('ld b, a') - output.extend(_32bit_oper(op1)) - label = tmp_label() - output.append('%s:' % label) - output.append('call __SHRA32') - output.append('djnz %s' % label) - output.append('push de') - output.append('push hl') - REQUIRES.add('shra32.asm') - return output - - -def _shl32(ins): - """ Logical Left shift 32bit unsigned integers. - The result is pushed onto the stack. - - Optimizations: - - * If 2nd operand is 0, do nothing - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - output = _32bit_oper(op1) - - if int(op2) == 0: - output.append('push de') - output.append('push hl') - return output - - if int(op2) > 1: - label = tmp_label() - output.append('ld b, %s' % op2) - output.append('%s:' % label) - output.append('call __SHL32') - output.append('djnz %s' % label) - else: - output.append('call __SHL32') - - output.append('push de') - output.append('push hl') - REQUIRES.add('shl32.asm') - return output - - output = _8bit_oper(op2) - output.append('ld b, a') - output.extend(_32bit_oper(op1)) - label = tmp_label() - output.append('%s:' % label) - output.append('call __SHL32') - output.append('djnz %s' % label) - output.append('push de') - output.append('push hl') - REQUIRES.add('shl32.asm') - return output diff --git a/arch/zx48k/backend/__8bit.py b/arch/zx48k/backend/__8bit.py deleted file mode 100644 index 316bcbe46..000000000 --- a/arch/zx48k/backend/__8bit.py +++ /dev/null @@ -1,1052 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim: ts=4:sw=4:et - -# -------------------------------------------------------------- -# Copyleft (k) 2008, by Jose M. Rodriguez-Rosa -# (a.k.a. Boriel, http://www.boriel.com) -# -# This module contains 8 bit boolean, arithmetic and -# comparation intermediate-code traductions -# -------------------------------------------------------------- - -from .__common import REQUIRES, is_int, is_2n, _int_ops, tmp_label - - -def int8(op): - """ Returns the operator converted to 8 bit unsigned integer. - For signed ones, it returns the 8bit C2 (Two Complement) - """ - return int(op) & 0xFF - - -def _8bit_oper(op1, op2=None, reversed_=False): - """ Returns pop sequence for 8 bits operands - 1st operand in H, 2nd operand in A (accumulator) - - For some operations (like comparisons), you can swap - operands extraction by setting reversed = True - """ - output = [] - - if op2 is not None and reversed_: - tmp = op1 - op1 = op2 - op2 = tmp - - op = op1 - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - if is_int(op): - op = int(op) - - if indirect: - output.append('ld a, (%i)' % op) - else: - if op == 0: - output.append('xor a') - else: - output.append('ld a, %i' % int8(op)) - else: - if immediate: - if indirect: - output.append('ld a, (%s)' % op) - else: - output.append('ld a, %s' % op) - elif op[0] == '_': - if indirect: - idx = 'bc' if reversed_ else 'hl' - output.append('ld %s, (%s)' % (idx, op)) # can't use HL - output.append('ld a, (%s)' % idx) - else: - output.append('ld a, (%s)' % op) - else: - if immediate: - output.append('ld a, %s' % op) - elif indirect: - idx = 'bc' if reversed_ else 'hl' - output.append('pop %s' % idx) - output.append('ld a, (%s)' % idx) - else: - output.append('pop af') - - if op2 is None: - return output - - if not reversed_: - tmp = output - output = [] - - op = op2 - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - if is_int(op): - op = int(op) - - if indirect: - output.append('ld hl, (%i - 1)' % op) - else: - output.append('ld h, %i' % int8(op)) - else: - if immediate: - if indirect: - output.append('ld hl, %s' % op) - output.append('ld h, (hl)') - else: - output.append('ld h, %s' % op) - elif op[0] == '_': - if indirect: - output.append('ld hl, (%s)' % op) - output.append('ld h, (hl)' % op) - else: - output.append('ld hl, (%s - 1)' % op) - else: - output.append('pop hl') - - if indirect: - output.append('ld h, (hl)') - - if not reversed_: - output.extend(tmp) - - return output - - -def _add8(ins): - """ Pops last 2 bytes from the stack and adds them. - Then push the result onto the stack. - - Optimizations: - * If any of the operands is ZERO, - then do NOTHING: A + 0 = 0 + A = A - - * If any of the operands is 1, then - INC is used - - * If any of the operands is -1 (255), then - DEC is used - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) - if op2 == 0: # Nothing to add: A + 0 = A - output.append('push af') - return output - - op2 = int8(op2) - - if op2 == 1: # Adding 1 is just an inc - output.append('inc a') - output.append('push af') - return output - - if op2 == 0xFF: # Adding 255 is just a dec - output.append('dec a') - output.append('push af') - return output - - output.append('add a, %i' % int8(op2)) - output.append('push af') - return output - - if op2[0] == '_': # stack optimization - op1, op2 = op2, op1 - - output = _8bit_oper(op1, op2) - output.append('add a, h') - output.append('push af') - - return output - - -def _sub8(ins): - """ Pops last 2 bytes from the stack and subtract them. - Then push the result onto the stack. Top-1 of the stack is - subtracted Top - _sub8 t1, a, b === t1 <-- a - b - - Optimizations: - * If 2nd op is ZERO, - then do NOTHING: A - 0 = A - - * If 1st operand is 0, then - just do a NEG - - * If any of the operands is 1, then - DEC is used - - * If any of the operands is -1 (255), then - INC is used - """ - - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): # 2nd operand - op2 = int8(op2) - output = _8bit_oper(op1) - - if op2 == 0: - output.append('push af') - return output # A - 0 = A - - op2 = int8(op2) - - if op2 == 1: # A - 1 == DEC A - output.append('dec a') - output.append('push af') - return output - - if op2 == 0xFF: # A - (-1) == INC A - output.append('inc a') - output.append('push af') - return output - - output.append('sub %i' % op2) - output.append('push af') - return output - - if is_int(op1): # 1st operand is numeric? - if int8(op1) == 0: # 0 - A = -A ==> NEG A - output = _8bit_oper(op2) - output.append('neg') - output.append('push af') - return output - - # At this point, even if 1st operand is numeric, proceed - # normally - - if op2[0] == '_': # Optimization when 2nd operand is an id - rev = True - op1, op2 = op2, op1 - else: - rev = False - - output = _8bit_oper(op1, op2, rev) - output.append('sub h') - output.append('push af') - - return output - - -def _mul8(ins): - """ Multiplies 2 las values from the stack. - - Optimizations: - * If any of the ops is ZERO, - then do A = 0 ==> XOR A, cause A * 0 = 0 * A = 0 - - * If any ot the ops is ONE, do NOTHING - A * 1 = 1 * A = A - """ - - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) - if op2 == 1: # A * 1 = 1 * A = A - output.append('push af') - return output - - if op2 == 0: - output.append('xor a') - output.append('push af') - return output - - if op2 == 2: # A * 2 == A SLA 1 - output.append('add a, a') - output.append('push af') - return output - - if op2 == 4: # A * 4 == A SLA 2 - output.append('add a, a') - output.append('add a, a') - output.append('push af') - return output - - output.append('ld h, %i' % int8(op2)) - else: - if op2[0] == '_': # stack optimization - op1, op2 = op2, op1 - - output = _8bit_oper(op1, op2) - - output.append('call __MUL8_FAST') # Inmmediate - output.append('push af') - REQUIRES.add('mul8.asm') - return output - - -def _divu8(ins): - """ Divides 2 8bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 1 then - do nothing - - * If 2nd op is 2 then - Shift Right Logical - """ - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op2 = int8(op2) - - output = _8bit_oper(op1) - if op2 == 1: - output.append('push af') - return output - - if op2 == 2: - output.append('srl a') - output.append('push af') - return output - - output.append('ld h, %i' % int8(op2)) - else: - if op2[0] == '_': # Optimization when 2nd operand is an id - if is_int(op1) and int(op1) == 0: - output = list() # Optimization: Discard previous op if not from the stack - output.append('xor a') - output.append('push af') - return output - - rev = True - op1, op2 = op2, op1 - else: - rev = False - - output = _8bit_oper(op1, op2, rev) - - output.append('call __DIVU8_FAST') - output.append('push af') - REQUIRES.add('div8.asm') - return output - - -def _divi8(ins): - """ Divides 2 8bit signed integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd op is 1 then - do nothing - - * If 2nd op is 2 then - Shift Right Arithmetic - """ - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op2 = int(op2) & 0xFF - output = _8bit_oper(op1) - - if op2 == 1: - output.append('push af') - return output - - if op2 == -1: - output.append('neg') - output.append('push af') - return output - - if op2 == 2: - output.append('sra a') - output.append('push af') - return output - - output.append('ld h, %i' % int8(op2)) - else: - if op2[0] == '_': # Optimization when 2nd operand is an id - if is_int(op1) and int(op1) == 0: - output = [] # Optimization: Discard previous op if not from the stack - output.append('xor a') - output.append('push af') - return output - - rev = True - op1, op2 = op2, op1 - else: - rev = False - - output = _8bit_oper(op1, op2, rev) - - output.append('call __DIVI8_FAST') - output.append('push af') - REQUIRES.add('div8.asm') - return output - - -def _modu8(ins): - """ Reminder of div. 2 8bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd operands is 1 then - returns 0 - - * If 2nd operand = 2^n => do AND (2^n - 1) - - """ - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op2 = int8(op2) - - output = _8bit_oper(op1) - if op2 == 1: - if op1[0] == '_': - output = [] # Optimization: Discard previous op if not from the stack - - output.append('xor a') - output.append('push af') - return output - - if is_2n(op2): - output.append('and %i' % (op2 - 1)) - output.append('push af') - return output - - output.append('ld h, %i' % int8(op2)) - else: - if op2[0] == '_': # Optimization when 2nd operand is an id - if is_int(op1) and int(op1) == 0: - output = [] # Optimization: Discard previous op if not from the stack - output.append('xor a') - output.append('push af') - return output - - rev = True - op1, op2 = op2, op1 - else: - rev = False - - output = _8bit_oper(op1, op2, rev) - - output.append('call __MODU8_FAST') - output.append('push af') - REQUIRES.add('div8.asm') - return output - - -def _modi8(ins): - """ Reminder of div. 2 8bit unsigned integers. The result is pushed onto the stack. - - Optimizations: - * If 2nd operands is 1 then - returns 0 - - * If 2nd operand = 2^n => do AND (2^n - 1) - - """ - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op2 = int8(op2) - - output = _8bit_oper(op1) - if op2 == 1: - if op1[0] == '_': - output = [] # Optimization: Discard previous op if not from the stack - - output.append('xor a') - output.append('push af') - return output - - if is_2n(op2): - output.append('and %i' % (op2 - 1)) - output.append('push af') - return output - - output.append('ld h, %i' % int8(op2)) - else: - if op2[0] == '_': # Optimization when 2nd operand is an id - if is_int(op1) and int(op1) == 0: - output = [] # Optimization: Discard previous op if not from the stack - output.append('xor a') - output.append('push af') - return output - - rev = True - op1, op2 = op2, op1 - else: - rev = False - - output = _8bit_oper(op1, op2, rev) - - output.append('call __MODI8_FAST') - output.append('push af') - REQUIRES.add('div8.asm') - return output - - -def _ltu8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit unsigned version - """ - output = _8bit_oper(ins.quad[2], ins.quad[3]) - output.append('cp h') - output.append('sbc a, a') - output.append('push af') - - return output - - -def _lti8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit signed version - """ - output = [] - output.extend(_8bit_oper(ins.quad[2], ins.quad[3])) - output.append('call __LTI8') - output.append('push af') - REQUIRES.add('lti8.asm') - - return output - - -def _gtu8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit unsigned version - """ - output = _8bit_oper(ins.quad[2], ins.quad[3], reversed_=True) - output.append('cp h') - output.append('sbc a, a') - output.append('push af') - - return output - - -def _gti8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit signed version - """ - output = _8bit_oper(ins.quad[2], ins.quad[3], reversed_=True) - output.append('call __LTI8') - output.append('push af') - REQUIRES.add('lti8.asm') - - return output - - -def _eq8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand == 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit un/signed version - """ - if is_int(ins.quad[3]): - output = _8bit_oper(ins.quad[2]) - n = int8(ins.quad[3]) - if n: - if n == 1: - output.append('dec a') - else: - output.append('sub %i' % n) - else: - output = _8bit_oper(ins.quad[2], ins.quad[3]) - output.append('sub h') - - output.append('sub 1') # Sets Carry only if 0 - output.append('sbc a, a') - output.append('push af') - - return output - - -def _leu8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit unsigned version - """ - output = _8bit_oper(ins.quad[2], ins.quad[3], reversed_=True) - output.append('sub h') # Carry if H > A - output.append('ccf') # Negates => Carry if H <= A - output.append('sbc a, a') - output.append('push af') - - return output - - -def _lei8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit signed version - """ - output = _8bit_oper(ins.quad[2], ins.quad[3]) - output.append('call __LEI8') - output.append('push af') - REQUIRES.add('lei8.asm') - - return output - - -def _geu8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit unsigned version - """ - if is_int(ins.quad[3]): - output = _8bit_oper(ins.quad[2]) - n = int8(ins.quad[3]) - if n: - output.append('sub %i' % n) - else: - output.append('cp a') - else: - output = _8bit_oper(ins.quad[2], ins.quad[3]) - output.append('sub h') - - output.append('ccf') - output.append('sbc a, a') - output.append('push af') - - return output - - -def _gei8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit signed version - """ - output = _8bit_oper(ins.quad[2], ins.quad[3], reversed_=True) - output.append('call __LEI8') - output.append('push af') - REQUIRES.add('lei8.asm') - - return output - - -def _ne8(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand != 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - 8 bit un/signed version - """ - if is_int(ins.quad[3]): - output = _8bit_oper(ins.quad[2]) - n = int8(ins.quad[3]) - if n: - if n == 1: - output.append('dec a') - else: - output.append('sub %i' % int8(ins.quad[3])) - else: - output = _8bit_oper(ins.quad[2], ins.quad[3]) - output.append('sub h') - - output.append('push af') - - return output - - -def _or8(ins): - """ Pops top 2 operands out of the stack, and checks - if 1st operand OR (logical) 2nd operand (top of the stack), - pushes 0 if False, not 0 if True. - - 8 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) - if op2 == 0: # X or False = X - output.append('push af') - return output - - # X or True = True - output.append('ld a, 1') # True - output.append('push af') - return output - - output = _8bit_oper(op1, op2) - output.append('or h') - output.append('push af') - - return output - - -def _bor8(ins): - """ pops top 2 operands out of the stack, and does - OR (bitwise) with 1st and 2nd operand (top of the stack), - pushes result. - - 8 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) - if op2 == 0: # X | 0 = X - output.append('push af') - return output - - if op2 == 0xFF: # X | 0xFF = 0xFF - output.append('ld a, 0FFh') - output.append('push af') - return output - - op1, op2 = tuple(ins.quad[2:]) - - output = _8bit_oper(op1, op2) - output.append('or h') - output.append('push af') - - return output - - -def _and8(ins): - """ Pops top 2 operands out of the stack, and checks - if 1st operand AND (logical) 2nd operand (top of the stack), - pushes 0 if False, not 0 if True. - - 8 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) # Pops the stack (if applicable) - if op2 != 0: # X and True = X - output.append('push af') - return output - - # False and X = False - output.append('xor a') - output.append('push af') - return output - - output = _8bit_oper(op1, op2) - # output.append('call __AND8') - lbl = tmp_label() - output.append('or a') - output.append('jr z, %s' % lbl) - output.append('ld a, h') - output.append('%s:' % lbl) - output.append('push af') - # REQUIRES.add('and8.asm') - - return output - - -def _band8(ins): - """ Pops top 2 operands out of the stack, and does - 1st AND (bitwise) 2nd operand (top of the stack), - pushes the result. - - 8 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) - if op2 == 0xFF: # X & 0xFF = X - output.append('push af') - return output - - if op2 == 0: # X and 0 = 0 - output.append('xor a') - output.append('push af') - return output - - op1, op2 = tuple(ins.quad[2:]) - - output = _8bit_oper(op1, op2) - output.append('and h') - output.append('push af') - - return output - - -def _xor8(ins): - """ Pops top 2 operands out of the stack, and checks - if 1st operand XOR (logical) 2nd operand (top of the stack), - pushes 0 if False, 1 if True. - - 8 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) # True or X = not X - if op2 == 0: # False xor X = X - output.append('push af') - return output - - output.append('sub 1') - output.append('sbc a, a') - output.append('push af') - return output - - output = _8bit_oper(op1, op2) - output.append('call __XOR8') - output.append('push af') - REQUIRES.add('xor8.asm') - - return output - - -def _bxor8(ins): - """ Pops top 2 operands out of the stack, and does - 1st operand XOR (bitwise) 2nd operand (top of the stack), - pushes the result - - 8 bit un/signed version - """ - op1, op2 = tuple(ins.quad[2:]) - if _int_ops(op1, op2) is not None: - op1, op2 = _int_ops(op1, op2) - - output = _8bit_oper(op1) - if op2 == 0: # 0 xor X = X - output.append('push af') - return output - - if op2 == 0xFF: # X xor 0xFF = ~X - output.append('cpl') - output.append('push af') - return output - - op1, op2 = tuple(ins.quad[2:]) - - output = _8bit_oper(op1, op2) - output.append('xor h') - output.append('push af') - - return output - - -def _not8(ins): - """ Negates (Logical NOT) top of the stack (8 bits in AF) - """ - output = _8bit_oper(ins.quad[2]) - output.append('sub 1') # Gives carry only if A = 0 - output.append('sbc a, a') # Gives FF only if Carry else 0 - output.append('push af') - - return output - - -def _bnot8(ins): - """ Negates (BITWISE NOT) top of the stack (8 bits in AF) - """ - output = _8bit_oper(ins.quad[2]) - output.append('cpl') # Gives carry only if A = 0 - output.append('push af') - - return output - - -def _neg8(ins): - """ Negates top of the stack (8 bits in AF) - """ - output = _8bit_oper(ins.quad[2]) - output.append('neg') - output.append('push af') - - return output - - -def _abs8(ins): - """ Absolute value of top of the stack (8 bits in AF) - """ - output = _8bit_oper(ins.quad[2]) - output.append('call __ABS8') - output.append('push af') - REQUIRES.add('abs8.asm') - return output - - -def _shru8(ins): - """ Shift 8bit unsigned integer to the right. The result is pushed onto the stack. - - Optimizations: - * If 1nd or 2nd op is 0 then - do nothing - - * If 2nd op is < 4 then - unroll loop - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - op2 = int8(op2) - - output = _8bit_oper(op1) - if op2 == 0: - output.append('push af') - return output - - if op2 < 4: - output.extend(['srl a'] * op2) - output.append('push af') - return output - - label = tmp_label() - output.append('ld b, %i' % int8(op2)) - output.append('%s:' % label) - output.append('srl a') - output.append('djnz %s' % label) - output.append('push af') - return output - - if is_int(op1) and int(op1) == 0: - output = _8bit_oper(op2) - output.append('xor a') - output.append('push af') - return output - - output = _8bit_oper(op1, op2, True) - label = tmp_label() - label2 = tmp_label() - output.append('or a') - output.append('ld b, a') - output.append('ld a, h') - output.append('jr z, %s' % label2) - output.append('%s:' % label) - output.append('srl a') - output.append('djnz %s' % label) - output.append('%s:' % label2) - output.append('push af') - return output - - -def _shri8(ins): - """ Shift 8bit signed integer to the right. The result is pushed onto the stack. - - Optimizations: - * If 1nd or 2nd op is 0 then - do nothing - - * If 2nd op is < 4 then - unroll loop - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_int(op2): - op2 = int8(op2) - - output = _8bit_oper(op1) - if op2 == 0: - output.append('push af') - return output - - if op2 < 4: - output.extend(['sra a'] * op2) - output.append('push af') - return output - - label = tmp_label() - output.append('ld b, %i' % int8(op2)) - output.append('%s:' % label) - output.append('sra a') - output.append('djnz %s' % label) - output.append('push af') - return output - - if is_int(op1) and int(op1) == 0: - output = _8bit_oper(op2) - output.append('xor a') - output.append('push af') - return output - - output = _8bit_oper(op1, op2, True) - label = tmp_label() - label2 = tmp_label() - output.append('or a') - output.append('ld b, a') - output.append('ld a, h') - output.append('jr z, %s' % label2) - output.append('%s:' % label) - output.append('sra a') - output.append('djnz %s' % label) - output.append('%s:' % label2) - output.append('push af') - return output - - -def _shl8(ins): - """ Shift 8bit (un)signed integer to the left. The result is pushed onto the stack. - - Optimizations: - * If 1nd or 2nd op is 0 then - do nothing - - * If 2nd op is < 4 then - unroll loop - """ - op1, op2 = tuple(ins.quad[2:]) - if is_int(op2): - op2 = int8(op2) - - output = _8bit_oper(op1) - if op2 == 0: - output.append('push af') - return output - - if op2 < 6: - output.extend(['add a, a'] * op2) - output.append('push af') - return output - - label = tmp_label() - output.append('ld b, %i' % int8(op2)) - output.append('%s:' % label) - output.append('add a, a') - output.append('djnz %s' % label) - output.append('push af') - return output - - if is_int(op1) and int(op1) == 0: - output = _8bit_oper(op2) - output.append('xor a') - output.append('push af') - return output - - output = _8bit_oper(op1, op2, True) - label = tmp_label() - label2 = tmp_label() - output.append('or a') - output.append('ld b, a') - output.append('ld a, h') - output.append('jr z, %s' % label2) - output.append('%s:' % label) - output.append('add a, a') - output.append('djnz %s' % label) - output.append('%s:' % label2) - output.append('push af') - return output diff --git a/arch/zx48k/backend/__array.py b/arch/zx48k/backend/__array.py deleted file mode 100644 index c29ffcff2..000000000 --- a/arch/zx48k/backend/__array.py +++ /dev/null @@ -1,398 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim:ts=4:et:sw=4: - -# -------------------------------------------------------------- -# Copyleft (k) 2008, by Jose M. Rodriguez-Rosa -# (a.k.a. Boriel, http://www.boriel.com) -# -# This module contains array load/store -# intermediate-code traductions -# -------------------------------------------------------------- - - -from .__common import REQUIRES, is_int -from .__f16 import _f16_oper -from .__float import _fpush, _float_oper -from .errors import InvalidICError - - -def _addr(value): - ''' Common subroutine for emitting array address - ''' - output = [] - - try: - indirect = False - if value[0] == '*': - indirect = True - value = value[1:] - - value = int(value) & 0xFFFF - if indirect: - output.append('ld hl, (%s)' % str(value)) - else: - output.append('ld hl, %s' % str(value)) - - except ValueError: - if value[0] == '_': - output.append('ld hl, %s' % str(value)) - if indirect: - output.append('ld c, (hl)') - output.append('inc hl') - output.append('ld h, (hl)') - output.append('ld l, c') - else: - output.append('pop hl') - if indirect: - output.append('ld c, (hl)') - output.append('inc hl') - output.append('ld h, (hl)') - output.append('ld l, c') - - output.append('call __ARRAY') - REQUIRES.add('array.asm') - - return output - - -def _aaddr(ins): - ''' Loads the address of an array element - into the stack. - ''' - output = _addr(ins.quad[2]) - output.append('push hl') - - return output - - -def _aload8(ins): - ''' Loads an 8 bit value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - ''' - output = _addr(ins.quad[2]) - output.append('ld a, (hl)') - output.append('push af') - - return output - - -def _aload16(ins): - ''' Loads a 16 bit value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - ''' - output = _addr(ins.quad[2]) - - output.append('ld e, (hl)') - output.append('inc hl') - output.append('ld d, (hl)') - output.append('ex de, hl') - output.append('push hl') - - return output - - -def _aload32(ins): - ''' Load a 32 bit value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - ''' - output = _addr(ins.quad[2]) - - output.append('call __ILOAD32') - output.append('push de') - output.append('push hl') - - REQUIRES.add('iload32.asm') - - return output - - -def _aloadf(ins): - ''' Loads a floating point value from a memory address. - If 2nd arg. start with '*', it is always treated as - an indirect value. - ''' - output = _addr(ins.quad[2]) - output.append('call __LOADF') - output.extend(_fpush()) - - REQUIRES.add('iloadf.asm') - - return output - - -def _aloadstr(ins): - ''' Loads a string value from a memory address. - ''' - output = _addr(ins.quad[2]) - - output.append('call __ILOADSTR') - output.append('push hl') - REQUIRES.add('loadstr.asm') - - return output - - -def _astore8(ins): - ''' Stores 2º operand content into address of 1st operand. - 1st operand is an array element. Dimensions are pushed into the - stack. - Use '*' for indirect store on 1st operand (A pointer to an array) - ''' - output = _addr(ins.quad[1]) - op = ins.quad[2] - - indirect = op[0] == '*' - if indirect: - op = op[1:] - - immediate = op[0] == '#' - if immediate: - op = op[1:] - - if is_int(op): - if indirect: - if immediate: - op = str(int(op) & 0xFFFF) # Truncate to 16bit pointer - output.append('ld a, (%s)' % op) - else: - output.append('ld de, (%s)' % op) - output.append('ld a, (de)') - else: - op = str(int(op) & 0xFF) # Truncate to byte - output.append('ld (hl), %s' % op) - return output - - elif op[0] == '_': - if indirect: - if immediate: - output.append('ld a, (%s)' % op) # Redundant: *#_id == _id - else: - output.append('ld de, (%s)' % op) # *_id - output.append('ld a, (de)') - else: - if immediate: - output.append('ld a, %s' % op) # #_id - else: - output.append('ld a, (%s)' % op) # _id - else: - output.append('pop af') # tn - - output.append('ld (hl), a') - - return output - - -def _astore16(ins): - ''' Stores 2º operand content into address of 1st operand. - store16 a, x => *(&a) = x - Use '*' for indirect store on 1st operand. - ''' - output = _addr(ins.quad[1]) - op = ins.quad[2] - - indirect = op[0] == '*' - if indirect: - op = op[1:] - - immediate = op[0] == '#' - if immediate: - op = op[1:] - - if is_int(op): - op = str(int(op) & 0xFFFF) # Truncate to 16bit pointer - - if indirect: - if immediate: - output.append('ld de, (%s)' % op) - else: - output.append('ld de, (%s)' % op) - output.append('call __LOAD_DE_DE') - REQUIRES.add('lddede.asm') - else: - H = int(op) >> 8 - L = int(op) & 0xFF - output.append('ld (hl), %i' % L) - output.append('inc hl') - output.append('ld (hl), %i' % H) - return output - - elif op[0] == '_': - if indirect: - if immediate: - output.append('ld de, (%s)' % op) # redundant: *#_id == _id - else: - output.append('ld de, (%s)' % op) # *_id - output.append('call __LOAD_DE_DE') - REQUIRES.add('lddede.asm') - else: - if immediate: - output.append('ld de, %s' % op) - else: - output.append('ld de, (%s)' % op) - else: - output.append('pop de') - - output.append('ld (hl), e') - output.append('inc hl') - output.append('ld (hl), d') - - return output - - -def _astore32(ins): - ''' Stores 2º operand content into address of 1st operand. - store16 a, x => *(&a) = x - ''' - output = _addr(ins.quad[1]) - - value = ins.quad[2] - if value[0] == '*': - value = value[1:] - indirect = True - else: - indirect = False - - try: - value = int(ins.quad[2]) & 0xFFFFFFFF # Immediate? - if indirect: - output.append('push hl') - output.append('ld hl, %i' % (value & 0xFFFF)) - output.append('call __ILOAD32') - output.append('ld b, h') - output.append('ld c, l') # BC = Lower 16 bits - output.append('pop hl') - REQUIRES.add('iload32.asm') - else: - output.append('ld de, %i' % (value >> 16)) - output.append('ld bc, %i' % (value & 0xFFFF)) - except ValueError: - output.append('pop bc') - output.append('pop de') - - output.append('call __STORE32') - REQUIRES.add('store32.asm') - - return output - - -def _astoref16(ins): - ''' Stores 2º operand content into address of 1st operand. - storef16 a, x => *(&a) = x - ''' - output = _addr(ins.quad[1]) - - value = ins.quad[2] - if value[0] == '*': - value = value[1:] - indirect = True - else: - indirect = False - - if indirect: - output.append('push hl') - output.extend(_f16_oper(ins.quad[2], useBC=True)) - output.append('pop hl') - REQUIRES.add('iload32.asm') - else: - output.extend(_f16_oper(ins.quad[2], useBC=True)) - - output.append('call __STORE32') - REQUIRES.add('store32.asm') - - return output - - -def _astoref(ins): - ''' Stores a floating point value into a memory address. - ''' - output = _addr(ins.quad[1]) - - value = ins.quad[2] - if value[0] == '*': - value = value[1:] - indirect = True - else: - indirect = False - - if indirect: - output.append('push hl') - output.extend(_float_oper(ins.quad[2])) - output.append('pop hl') - else: - output.extend(_float_oper(ins.quad[2])) - - output.append('call __STOREF') - REQUIRES.add('storef.asm') - - return output - - -def _astorestr(ins): - ''' Stores a string value into a memory address. - It copies content of 2nd operand (string), into 1st, reallocating - dynamic memory for the 1st str. These instruction DOES ALLOW - immediate strings for the 2nd parameter, starting with '#'. - ''' - output = _addr(ins.quad[1]) - op = ins.quad[2] - - indirect = op[0] == '*' - if indirect: - op = op[1:] - - immediate = op[0] == '#' - if immediate: - op = op[1:] - - temporal = op[0] != '$' - if not temporal: - op = op[1:] - - if is_int(op): - op = str(int(op) & 0xFFFF) - if indirect: - if immediate: # *# = ld hl, (number) - output.append('ld de, (%s)' % op) - else: - output.append('ld de, (%s)' % op) - output.append('call __LOAD_DE_DE') - REQUIRES.add('lddede.asm') - else: - # Integer does not make sense here (unless it's a ptr) - raise InvalidICError(str(ins)) - - output.append('ld de, (%s)' % op) - elif op[0] == '_': # an identifier - temporal = False # Global var is not a temporary string - - if indirect: - if immediate: # *#_id = _id - output.append('ld de, (%s)' % op) - else: # *_id - output.append('ld de, (%s)' % op) - output.append('call __LOAD_DE_DE') - REQUIRES.add('lddede.asm') - else: - if immediate: - output.append('ld de, %s' % op) - else: - output.append('ld de, (%s)' % op) - else: # tn - output.append('pop de') - - if indirect: - output.append('call __LOAD_DE_DE') - REQUIRES.add('lddede.asm') - - if not temporal: - output.append('call __STORE_STR') - REQUIRES.add('storestr.asm') - else: # A value already on dynamic memory - output.append('call __STORE_STR2') - REQUIRES.add('storestr2.asm') - - return output diff --git a/arch/zx48k/backend/__common.py b/arch/zx48k/backend/__common.py deleted file mode 100644 index 21dc518e1..000000000 --- a/arch/zx48k/backend/__common.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim ts=4:et:sw=4:ai - -import math -from .errors import TempAlreadyFreedError - -MEMORY = [] # Must be initialized by with init() - -# Counter for generated labels (__LABEL0, __LABEL1, __LABELN...) -LABEL_COUNTER = 0 - -# Counter for generated tmp labels (__TMP0, __TMP1, __TMPN) -TMP_COUNTER = 0 -TMP_STORAGES = [] - -# Set containing REQUIRED libraries -REQUIRES = set() # Set of required libraries (included once) - -# Set containing automatic on start called routines -INITS = set() # Set of INIT routines - -# CONSTANT LN(2) -__LN2 = math.log(2) - -# GENERATED labels __LABELXX -TMP_LABELS = set() - - -def init(): - global LABEL_COUNTER - global TMP_COUNTER - - LABEL_COUNTER = 0 - TMP_COUNTER = 0 - - del MEMORY[:] - del TMP_STORAGES[:] - REQUIRES.clear() - INITS.clear() - TMP_LABELS.clear() - - -def log2(x) -> float: - """ Returns log2(x) - """ - return math.log(x) / __LN2 - - -def is_2n(x) -> bool: - """ Returns true if x is an exact - power of 2 - """ - l = log2(x) - return l == int(l) - - -def tmp_label() -> str: - global LABEL_COUNTER - global TMP_LABELS - - result = '__LABEL%i' % LABEL_COUNTER - TMP_LABELS.add(result) - LABEL_COUNTER += 1 - - return result - - -def tmp_temp() -> str: - global TMP_COUNTER - - for i in range(TMP_COUNTER): - result = '__TEMP%i' % i - - if result not in TMP_STORAGES: - TMP_STORAGES.append(result) - return result - - result = '__TEMP%i' % TMP_COUNTER - TMP_STORAGES.append(result) - TMP_COUNTER += 1 - - return result - - -def tmp_remove(label): - if label not in TMP_STORAGES: - raise TempAlreadyFreedError(label) - - TMP_STORAGES.pop(TMP_STORAGES.index(label)) - - -# ------------------------------------------------------------------ -# Operands checking -# ------------------------------------------------------------------ -def is_int(op): - """ Returns True if the given operand (string) - contains an integer number - """ - try: - int(op) - return True - - except ValueError: - pass - - return False - - -def is_float(op): - """ Returns True if the given operand (string) - contains a floating point number - """ - try: - float(op) - return True - - except ValueError: - pass - - return False - - -def _int_ops(op1, op2, swap=True): - """ Receives a list with two strings (operands). - If none of them contains integers, returns None. - Otherwise, returns a t-uple with (op[0], op[1]), - where op[1] is the integer one (the list is swapped) - unless swap is False (e.g. sub and div used this - because they're not commutative). - - The integer operand is always converted to int type. - """ - if is_int(op1): - if swap: - return op2, int(op1) - else: - return int(op1), op2 - - if is_int(op2): - return op1, int(op2) - - return None - - -def _f_ops(op1, op2, swap=True): - """ Receives a list with two strings (operands). - If none of them contains integers, returns None. - Otherwise, returns a t-uple with (op[0], op[1]), - where op[1] is the integer one (the list is swapped) - unless swap is False (e.g. sub and div used this - because they're not commutative). - - The integer operand is always converted to int type. - """ - if is_float(op1): - if swap: - return op2, float(op1) - else: - return float(op1), op2 - - if is_float(op2): - return op1, float(op2) - - return None diff --git a/arch/zx48k/backend/__f16.py b/arch/zx48k/backend/__f16.py deleted file mode 100644 index 668c6f0ce..000000000 --- a/arch/zx48k/backend/__f16.py +++ /dev/null @@ -1,434 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# -------------------------------------------------------------- -# Copyleft (k) 2008, by Jose M. Rodriguez-Rosa -# (a.k.a. Boriel, http://www.boriel.com) -# -# This module contains 8 bit boolean, arithmetic and -# comparation intermediate-code traductions -# -------------------------------------------------------------- - -from .__common import REQUIRES, is_float, _f_ops -from .__32bit import _add32, _sub32, _lti32, _gti32, _gei32, _lei32, _ne32, _eq32 -from .__32bit import _and32, _xor32, _or32, _not32, _neg32, _abs32 -from .__float import _negf - - -# ----------------------------------------------------- -# Fixed Point (16.16) bits operands -# ----------------------------------------------------- -def f16(op): - """ Returns a floating point operand converted to 32 bits unsigned int. - Negative numbers are returned in 2 complement. - - The result is returned in a tuple (DE, HL) => High16 (Int part), Low16 (Decimal part) - """ - op = float(op) - - negative = op < 0 - if negative: - op = -op - - DE = int(op) - HL = int((op - DE) * 2**16) & 0xFFFF - DE &= 0xFFFF - - if negative: # Do C2 - DE ^= 0xFFFF - HL ^= 0xFFFF - - DEHL = ((DE << 16) | HL) + 1 - HL = DEHL & 0xFFFF - DE = (DEHL >> 16) & 0xFFFF - - return (DE, HL) - - -def _f16_oper(op1, op2=None, useBC=False, reversed=False): - """ Returns pop sequence for 32 bits operands - 1st operand in HLDE, 2nd operand remains in the stack - - Now it does support operands inversion calling __SWAP32. - - However, if 1st operand is integer (immediate) or indirect, the stack - will be rearranged, so it contains a 32 bit pushed parameter value for the - subroutine to be called. - - If preserveHL is True, then BC will be used instead of HL for lower part - for the 1st operand. - """ - output = [] - - if op1 is not None: - op1 = str(op1) - - if op2 is not None: - op2 = str(op2) - - op = op2 if op2 is not None else op1 - - float1 = False # whether op1 (2nd operand) is float - - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - hl = 'hl' if not useBC and not indirect else 'bc' - - if is_float(op): - float1 = True - op = float(op) - - if indirect: - op = int(op) & 0xFFFF - if immediate: - output.append('ld hl, %i' % op) - else: - output.append('ld hl, (%i)' % op) - - output.append('call __ILOAD32') - REQUIRES.add('iload32.asm') - - if preserveHL: # noqa TODO: it will fail - output.append('ld b, h') - output.append('ld c, l') - else: - DE, HL = f16(op) - output.append('ld de, %i' % DE) - output.append('ld %s, %i' % (hl, HL)) - else: - if op[0] == '_': - if immediate: - output.append('ld %s, %s' % (hl, op)) - else: - output.append('ld %s, (%s)' % (hl, op)) - else: - output.append('pop %s' % hl) - - if indirect: - output.append('call __ILOAD32') - REQUIRES.add('iload32.asm') - - if preserveHL: # noqa TODO: it will fail - output.append('ld b, h') - output.append('ld c, l') - else: - if op[0] == '_': - output.append('ld de, (%s + 2)' % op) - else: - output.append('pop de') - - if op2 is not None: - op = op1 - - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - immediate = (op[0] == '#') - if immediate: - op = op[1:] - - if is_float(op): - op = float(op) - - if indirect: - op = int(op) - output.append('exx') - if immediate: - output.append('ld hl, %i' % (op & 0xFFFF)) - else: - output.append('ld hl, (%i)' % (op & 0xFFFF)) - - output.append('call __ILOAD32') - output.append('push de') - output.append('push hl') - output.append('exx') - REQUIRES.add('iload32.asm') - else: - DE, HL = f16(op) - output.append('ld bc, %i' % DE) - output.append('push bc') - output.append('ld bc, %i' % HL) - output.append('push bc') - else: - if indirect: - output.append('exx') # uses alternate set to put it on the stack - if op[0] == '_': - if immediate: - output.append('ld hl, %s' % op) - else: - output.append('ld hl, (%s)' % op) - else: - output.append('pop hl') # Pointers are only 16 bits *** - - output.append('call __ILOAD32') - output.append('push de') - output.append('push hl') - output.append('exx') - REQUIRES.add('iload32.asm') - elif op[0] == '_': # an address - if float1 or op1[0] == '_': # If previous op was constant, we can use hl in advance - tmp = output - output = [] - output.append('ld hl, (%s + 2)' % op) - output.append('push hl') - output.append('ld hl, (%s)' % op) - output.append('push hl') - output.extend(tmp) - else: - output.append('ld bc, (%s + 2)' % op) - output.append('push bc') - output.append('ld bc, (%s)' % op) - output.append('push bc') - else: - pass # 2nd operand remains in the stack - - if op2 is not None and reversed: - output.append('call __SWAP32') - REQUIRES.add('swap32.asm') - - return output - - -def _f16_to_32bit(ins): - """ If any of the operands within the ins(truction) are numeric, - convert them to its 32bit representation, otherwise leave them - as they are. - """ - ins.quad = [x for x in ins.quad] - for i in range(2, len(ins.quad)): - if is_float(ins.quad[i]): - de, hl = f16(ins.quad[i]) - ins.quad[i] = str((de << 16) | hl) - - ins.quad = tuple(ins.quad) - return ins - - -def _addf16(ins): - """ Pops last 2 bytes from the stack and adds them. - Then push the result onto the stack. - - Optimizations: - * If any of the operands is ZERO, - then do NOTHING: A + 0 = 0 + A = A - """ - return _add32(_f16_to_32bit(ins)) - - -def _subf16(ins): - """ Pops last 2 dwords from the stack and subtract them. - Then push the result onto the stack. - NOTE: The operation is TOP[0] = TOP[-1] - TOP[0] - - If TOP[0] is 0, nothing is done - """ - return _sub32(_f16_to_32bit(ins)) - - -def _mulf16(ins): - """ Multiplies 2 32bit (16.16) fixed point numbers. The result is pushed onto the stack. - """ - op1, op2 = tuple(ins.quad[2:]) - - if _f_ops(op1, op2) is not None: - op1, op2 = _f_ops(op1, op2) - - if op2 == 1: # A * 1 => A - output = _f16_oper(op1) - output.append('push de') - output.append('push hl') - return output - - if op2 == -1: - return _neg32(ins) - - output = _f16_oper(op1) - if op2 == 0: - output.append('ld hl, 0') - output.append('ld e, h') - output.append('ld d, l') - output.append('push de') - output.append('push hl') - return output - - output = _f16_oper(op1, str(op2)) - output.append('call __MULF16') - output.append('push de') - output.append('push hl') - REQUIRES.add('mulf16.asm') - return output - - -def _divf16(ins): - """ Divides 2 32bit (16.16) fixed point numbers. The result is pushed onto the stack. - - Optimizations: - - * If 2nd operand is 1, do nothing - * If 2nd operand is -1, do NEG32 - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_float(op2): - if float(op2) == 1: - output = _f16_oper(op1) - output.append('push de') - output.append('push hl') - return output - - if float(op2) == -1: - return _negf(ins) - - rev = not is_float(op1) and op1[0] != 't' and op2[0] == 't' - - output = _f16_oper(op1, op2, reversed=rev) - output.append('call __DIVF16') - output.append('push de') - output.append('push hl') - REQUIRES.add('divf16.asm') - return output - - -def _modf16(ins): - """ Reminder of div. 2 32bit (16.16) fixed point numbers. The result is pushed onto the stack. - Optimizations: - * If 2nd op is 1. Returns 0 - """ - op1, op2 = tuple(ins.quad[2:]) - - if is_float(op2) and float(op2) == 1: - output = _f16_oper(op1) - output.append('ld hl, 0') - output.append('push hl') - output.append('push hl') - return output - - rev = not is_float(op1) and op1[0] != 't' and op2[0] == 't' - - output = _f16_oper(op1, op2, reversed=rev) - output.append('call __MODF16') - output.append('push de') - output.append('push hl') - REQUIRES.add('modf16.asm') - return output - - -def _negf16(ins): - """ Negates (arithmetic) top of the stack (Fixed point in DE.HL) - - Fixed point signed version - """ - return _neg32(_f16_to_32bit(ins)) - - -def _ltf16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _lti32(_f16_to_32bit(ins)) - - -def _gtf16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _gti32(_f16_to_32bit(ins)) - - -def _lef16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _lei32(_f16_to_32bit(ins)) - - -def _gef16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _gei32(_f16_to_32bit(ins)) - - -def _eqf16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand == 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _eq32(_f16_to_32bit(ins)) - - -def _nef16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand != 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _ne32(_f16_to_32bit(ins)) - - -def _orf16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand OR (Logical) 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _or32(_f16_to_32bit(ins)) - - -def _xorf16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand XOR (Logical) 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _xor32(_f16_to_32bit(ins)) - - -def _andf16(ins): - """ Compares & pops top 2 operands out of the stack, and checks - if the 1st operand AND (Logical) 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Fixed point signed version - """ - return _and32(_f16_to_32bit(ins)) - - -def _notf16(ins): - """ Negates top of the stack (Fixed point in DE.HL) - - Fixed point signed version - """ - return _not32(_f16_to_32bit(ins)) - - -def _absf16(ins): - """ Absolute value of top of the stack (Fixed point in DE.HL) - - Fixed point signed version - """ - return _abs32(_f16_to_32bit(ins)) diff --git a/arch/zx48k/backend/__float.py b/arch/zx48k/backend/__float.py deleted file mode 100644 index fd7091319..000000000 --- a/arch/zx48k/backend/__float.py +++ /dev/null @@ -1,425 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim:ts=4:et:sw=4: - -# -------------------------------------------------------------- -# Copyleft (k) 2008, by Jose M. Rodriguez-Rosa -# (a.k.a. Boriel, http://www.boriel.com) -# -# This module contains 8 bit boolean, arithmetic and -# comparation intermediate-code traductions -# -------------------------------------------------------------- - -from .__common import REQUIRES, is_float, _f_ops - -# ----------------------------------------------------- -# Floating Point operators -# ----------------------------------------------------- -from src.api import fp - - -def _float(op): - ''' Returns a floating point operand converted to 5 byte (40 bits) unsigned int. - The result is returned in a tuple (C, DE, HL) => Exp, mantissa =>High16 (Int part), Low16 (Decimal part) - ''' - return fp.immediate_float(float(op)) - - -def _fpop(): - ''' Returns the pop sequence of a float - ''' - output = [] - output.append('pop af') - output.append('pop de') - output.append('pop bc') - - return output - - -def _fpush(): - ''' Returns the push sequence of a float - ''' - output = [] - output.append('push bc') - output.append('push de') - output.append('push af') - - return output - - -def _float_oper(op1, op2=None): - ''' Returns pop sequence for floating point operands - 1st operand in A DE BC, 2nd operand remains in the stack - - Unlike 8bit and 16bit version, this does not supports - operands inversion. Since many of the instructions are implemented - as functions, they must support this. - - However, if 1st operand is a number (immediate) or indirect, the stack - will be rearranged, so it contains a 48 bit pushed parameter value for the - subroutine to be called. - ''' - output = [] - op = op2 if op2 is not None else op1 - - indirect = (op[0] == '*') - if indirect: - op = op[1:] - - if is_float(op): - op = float(op) - - if indirect: - op = int(op) & 0xFFFF - output.append('ld hl, (%i)' % op) - output.append('call __ILOADF') - REQUIRES.add('iloadf.asm') - else: - A, DE, BC = _float(op) - output.append('ld a, %s' % A) - output.append('ld de, %s' % DE) - output.append('ld bc, %s' % BC) - else: - if indirect: - if op[0] == '_': - output.append('ld hl, (%s)' % op) - else: - output.append('pop hl') - - output.append('call __ILOADF') - REQUIRES.add('iloadf.asm') - else: - if op[0] == '_': - output.append('ld a, (%s)' % op) - output.append('ld de, (%s + 1)' % op) - output.append('ld bc, (%s + 3)' % op) - else: - output.extend(_fpop()) - - if op2 is not None: - op = op1 - if is_float(op): # An float must be in the stack. Let's pushit - A, DE, BC = _float(op) - output.append('ld hl, %s' % BC) - output.append('push hl') - output.append('ld hl, %s' % DE) - output.append('push hl') - output.append('ld h, %s' % A) - output.append('push hl') - elif op[0] == '*': # Indirect - op = op[1:] - output.append('exx') # uses alternate set to put it on the stack - output.append("ex af, af'") - if is_int(op): # noqa TODO: it will fail - op = int(op) - output.append('ld hl, %i' % op) - elif op[0] == '_': - output.append('ld hl, (%s)' % op) - else: - output.append('pop hl') - - output.append('call __ILOADF') - output.extend(_fpush()) - output.append("ex af, af'") - output.append('exx') - REQUIRES.add('iloadf.asm') - elif op[0] == '_': - if is_float(op2): - tmp = output - output = [] - output.append('ld hl, %s + 4' % op) - ''' - output.append('ld hl, (%s + 3)' % op) - output.append('push hl') - output.append('ld hl, (%s + 1)' % op) - output.append('push hl') - output.append('ld a, (%s)' % op) - output.append('push af') - ''' - output.append('call __FP_PUSH_REV') - output.extend(tmp) - REQUIRES.add('pushf.asm') - else: - ''' - output.append('ld hl, (%s + 3)' % op) - output.append('push hl') - output.append('ld hl, (%s + 1)' % op) - output.append('push hl') - output.append('ld hl, (%s - 1)' % op) - output.append('push hl') - ''' - output.append('ld hl, %s + 4' % op) - output.append('call __FP_PUSH_REV') - REQUIRES.add('pushf.asm') - else: - pass # Else do nothing, and leave the op onto the stack - - return output - - -# ----------------------------------------------------- -# Arithmetic operations -# ----------------------------------------------------- - -def _addf(ins): - ''' Adds 2 float values. The result is pushed onto the stack. - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _f_ops(op1, op2) is not None: - opa, opb = _f_ops(op1, op2) - if opb == 0: # A + 0 => A - output = _float_oper(opa) - output.extend(_fpush()) - return output - - output = _float_oper(op1, op2) - output.append('call __ADDF') - output.extend(_fpush()) - REQUIRES.add('addf.asm') - return output - - -def _subf(ins): - ''' Subtract 2 float values. The result is pushed onto the stack. - ''' - op1, op2 = tuple(ins.quad[2:]) - - if is_float(op2) and float(op2) == 0: # Nothing to do: A - 0 = A - output = _float_oper(op1) - output.extend(_fpush()) - return output - - output = _float_oper(op1, op2) - output.append('call __SUBF') - output.extend(_fpush()) - REQUIRES.add('subf.asm') - return output - - -def _mulf(ins): - ''' Multiplie 2 float values. The result is pushed onto the stack. - ''' - op1, op2 = tuple(ins.quad[2:]) - - if _f_ops(op1, op2) is not None: - opa, opb = _f_ops(op1, op2) - if opb == 1: # A * 1 => A - output = _float_oper(opa) - output.extend(_fpush()) - return output - - output = _float_oper(op1, op2) - output.append('call __MULF') - output.extend(_fpush()) - REQUIRES.add('mulf.asm') - return output - - -def _divf(ins): - ''' Divides 2 float values. The result is pushed onto the stack. - ''' - op1, op2 = tuple(ins.quad[2:]) - - if is_float(op2) and float(op2) == 1: # Nothing to do. A / 1 = A - output = _float_oper(op1) - output.extend(_fpush()) - return output - - output = _float_oper(op1, op2) - output.append('call __DIVF') - output.extend(_fpush()) - REQUIRES.add('divf.asm') - return output - - -def _modf(ins): - ''' Reminder of div. 2 float values. The result is pushed onto the stack. - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __MODF') - output.extend(_fpush()) - REQUIRES.add('modf.asm') - return output - - -def _powf(ins): - ''' Exponentiation of 2 float values. The result is pushed onto the stack. - ''' - op1, op2 = tuple(ins.quad[2:]) - - if is_float(op2) and float(op2) == 1: # Nothing to do. A ^ 1 = A - output = _float_oper(op1) - output.extend(_fpush()) - return output - - output = _float_oper(op1, op2) - output.append('call __POW') - output.extend(_fpush()) - REQUIRES.add('pow.asm') - return output - - -def _ltf(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand < 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __LTF') - output.append('push af') - REQUIRES.add('ltf.asm') - return output - - -def _gtf(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand > 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __GTF') - output.append('push af') - REQUIRES.add('gtf.asm') - return output - - -def _lef(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand <= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __LEF') - output.append('push af') - REQUIRES.add('lef.asm') - return output - - -def _gef(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand >= 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __GEF') - output.append('push af') - REQUIRES.add('gef.asm') - return output - - -def _eqf(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand == 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __EQF') - output.append('push af') - REQUIRES.add('eqf.asm') - return output - - -def _nef(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand != 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __NEF') - output.append('push af') - REQUIRES.add('nef.asm') - return output - - -def _orf(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand || 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __ORF') - output.append('push af') - REQUIRES.add('orf.asm') - return output - - -def _xorf(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand ~~ 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __XORF') - output.append('push af') - REQUIRES.add('xorf.asm') - return output - - -def _andf(ins): - ''' Compares & pops top 2 operands out of the stack, and checks - if the 1st operand && 2nd operand (top of the stack). - Pushes 0 if False, 1 if True. - - Floating Point version - ''' - op1, op2 = tuple(ins.quad[2:]) - output = _float_oper(op1, op2) - output.append('call __ANDF') - output.append('push af') - REQUIRES.add('andf.asm') - return output - - -def _notf(ins): - ''' Negates top of the stack (48 bits) - ''' - output = _float_oper(ins.quad[2]) - output.append('call __NOTF') - output.append('push af') - REQUIRES.add('notf.asm') - return output - - -def _negf(ins): - ''' Changes sign of top of the stack (48 bits) - ''' - output = _float_oper(ins.quad[2]) - output.append('call __NEGF') - output.extend(_fpush()) - REQUIRES.add('negf.asm') - return output - - -def _absf(ins): - ''' Absolute value of top of the stack (48 bits) - ''' - output = _float_oper(ins.quad[2]) - output.append('res 7, e') # Just resets the sign bit! - output.extend(_fpush()) - return output diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py deleted file mode 100644 index e7be4f410..000000000 --- a/arch/zx48k/backend/__init__.py +++ /dev/null @@ -1,2380 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# vim:ts=4:sw=4:et - -import math -import re -from typing import List - -from . import errors -from .errors import InvalidICError as InvalidIC - - -# 8 bit arithmetic functions -from .__8bit import _add8, _sub8, _mul8, _divu8, _divi8, _modu8, _modi8, _neg8, _abs8 -# 8 bit comparison functions -from .__8bit import _eq8, _lti8, _ltu8, _gti8, _gtu8, _ne8, _leu8, _lei8, _geu8, _gei8 -# 8 bit boolean functions -from .__8bit import _or8, _and8, _not8, _xor8, _8bit_oper -# 8 bit shift operations -from .__8bit import _shru8, _shri8, _shl8 -# 8 bit bitwise operations -from .__8bit import _bor8, _band8, _bnot8, _bxor8 - -# 16 bit arithmetic functions -from .__16bit import _add16, _sub16, _mul16, _divu16, _divi16, _modu16, _modi16, _neg16, _abs16 -# 16 bit comparison functions -from .__16bit import _eq16, _lti16, _ltu16, _gti16, _gtu16, _ne16, _leu16, _lei16, _geu16, _gei16 -# 16 bit boolean functions -from .__16bit import _or16, _and16, _not16, _xor16, _16bit_oper -# 16 bit shift operations -from .__16bit import _shru16, _shri16, _shl16 -# 16 bit bitwise operations -from .__16bit import _band16, _bor16, _bxor16, _bnot16 - -# 32 bit arithmetic functions -from .__32bit import _add32, _sub32, _mul32, _divu32, _divi32, _modu32, _modi32, _neg32, _abs32 -# 32 bit comparison functions -from .__32bit import _eq32, _lti32, _ltu32, _gti32, _gtu32, _ne32, _leu32, _lei32, _geu32, _gei32 -# 32 bit boolean functions -from .__32bit import _or32, _and32, _not32, _xor32, _32bit_oper -# 32 bit shift operations -from .__32bit import _shru32, _shri32, _shl32 -# 32 bit bitwise operations -from .__32bit import _band32, _bor32, _bxor32, _bnot32 - -# Fixed Point arithmetic functions -from .__f16 import _addf16, _subf16, _mulf16, _divf16, _modf16, _negf16, _absf16 -# Fixed Point comparison functions -from .__f16 import _eqf16, _ltf16, _gtf16, _nef16, _lef16, _gef16 -# Fixed Point boolean functions -from .__f16 import _orf16, _andf16, _notf16, _xorf16, _f16_oper - -from .__f16 import f16 # Returns DE,HL of a decimal value - -# Floating Point arithmetic functions -from .__float import _addf, _subf, _mulf, _divf, _modf, _negf, _powf, _absf -# Floating Point comparison functions -from .__float import _eqf, _ltf, _gtf, _nef, _lef, _gef -# Floating Point boolean functions -from .__float import _orf, _andf, _notf, _xorf, _float_oper, _fpush, _fpop - -# String arithmetic functions -from .__str import _addstr -# String comparison functions -from .__str import _ltstr, _gtstr, _eqstr, _lestr, _gestr, _nestr, _str_oper, _lenstr - -# Param load and store instructions -from .__pload import _pload8, _pload16, _pload32, _ploadf, _ploadstr, _fploadstr -from .__pload import _pstore8, _pstore16, _pstore32, _pstoref16, _pstoref, _pstorestr -from .__pload import _paddr - -from . import __common -from .__common import MEMORY, LABEL_COUNTER, TMP_LABELS, TMP_COUNTER, TMP_STORAGES, REQUIRES, INITS -from .__common import is_int, is_float, tmp_label - -# Array store and load instructions -from .__array import _aload8, _aload16, _aload32, _aloadf, _aloadstr -from .__array import _astore8, _astore16, _astore32, _astoref16, _astoref, _astorestr -from .__array import _aaddr - -# Array store and load instructions -from .__parray import _paload8, _paload16, _paload32, _paloadf, _paloadstr -from .__parray import _pastore8, _pastore16, _pastore32, _pastoref16, _pastoref, _pastorestr -from .__parray import _paaddr - -# External functions -from ..optimizer.helpers import HI16, LO16 -from arch.zx48k.optimizer.asm import Asm -from src.api.config import OPTIONS -import src.api.fp - -from arch.zx48k.peephole import engine - - -__all__ = [ - '_fpop', - 'LABEL_COUNTER', - 'MEMORY', - 'TMP_COUNTER', - 'TMP_STORAGES', - 'HI16', - 'LO16', -] - -# Label RegExp -RE_LABEL = re.compile(r'^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') - -# (ix +/- ...) regexp -RE_IX_IDX = re.compile(r'^\([ \t]*ix[ \t]*[-+][ \t]*.+\)$') - -# Label for the program START end EXIT -START_LABEL = '__START_PROGRAM' -END_LABEL = '__END_PROGRAM' -CALL_BACK = '__CALL_BACK__' -MAIN_LABEL = '__MAIN_PROGRAM__' -DATA_LABEL = 'ZXBASIC_USER_DATA' -DATA_END_LABEL = 'ZXBASIC_USER_DATA_END' - -# Whether to use the FunctionExit scheme -FLAG_use_function_exit = False - -# Whether an 'end' has already been emmitted -FLAG_end_emitted = False - -# Default code ORG -OPTIONS.add_option_if_not_defined('org', int, 32768) - -# Default HEAP SIZE (Dynamic memory) in bytes -OPTIONS.add_option_if_not_defined('heap_size', int, 4768) # A bit more than 4K - -# List of modules that, if included, should call MEM_INIT -MEMINITS = ['alloc.asm', 'loadstr.asm', 'storestr2.asm', 'storestr.asm', 'strcpy.asm', - 'string.asm', 'strslice.asm', 'strcat.asm'] - -# Internal data types definition, with its size in bytes, or -1 if it is variable (string) -# Compound types are only arrays, and have the t -YY_TYPES = { - 'u8': 1, # 8 bit unsigned integer - 'u16': 2, # 16 bit unsigned integer - 'u32': 4, # 32 bit unsigned integer - 'i8': 1, # 8 bit SIGNED integer - 'i16': 2, # 16 bit SIGNED integer - 'i32': 4, # 32 bit SIGNED integer - 'f16': 4, # -32768.9999 to 32767.9999 -aprox.- fixed point decimal (step = 1/2^16) - 'f': 5, # Floating point -} - -RE_BOOL = re.compile(r'^(eq|ne|lt|le|gt|ge|and|or|xor|not)(((u|i)(8|16|32))|(f16|f|str))$') -RE_HEXA = re.compile(r'^[0-9A-F]+$') - -# CONSTANT LN(2) -__LN2 = math.log(2) - -# This will be appended at the end (useful for lvard, for example) -AT_END = [] - -# A table with ASM block entered by the USER (these won't be optimized) -ASMS = {} -ASMCOUNT = 0 # ASM blocks counter - - -def init(): - """ Initializes this module - """ - global ASMS - global ASMCOUNT - global AT_END - global FLAG_end_emitted - global FLAG_use_function_exit - - __common.init() - - ASMS = {} - ASMCOUNT = 0 - AT_END = [] - FLAG_use_function_exit = False - FLAG_end_emitted = False - - # Default code ORG - OPTIONS.add_option('org', int, 32768) - # Default HEAP SIZE (Dynamic memory) in bytes - OPTIONS.add_option('heap_size', int, 4768) # A bit more than 4K - # Labels for HEAP START (might not be used if not needed) - OPTIONS.add_option('heap_start_label', str, 'ZXBASIC_MEM_HEAP') - # Labels for HEAP SIZE (might not be used if not needed) - OPTIONS.add_option('heap_size_label', str, 'ZXBASIC_HEAP_SIZE') - # Flag for headerless mode (No prologue / epilogue) - OPTIONS.add_option('headerless', bool, False) - - engine.main() # inits the optimizer - - -def new_ASMID(): - """ Returns a new unique ASM block id - """ - global ASMCOUNT - - result = '##ASM%i' % ASMCOUNT - ASMCOUNT += 1 - return result - - -def log2(x): - """ Returns log2(x) - """ - return math.log(x) / __LN2 - - -def is_2n(x): - """ Returns true if x is an exact - power of 2 - """ - l = log2(x) - return l == int(l) - - -def is_int_type(stype): - """ Returns whether a given type is integer - """ - return stype[0] in ('u', 'i') - - -def get_bytes(elements: List[str]) -> List[str]: - """ Returns a list a default set of bytes/words in hexadecimal - (starting with an hex number) or literals (starting with #). - Numeric values with more than 2 digits represents a WORD (2 bytes) value. - E.g. '01' => 01h, '001' => 1, 0 bytes (0001h) - Literal values starts with # (1 byte) or ## (2 bytes) - E.g. '#label + 1' => (label + 1) & 0xFF - '##(label + 1)' => (label + 1) & 0xFFFF - """ - output = [] - - for x in elements: - if x.startswith('##'): # 2-byte literal - output.append('({}) & 0xFF'.format(x[2:])) - output.append('(({}) >> 8) & 0xFF'.format(x[2:])) - continue - - if x.startswith('#'): # 1-byte literal - output.append('({}) & 0xFF'.format(x[1:])) - continue - - # must be an hex number - assert RE_HEXA.match(x), 'expected an hex number, got "%s"' % x - output.append('%02X' % int(x[-2:], 16)) - if len(x) > 2: - output.append('%02X' % int(x[-4:-2:], 16)) - - return output - - -def get_bytes_size(elements: List[str]) -> int: - """ Defines a memory space with a default set of bytes/words in hexadecimal - (starting with an hex number) or literals (starting with #). - Numeric values with more than 2 digits represents a WORD (2 bytes) value. - E.g. '01' => 01h, '001' => 1, 0 bytes (0001h) - Literal values starts with # (1 byte) or ## (2 bytes) - E.g. '#label + 1' => (label + 1) & 0xFF - '##(label + 1)' => (label + 1) & 0xFFFF - """ - return len(get_bytes(elements)) - - -# ------------------------------------------------------------------ -# Typecast conversions -# ------------------------------------------------------------------ - -def to_byte(stype): - """ Returns the instruction sequence for converting from - the given type to byte. - """ - output = [] - - if stype in ('i8', 'u8'): - return [] - - if is_int_type(stype): - output.append('ld a, l') - elif stype == 'f16': - output.append('ld a, e') - elif stype == 'f': # Converts C ED LH to byte - output.append('call __FTOU32REG') - output.append('ld a, l') - REQUIRES.add('ftou32reg.asm') - - return output - - -def to_word(stype): - """ Returns the instruction sequence for converting the given - type stored in DE,HL to word (unsigned) HL. - """ - output = [] # List of instructions - - if stype == 'u8': # Byte to word - output.append('ld l, a') - output.append('ld h, 0') - - elif stype == 'i8': # Signed byte to word - output.append('ld l, a') - output.append('add a, a') - output.append('sbc a, a') - output.append('ld h, a') - - elif stype == 'f16': # Must MOVE HL into DE - output.append('ex de, hl') - - elif stype == 'f': - output.append('call __FTOU32REG') - REQUIRES.add('ftou32reg.asm') - - return output - - -def to_long(stype): - """ Returns the instruction sequence for converting the given - type stored in DE,HL to long (DE, HL). - """ - output = [] # List of instructions - - if stype in ('i8', 'u8', 'f16'): # Byte to word - output = to_word(stype) - - if stype != 'f16': # If its a byte, just copy H to D,E - output.append('ld e, h') - output.append('ld d, h') - - if stype in ('i16', 'f16'): # Signed byte or fixed to word - output.append('ld a, h') - output.append('add a, a') - output.append('sbc a, a') - output.append('ld e, a') - output.append('ld d, a') - - elif stype == 'u16': - output.append('ld de, 0') - - elif stype == 'f': - output.append('call __FTOU32REG') - REQUIRES.add('ftou32reg.asm') - - return output - - -def to_fixed(stype): - """ Returns the instruction sequence for converting the given - type stored in DE,HL to fixed DE,HL. - """ - output = [] # List of instructions - - if is_int_type(stype): - output = to_word(stype) - output.append('ex de, hl') - output.append('ld hl, 0') # 'Truncate' the fixed point - elif stype == 'f': - output.append('call __FTOF16REG') - REQUIRES.add('ftof16reg.asm') - - return output - - -def to_float(stype): - """ Returns the instruction sequence for converting the given - type stored in DE,HL to fixed DE,HL. - """ - output = [] # List of instructions - - if stype == 'f': - return [] # Nothing to do - - if stype == 'f16': - output.append('call __F16TOFREG') - REQUIRES.add('f16tofreg.asm') - return output - - # If we reach this point, it's an integer type - if stype == 'u8': - output.append('call __U8TOFREG') - elif stype == 'i8': - output.append('call __I8TOFREG') - else: - output = to_long(stype) - if stype in ('i16', 'i32'): - output.append('call __I32TOFREG') - else: - output.append('call __U32TOFREG') - - REQUIRES.add('u32tofreg.asm') - - return output - - -# ------------------------------------------------------------------ -# Lowlevel (to ASM) instructions implementation -# ------------------------------------------------------------------ -def _nop(ins): - """ Returns nothing. (Ignored nop) - """ - return [] - - -def _org(ins): - """ Outputs an origin of code. - """ - return ['org %s' % str(ins.quad[1])] - - -def _exchg(ins): - """ Exchange ALL registers. If the processor - does not support this, it must be implemented saving registers in a memory - location. - """ - output = [] - output.append('ex af, af\'') - output.append('exx') - return output - - -def _end(ins): - """ Outputs the ending sequence - """ - global FLAG_end_emitted - output = _16bit_oper(ins.quad[1]) - output.append('ld b, h') - output.append('ld c, l') - - if FLAG_end_emitted: - return output + ['jp %s' % END_LABEL] - - FLAG_end_emitted = True - - output.append('%s:' % END_LABEL) - if OPTIONS.headerless: - return output + ['ret'] - - output.append('di') - output.append('ld hl, (%s)' % CALL_BACK) - output.append('ld sp, hl') - output.append('exx') - output.append('pop hl') - output.append('exx') - output.append('pop iy') - output.append('pop ix') - output.append('ei') - output.append('ret') - output.append('%s:' % CALL_BACK) - output.append('DEFW 0') - - return output - - -def _label(ins): - """ Defines a Label. - """ - return ['%s:' % str(ins.quad[1])] - - -def _deflabel(ins): - """ Defines a Label with a value. - """ - return ['%s EQU %s' % (str(ins.quad[1]), str(ins.quad[2]))] - - -def _data(ins): - """ Defines a data item (binary). - It's just a constant expression to be converted do binary data "as is" - - 1st parameter is the type-size (u8 or i8 for byte, u16 or i16 for word, etc) - 2nd parameter is the list of expressions. All of them will be converted to the - type required. - """ - output = [] - t = ins.quad[1] - q = eval(ins.quad[2]) - - if t in ('i8', 'u8'): - size = 'B' - elif t in ('i16', 'u16'): - size = 'W' - elif t in ('i32', 'u32'): - size = 'W' - z = list() - for expr in ins.quad[2]: - z.extend(['(%s) & 0xFFFF' % expr, '(%s) >> 16' % expr]) - q = z - elif t == 'str': - size = "B" - q = ['"%s"' % x.replace('"', '""') for x in q] - elif t == 'f': - dat_ = [src.api.fp.immediate_float(float(x)) for x in q] - for x in dat_: - output.extend(['DEFB %s' % x[0], 'DEFW %s, %s' % (x[1], x[2])]) - return output - else: - raise InvalidIC(ins.quad, 'Unimplemented data size %s for %s' % (t, q)) - - for x in q: - output.append('DEF%s %s' % (size, x)) - - return output - - -def _var(ins): - """ Defines a memory variable. - """ - output = [] - output.append('%s:' % ins.quad[1]) - output.append('DEFB %s' % ((int(ins.quad[2]) - 1) * '00, ' + '00')) - - return output - - -def _varx(ins): - """ Defines a memory space with a default CONSTANT expression - 1st parameter is the var name - 2nd parameter is the type-size (u8 or i8 for byte, u16 or i16 for word, etc) - 3rd parameter is the list of expressions. All of them will be converted to the - type required. - """ - output = [] - output.append('%s:' % ins.quad[1]) - q = eval(ins.quad[3]) - - if ins.quad[2] in ('i8', 'u8'): - size = 'B' - elif ins.quad[2] in ('i16', 'u16'): - size = 'W' - elif ins.quad[2] in ('i32', 'u32'): - size = 'W' - z = list() - for expr in q: - z.extend(['(%s) & 0xFFFF' % expr, '(%s) >> 16' % expr]) - q = z - else: - raise InvalidIC(ins.quad, 'Unimplemented vard size: %s' % ins.quad[2]) - - for x in q: - output.append('DEF%s %s' % (size, x)) - - return output - - -def _vard(ins): - """ Defines a memory space with a default set of bytes/words in hexadecimal - (starting with an hex number) or literals (starting with #). - Numeric values with more than 2 digits represents a WORD (2 bytes) value. - E.g. '01' => 01h, '001' => 1, 0 bytes (0001h) - Literal values starts with # (1 byte) or ## (2 bytes) - E.g. '#label + 1' => (label + 1) & 0xFF - '##(label + 1)' => (label + 1) & 0xFFFF - """ - output = [] - output.append('%s:' % ins.quad[1]) - - q = eval(ins.quad[2]) - - for x in q: - if x[0] == '#': # literal? - size_t = 'W' if x[1] == '#' else 'B' - output.append('DEF{0} {1}'.format(size_t, x.lstrip('#'))) - continue - - # must be an hex number - x = x.upper() - assert RE_HEXA.match(x), 'expected an hex number, got "%s"' % x - size_t = 'B' if len(x) <= 2 else 'W' - if x[0] > '9': # Not a number? - x = '0' + x - output.append('DEF{0} {1}h'.format(size_t, x)) - - return output - - -def _lvarx(ins): - """ Defines a local variable. 1st param is offset of the local variable. - 2nd param is the type a list of bytes in hexadecimal. - """ - output = [] - - l = eval(ins.quad[3]) # List of bytes to push - label = tmp_label() - offset = int(ins.quad[1]) - tmp = list(ins.quad) - tmp[1] = label - ins.quad = tmp - AT_END.extend(_varx(ins)) - - output.append('push ix') - output.append('pop hl') - output.append('ld bc, %i' % -offset) - output.append('add hl, bc') - output.append('ex de, hl') - output.append('ld hl, %s' % label) - output.append('ld bc, %i' % (len(l) * YY_TYPES[ins.quad[2]])) - output.append('ldir') - - return output - - -def _lvard(ins): - """ Defines a local variable. 1st param is offset of the local variable. - 2nd param is a list of bytes in hexadecimal. - """ - output = [] - - label = tmp_label() - offset = int(ins.quad[1]) - tmp = list(ins.quad) - tmp[1] = label - ins.quad = tmp - AT_END.extend(_vard(ins)) - - output.append('push ix') - output.append('pop hl') - output.append('ld bc, %i' % -offset) - output.append('add hl, bc') - output.append('ex de, hl') - output.append('ld hl, %s' % label) - output.append('ld bc, %i' % get_bytes_size(eval(tmp[2]))) - output.append('ldir') - - return output - - -def _larrd(ins): - """ Defines a local array. - - 1st param is offset of the local variable. - - 2nd param is a list of bytes in hexadecimal corresponding to the index table - - 3rd param is the size of elements in byte - - 4th param is a list (might be empty) of byte to initialize the array with - - 5th param is a list (might be empty or 2 elements) of [lbound, ubound] labels. - """ - output = [] - - label = tmp_label() - offset = int(ins.quad[1]) - elements_size = ins.quad[3] - AT_END.extend(_vard(Quad('vard', label, ins.quad[2]))) - - bounds = eval(ins.quad[5]) - if not isinstance(bounds, list) or len(bounds) not in (0, 2): - raise InvalidIC(ins.quad, 'Bounds list length must be 0 or 2, not %s' % ins.quad[5]) - - if bounds: - output.extend([ - 'ld hl, %s' % bounds[1], - 'push hl', - 'ld hl, %s' % bounds[0], - 'push hl', - ]) - - must_initialize = ins.quad[4] != '[]' - if must_initialize: - label2 = tmp_label() - AT_END.extend(_vard(Quad('vard', label2, ins.quad[4]))) - output.extend([ - 'ld hl, %s' % label2, - 'push hl' - ]) - - output.extend([ - 'ld hl, %i' % -offset, - 'ld de, %s' % label, - 'ld bc, %s' % elements_size, - ]) - - suffix = '_WITH_BOUNDS' if bounds else '' - if must_initialize: - output.append('call __ALLOC_INITIALIZED_LOCAL_ARRAY' + suffix) - else: - output.append('call __ALLOC_LOCAL_ARRAY' + suffix) - - REQUIRES.add('arrayalloc.asm') - return output - - -def _out(ins): - """ Translates OUT to asm. - """ - output = _8bit_oper(ins.quad[2]) - output.extend(_16bit_oper(ins.quad[1])) - output.append('ld b, h') - output.append('ld c, l') - output.append('out (c), a') - - return output - - -def _in(ins): - """ Translates IN to asm. - """ - output = _16bit_oper(ins.quad[1]) - output.append('ld b, h') - output.append('ld c, l') - output.append('in a, (c)') - output.append('push af') - - return output - - -def _load8(ins): - """ Loads an 8 bit value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - """ - output = _8bit_oper(ins.quad[2]) - output.append('push af') - return output - - -def _load16(ins): - """ Loads a 16 bit value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - """ - output = _16bit_oper(ins.quad[2]) - output.append('push hl') - return output - - -def _load32(ins): - """ Load a 32 bit value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - """ - output = _32bit_oper(ins.quad[2]) - output.append('push de') - output.append('push hl') - return output - - -def _loadf16(ins): - """ Load a 32 bit (16.16) fixed point value from a memory address - If 2nd arg. start with '*', it is always treated as - an indirect value. - """ - output = _f16_oper(ins.quad[2]) - output.append('push de') - output.append('push hl') - return output - - -def _loadf(ins): - """ Loads a floating point value from a memory address. - If 2nd arg. start with '*', it is always treated as - an indirect value. - """ - output = _float_oper(ins.quad[2]) - output.extend(_fpush()) - return output - - -def _loadstr(ins): - """ Loads a string value from a memory address. - """ - temporal, output = _str_oper(ins.quad[2], no_exaf=True) - - if not temporal: - output.append('call __LOADSTR') - REQUIRES.add('loadstr.asm') - - output.append('push hl') - return output - - -def _store8(ins): - """ Stores 2nd operand content into address of 1st operand. - store8 a, x => a = x - Use '*' for indirect store on 1st operand. - """ - output = _8bit_oper(ins.quad[2]) - - op = ins.quad[1] - - indirect = op[0] == '*' - if indirect: - op = op[1:] - - immediate = op[0] == '#' - if immediate: - op = op[1:] - - if is_int(op) or op[0] == '_': - if is_int(op): - op = str(int(op) & 0xFFFF) - - if immediate: - if indirect: - output.append('ld (%s), a' % op) - else: # ??? - output.append('ld (%s), a' % op) - elif indirect: - output.append('ld hl, (%s)' % op) - output.append('ld (hl), a') - else: - output.append('ld (%s), a' % op) - else: - if immediate: - if indirect: # A label not starting with _ - output.append('ld hl, (%s)' % op) - output.append('ld (hl), a') - else: - output.append('ld (%s), a' % op) - return output - else: - output.append('pop hl') - - if indirect: - output.append('ld e, (hl)') - output.append('inc hl') - output.append('ld d, (hl)') - output.append('ld (de), a') - else: - output.append('ld (hl), a') - - return output - - -def _store16(ins): - """ Stores 2nd operand content into address of 1st operand. - store16 a, x => *(&a) = x - Use '*' for indirect store on 1st operand. - """ - output = [] - output = _16bit_oper(ins.quad[2]) - - try: - value = ins.quad[1] - indirect = False - if value[0] == '*': - indirect = True - value = value[1:] - - value = int(value) & 0xFFFF - if indirect: - output.append('ex de, hl') - output.append('ld hl, (%s)' % str(value)) - output.append('ld (hl), e') - output.append('inc hl') - output.append('ld (hl), d') - else: - output.append('ld (%s), hl' % str(value)) - except ValueError: - if value[0] == '_': - if indirect: - output.append('ex de, hl') - output.append('ld hl, (%s)' % str(value)) - output.append('ld (hl), e') - output.append('inc hl') - output.append('ld (hl), d') - else: - output.append('ld (%s), hl' % str(value)) - elif value[0] == '#': - value = value[1:] - if indirect: - output.append('ex de, hl') - output.append('ld hl, (%s)' % str(value)) - output.append('ld (hl), e') - output.append('inc hl') - output.append('ld (hl), d') - else: - output.append('ld (%s), hl' % str(value)) - else: - output.append('ex de, hl') - if indirect: - output.append('pop hl') - output.append('ld a, (hl)') - output.append('inc hl') - output.append('ld h, (hl)') - output.append('ld l, a') - else: - output.append('pop hl') - - output.append('ld (hl), e') - output.append('inc hl') - output.append('ld (hl), d') - - return output - - -def _store32(ins): - """ Stores 2nd operand content into address of 1st operand. - store16 a, x => *(&a) = x - """ - op = ins.quad[1] - - indirect = op[0] == '*' - if indirect: - op = op[1:] - - immediate = op[0] == '#' # Might make no sense here? - if immediate: - op = op[1:] - - if is_int(op) or op[0] == '_' or immediate: - output = _32bit_oper(ins.quad[2], preserveHL=indirect) - - if is_int(op): - op = str(int(op) & 0xFFFF) - - if indirect: - output.append('ld hl, (%s)' % op) - output.append('call __STORE32') - REQUIRES.add('store32.asm') - - return output - - output.append('ld (%s), hl' % op) - output.append('ld (%s + 2), de' % op) - - return output - - output = _32bit_oper(ins.quad[2], preserveHL=True) - output.append('pop hl') - - if indirect: - output.append('call __ISTORE32') - REQUIRES.add('store32.asm') - - return output - - output.append('call __STORE32') - REQUIRES.add('store32.asm') - - return output - - -def _storef16(ins): - """ Stores 2º operand content into address of 1st operand. - store16 a, x => *(&a) = x - """ - value = ins.quad[2] - if is_float(value): - val = float(ins.quad[2]) # Immediate? - (de, hl) = f16(val) - q = list(ins.quad) - q[2] = (de << 16) | hl - ins.quad = tuple(q) - - return _store32(ins) - - -def _storef(ins): - """ Stores a floating point value into a memory address. - """ - output = _float_oper(ins.quad[2]) - - op = ins.quad[1] - - indirect = op[0] == '*' - if indirect: - op = op[1:] - - immediate = op[0] == '#' # Might make no sense here? - if immediate: - op = op[1:] - - if is_int(op) or op[0] == '_': - if is_int(op): - op = str(int(op) & 0xFFFF) - - if indirect: - output.append('ld hl, (%s)' % op) - else: - output.append('ld hl, %s' % op) - else: - output.append('pop hl') - if indirect: - output.append('call __ISTOREF') - REQUIRES.add('storef.asm') - - return output - - output.append('call __STOREF') - REQUIRES.add('storef.asm') - - return output - - -def _storestr(ins): - """ Stores a string value into a memory address. - It copies content of 2nd operand (string), into 1st, reallocating - dynamic memory for the 1st str. These instruction DOES ALLOW - inmediate strings for the 2nd parameter, starting with '#'. - - Must prepend '#' (immediate sigil) to 1st operand, as we need - the & address of the destination. - """ - op1 = ins.quad[1] - indirect = op1[0] == '*' - if indirect: - op1 = op1[1:] - - immediate = op1[0] == '#' - if immediate and not indirect: - raise InvalidIC('storestr does not allow immediate destination', ins.quad) - - if not indirect: - op1 = '#' + op1 - - tmp1, tmp2, output = _str_oper(op1, ins.quad[2], no_exaf=True) - - if not tmp2: - output.append('call __STORE_STR') - REQUIRES.add('storestr.asm') - else: - output.append('call __STORE_STR2') - REQUIRES.add('storestr2.asm') - - return output - - -def _cast(ins): - """ Convert data from typeA to typeB (only numeric data types) - """ - # Signed and unsigned types are the same in the Z80 - tA = ins.quad[2] # From TypeA - tB = ins.quad[3] # To TypeB - - YY_TYPES[tA] # Type sizes - xsB = sB = YY_TYPES[tB] # Type sizes - - output = [] - if tA in ('u8', 'i8'): - output.extend(_8bit_oper(ins.quad[4])) - elif tA in ('u16', 'i16'): - output.extend(_16bit_oper(ins.quad[4])) - elif tA in ('u32', 'i32'): - output.extend(_32bit_oper(ins.quad[4])) - elif tA == 'f16': - output.extend(_f16_oper(ins.quad[4])) - elif tA == 'f': - output.extend(_float_oper(ins.quad[4])) - else: - raise errors.GenericError( - 'Internal error: invalid typecast from %s to %s' % (tA, tB)) - - if tB in ('u8', 'i8'): # It was a byte - output.extend(to_byte(tA)) - elif tB in ('u16', 'i16'): - output.extend(to_word(tA)) - elif tB in ('u32', 'i32'): - output.extend(to_long(tA)) - elif tB == 'f16': - output.extend(to_fixed(tA)) - elif tB == 'f': - output.extend(to_float(tA)) - - xsB += sB % 2 # make it even (round up) - - if xsB > 4: - output.extend(_fpush()) - else: - if xsB > 2: - output.append('push de') # Fixed or 32 bit Integer - - if sB > 1: - output.append('push hl') # 16 bit Integer - else: - output.append('push af') # 8 bit Integer - - return output - - -# ------------------- FLOW CONTROL instructions ------------------- - -def _jump(ins): - """ Jump to a label - """ - return ['jp %s' % str(ins.quad[1])] - - -def _jzero8(ins): - """ Jumps if top of the stack (8bit) is 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) == 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _8bit_oper(value) - output.append('or a') - output.append('jp z, %s' % str(ins.quad[2])) - return output - - -def _jzero16(ins): - """ Jumps if top of the stack (16bit) is 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) == 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _16bit_oper(value) - output.append('ld a, h') - output.append('or l') - output.append('jp z, %s' % str(ins.quad[2])) - return output - - -def _jzero32(ins): - """ Jumps if top of the stack (32bit) is 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) == 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _32bit_oper(value) - output.append('ld a, h') - output.append('or l') - output.append('or e') - output.append('or d') - output.append('jp z, %s' % str(ins.quad[2])) - return output - - -def _jzerof16(ins): - """ Jumps if top of the stack (32bit) is 0 to arg(1) - (For Fixed point 16.16 bit values) - """ - value = ins.quad[1] - if is_float(value): - if float(value) == 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _f16_oper(value) - output.append('ld a, h') - output.append('or l') - output.append('or e') - output.append('or d') - output.append('jp z, %s' % str(ins.quad[2])) - return output - - -def _jzerof(ins): - """ Jumps if top of the stack (40bit, float) is 0 to arg(1) - """ - value = ins.quad[1] - if is_float(value): - if float(value) == 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _float_oper(value) - output.append('ld a, c') - output.append('or l') - output.append('or h') - output.append('or e') - output.append('or d') - output.append('jp z, %s' % str(ins.quad[2])) - return output - - -def _jzerostr(ins): - """ Jumps if top of the stack contains a NULL pointer - or its len is Zero - """ - output = [] - disposable = False # True if string must be freed from memory - - if ins.quad[1][0] == '_': # Variable? - output.append('ld hl, (%s)' % ins.quad[1][0]) - else: - output.append('pop hl') - output.append('push hl') # Saves it for later - disposable = True - - output.append('call __STRLEN') - - if disposable: - output.append('ex (sp), hl') - output.append('call __MEM_FREE') - output.append('pop hl') - REQUIRES.add('alloc.asm') - - output.append('ld a, h') - output.append('or l') - output.append('jp z, %s' % str(ins.quad[2])) - REQUIRES.add('strlen.asm') - return output - - -def _jnzero8(ins): - """ Jumps if top of the stack (8bit) is != 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) != 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _8bit_oper(value) - output.append('or a') - output.append('jp nz, %s' % str(ins.quad[2])) - return output - - -def _jnzero16(ins): - """ Jumps if top of the stack (16bit) is != 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) != 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _16bit_oper(value) - output.append('ld a, h') - output.append('or l') - output.append('jp nz, %s' % str(ins.quad[2])) - return output - - -def _jnzero32(ins): - """ Jumps if top of the stack (32bit) is !=0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) != 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _32bit_oper(value) - output.append('ld a, h') - output.append('or l') - output.append('or e') - output.append('or d') - output.append('jp nz, %s' % str(ins.quad[2])) - return output - - -def _jnzerof16(ins): - """ Jumps if top of the stack (32bit) is !=0 to arg(1) - Fixed Point (16.16 bit) values. - """ - value = ins.quad[1] - if is_float(value): - if float(value) != 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _f16_oper(value) - output.append('ld a, h') - output.append('or l') - output.append('or e') - output.append('or d') - output.append('jp nz, %s' % str(ins.quad[2])) - return output - - -def _jnzerof(ins): - """ Jumps if top of the stack (40bit, float) is != 0 to arg(1) - """ - value = ins.quad[1] - if is_float(value): - if float(value) != 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _float_oper(value) - output.append('ld a, c') - output.append('or l') - output.append('or h') - output.append('or e') - output.append('or d') - output.append('jp nz, %s' % str(ins.quad[2])) - return output - - -def _jnzerostr(ins): - """ Jumps if top of the stack contains a string with - at less 1 char - """ - output = [] - disposable = False # True if string must be freed from memory - - if ins.quad[1][0] == '_': # Variable? - output.append('ld hl, (%s)' % ins.quad[1][0]) - else: - output.append('pop hl') - output.append('push hl') # Saves it for later - disposable = True - - output.append('call __STRLEN') - - if disposable: - output.append('ex (sp), hl') - output.append('call __MEM_FREE') - output.append('pop hl') - REQUIRES.add('alloc.asm') - - output.append('ld a, h') - output.append('or l') - output.append('jp nz, %s' % str(ins.quad[2])) - - REQUIRES.add('strlen.asm') - - return output - - -def _jgezerou8(ins): - """ Jumps if top of the stack (8bit) is >= 0 to arg(1) - Always TRUE for unsigned - """ - output = [] - value = ins.quad[1] - if not is_int(value): - output = _8bit_oper(value) - - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _jgezeroi8(ins): - """ Jumps if top of the stack (8bit) is >= 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) >= 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _8bit_oper(value) - output.append('add a, a') # Puts sign into carry - output.append('jp nc, %s' % str(ins.quad[2])) - return output - - -def _jgezerou16(ins): - """ Jumps if top of the stack (16bit) is >= 0 to arg(1) - Always TRUE for unsigned - """ - output = [] - value = ins.quad[1] - if not is_int(value): - output = _16bit_oper(value) - - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _jgezeroi16(ins): - """ Jumps if top of the stack (16bit) is >= 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) >= 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _16bit_oper(value) - output.append('add hl, hl') # Puts sign into carry - output.append('jp nc, %s' % str(ins.quad[2])) - return output - - -def _jgezerou32(ins): - """ Jumps if top of the stack (23bit) is >= 0 to arg(1) - Always TRUE for unsigned - """ - output = [] - value = ins.quad[1] - if not is_int(value): - output = _32bit_oper(value) - - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _jgezeroi32(ins): - """ Jumps if top of the stack (32bit) is >= 0 to arg(1) - """ - value = ins.quad[1] - if is_int(value): - if int(value) >= 0: - return ['jp %s' % str(ins.quad[2])] # Always true - else: - return [] - - output = _32bit_oper(value) - output.append('ld a, d') - output.append('add a, a') # Puts sign into carry - output.append('jp nc, %s' % str(ins.quad[2])) - return output - - -def _jgezerof16(ins): - """ Jumps if top of the stack (32bit, fixed point) is >= 0 to arg(1) - """ - value = ins.quad[1] - if is_float(value): - if float(value) >= 0: - return ['jp %s' % str(ins.quad[2])] # Always true - - output = _f16_oper(value) - output.append('ld a, d') - output.append('add a, a') # Puts sign into carry - output.append('jp nc, %s' % str(ins.quad[2])) - return output - - -def _jgezerof(ins): - """ Jumps if top of the stack (40bit, float) is >= 0 to arg(1) - """ - value = ins.quad[1] - if is_float(value): - if float(value) >= 0: - return ['jp %s' % str(ins.quad[2])] # Always true - - output = _float_oper(value) - output.append('ld a, e') # Take sign from mantissa (bit 7) - output.append('add a, a') # Puts sign into carry - output.append('jp nc, %s' % str(ins.quad[2])) - return output - - -def _ret(ins): - """ Returns from a procedure / function - """ - return ['jp %s' % str(ins.quad[1])] - - -def _ret8(ins): - """ Returns from a procedure / function an 8bits value - """ - output = _8bit_oper(ins.quad[1]) - output.append('#pragma opt require a') - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _ret16(ins): - """ Returns from a procedure / function a 16bits value - """ - output = _16bit_oper(ins.quad[1]) - output.append('#pragma opt require hl') - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _ret32(ins): - """ Returns from a procedure / function a 32bits value (even Fixed point) - """ - output = _32bit_oper(ins.quad[1]) - output.append('#pragma opt require hl,de') - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _retf16(ins): - """ Returns from a procedure / function a Fixed Point (32bits) value - """ - output = _f16_oper(ins.quad[1]) - output.append('#pragma opt require hl,de') - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _retf(ins): - """ Returns from a procedure / function a Floating Point (40bits) value - """ - output = _float_oper(ins.quad[1]) - output.append('#pragma opt require a,bc,de') - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _retstr(ins): - """ Returns from a procedure / function a string pointer (16bits) value - """ - tmp, output = _str_oper(ins.quad[1], no_exaf=True) - - if not tmp: - output.append('call __LOADSTR') - REQUIRES.add('loadstr.asm') - - output.append('#pragma opt require hl') - output.append('jp %s' % str(ins.quad[2])) - return output - - -def _call(ins): - """ Calls a function XXXX (or address XXXX) - 2nd parameter contains size of the returning result if any, and will be - pushed onto the stack. - """ - output = [] - output.append('call %s' % str(ins.quad[1])) - - try: - val = int(ins.quad[2]) - if val == 1: - output.append('push af') # Byte - else: - if val > 4: - output.extend(_fpush()) - else: - if val > 2: - output.append('push de') - if val > 1: - output.append('push hl') - - except ValueError: - pass - - return output - - -def _leave(ins): - """ Return from a function popping N bytes from the stack - Use '__fastcall__' as 1st parameter, to just return - """ - global FLAG_use_function_exit - - output = [] - - if ins.quad[1] == '__fastcall__': - output.append('ret') - return output - - nbytes = int(ins.quad[1]) # Number of bytes to pop (params size) - - if nbytes == 0: - output.append('ld sp, ix') - output.append('pop ix') - output.append('ret') - - return output - - if nbytes == 1: - output.append('ld sp, ix') - output.append('pop ix') - output.append('inc sp') # "Pops" 1 byte - output.append('ret') - - return output - - if nbytes <= 11: # Number of bytes it worth the hassle to "pop" off the stack - output.append('ld sp, ix') - output.append('pop ix') - output.append('exx') - output.append('pop hl') - for i in range((nbytes >> 1) - 1): - output.append('pop bc') # Removes (n * 2 - 2) bytes form the stack - - if nbytes & 1: # Odd? - output.append('inc sp') # "Pops" 1 byte (This should never happens, since params are always even-sized) - - output.append('ex (sp), hl') # Place back return address - output.append('exx') - output.append('ret') - - return output - - if not FLAG_use_function_exit: - FLAG_use_function_exit = True # Use standard exit - output.append('exx') - output.append('ld hl, %i' % nbytes) - output.append('__EXIT_FUNCTION:') - output.append('ld sp, ix') - output.append('pop ix') - output.append('pop de') - output.append('add hl, sp') - output.append('ld sp, hl') - output.append('push de') - output.append('exx') - output.append('ret') - else: - output.append('exx') - output.append('ld hl, %i' % nbytes) - output.append('jp __EXIT_FUNCTION') - - return output - - -def _enter(ins): - """ Enter function sequence for doing a function start - ins.quad[1] contains size (in bytes) of local variables - Use '__fastcall__' as 1st parameter to prepare a fastcall - function (no local variables). - """ - output = [] - - if ins.quad[1] == '__fastcall__': - return output - - output.append('push ix') - output.append('ld ix, 0') - output.append('add ix, sp') - - size_bytes = int(ins.quad[1]) - - if size_bytes != 0: - if size_bytes < 7: - output.append('ld hl, 0') - output.extend(['push hl'] * (size_bytes >> 1)) - - if size_bytes % 2: # odd? - output.append('push hl') - output.append('inc sp') - else: - output.append('ld hl, -%i' % size_bytes) # "Pushes nn bytes" - output.append('add hl, sp') - output.append('ld sp, hl') - output.append('ld (hl), 0') - output.append('ld bc, %i' % (size_bytes - 1)) - output.append('ld d, h') - output.append('ld e, l') - output.append('inc de') - output.append('ldir') # Clear with ZEROs - - return output - - -def _param8(ins): - """ Pushes 8bit param into the stack - """ - output = _8bit_oper(ins.quad[1]) - output.append('push af') - return output - - -def _param16(ins): - """ Pushes 16bit param into the stack - """ - output = _16bit_oper(ins.quad[1]) - output.append('push hl') - return output - - -def _param32(ins): - """ Pushes 32bit param into the stack - """ - output = _32bit_oper(ins.quad[1]) - output.append('push de') - output.append('push hl') - return output - - -def _paramf16(ins): - """ Pushes 32bit fixed point param into the stack - """ - output = _f16_oper(ins.quad[1]) - output.append('push de') - output.append('push hl') - return output - - -def _paramf(ins): - """ Pushes 40bit (float) param into the stack - """ - output = _float_oper(ins.quad[1]) - output.extend(_fpush()) - return output - - -def _paramstr(ins): - """ Pushes an 16 bit unsigned value, which points - to a string. For indirect values, it will push - the pointer to the pointer :-) - """ - (tmp, output) = _str_oper(ins.quad[1]) - output.pop() # Remove a register flag (useless here) - tmp = ins.quad[1][0] in ('#', '_') # Determine if the string must be duplicated - - if tmp: - output.append('call __LOADSTR') # Must be duplicated - REQUIRES.add('loadstr.asm') - - output.append('push hl') - return output - - -def _fparam8(ins): - """ Passes a byte as a __FASTCALL__ parameter. - This is done by popping out of the stack for a - value, or by loading it from memory (indirect) - or directly (immediate) - """ - return _8bit_oper(ins.quad[1]) - - -def _fparam16(ins): - """ Passes a word as a __FASTCALL__ parameter. - This is done by popping out of the stack for a - value, or by loading it from memory (indirect) - or directly (immediate) - """ - return _16bit_oper(ins.quad[1]) - - -def _fparam32(ins): - """ Passes a dword as a __FASTCALL__ parameter. - This is done by popping out of the stack for a - value, or by loading it from memory (indirect) - or directly (immediate) - """ - return _32bit_oper(ins.quad[1]) - - -def _fparamf16(ins): - """ Passes a 16.16 fixed point as a __FASTCALL__ parameter. - This is done by popping out of the stack for a - value, or by loading it from memory (indirect) - or directly (immediate) - """ - return _f16_oper(ins.quad[1]) - - -def _fparamf(ins): - """ Passes a floating point as a __FASTCALL__ parameter. - This is done by popping out of the stack for a - value, or by loading it from memory (indirect) - or directly (immediate) - """ - return _float_oper(ins.quad[1]) - - -def _fparamstr(ins): - """ Passes a string ptr as a __FASTCALL__ parameter. - This is done by popping out of the stack for a - value, or by loading it from memory (indirect) - or directly (immediate) --prefixed with '#'-- - """ - (tmp1, output) = _str_oper(ins.quad[1]) - - return output - - -def _memcopy(ins): - """ Copies a block of memory from param 2 addr - to param 1 addr. - """ - output = _16bit_oper(ins.quad[3]) - output.append('ld b, h') - output.append('ld c, l') - output.extend(_16bit_oper(ins.quad[1], ins.quad[2], reversed=True)) - output.append('ldir') # *** - - return output - - -def _inline(ins): - """ Inline code - """ - tmp = [x.strip(' \t\r\n') for x in ins.quad[1].split('\n')] # Split lines - - i = 0 - while i < len(tmp): - if not tmp[i] or tmp[i][0] == ';': # a comment or empty string? - tmp.pop(i) - continue - - if tmp[i][0] == '#': # A preprocessor directive - i += 1 - continue - - match = RE_LABEL.match(tmp[i]) - if not match: - tmp[i] = '\t' + tmp[i] - i += 1 - continue - - if len(tmp[i][-1]) == ':': - i += 1 - continue # This is already a single label - - tmp[i] = tmp[i][match.end() + 1:].strip(' \n') - tmp.insert(i, match.group()) - i += 1 - - output = [] - if not tmp: - return output - - ASMLABEL = new_ASMID() - ASMS[ASMLABEL] = tmp - output.append('#line %s' % ins.quad[2]) - output.append(ASMLABEL) - output.append('#line %i' % (int(ins.quad[2]) + len(tmp))) - - return output - - -# -------- 3 address code implementation ---------- - -class Quad(object): - """ Implements a Quad code instruction. - """ - - def __init__(self, *args): - """ Creates a quad-uple checking it has the current params. - Operators should be passed as Quad('+', tSymbol, val1, val2) - """ - if not args: - raise InvalidIC('') - - if args[0] not in QUADS.keys(): - errors.throw_invalid_quad_code(args[0]) - - if len(args) - 1 != QUADS[args[0]][0]: - errors.throw_invalid_quad_params(args[0], len(args) - 1) - - args = tuple([str(x) for x in args]) # Convert it to strings - - self.quad = args - self.op = args[0] - - def __str__(self): - """ String representation - """ - return str(self.quad) - - -# Table describing operations -# 'OPERATOR' -> [Number of arguments] -QUADS = { - 'addu8': [3, _add8], - 'addi8': [3, _add8], - 'addi16': [3, _add16], - 'addu16': [3, _add16], - 'addi32': [3, _add32], - 'addu32': [3, _add32], - 'addf16': [3, _addf16], - 'addf': [3, _addf], - - 'addstr': [3, _addstr], - - 'data': [2, _data], - - 'subi8': [3, _sub8], - 'subu8': [3, _sub8], - 'subi16': [3, _sub16], - 'subu16': [3, _sub16], - 'subi32': [3, _sub32], - 'subu32': [3, _sub32], - 'subf16': [3, _subf16], - 'subf': [3, _subf], - - 'muli8': [3, _mul8], - 'mulu8': [3, _mul8], - 'muli16': [3, _mul16], - 'mulu16': [3, _mul16], - 'muli32': [3, _mul32], - 'mulu32': [3, _mul32], - 'mulf16': [3, _mulf16], - 'mulf': [3, _mulf], - - 'divu8': [3, _divu8], - 'divi8': [3, _divi8], - 'divu16': [3, _divu16], - 'divi16': [3, _divi16], - 'divu32': [3, _divu32], - 'divi32': [3, _divi32], - 'divf16': [3, _divf16], - 'divf': [3, _divf], - - 'powf': [3, _powf], - - 'modu8': [3, _modu8], - 'modi8': [3, _modi8], - 'modu16': [3, _modu16], - 'modi16': [3, _modi16], - 'modu32': [3, _modu32], - 'modi32': [3, _modi32], - 'modf16': [3, _modf16], - 'modf': [3, _modf], - - 'shru8': [3, _shru8], - 'shri8': [3, _shri8], - 'shlu8': [3, _shl8], - 'shli8': [3, _shl8], - - 'shru16': [3, _shru16], - 'shri16': [3, _shri16], - 'shlu16': [3, _shl16], - 'shli16': [3, _shl16], - - 'shru32': [3, _shru32], - 'shri32': [3, _shri32], - 'shlu32': [3, _shl32], - 'shli32': [3, _shl32], - - 'ltu8': [3, _ltu8], - 'lti8': [3, _lti8], - 'ltu16': [3, _ltu16], - 'lti16': [3, _lti16], - 'ltu32': [3, _ltu32], - 'lti32': [3, _lti32], - 'ltf16': [3, _ltf16], - 'ltf': [3, _ltf], - 'ltstr': [3, _ltstr], - - 'gtu8': [3, _gtu8], - 'gti8': [3, _gti8], - 'gtu16': [3, _gtu16], - 'gti16': [3, _gti16], - 'gtu32': [3, _gtu32], - 'gti32': [3, _gti32], - 'gtf16': [3, _gtf16], - 'gtf': [3, _gtf], - 'gtstr': [3, _gtstr], - - 'leu8': [3, _leu8], - 'lei8': [3, _lei8], - 'leu16': [3, _leu16], - 'lei16': [3, _lei16], - 'leu32': [3, _leu32], - 'lei32': [3, _lei32], - 'lef16': [3, _lef16], - 'lef': [3, _lef], - 'lestr': [3, _lestr], - - 'geu8': [3, _geu8], - 'gei8': [3, _gei8], - 'geu16': [3, _geu16], - 'gei16': [3, _gei16], - 'geu32': [3, _geu32], - 'gei32': [3, _gei32], - 'gef16': [3, _gef16], - 'gef': [3, _gef], - 'gestr': [3, _gestr], - - 'equ8': [3, _eq8], - 'eqi8': [3, _eq8], - 'equ16': [3, _eq16], - 'eqi16': [3, _eq16], - 'equ32': [3, _eq32], - 'eqi32': [3, _eq32], - 'eqf16': [3, _eqf16], - 'eqf': [3, _eqf], - 'eqstr': [3, _eqstr], - - 'neu8': [3, _ne8], - 'nei8': [3, _ne8], - 'neu16': [3, _ne16], - 'nei16': [3, _ne16], - 'neu32': [3, _ne32], - 'nei32': [3, _ne32], - 'nef16': [3, _nef16], - 'nef': [3, _nef], - 'nestr': [3, _nestr], - - 'absi8': [2, _abs8], # x = -x if x < 0 - 'absi16': [2, _abs16], # x = -x if x < 0 - 'absi32': [2, _abs32], # x = -x if x < 0 - 'absf16': [2, _absf16], # x = -x if x < 0 - 'absf': [2, _absf], # x = -x if x < 0 - - 'negu8': [2, _neg8], # x = -y - 'negi8': [2, _neg8], # x = -y - 'negu16': [2, _neg16], # x = -y - 'negi16': [2, _neg16], # x = -y - 'negu32': [2, _neg32], # x = -y - 'negi32': [2, _neg32], # x = -y - 'negf16': [2, _negf16], # x = -y - 'negf': [2, _negf], # x = -y - - 'andu8': [3, _and8], # x = A and B - 'andi8': [3, _and8], # x = A and B - 'andu16': [3, _and16], # x = A and B - 'andi16': [3, _and16], # x = A and B - 'andu32': [3, _and32], # x = A and B - 'andi32': [3, _and32], # x = A and B - 'andf16': [3, _andf16], # x = A and B - 'andf': [3, _andf], # x = A and B - - 'oru8': [3, _or8], # x = A or B - 'ori8': [3, _or8], # x = A or B - 'oru16': [3, _or16], # x = A or B - 'ori16': [3, _or16], # x = A or B - 'oru32': [3, _or32], # x = A or B - 'ori32': [3, _or32], # x = A or B - 'orf16': [3, _orf16], # x = A or B - 'orf': [3, _orf], # x = A or B - - 'xoru8': [3, _xor8], # x = A xor B - 'xori8': [3, _xor8], # x = A xor B - 'xoru16': [3, _xor16], # x = A xor B - 'xori16': [3, _xor16], # x = A xor B - 'xoru32': [3, _xor32], # x = A xor B - 'xori32': [3, _xor32], # x = A xor B - 'xorf16': [3, _xorf16], # x = A xor B - 'xorf': [3, _xorf], # x = A xor B - - 'notu8': [2, _not8], # x = not B - 'noti8': [2, _not8], # x = not B - 'notu16': [2, _not16], # x = not B - 'noti16': [2, _not16], # x = not B - 'notu32': [2, _not32], # x = not B - 'noti32': [2, _not32], # x = not B - 'notf16': [2, _notf16], # x = not B - 'notf': [2, _notf], # x = not B - - 'jump': [1, _jump], # jmp LABEL - - 'lenstr': [2, _lenstr], # Gets strlen - - 'jzeroi8': [2, _jzero8], # if X == 0 jmp LABEL - 'jzerou8': [2, _jzero8], # if X == 0 jmp LABEL - 'jzeroi16': [2, _jzero16], # if X == 0 jmp LABEL - 'jzerou16': [2, _jzero16], # if X == 0 jmp LABEL - 'jzeroi32': [2, _jzero32], # if X == 0 jmp LABEL (32bit, fixed) - 'jzerou32': [2, _jzero32], # if X == 0 jmp LABEL (32bit, fixed) - 'jzerof16': [2, _jzerof16], # if X == 0 jmp LABEL (32bit, fixed) - 'jzerof': [2, _jzerof], # if X == 0 jmp LABEL (float) - 'jzerostr': [2, _jzerostr], # if str is NULL or len(str) == 0, jmp LABEL - - 'jnzeroi8': [2, _jnzero8], # if X != 0 jmp LABEL - 'jnzerou8': [2, _jnzero8], # if X != 0 jmp LABEL - 'jnzeroi16': [2, _jnzero16], # if X != 0 jmp LABEL - 'jnzerou16': [2, _jnzero16], # if X != 0 jmp LABEL - 'jnzeroi32': [2, _jnzero32], # if X != 0 jmp LABEL (32bit, fixed) - 'jnzerou32': [2, _jnzero32], # if X != 0 jmp LABEL (32bit, fixed) - 'jnzerof16': [2, _jnzerof16], # if X != 0 jmp LABEL (32bit, fixed) - 'jnzerof': [2, _jnzerof], # if X != 0 jmp LABEL (float) - 'jnzerostr': [2, _jnzerostr], # if str is not NULL and len(str) > 0, jmp LABEL - - 'jgezeroi8': [2, _jgezeroi8], # if X >= 0 jmp LABEL - 'jgezerou8': [2, _jgezerou8], # if X >= 0 jmp LABEL (ALWAYS TRUE) - 'jgezeroi16': [2, _jgezeroi16], # if X >= 0 jmp LABEL - 'jgezerou16': [2, _jgezerou16], # if X >= 0 jmp LABEL (ALWAYS TRUE) - 'jgezeroi32': [2, _jgezeroi32], # if X >= 0 jmp LABEL (32bit, fixed) - 'jgezerou32': [2, _jgezerou32], # if X >= 0 jmp LABEL (32bit, fixed) (always true) - 'jgezerof16': [2, _jgezerof16], # if X >= 0 jmp LABEL (32bit, fixed) - 'jgezerof': [2, _jgezerof], # if X >= 0 jmp LABEL (float) - - 'paramu8': [1, _param8], # Push 8 bit param onto the stack - 'parami8': [1, _param8], # Push 8 bit param onto the stack - 'paramu16': [1, _param16], # Push 16 bit param onto the stack - 'parami16': [1, _param16], # Push 16 bit param onto the stack - 'paramu32': [1, _param32], # Push 32 bit param onto the stack - 'parami32': [1, _param32], # Push 32 bit param onto the stack - 'paramf16': [1, _paramf16], # Push 32 bit param onto the stack - 'paramf': [1, _paramf], # Push float param - 6 BYTES (always even) onto the stack - 'paramstr': [1, _paramstr], # Push float param - 6 BYTES (always even) onto the stack - - 'fparamu8': [1, _fparam8], # __FASTCALL__ parameter - 'fparami8': [1, _fparam8], # __FASTCALL__ parameter - 'fparamu16': [1, _fparam16], # __FASTCALL__ parameter - 'fparami16': [1, _fparam16], # __FASTCALL__ parameter - 'fparamu32': [1, _fparam32], # __FASTCALL__ parameter - 'fparami32': [1, _fparam32], # __FASTCALL__ parameter - 'fparamf16': [1, _fparamf16], # __FASTCALL__ parameter - 'fparamf': [1, _fparamf], # __FASTCALL__ parameter - 'fparamstr': [1, _fparamstr], # __FASTCALL__ parameter - - 'call': [2, _call], # Call Address, NNNN --- NNNN = Size (in bytes) of the returned value (0 for procedure) - - 'ret': [1, _ret], # Returns from a function call (enters the 'leave' sequence'), returning no value - 'reti8': [2, _ret8], # Returns from a function call (enters the 'leave' sequence'), returning 8 bit value - 'retu8': [2, _ret8], # Returns from a function call (enters the 'leave' sequence'), returning 8 bit value - 'reti16': [2, _ret16], # Returns from a function call (enters the 'leave' sequence'), returning 16 bit value - 'retu16': [2, _ret16], # Returns from a function call (enters the 'leave' sequence'), returning 16 bit value - 'reti32': [2, _ret32], # Returns from a function call (enters the 'leave' sequence'), returning 32 bit value - 'retu32': [2, _ret32], # Returns from a function call (enters the 'leave' sequence'), returning 32 bit value - 'retf16': [2, _retf16], # Returns from a function call (enters the 'leave' sequence'), returning fixed point - 'retf': [2, _retf], # Returns from a function call (enters the 'leave' sequence'), returning fixed point - 'retstr': [2, _retstr], # Returns from a function call (enters the 'leave' sequence'), returning fixed point - - 'leave': [1, _leave], # LEAVE label, NN -> NN = Size of parameters in bytes (End of function