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') REQUIRES.add('and8.asm') return output
def _pstoref(ins): ''' Stores 2nd parameter at stack pointer (SP) + X, being X 1st parameter. 1st operand must be a SIGNED integer. ''' value = ins.quad[2] offset = ins.quad[1] indirect = offset[0] == '*' if indirect: offset = offset[1:] I = int(offset) if I >= 0: I += 4 # Return Address + "push IX" output = _float_oper(value) if indirect: output.append('ld hl, %i' % I) output.append('call __PISTOREF') REQUIRES.add('storef.asm') return output # direct store output.append('ld hl, %i' % I) output.append('call __PSTOREF') REQUIRES.add('pstoref.asm') 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') output.append('push af') REQUIRES.add('and8.asm') return output
def _pstoref16(ins): ''' Stores 2nd parameter at stack pointer (SP) + X, being X 1st parameter. 1st operand must be a SIGNED integer. ''' value = ins.quad[2] offset = ins.quad[1] indirect = offset[0] == '*' bytes = 3 if indirect: offset = offset[1:] I = int(offset) if I >= 0: I += 4 # Return Address + "push IX" output = _f16_oper(value) ix_changed = not (-128 + bytes <= I <= 127 - bytes) # Offset > 127 bytes. Need to change IX if indirect: output.append('ld bc, %i' % I) output.append('call __PISTORE32') REQUIRES.add('pistore32.asm') return output # direct store output.append('ld bc, %i' % I) output.append('call __PSTORE32') REQUIRES.add('pstore32.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 _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_int(op2): if int(op2) == 1: output = _f16b_opers(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 _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 _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 _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 _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 _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 _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 _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 _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 _pastore16(ins): ''' Stores 2º operand content into address of 1st operand. store16 a, x => *(&a) = x Use '*' for indirect store on 1st operand. ''' output = _paddr(ins.quad[1]) value = ins.quad[2] if value[0] == '*': value = value[1:] indirect = True else: indirect = False try: value = int(ins.quad[2]) & 0xFFFF output.append('ld de, %i' % value) if indirect: output.append('call __LOAD_DE_DE') REQUIRES.add('lddede.asm') except ValueError: output.append('pop de') output.append('ld (hl), e') output.append('inc hl') output.append('ld (hl), d') 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 _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 _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_int(op2): if int(op2) == 1: output = _f16b_opers(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 _pastoref16(ins): ''' Stores 2º operand content into address of 1st operand. storef16 a, x => *(&a) = x ''' output = _paddr(ins.quad[1]) value = ins.quad[2] if value[0] == '*': value = value[1:] indirect = True else: indirect = False try: if indirect: value = int(ins.quad[2]) 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: de, hl = f16(value) output.append('ld de, %i' % de) output.append('ld bc, %i' % hl) except ValueError: output.append('pop bc') output.append('pop de') output.append('call __STORE32') REQUIRES.add('store32.asm') return output
def _paddr(offset): ''' Generic array address parameter loading. Emmits output code for setting IX at the right location. bytes = Number of bytes to load: 1 => 8 bit value 2 => 16 bit value / string 4 => 32 bit value / f16 value 5 => 40 bit value ''' output = [] indirect = offset[0] == '*' if indirect: offset = offset[1:] I = int(offset) if I >= 0: I += 4 # Return Address + "push IX" output.append('push ix') output.append('pop hl') output.append('ld de, %i' % I) output.append('add hl, de') 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 _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 _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 _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 _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 _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 _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 _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 _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 _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 _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 _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 _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