{ Copyright (c) 2008 by Florian Klaempfl Member of the Free Pascal development team This unit implements the code generator for the MOS Technology 65 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************** } unit cgcpu; {$i fpcdefs.inc} interface uses globtype,symtype,symdef, cgbase,cgutils,cgobj, aasmbase,aasmcpu,aasmtai,aasmdata, parabase, cpubase,cpuinfo,node,cg64f32,rgcpu; type tregisterlist = array of tregister; { tcgmos6502 } tcgmos6502 = class(tcg) { true, if the next arithmetic operation should modify the flags } cgsetflags : boolean; procedure init_register_allocators;override; procedure done_register_allocators;override; procedure getcpuregisters(list:TAsmList;regs:tregisterlist); procedure ungetcpuregisters(list:TAsmList;regs:tregisterlist); function getaddressregister(list:TAsmList):TRegister;override; function GetOffsetReg(const r: TRegister;ofs : shortint): TRegister;override; function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): TRegister;override; procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override; procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);override; procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override; procedure a_load_reg_cgpara(list : TAsmList; size : tcgsize;r : tregister; const cgpara : tcgpara);override; procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const cgpara : TCGPara);override; procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override; procedure a_call_reg(list : TAsmList;reg: tregister);override; procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override; procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override; { move instructions } procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override; procedure a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);override; procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override; procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override; procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override; { fpu move instructions } procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override; procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override; procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override; { comparison operations } procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; l : tasmlabel);override; procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override; procedure a_jmp_name(list : TAsmList;const s : string); override; procedure a_jmp_always(list : TAsmList;l: tasmlabel); override; procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override; { 6502-specific unsigned comparison code generation jmp helper } procedure a_jmp_unsigned_cmp_3way(list : TAsmList;onbelow,onequal,onabove: tasmlabel); { 6502-specific signed comparison code generation jmp helper } procedure a_jmp_signed_cmp_3way(list : TAsmList;onless,onequal,ongreater: tasmlabel); procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override; procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override; procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override; procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override; procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override; procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override; procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override; procedure g_save_registers(list : TAsmList);override; procedure g_restore_registers(list : TAsmList);override; procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel); //function normalize_ref(list : TAsmList;ref : treference; const refopertypes:trefoperandtypes; out allocatedregs:tregisterlist) : treference; procedure adjust_normalized_ref(list: TAsmList;var ref: treference; value: longint); procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister); //procedure a_adjust_sp(list: TAsmList; value: longint); protected procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister); procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister); procedure gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean); end; tcg64fmos6502 = class(tcg64f32) procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override; procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override; end; procedure create_codegen; { OP_NONE, OP_MOVE, { replaced operation with direct load } OP_ADD, { simple addition } OP_AND, { simple logical and } OP_DIV, { simple unsigned division } OP_IDIV, { simple signed division } OP_IMUL, { simple signed multiply } OP_MUL, { simple unsigned multiply } OP_NEG, { simple negate } OP_NOT, { simple logical not } OP_OR, { simple logical or } OP_SAR, { arithmetic shift-right } OP_SHL, { logical shift left } OP_SHR, { logical shift right } OP_SUB, { simple subtraction } OP_XOR, { simple exclusive or } OP_ROL, { rotate left } OP_ROR { rotate right } } const TOpCG2AsmOp: Array[topcg] of TAsmOp = ( A_NONE, { OP_NONE } A_NONE, { OP_MOVE } A_NONE, { OP_ADD } A_AND, { OP_AND } A_NONE, { OP_DIV } A_NONE, { OP_IDIV } A_NONE, { OP_IMUL } A_NONE, { OP_MUL } A_NONE, { OP_NEG } A_NONE, { OP_NOT } A_ORA, { OP_OR } A_NONE, { OP_SAR } A_ASL, { OP_SHL } A_LSR, { OP_SHR } A_NONE, { OP_SUB } A_EOR, { OP_XOR } A_NONE, { OP_ROL } A_NONE); { OP_ROR } implementation uses globals,verbose,systems,cutils, fmodule, symconst,symsym,symtable, tgobj,rgobj, procinfo,cpupi, paramgr; function ref2string(const ref : treference) : string; begin result:='[base:'+std_regname(ref.base)+' index:'+std_regname(ref.index)+' refaddr:' + tostr(ord(ref.refaddr)) + ' offset:' + tostr(ref.offset) + ' symbol:'; if (assigned(ref.symbol)) then result := result + ref.symbol.name; result:=result+']'; end; function use_push(const cgpara:tcgpara):boolean; begin result:=(not paramanager.use_fixed_stack) and assigned(cgpara.location) and (cgpara.location^.loc=LOC_REFERENCE) and (cgpara.location^.reference.index=NR_STACK_POINTER_REG); end; procedure tcgmos6502.init_register_allocators; begin inherited init_register_allocators; rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE, [RS_RZB0,RS_RZB1,RS_RZB2,RS_RZB3,RS_RZB4,RS_RZB5,RS_RZB6,RS_RZB7,RS_RZB8,RS_RZB9,RS_RZB10,RS_RZB11,RS_RZB249, RS_RZW187,RS_RZW243,RS_RZW245,RS_RZW247],first_int_imreg,[]); end; procedure tcgmos6502.done_register_allocators; begin rg[R_INTREGISTER].free; inherited done_register_allocators; end; procedure tcgmos6502.getcpuregisters(list: TAsmList; regs: tregisterlist); var r: tregister; begin for r in regs do getcpuregister(list,r); end; procedure tcgmos6502.ungetcpuregisters(list: TAsmList; regs: tregisterlist); var r: tregister; begin for r in regs do ungetcpuregister(list,r); end; function tcgmos6502.getaddressregister(list: TAsmList): TRegister; begin Result:=getintregister(list,OS_ADDR); end; function tcgmos6502.GetOffsetReg(const r: TRegister; ofs: shortint): TRegister; var i: Integer; begin result:=r; for i:=1 to ofs do result:=GetNextReg(result); end; function tcgmos6502.GetOffsetReg64(const r, rhi: TRegister; ofs: shortint): TRegister; var i: Integer; begin if ofs>=4 then begin result:=rhi; dec(ofs,4); end else result:=r; for i:=1 to ofs do result:=GetNextReg(result); end; procedure tcgmos6502.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara); //procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation); // var // ref : treference; // begin // paramanager.allocparaloc(list,paraloc); // case paraloc^.loc of // LOC_REGISTER,LOC_CREGISTER: // a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register); // LOC_REFERENCE,LOC_CREFERENCE: // begin // reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,ctempposinvalid,2,[]); // a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref); // end; // else // internalerror(2002071003); // end; // end; // //var // i, i2 : longint; // hp : PCGParaLocation; begin //if use_push(cgpara) then // begin // case tcgsize2size[cgpara.Size] of // 1: // begin // cgpara.check_simple_location; // getcpuregister(list,NR_A); // a_load_reg_reg(list,OS_8,OS_8,r,NR_A); // list.concat(taicpu.op_reg(A_PUSH,NR_AF)); // list.concat(taicpu.op_reg(A_INC,NR_SP)); // ungetcpuregister(list,NR_A); // end; // 2: // begin // cgpara.check_simple_location; // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,r,NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H); // list.concat(taicpu.op_reg(A_PUSH,NR_HL)); // getcpuregister(list,NR_H); // getcpuregister(list,NR_L); // end; // 4: // begin // cgpara.check_simple_location; // // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(GetNextReg(r)),NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(GetNextReg(GetNextReg(r))),NR_H); // list.concat(taicpu.op_reg(A_PUSH,NR_HL)); // getcpuregister(list,NR_H); // getcpuregister(list,NR_L); // // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,r,NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H); // list.concat(taicpu.op_reg(A_PUSH,NR_HL)); // getcpuregister(list,NR_H); // getcpuregister(list,NR_L); // end; // else // internalerror(2020040801); // end; // end //else // begin // if not(tcgsize2size[cgpara.Size] in [1..4]) then // internalerror(2014011101); // // hp:=cgpara.location; // // i:=0; // while iWord(a shr 16) then // list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a))); // list.Concat(taicpu.op_reg(A_PUSH,NR_IY)); // ungetcpuregister(list,NR_IY); // end; // else // internalerror(2020040701); // end; // end //else // begin // hp:=paraloc.location; // // i:=1; // while i<=tcgsize2size[paraloc.Size] do // begin // if not(assigned(hp)) then // internalerror(2014011105); // //paramanager.allocparaloc(list,hp); // case hp^.loc of // LOC_REGISTER,LOC_CREGISTER: // begin // if (tcgsize2size[hp^.size]<>1) or // (hp^.shiftval<>0) then // internalerror(2015041101); // a_load_const_reg(list,hp^.size,(a shr (8*(i-1))) and $ff,hp^.register); // // inc(i,tcgsize2size[hp^.size]); // hp:=hp^.Next; // end; // LOC_REFERENCE,LOC_CREFERENCE: // begin // reference_reset(ref,paraloc.alignment,[]); // ref.base:=hp^.reference.index; // ref.offset:=hp^.reference.offset; // a_load_const_ref(list,hp^.size,a shr (8*(i-1)),ref); // // inc(i,tcgsize2size[hp^.size]); // hp:=hp^.Next; // end; // else // internalerror(2002071005); // end; // end; // end; end; procedure tcgmos6502.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara); //procedure pushdata(paraloc:pcgparalocation;ofs:tcgint); //var // pushsize : tcgsize; // opsize : topsize; // tmpreg : tregister; // href,tmpref: treference; //begin // if not assigned(paraloc) then // exit; // if (paraloc^.loc<>LOC_REFERENCE) or // (paraloc^.reference.index<>NR_STACK_POINTER_REG) or // (tcgsize2size[paraloc^.size]>4) then // internalerror(200501162); // { Pushes are needed in reverse order, add the size of the // current location to the offset where to load from. This // prevents wrong calculations for the last location when // the size is not a power of 2 } // if assigned(paraloc^.next) then // pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]); // { Push the data starting at ofs } // href:=r; // inc(href.offset,ofs); // {if tcgsize2size[paraloc^.size]>cgpara.alignment then} // pushsize:=paraloc^.size // {else // pushsize:=int_cgsize(cgpara.alignment)}; // {Writeln(pushsize);} // case tcgsize2size[pushsize] of // 1: // begin // tmpreg:=getintregister(list,OS_8); // a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg); // getcpuregister(list,NR_A); // a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A); // list.concat(taicpu.op_reg(A_PUSH,NR_AF)); // list.concat(taicpu.op_reg(A_INC,NR_SP)); // ungetcpuregister(list,NR_A); // end; // 2: // begin // tmpreg:=getintregister(list,OS_16); // a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg); // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H); // list.concat(taicpu.op_reg(A_PUSH,NR_HL)); // ungetcpuregister(list,NR_H); // ungetcpuregister(list,NR_L); // end; // 4: // begin // tmpreg:=getintregister(list,OS_16); // inc(href.offset,2); // a_load_ref_reg(list,OS_16,OS_16,href,tmpreg); // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H); // list.concat(taicpu.op_reg(A_PUSH,NR_HL)); // ungetcpuregister(list,NR_H); // ungetcpuregister(list,NR_L); // dec(href.offset,2); // a_load_ref_reg(list,OS_16,OS_16,href,tmpreg); // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H); // list.concat(taicpu.op_reg(A_PUSH,NR_HL)); // ungetcpuregister(list,NR_H); // ungetcpuregister(list,NR_L); // end; // else // internalerror(2020040803); // end; //end; //var // tmpref, ref, href: treference; // location: pcgparalocation; // sizeleft: tcgint; // len: tcgint; begin //{ cgpara.size=OS_NO requires a copy on the stack } //if use_push(cgpara) then // begin // { Record copy? } // if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then // begin // cgpara.check_simple_location; // len:=align(cgpara.intsize,cgpara.alignment); // g_stackpointer_alloc(list,len); // reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]); // g_concatcopy(list,r,href,len); // end // else // begin // if tcgsize2size[cgpara.size]<>tcgsize2size[size] then // internalerror(200501161); // { We need to push the data in reverse order, // therefor we use a recursive algorithm } // pushdata(cgpara.location,0); // end // end //else // begin // location := cgpara.location; // tmpref := r; // sizeleft := cgpara.intsize; // while assigned(location) do // begin // paramanager.allocparaloc(list,location); // case location^.loc of // LOC_REGISTER,LOC_CREGISTER: // a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register); // LOC_REFERENCE: // begin // reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,cgpara.alignment,[]); // { doubles in softemu mode have a strange order of registers and references } // if location^.size=OS_32 then // g_concatcopy(list,tmpref,ref,4) // else // begin // g_concatcopy(list,tmpref,ref,sizeleft); // if assigned(location^.next) then // internalerror(2005010710); // end; // end; // LOC_VOID: // begin // // nothing to do // end; // else // internalerror(2002081103); // end; // inc(tmpref.offset,tcgsize2size[location^.size]); // dec(sizeleft,tcgsize2size[location^.size]); // location := location^.next; // end; // end; end; procedure tcgmos6502.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara); var tmpreg: tregister; begin tmpreg:=getaddressregister(list); a_loadaddr_ref_reg(list,r,tmpreg); a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc); end; procedure tcgmos6502.a_call_name(list : TAsmList;const s : string; weak: boolean); var sym: TAsmSymbol; begin if weak then sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION) else sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION); list.concat(taicpu.op_sym(A_JSR,sym)); include(current_procinfo.flags,pi_do_call); end; procedure tcgmos6502.a_call_reg(list : TAsmList;reg: tregister); //var // l : TAsmLabel; // ref : treference; begin //{ HACK: at this point all registers are allocated, due to the way the // calling convention works, but we need to free some registers, in order // for the following code to work, so we do it here } //dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); // //getcpuregister(list,NR_L); //a_load_reg_reg(list,OS_8,OS_8,reg,NR_L); //getcpuregister(list,NR_H); //a_load_reg_reg(list,OS_8,OS_8,GetNextReg(reg),NR_H); //current_asmdata.getjumplabel(l); //reference_reset(ref,0,[]); //ref.symbol:=l; //list.concat(taicpu.op_ref_reg(A_LD,ref,NR_HL)); //ungetcpuregister(list,NR_H); //ungetcpuregister(list,NR_L); // //{ allocate them again, right before the actual call instruction } //alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); // //list.concat(tai_const.Create_8bit($CD)); { $CD is the opcode of the call instruction } //list.concat(tai_label.Create(l)); //list.concat(tai_const.Create_16bit(0)); //include(current_procinfo.flags,pi_do_call); end; procedure tcgmos6502.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); begin list.Concat(tai_comment.Create(strpnew('TODO: a_op_const_reg '+topcg2str(Op)+' '+tcgsize2str(size)+' '+tostr(a)+' '+std_regname(reg)))); if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then internalerror(2012102403); a_op_const_reg_internal(list,Op,size,a,reg,NR_NO); end; procedure tcgmos6502.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); begin list.Concat(tai_comment.Create(strpnew('TODO: a_op_reg_reg '+topcg2str(Op)+' '+tcgsize2str(size)+' '+std_regname(src)+' '+std_regname(dst)))); if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then internalerror(2012102401); a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO); end; procedure tcgmos6502.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister); var i : integer; procedure NextSrcDst; begin if i=5 then begin dst:=dsthi; src:=srchi; end else begin dst:=GetNextReg(dst); src:=GetNextReg(src); end; end; const shiftcountreg = NR_X; maskshiftcount = true; var skipshift, shiftloopstart, rornocarry: TAsmLabel; shiftthruaccumulator: Boolean; // tmpreg,tmpreg2: tregister; // instr : taicpu; // l1,l2 : tasmlabel; begin case op of OP_ADD: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); list.concat(taicpu.op_none(A_CLC)); list.concat(taicpu.op_reg(A_ADC,src)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then begin for i:=2 to tcgsize2size[size] do begin NextSrcDst; a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); list.concat(taicpu.op_reg(A_ADC,src)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); end; end; ungetcpuregister(list,NR_A); end; OP_SUB: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); list.concat(taicpu.op_none(A_SEC)); list.concat(taicpu.op_reg(A_SBC,src)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then begin for i:=2 to tcgsize2size[size] do begin NextSrcDst; a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); list.concat(taicpu.op_reg(A_SBC,src)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); end; end; ungetcpuregister(list,NR_A); end; OP_NEG: begin getcpuregister(list,NR_A); list.concat(taicpu.op_none(A_SEC)); for i:=1 to tcgsize2size[size] do begin if i<>1 then NextSrcDst; a_load_const_reg(list,OS_8,0,NR_A); list.concat(taicpu.op_reg(A_SBC,src)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); end; end; OP_NOT: begin getcpuregister(list,NR_A); for i:=1 to tcgsize2size[size] do begin if i<>1 then NextSrcDst; a_load_reg_reg(list,OS_8,OS_8,src,NR_A); list.concat(taicpu.op_const(A_EOR,$FF)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); end; ungetcpuregister(list,NR_A); end; // OP_MUL,OP_IMUL: // begin // tmpreg:=dst; // if size in [OS_16,OS_S16] then // begin // tmpreg:=getintregister(list,size); // a_load_reg_reg(list,size,size,dst,tmpreg); // end; // gen_multiply(list,op,size,src,tmpreg,dst,false); // end; OP_DIV,OP_IDIV: { special stuff, needs separate handling inside code generator } internalerror(2017032604); OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR: begin current_asmdata.getjumplabel(skipshift); current_asmdata.getjumplabel(shiftloopstart); if maskshiftcount then begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,src,NR_A); case size of OS_64,OS_S64: list.Concat(taicpu.op_const(A_AND,63)); OS_32,OS_S32,OS_16,OS_S16,OS_8,OS_S8: list.Concat(taicpu.op_const(A_AND,31)); else internalerror(2024050101); end; list.Concat(taicpu.op_cond_sym(A_Bxx,C_EQ,skipshift)); getcpuregister(list,shiftcountreg); a_load_reg_reg(list,OS_8,OS_8,NR_A,shiftcountreg); { TAX/TAY } ungetcpuregister(list,NR_A); end else begin getcpuregister(list,shiftcountreg); a_load_reg_reg(list,OS_8,OS_8,src,shiftcountreg); { LDX/LDY } { BEQ skip (the zero flag has already been set by the LDX/LDY instruction) } list.Concat(taicpu.op_cond_sym(A_Bxx,C_EQ,skipshift)); end; shiftthruaccumulator:=(size in [OS_8,OS_S8]) and not(cs_opt_size in current_settings.optimizerswitches); if shiftthruaccumulator then begin { mov dest to A } getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); end; cg.a_label(list,shiftloopstart); if shiftthruaccumulator then case op of OP_SHL,OP_SHR: list.concat(taicpu.op_reg(topcg2asmop[op],NR_A)); OP_SAR: begin list.concat(taicpu.op_const(A_CMP,$80)); list.concat(taicpu.op_reg(A_ROR,NR_A)); end; OP_ROL: begin list.concat(taicpu.op_reg(A_ASL,NR_A)); list.concat(taicpu.op_const(A_ADC,0)); end; OP_ROR: begin list.concat(taicpu.op_reg(A_LSR,NR_A)); current_asmdata.getjumplabel(rornocarry); list.concat(taicpu.op_cond_sym(A_Bxx,C_CC,rornocarry)); list.concat(taicpu.op_const(A_ADC,$7F)); cg.a_label(list,rornocarry); end; else internalerror(2024050102); end else case op of OP_SHL: begin list.concat(taicpu.op_reg(A_ASL,dst)); for i:=1 to tcgsize2size[size]-1 do list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(dst,dsthi,i))); end; OP_ROL: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); list.concat(taicpu.op_reg(A_ASL,NR_A)); for i:=1 to tcgsize2size[size]-1 do list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(dst,dsthi,i))); list.concat(taicpu.op_const(A_ADC,0)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); ungetcpuregister(list,NR_A); end; OP_SHR: begin list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1))); for i:=tcgsize2size[size]-2 downto 0 do list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,i))); end; OP_SAR: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1),NR_A); list.concat(taicpu.op_const(A_CMP,$80)); list.concat(taicpu.op_reg(A_ROR,NR_A)); a_load_reg_reg(list,OS_8,OS_8,NR_A,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)); ungetcpuregister(list,NR_A); for i:=tcgsize2size[size]-2 downto 0 do list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,i))); end; OP_ROR: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1),NR_A); list.concat(taicpu.op_reg(A_LSR,NR_A)); for i:=tcgsize2size[size]-2 downto 0 do list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,i))); current_asmdata.getjumplabel(rornocarry); list.concat(taicpu.op_cond_sym(A_Bxx,C_CC,rornocarry)); list.concat(taicpu.op_const(A_ADC,$7F)); cg.a_label(list,rornocarry); a_load_reg_reg(list,OS_8,OS_8,NR_A,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)); ungetcpuregister(list,NR_A); end; else internalerror(2024050104); end; { DEX/DEY } case shiftcountreg of NR_X: list.concat(taicpu.op_none(A_DEX)); NR_Y: list.concat(taicpu.op_none(A_DEY)); else internalerror(2024050103); end; list.concat(taicpu.op_cond_sym(A_Bxx,C_NE,shiftloopstart)); { mov A to dest } if shiftthruaccumulator then begin a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); ungetcpuregister(list,NR_A); end; cg.a_label(list,skipshift); end; OP_AND,OP_OR,OP_XOR: begin getcpuregister(list,NR_A); for i:=1 to tcgsize2size[size] do begin if i<>1 then NextSrcDst; a_load_reg_reg(list,OS_8,OS_8,dst,NR_A); list.concat(taicpu.op_reg(topcg2asmop[op],src)); a_load_reg_reg(list,OS_8,OS_8,NR_A,dst); end; ungetcpuregister(list,NR_A); end; else begin list.Concat(tai_comment.Create(strpnew('TODO: a_op_reg_reg_internal '+topcg2str(Op)))); //internalerror(2011022004); end; end; end; procedure tcgmos6502.a_op_const_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister); var i : byte; procedure NextReg; begin if i=4 then reg:=reghi else reg:=GetNextReg(reg); end; var mask : qword; shift : byte; curvalue : byte; tmpop: TAsmOp; // l1: TAsmLabel; // instr: taicpu; tmpreg : tregister; tmpreg64 : tregister64; FirstADCSBC: Boolean; begin if is_6502_general_purpose_register(reg) then begin if not (size in [OS_8,OS_S8]) then internalerror(2024050201); if reghi<>NR_NO then internalerror(2024050202); end; optimize_op_const(size,op,a); mask:=$ff; shift:=0; // l1:=nil; case op of OP_NONE: begin { Opcode is optimized away } end; OP_MOVE: begin { Optimized, replaced with a simple load } a_load_const_reg(list,size,a,reg); end; OP_AND: if reg=NR_A then list.concat(taicpu.op_const(A_AND,a and $ff)) else begin curvalue:=a and mask; for i:=1 to tcgsize2size[size] do begin case curvalue of 0: begin getcpuregister(list,NR_A); list.concat(taicpu.op_const(A_LDA,0)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; $ff: {nothing}; else begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); list.concat(taicpu.op_const(A_AND,curvalue)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; end; if i<>tcgsize2size[size] then begin NextReg; mask:=mask shl 8; inc(shift,8); curvalue:=(qword(a) and mask) shr shift; end; end; end; OP_OR: if reg=NR_A then list.concat(taicpu.op_const(A_ORA,a and $ff)) else begin curvalue:=a and mask; for i:=1 to tcgsize2size[size] do begin case curvalue of 0: {nothing}; $ff: begin getcpuregister(list,NR_A); list.concat(taicpu.op_const(A_LDA,$ff)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; else begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); list.concat(taicpu.op_const(A_ORA,curvalue)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; end; if i<>tcgsize2size[size] then begin NextReg; mask:=mask shl 8; inc(shift,8); curvalue:=(qword(a) and mask) shr shift; end; end; end; OP_XOR: if reg=NR_A then list.concat(taicpu.op_const(A_EOR,a and $ff)) else begin curvalue:=a and mask; for i:=1 to tcgsize2size[size] do begin case curvalue of 0: {nothing}; else begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); list.concat(taicpu.op_const(A_EOR,curvalue)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; end; if i<>tcgsize2size[size] then begin NextReg; mask:=mask shl 8; inc(shift,8); curvalue:=(qword(a) and mask) shr shift; end; end; end; // OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR: // begin // if size in [OS_64,OS_S64] then // a:=a and 63 // else // a:=a and 31; // if a<>0 then // begin // if a>1 then // begin // current_asmdata.getjumplabel(l1); // getcpuregister(list,NR_B); // list.concat(taicpu.op_reg_const(A_LD,NR_B,a)); // end; // if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then // case op of // OP_ROL: // begin // list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1))); // list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1))); // end; // OP_ROR: // begin // list.concat(taicpu.op_reg(A_RLC,reg)); // list.concat(taicpu.op_reg(A_RRC,reg)); // end; // else // ; // end; // if a>1 then // cg.a_label(list,l1); // case op of // OP_SHL: // list.concat(taicpu.op_reg(A_SLA,reg)); // OP_SHR: // list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1))); // OP_SAR: // list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1))); // OP_ROL: // if size in [OS_8,OS_S8] then // list.concat(taicpu.op_reg(A_RLC,reg)) // else // list.concat(taicpu.op_reg(A_RL,reg)); // OP_ROR: // if size in [OS_8,OS_S8] then // list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1))) // else // list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1))); // else // internalerror(2020040905); // end; // if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then // begin // for i:=2 to tcgsize2size[size] do // begin // case op of // OP_ROR, // OP_SHR, // OP_SAR: // list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i))); // OP_ROL, // OP_SHL: // list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(reg,reghi,i-1))); // else // internalerror(2020040906); // end; // end; // end; // if a>1 then // begin // instr:=taicpu.op_sym(A_DJNZ,l1); // instr.is_jmp:=true; // list.concat(instr); // ungetcpuregister(list,NR_B); // end; // end; // end; OP_ADD: if reg=NR_A then begin list.concat(taicpu.op_none(A_CLC)); list.concat(taicpu.op_const(A_ADC,a and $ff)); end else if (reg=NR_X) and ((a and $ff) = 1) then list.concat(taicpu.op_none(A_INX)) else if (reg=NR_X) and ((a and $ff) = 255) then list.concat(taicpu.op_none(A_DEX)) else if (reg=NR_Y) and ((a and $ff) = 1) then list.concat(taicpu.op_none(A_INY)) else if (reg=NR_Y) and ((a and $ff) = 255) then list.concat(taicpu.op_none(A_DEY)) else begin curvalue:=a and mask; tmpop:=A_NONE; for i:=1 to tcgsize2size[size] do begin if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then tmpop:=A_INC else if (tmpop=A_NONE) and (curvalue=255) and (i=tcgsize2size[size]) then tmpop:=A_DEC else if (tmpop=A_NONE) and (curvalue<>0) then begin tmpop:=A_ADC; FirstADCSBC:=True; end; case tmpop of A_NONE: {nothing}; A_INC,A_DEC: list.concat(taicpu.op_reg(tmpop,reg)); A_ADC: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); if FirstADCSBC then begin list.concat(taicpu.op_none(A_CLC)); FirstADCSBC:=False; end; list.concat(taicpu.op_const(tmpop,curvalue)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; else internalerror(2020040901); end; if i<>tcgsize2size[size] then begin NextReg; mask:=mask shl 8; inc(shift,8); curvalue:=(qword(a) and mask) shr shift; end; end; end; OP_SUB: if reg=NR_A then begin list.concat(taicpu.op_none(A_SEC)); list.concat(taicpu.op_const(A_SBC,a and $ff)); end else if (reg=NR_X) and ((a and $ff) = 1) then list.concat(taicpu.op_none(A_DEX)) else if (reg=NR_X) and ((a and $ff) = 255) then list.concat(taicpu.op_none(A_INX)) else if (reg=NR_Y) and ((a and $ff) = 1) then list.concat(taicpu.op_none(A_DEY)) else if (reg=NR_Y) and ((a and $ff) = 255) then list.concat(taicpu.op_none(A_INY)) else begin curvalue:=a and mask; tmpop:=A_NONE; for i:=1 to tcgsize2size[size] do begin if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then tmpop:=A_DEC else if (tmpop=A_NONE) and (curvalue=255) and (i=tcgsize2size[size]) then tmpop:=A_INC else if (tmpop=A_NONE) and (curvalue<>0) then begin tmpop:=A_SBC; FirstADCSBC:=True; end; case tmpop of A_NONE: {nothing}; A_DEC,A_INC: list.concat(taicpu.op_reg(tmpop,reg)); A_SBC: begin getcpuregister(list,NR_A); a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); if FirstADCSBC then begin list.concat(taicpu.op_none(A_SEC)); FirstADCSBC:=False; end; list.concat(taicpu.op_const(tmpop,curvalue)); a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; else internalerror(2020040902); end; if i<>tcgsize2size[size] then begin NextReg; mask:=mask shl 8; inc(shift,8); curvalue:=(qword(a) and mask) shr shift; end; end; end; else begin if size in [OS_64,OS_S64] then begin tmpreg64.reglo:=getintregister(list,OS_32); tmpreg64.reghi:=getintregister(list,OS_32); cg64.a_load64_const_reg(list,a,tmpreg64); cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi)); end else begin {$if 0} { code not working yet } if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then begin tmpreg:=reg; for i:=1 to 4 do begin list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1)); tmpreg:=GetNextReg(tmpreg); end; end else {$endif} begin tmpreg:=getintregister(list,size); a_load_const_reg(list,size,a,tmpreg); a_op_reg_reg(list,op,size,tmpreg,reg); end; end; end; end; end; procedure tcgmos6502.gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean); //var // pd: tprocdef; // paraloc1, paraloc2: tcgpara; // ai: taicpu; // hl, no_overflow: TAsmLabel; // name: String; begin //if size in [OS_8,OS_S8] then // begin // if size=OS_8 then // name:='fpc_mul_byte' // else // name:='fpc_mul_shortint'; // // if check_overflow then // name:=name+'_checkoverflow'; // // pd:=search_system_proc(name); // paraloc1.init; // paraloc2.init; // paramanager.getcgtempparaloc(list,pd,1,paraloc1); // paramanager.getcgtempparaloc(list,pd,2,paraloc2); // a_load_reg_cgpara(list,OS_8,src1,paraloc2); // a_load_reg_cgpara(list,OS_8,src2,paraloc1); // paramanager.freecgpara(list,paraloc2); // paramanager.freecgpara(list,paraloc1); // alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); // a_call_name(list,upper(name),false); // dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); // cg.a_reg_alloc(list,NR_L); // cg.a_load_reg_reg(list,OS_8,OS_8,NR_L,dst); // cg.a_reg_dealloc(list,NR_L); // paraloc2.done; // paraloc1.done; // end //else if size in [OS_16,OS_S16] then // begin // if size=OS_16 then // name:='fpc_mul_word' // else // name:='fpc_mul_integer'; // // if check_overflow then // name:=name+'_checkoverflow'; // // pd:=search_system_proc(name); // paraloc1.init; // paraloc2.init; // paramanager.getcgtempparaloc(list,pd,1,paraloc1); // paramanager.getcgtempparaloc(list,pd,2,paraloc2); // a_load_reg_cgpara(list,OS_16,src1,paraloc2); // a_load_reg_cgpara(list,OS_16,src2,paraloc1); // paramanager.freecgpara(list,paraloc2); // paramanager.freecgpara(list,paraloc1); // alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); // a_call_name(list,upper(name),false); // dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); // cg.a_reg_alloc(list,NR_L); // cg.a_reg_alloc(list,NR_H); // cg.a_load_reg_reg(list,OS_8,OS_8,NR_L,dst); // cg.a_reg_dealloc(list,NR_L); // cg.a_load_reg_reg(list,OS_8,OS_8,NR_H,GetNextReg(dst)); // cg.a_reg_dealloc(list,NR_H); // paraloc2.done; // paraloc1.done; // end //else // internalerror(2011022002); end; procedure tcgmos6502.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister); var mask : qword; shift : byte; i : byte; begin list.Concat(tai_comment.Create(strpnew('TODO: a_load_const_reg '+tcgsize2str(size)+' '+tostr(a)+' '+std_regname(reg)))); if is_6502_general_purpose_register(reg) then begin if not (size in [OS_8,OS_S8]) then internalerror(2024040704); if reg=NR_A then list.Concat(taicpu.op_const(A_LDA,byte(a))) else if reg=NR_X then list.Concat(taicpu.op_const(A_LDX,byte(a))) else if reg=NR_Y then list.Concat(taicpu.op_const(A_LDY,byte(a))) else internalerror(2024040705); end else begin getcpuregister(list,NR_A); mask:=$ff; shift:=0; for i:=tcgsize2size[size] downto 1 do begin list.Concat(taicpu.op_const(A_LDA,(qword(a) and mask) shr shift)); list.Concat(taicpu.op_reg(A_STA,reg)); if i<>1 then begin mask:=mask shl 8; inc(shift,8); reg:=GetNextReg(reg); end; end; ungetcpuregister(list,NR_A); end; end; procedure tcgmos6502.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); var mask : qword; shift : byte; href: treference; i: Integer; begin list.Concat(tai_comment.Create(strpnew('TODO: a_load_const_ref '+tcgsize2str(size) + ' '+tostr(a)+' '+ref2string(ref)))); mask:=$ff; shift:=0; href:=ref; if (href.base=NR_NO) and (href.index=NR_NO) then begin { TODO: get/unget register A } for i:=tcgsize2size[size] downto 1 do begin list.Concat(taicpu.op_const(A_LDA,(qword(a) and mask) shr shift)); list.Concat(taicpu.op_ref(A_STA,href)); if i<>1 then begin mask:=mask shl 8; inc(shift,8); inc(href.offset); end; end; end; //if (href.base=NR_NO) and (href.index<>NR_NO) then // begin // href.base:=href.index; // href.index:=NR_NO; // end; //if is_ref_in_opertypes(href,[OT_REF_IX_d,OT_REF_IY_d]) or // (is_ref_hl(href) and (size in [OS_8,OS_S8])) then // begin // for i:=tcgsize2size[size] downto 1 do // begin // list.Concat(taicpu.op_ref_const(A_LD,href,(qword(a) and mask) shr shift)); // if i<>1 then // begin // mask:=mask shl 8; // inc(shift,8); // inc(href.offset); // end; // end; // end //else // inherited; end; //function tcgmos6502.normalize_ref(list: TAsmList; ref: treference; // const refopertypes: trefoperandtypes; out allocatedregs: tregisterlist): treference; // var // tmpref : treference; // l : tasmlabel; // begin // SetLength(allocatedregs,0); // // if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then // begin // ref.base:=ref.index; // ref.index:=NR_NO; // end; // // if is_ref_in_opertypes(ref,refopertypes) then // begin // Result:=ref; // exit; // end; // // { can we use the HL register? } // if OT_REF_HL in refopertypes then // begin // SetLength(allocatedregs,2); // allocatedregs[0]:=NR_H; // allocatedregs[1]:=NR_L; // getcpuregisters(list,allocatedregs); // if assigned(ref.symbol) or (ref.offset<>0) then // begin // if assigned(ref.symbol) then // begin // reference_reset(tmpref,0,[]); // tmpref.symbol:=ref.symbol; // tmpref.offset:=ref.offset; // // tmpref.refaddr:=addr_full; // list.concat(taicpu.op_reg_ref(A_LD,NR_HL,tmpref)); // end // else // list.concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset)); // if (ref.base=NR_IX) or (ref.base=NR_IY) then // begin // getcpuregister(list,NR_D); // getcpuregister(list,NR_E); // list.concat(taicpu.op_reg(A_PUSH,ref.base)); // list.concat(taicpu.op_reg(A_POP,NR_DE)); // list.concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_DE)); // ungetcpuregister(list,NR_E); // ungetcpuregister(list,NR_D); // end // else if ref.base<>NR_NO then // begin // getcpuregister(list,NR_A); // emit_mov(list,NR_A,NR_L); // list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.base)); // emit_mov(list,NR_L,NR_A); // emit_mov(list,NR_A,NR_H); // list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.base))); // emit_mov(list,NR_H,NR_A); // ungetcpuregister(list,NR_A); // end; // if ref.index<>NR_NO then // begin // if ref.scalefactor>1 then // internalerror(2020042002); // getcpuregister(list,NR_A); // emit_mov(list,NR_A,NR_L); // list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index)); // emit_mov(list,NR_L,NR_A); // emit_mov(list,NR_A,NR_H); // list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index))); // emit_mov(list,NR_H,NR_A); // ungetcpuregister(list,NR_A); // end; // end // else // begin // { not assigned(ref.symbol) and (ref.offset=0) } // if (ref.base=NR_IX) or (ref.base=NR_IY) then // begin // list.concat(taicpu.op_reg(A_PUSH,ref.base)); // list.concat(taicpu.op_reg(A_POP,NR_HL)); // end // else if ref.base<>NR_NO then // begin // emit_mov(list,NR_L,ref.base); // emit_mov(list,NR_H,GetNextReg(ref.base)); // end; // if ref.index<>NR_NO then // begin // if ref.scalefactor>1 then // internalerror(2020042003); // getcpuregister(list,NR_A); // emit_mov(list,NR_A,NR_L); // list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index)); // emit_mov(list,NR_L,NR_A); // emit_mov(list,NR_A,NR_H); // list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index))); // emit_mov(list,NR_H,NR_A); // ungetcpuregister(list,NR_A); // end; // end; // reference_reset_base(result,NR_HL,0,ctempposinvalid,0,[]); // end // else // internalerror(2020042001); // end; procedure tcgmos6502.adjust_normalized_ref(list: TAsmList; var ref: treference; value: longint); //var // i: Integer; begin inc(ref.offset,value); //if is_ref_addr16(ref) then // Inc(ref.offset,value) //else if is_ref_hl(ref) then // begin // if value>0 then // for i:=1 to value do // list.concat(taicpu.op_reg(A_INC,NR_HL)) // else // for i:=-1 downto value do // list.concat(taicpu.op_reg(A_DEC,NR_HL)); // end //else if is_ref_ix_d(ref) then // begin // if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then // inc(ref.offset,value) // else // begin // { todo: IX is the frame pointer, we cannot change it, so we } // { think of another mechanism to deal with this situation } // internalerror(2020042101); // //if value>0 then // // for i:=1 to value do // // list.concat(taicpu.op_reg(A_INC,NR_IX)) // //else // // for i:=-1 downto value do // // list.concat(taicpu.op_reg(A_DEC,NR_IX)); // end; // end //else if is_ref_iy_d(ref) then // begin // if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then // inc(ref.offset,value) // else // if value>0 then // for i:=1 to value do // list.concat(taicpu.op_reg(A_INC,NR_IY)) // else // for i:=-1 downto value do // list.concat(taicpu.op_reg(A_DEC,NR_IY)); // end; end; procedure tcgmos6502.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference); var href : treference; i : integer; // regsused: tregisterlist; begin list.Concat(tai_comment.Create(strpnew('TODO: a_load_reg_ref '+tcgsize2str(fromsize)+' '+tcgsize2str(tosize)+' '+std_regname(reg)+' '+ref2string(ref)))); if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then internalerror(2011021307); if tcgsize2size[fromsize]>tcgsize2size[tosize] then internalerror(2020040802); //href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused); href:=ref; if (href.base=NR_NO) and (href.index=NR_NO) and ((tcgsize2size[fromsize]=tcgsize2size[tosize]) or (fromsize in [OS_8,OS_16,OS_32])) then begin getcpuregister(list,NR_A); for i:=1 to tcgsize2size[fromsize] do begin a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); list.concat(taicpu.op_ref(A_STA,href)); if i<>tcgsize2size[fromsize] then reg:=GetNextReg(reg); if i<>tcgsize2size[tosize] then adjust_normalized_ref(list,href,1); end; for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do begin if i=(tcgsize2size[fromsize]+1) then list.concat(taicpu.op_const(A_LDA,0)); list.concat(taicpu.op_ref(A_STA,href)); if i<>tcgsize2size[tosize] then begin adjust_normalized_ref(list,href,1); reg:=GetNextReg(reg); end; end; ungetcpuregister(list,NR_A); end //else // begin // getcpuregister(list,NR_A); // for i:=1 to tcgsize2size[fromsize] do // begin // a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); // list.concat(taicpu.op_ref_reg(A_LD,href,NR_A)); // if i<>tcgsize2size[fromsize] then // reg:=GetNextReg(reg); // if i<>tcgsize2size[tosize] then // adjust_normalized_ref(list,href,1); // end; // list.concat(taicpu.op_none(A_RLA)); // list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A)); // for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do // begin // list.concat(taicpu.op_ref_reg(A_LD,href,NR_A)); // if i<>tcgsize2size[tosize] then // begin // adjust_normalized_ref(list,href,1); // reg:=GetNextReg(reg); // end; // end; // ungetcpuregister(list,NR_A); // end; //ungetcpuregisters(list,regsused); end; procedure tcgmos6502.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize; const Ref : treference;reg : tregister); var href : treference; i : integer; // regsused: tregisterlist; begin list.Concat(tai_comment.Create(strpnew('TODO: a_load_ref_reg '+tcgsize2str(fromsize)+' '+tcgsize2str(tosize)+' '+ref2string(Ref)+' '+std_regname(reg)))); if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then internalerror(2011021301); if tcgsize2size[fromsize]>=tcgsize2size[tosize] then fromsize:=tosize; //href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused); href:=Ref; if (href.base=NR_NO) and (href.index=NR_NO) and ((tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32])) then begin getcpuregister(list,NR_A); for i:=1 to tcgsize2size[fromsize] do begin list.concat(taicpu.op_ref(A_LDA,href)); list.concat(taicpu.op_reg(A_STA,reg)); //a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); //if i<>tcgsize2size[fromsize] then // adjust_normalized_ref(list,href,1); if i<>tcgsize2size[tosize] then reg:=GetNextReg(reg); end; //ungetcpuregisters(list,regsused); ungetcpuregister(list,NR_A); //for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do // begin // list.concat(taicpu.op_reg_const(A_LD,reg,0)); // if i<>tcgsize2size[tosize] then // reg:=GetNextReg(reg); // end; end //else // begin // getcpuregister(list,NR_A); // for i:=1 to tcgsize2size[fromsize] do // begin // list.concat(taicpu.op_reg_ref(A_LD,NR_A,href)); // a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); // // if i<>tcgsize2size[fromsize] then // adjust_normalized_ref(list,href,1); // if i<>tcgsize2size[tosize] then // reg:=GetNextReg(reg); // end; // ungetcpuregisters(list,regsused); // list.concat(taicpu.op_none(A_RLA)); // list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A)); // for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do // begin // emit_mov(list,reg,NR_A); // if i<>tcgsize2size[tosize] then // reg:=GetNextReg(reg); // end; // ungetcpuregister(list,NR_A); // end; end; procedure tcgmos6502.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister); var // conv_done: boolean; // tmpreg : tregister; i : integer; begin { sign extend AND #$80 ASL A -> sign bit goes to the Carry flag SBC #$01 ADC #$FF EOR #$FF } list.Concat(tai_comment.Create(strpnew('TODO: a_load_reg_reg '+tcgsize2str(fromsize)+' '+tcgsize2str(tosize)+' '+std_regname(reg1)+' '+std_regname(reg2)))); Writeln('TODO: a_load_reg_reg '+tcgsize2str(fromsize)+' '+tcgsize2str(tosize)+' '+std_regname(reg1)+' '+std_regname(reg2)); if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then internalerror(2011021310); if tcgsize2size[fromsize]>tcgsize2size[tosize] then fromsize:=tosize; if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then begin if reg1<>reg2 then for i:=1 to tcgsize2size[fromsize] do begin emit_mov(list,reg2,reg1); if i<>tcgsize2size[fromsize] then reg1:=GetNextReg(reg1); if i<>tcgsize2size[tosize] then reg2:=GetNextReg(reg2); end else for i:=1 to tcgsize2size[fromsize] do if i<>tcgsize2size[tosize] then reg2:=GetNextReg(reg2); if tcgsize2size[tosize]>tcgsize2size[fromsize] then begin getcpuregister(list,NR_A); list.Concat(taicpu.op_const(A_LDA,0)); for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do begin list.Concat(taicpu.op_reg(A_STA,reg2)); if i<>tcgsize2size[tosize] then reg2:=GetNextReg(reg2); end; ungetcpuregister(list,NR_A); end; end //else // begin // if reg1<>reg2 then // for i:=1 to tcgsize2size[fromsize]-1 do // begin // emit_mov(list,reg2,reg1); // reg1:=GetNextReg(reg1); // reg2:=GetNextReg(reg2); // end // else // for i:=1 to tcgsize2size[fromsize]-1 do // reg2:=GetNextReg(reg2); // emit_mov(list,reg2,reg1); // getcpuregister(list,NR_A); // emit_mov(list,NR_A,reg2); // reg2:=GetNextReg(reg2); // list.concat(taicpu.op_none(A_RLA)); // list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A)); // for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do // begin // emit_mov(list,reg2,NR_A); // if i<>tcgsize2size[tosize] then // reg2:=GetNextReg(reg2); // end; // ungetcpuregister(list,NR_A); // end; end; procedure tcgmos6502.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister); begin internalerror(2012010702); end; procedure tcgmos6502.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister); begin internalerror(2012010703); end; procedure tcgmos6502.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); begin internalerror(2012010704); end; { comparison operations } procedure tcgmos6502.a_cmp_const_reg_label(list : TAsmList;size : tcgsize; cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel); //var // swapped : boolean; // tmpreg : tregister; // i : byte; // tmpl: TAsmLabel; begin //tmpl:=nil; //if size in [OS_8,OS_S8]then // begin // if cmp_op in [OC_EQ,OC_NE,OC_B,OC_AE] then // begin // getcpuregister(list,NR_A); // a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); // list.concat(taicpu.op_reg_const(A_CP,NR_A,a)); // case cmp_op of // OC_EQ: // a_jmp_flags(list,F_E,l); // OC_NE: // a_jmp_flags(list,F_NE,l); // OC_B: // a_jmp_flags(list,F_C,l); // OC_AE: // a_jmp_flags(list,F_NC,l); // else // internalerror(2020042206); // end; // ungetcpuregister(list,NR_A); // end // else if cmp_op in [OC_A,OC_BE] then // begin // getcpuregister(list,NR_A); // a_load_const_reg(list,OS_8,a,NR_A); // list.concat(taicpu.op_reg_reg(A_CP,NR_A,reg)); // case cmp_op of // OC_A: // a_jmp_flags(list,F_C,l); // OC_BE: // a_jmp_flags(list,F_NC,l); // else // internalerror(2020042218); // end; // ungetcpuregister(list,NR_A); // end // else if cmp_op in [OC_LT,OC_GTE] then // begin // getcpuregister(list,NR_A); // a_load_reg_reg(list,OS_8,OS_8,reg,NR_A); // list.concat(taicpu.op_reg_const(A_SUB,NR_A,a)); // current_asmdata.getjumplabel(tmpl); // a_jmp_flags(list,F_PO,tmpl); // current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80)); // cg.a_label(current_asmdata.CurrAsmList,tmpl); // case cmp_op of // OC_LT: // a_jmp_flags(list,F_M,l); // OC_GTE: // a_jmp_flags(list,F_P,l); // else // internalerror(2020042219); // end; // ungetcpuregister(list,NR_A); // end // else if cmp_op in [OC_GT,OC_LTE] then // begin // getcpuregister(list,NR_A); // a_load_const_reg(list,OS_8,a,NR_A); // list.concat(taicpu.op_reg_reg(A_SUB,NR_A,reg)); // current_asmdata.getjumplabel(tmpl); // a_jmp_flags(list,F_PO,tmpl); // current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80)); // cg.a_label(current_asmdata.CurrAsmList,tmpl); // case cmp_op of // OC_GT: // a_jmp_flags(list,F_M,l); // OC_LTE: // a_jmp_flags(list,F_P,l); // else // internalerror(2020042220); // end; // ungetcpuregister(list,NR_A); // end; // end //else if cmp_op in [OC_EQ,OC_NE] then // begin // if cmp_op=OC_EQ then // current_asmdata.getjumplabel(tmpl); // for i:=0 to tcgsize2size[size]-1 do // begin // a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A); // list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i)))); // case cmp_op of // OC_EQ: // if i<>(tcgsize2size[size]-1) then // a_jmp_flags(list,F_NE,tmpl) // else // a_jmp_flags(list,F_E,l); // OC_NE: // a_jmp_flags(list,F_NE,l); // else // internalerror(2020042221); // end; // end; // if cmp_op=OC_EQ then // cg.a_label(current_asmdata.CurrAsmList,tmpl); // end //else if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE,OC_BE,OC_B,OC_AE,OC_A] then // begin // getcpuregister(list,NR_A); // current_asmdata.getjumplabel(tmpl); // for i:=tcgsize2size[size]-1 downto 0 do // begin // a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A); // list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i)))); // if (i=(tcgsize2size[size]-1)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then // case cmp_op of // OC_GTE, // OC_GT: // a_jmp_signed_cmp_3way(list,tmpl,nil,l); // OC_LT, // OC_LTE: // a_jmp_signed_cmp_3way(list,l,nil,tmpl); // else // internalerror(2020042222); // end // else if i<>0 then // case cmp_op of // OC_AE, // OC_A, // OC_GTE, // OC_GT: // a_jmp_unsigned_cmp_3way(list,tmpl,nil,l); // OC_BE, // OC_B, // OC_LT, // OC_LTE: // a_jmp_unsigned_cmp_3way(list,l,nil,tmpl); // else // internalerror(2020042223); // end // else // case cmp_op of // OC_A, // OC_GT: // a_jmp_unsigned_cmp_3way(list,nil,nil,l); // OC_B, // OC_LT: // a_jmp_unsigned_cmp_3way(list,l,nil,nil); // OC_AE, // OC_GTE: // a_jmp_unsigned_cmp_3way(list,nil,l,l); // OC_BE, // OC_LTE: // a_jmp_unsigned_cmp_3way(list,l,l,nil); // else // internalerror(2020042224); // end; // end; // cg.a_label(current_asmdata.CurrAsmList,tmpl); // ungetcpuregister(list,NR_A); // end //else // internalerror(2020042205); end; procedure tcgmos6502.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); begin internalerror(2020042301); end; procedure tcgmos6502.a_jmp_name(list : TAsmList;const s : string); var ai : taicpu; begin ai:=taicpu.op_sym(A_JMP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION)); ai.is_jmp:=true; list.concat(ai); end; procedure tcgmos6502.a_jmp_always(list : TAsmList;l: tasmlabel); var ai : taicpu; begin ai:=taicpu.op_sym(A_JMP,l); ai.is_jmp:=true; list.concat(ai); end; procedure tcgmos6502.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); var ai : taicpu; begin ai:=taicpu.op_cond_sym(A_Bxx,flags_to_cond(f),l); ai.is_jmp:=true; list.concat(ai); end; procedure tcgmos6502.a_jmp_unsigned_cmp_3way(list: TAsmList; onbelow, onequal, onabove: tasmlabel); var skiplabel: TAsmLabel; begin if (onbelow= nil) and (onequal= nil) and (onabove= nil) then {nothing} else if (onbelow= nil) and (onequal= nil) and (onabove<>nil) then begin current_asmdata.getjumplabel(skiplabel); a_jmp_flags(list,F_EQ,skiplabel); a_jmp_flags(list,F_CS,onabove); cg.a_label(list,skiplabel); end else if (onbelow= nil) and (onequal<>nil) and (onabove= nil) then a_jmp_flags(list,F_EQ,onequal) else if (onbelow= nil) and (onequal<>nil) and (onabove<>nil) then begin if onequal<>onabove then a_jmp_flags(list,F_EQ,onequal); a_jmp_flags(list,F_CS,onabove); end else if (onbelow<>nil) and (onequal= nil) and (onabove= nil) then a_jmp_flags(list,F_CC,onbelow) else if (onbelow<>nil) and (onequal= nil) and (onabove<>nil) then begin if onbelow<>onabove then a_jmp_flags(list,F_CC,onbelow); a_jmp_flags(list,F_NE,onabove); end else if (onbelow<>nil) and (onequal<>nil) and (onabove= nil) then begin a_jmp_flags(list,F_CC,onbelow); a_jmp_flags(list,F_EQ,onequal); end else if (onbelow<>nil) and (onequal<>nil) and (onabove<>nil) then begin if (onbelow=onequal) and (onequal=onabove) then a_jmp_always(list,onbelow) else if onequal=onabove then begin a_jmp_flags(list,F_CC,onbelow); a_jmp_always(list,onabove); end else if onbelow=onequal then begin a_jmp_flags(list,F_CC,onbelow); a_jmp_flags(list,F_EQ,onequal); a_jmp_always(list,onabove); end else if onbelow=onabove then begin a_jmp_flags(list,F_EQ,onequal); a_jmp_always(list,onabove); end else begin { the generic case - all 3 are different labels } a_jmp_flags(list,F_CC,onbelow); a_jmp_flags(list,F_EQ,onequal); a_jmp_always(list,onabove); end; end else begin { Shouldn't happen! All possible combinations are handled by the above code. } internalerror(2020042201); end; end; procedure tcgmos6502.a_jmp_signed_cmp_3way(list: TAsmList; onless, onequal, ongreater: tasmlabel); var skiplabel: TAsmLabel; begin if (onless= nil) and (onequal= nil) and (ongreater= nil) then {nothing} else if (onless= nil) and (onequal= nil) and (ongreater<>nil) then begin current_asmdata.getjumplabel(skiplabel); a_jmp_flags(list,F_EQ,skiplabel); a_jmp_flags(list,F_PL,ongreater); cg.a_label(list,skiplabel); end else if (onless= nil) and (onequal<>nil) and (ongreater= nil) then a_jmp_flags(list,F_EQ,onequal) else if (onless= nil) and (onequal<>nil) and (ongreater<>nil) then begin if onequal<>ongreater then a_jmp_flags(list,F_EQ,onequal); a_jmp_flags(list,F_PL,ongreater); end else if (onless<>nil) and (onequal= nil) and (ongreater= nil) then a_jmp_flags(list,F_MI,onless) else if (onless<>nil) and (onequal= nil) and (ongreater<>nil) then begin if onless<>ongreater then a_jmp_flags(list,F_MI,onless); a_jmp_flags(list,F_NE,ongreater); end else if (onless<>nil) and (onequal<>nil) and (ongreater= nil) then begin a_jmp_flags(list,F_MI,onless); a_jmp_flags(list,F_EQ,onequal); end else if (onless<>nil) and (onequal<>nil) and (ongreater<>nil) then begin if (onless=onequal) and (onequal=ongreater) then a_jmp_always(list,onless) else if onequal=ongreater then begin a_jmp_flags(list,F_MI,onless); a_jmp_always(list,ongreater); end else if onless=onequal then begin a_jmp_flags(list,F_MI,onless); a_jmp_flags(list,F_EQ,onequal); a_jmp_always(list,ongreater); end else if onless=ongreater then begin a_jmp_flags(list,F_EQ,onequal); a_jmp_always(list,ongreater); end else begin { the generic case - all 3 are different labels } a_jmp_flags(list,F_MI,onless); a_jmp_flags(list,F_EQ,onequal); a_jmp_always(list,ongreater); end; end else begin { Shouldn't happen! All possible combinations are handled by the above code. } internalerror(2020042204); end; end; procedure tcgmos6502.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); var l1,l2 : TAsmLabel; begin if f=F_CS then begin if reg<>NR_A then getcpuregister(list,NR_A); list.concat(taicpu.op_const(A_LDA,0)); list.concat(taicpu.op_reg(A_ASL,NR_A)); if reg<>NR_A then begin a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; end else if reg=NR_X then begin current_asmdata.getjumplabel(l1); current_asmdata.getjumplabel(l2); a_jmp_flags(list,f,l1); list.concat(taicpu.op_const(A_LDX,0)); a_jmp_always(list,l2); cg.a_label(list,l1); list.concat(taicpu.op_const(A_LDX,1)); cg.a_label(list,l2); end else if reg=NR_Y then begin current_asmdata.getjumplabel(l1); current_asmdata.getjumplabel(l2); a_jmp_flags(list,f,l1); list.concat(taicpu.op_const(A_LDY,0)); a_jmp_always(list,l2); cg.a_label(list,l1); list.concat(taicpu.op_const(A_LDY,1)); cg.a_label(list,l2); end else begin if reg<>NR_A then getcpuregister(list,NR_A); current_asmdata.getjumplabel(l1); current_asmdata.getjumplabel(l2); a_jmp_flags(list,f,l1); list.concat(taicpu.op_const(A_LDA,0)); a_jmp_always(list,l2); cg.a_label(list,l1); list.concat(taicpu.op_const(A_LDA,1)); cg.a_label(list,l2); if reg<>NR_A then begin a_load_reg_reg(list,OS_8,OS_8,NR_A,reg); ungetcpuregister(list,NR_A); end; end; end; procedure tcgmos6502.g_stackpointer_alloc(list: TAsmList; localsize: longint); begin //if localsize>0 then // begin // list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize)); // list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP)); // list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL)); // end; end; //procedure tcgmos6502.a_adjust_sp(list : TAsmList; value : longint); // var // i : integer; // sym: TAsmSymbol; // ref: treference; // begin // case value of // 0: // ; // -7..-1: // begin // for i:=value to -1 do // list.concat(taicpu.op_reg(A_DEC,NR_SP)); // end; // 1..7: // begin // for i:=1 to value do // list.concat(taicpu.op_reg(A_INC,NR_SP)); // end; // else // begin // sym:=current_asmdata.RefAsmSymbol('FPC_Z80_SAVE_HL',AT_DATA); // reference_reset_symbol(ref,sym,0,1,[]); // // // block interrupts // list.concat(taicpu.op_none(A_DI)); // // // save HL // list.concat(taicpu.op_ref_reg(A_LD,ref,NR_HL)); // // // adjust SP // list.concat(taicpu.op_reg_const(A_LD,NR_HL,value)); // list.concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP)); // list.concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL)); // // // restore HL // list.concat(taicpu.op_reg_ref(A_LD,NR_HL,ref)); // // // release interrupts // list.concat(taicpu.op_none(A_EI)); // end; // end; // end; procedure tcgmos6502.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean); //var // regsize,stackmisalignment: longint; begin //regsize:=0; //stackmisalignment:=0; //{ save old framepointer } //if not nostackframe then // begin // { return address } // inc(stackmisalignment,2); // list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil)); // if current_procinfo.framepointer=NR_FRAME_POINTER_REG then // begin // { push } // inc(stackmisalignment,2); // include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG); // list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG)); // { Return address and FP are both on stack } // current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2); // current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2)); // if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then // begin // list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0)); // list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG)) // end // else // begin // internalerror(2020040301); // (*push_regs; // gen_load_frame_for_exceptfilter(list); // { Need only as much stack space as necessary to do the calls. // Exception filters don't have own local vars, and temps are 'mapped' // to the parent procedure. // maxpushedparasize is already aligned at least on x86_64. } // localsize:=current_procinfo.maxpushedparasize;*) // end; // current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG); // end // else // begin // CGmessage(cg_d_stackframe_omited); // end; // // { allocate stackframe space } // if (localsize<>0) or // ((target_info.stackalign>sizeof(pint)) and // (stackmisalignment <> 0) and // ((pi_do_call in current_procinfo.flags) or // (po_assembler in current_procinfo.procdef.procoptions))) then // begin // if target_info.stackalign>sizeof(pint) then // localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment; // g_stackpointer_alloc(list,localsize); // if current_procinfo.framepointer=NR_STACK_POINTER_REG then // current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint)); // current_procinfo.final_localsize:=localsize; // end // end; end; procedure tcgmos6502.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); //var // regs : tcpuregisterset; // reg : TSuperRegister; // LocalSize : longint; // stacksize : longint; begin //{ every byte counts for Z80, so if a subroutine is marked as non-returning, we do // not generate any exit code, so we really trust the noreturn directive //} //if po_noreturn in current_procinfo.procdef.procoptions then // exit; // //{ remove stackframe } //if not nostackframe then // begin // stacksize:=current_procinfo.calc_stackframe_size; // if (target_info.stackalign>4) and // ((stacksize <> 0) or // (pi_do_call in current_procinfo.flags) or // { can't detect if a call in this case -> use nostackframe } // { if you (think you) know what you are doing } // (po_assembler in current_procinfo.procdef.procoptions)) then // stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint); // if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then // begin // if stacksize<>0 then // a_adjust_sp(list,stacksize); // end // else // begin // list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG)); // list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG)); // end; // list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil)); // end; list.concat(taicpu.op_none(A_RTS)); end; procedure tcgmos6502.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister); //var // tmpref : treference; begin //if assigned(ref.symbol) then // begin // reference_reset(tmpref,0,[]); // tmpref.symbol:=ref.symbol; // tmpref.offset:=ref.offset; // // tmpref.refaddr:=addr_lo8; // list.concat(taicpu.op_reg_ref(A_LD,r,tmpref)); // // tmpref.refaddr:=addr_hi8; // list.concat(taicpu.op_reg_ref(A_LD,GetNextReg(r),tmpref)); // // if (ref.base<>NR_NO) then // a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r); // if (ref.index<>NR_NO) then // a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r); // end //else if ref.base=NR_IX then // begin // list.concat(taicpu.op_reg(A_PUSH,NR_IX)); // getcpuregister(list,NR_H); // getcpuregister(list,NR_L); // list.concat(taicpu.op_reg(A_POP,NR_HL)); // emit_mov(list,r,NR_L); // ungetcpuregister(list,NR_L); // emit_mov(list,GetNextReg(r),NR_H); // ungetcpuregister(list,NR_H); // if (ref.index<>NR_NO) then // a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r); // if ref.offset<>0 then // a_op_const_reg(list,OP_ADD,OS_16,ref.offset,r); // end //else if (ref.base=NR_SP) or (ref.base=NR_BC) or (ref.base=NR_DE) then // begin // getcpuregister(list,NR_H); // getcpuregister(list,NR_L); // list.Concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset)); // list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,ref.base)); // emit_mov(list,r,NR_L); // ungetcpuregister(list,NR_L); // emit_mov(list,GetNextReg(r),NR_H); // ungetcpuregister(list,NR_H); // if (ref.index<>NR_NO) then // a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r); // end //else if ref.base<>NR_NO then // begin // a_op_const_reg_reg(list,OP_ADD,OS_16,ref.offset,ref.base,r); // if (ref.index<>NR_NO) then // a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r); // end //else if ref.index<>NR_NO then // a_op_const_reg_reg(list,OP_ADD,OS_16,ref.offset,ref.index,r) //else // a_load_const_reg(list,OS_16,ref.offset,r); end; procedure tcgmos6502.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint); //var // tmpreg,srcreg,dstreg: tregister; // srcref,dstref : treference; // i: Integer; begin //if (len<=2) and // is_ref_in_opertypes(source,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) and // is_ref_in_opertypes(dest,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then // begin // srcref:=source; // dstref:=dest; // tmpreg:=getintregister(list,OS_8); // for i:=1 to len do // begin // list.concat(taicpu.op_reg_ref(A_LD,tmpreg,srcref)); // list.concat(taicpu.op_ref_reg(A_LD,dstref,tmpreg)); // if i<>len then // begin // adjust_normalized_ref(list,srcref,1); // adjust_normalized_ref(list,dstref,1); // end; // end; // end //else // begin // srcreg:=getintregister(list,OS_16); // a_loadaddr_ref_reg(list,source,srcreg); // dstreg:=getintregister(list,OS_16); // a_loadaddr_ref_reg(list,dest,dstreg); // getcpuregister(list,NR_L); // a_load_reg_reg(list,OS_8,OS_8,srcreg,NR_L); // getcpuregister(list,NR_H); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(srcreg),NR_H); // getcpuregister(list,NR_E); // a_load_reg_reg(list,OS_8,OS_8,dstreg,NR_E); // getcpuregister(list,NR_D); // a_load_reg_reg(list,OS_8,OS_8,GetNextReg(dstreg),NR_D); // getcpuregister(list,NR_B); // getcpuregister(list,NR_C); // list.concat(taicpu.op_reg_const(A_LD,NR_BC,len)); // list.concat(taicpu.op_none(A_LDIR)); // ungetcpuregister(list,NR_B); // ungetcpuregister(list,NR_C); // ungetcpuregister(list,NR_D); // ungetcpuregister(list,NR_E); // ungetcpuregister(list,NR_H); // ungetcpuregister(list,NR_L); // end; end; procedure tcgmos6502.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); var hl : tasmlabel; ai : taicpu; cond : TAsmCond; begin list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck'))); //if not(cs_check_overflow in current_settings.localswitches) then // exit; //current_asmdata.getjumplabel(hl); //if not ((def.typ=pointerdef) or // ((def.typ=orddef) and // (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar, // pasbool8,pasbool16,pasbool32,pasbool64]))) then // cond:=C_VC //else // cond:=C_CC; //ai:=Taicpu.Op_Sym(A_BRxx,hl); //ai.SetCondition(cond); //ai.is_jmp:=true; //list.concat(ai); // //a_call_name(list,'FPC_OVERFLOW',false); //a_label(list,hl); end; procedure tcgmos6502.g_save_registers(list: TAsmList); begin { this is done by the entry code } end; procedure tcgmos6502.g_restore_registers(list: TAsmList); begin { this is done by the exit code } end; procedure tcgmos6502.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel); begin //case cond of // OC_EQ: // a_jmp_unsigned_cmp_3way(list,nil,l,nil); // OC_NE: // a_jmp_unsigned_cmp_3way(list,l,nil,l); // OC_A: // a_jmp_unsigned_cmp_3way(list,nil,nil,l); // OC_B: // a_jmp_unsigned_cmp_3way(list,l,nil,nil); // OC_AE: // a_jmp_unsigned_cmp_3way(list,nil,l,l); // OC_BE: // a_jmp_unsigned_cmp_3way(list,l,l,nil); // OC_GT: // a_jmp_signed_cmp_3way(list,nil,nil,l); // OC_LT: // a_jmp_signed_cmp_3way(list,l,nil,nil); // OC_GTE: // a_jmp_signed_cmp_3way(list,nil,l,l); // OC_LTE: // a_jmp_signed_cmp_3way(list,l,l,nil); // else // internalerror(2011082501); //end; end; procedure tcgmos6502.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister); //var // instr: taicpu; begin if reg1=reg2 then exit; if reg1=NR_A then begin if reg2=NR_X then list.Concat(taicpu.op_none(A_TAX)) else if reg2=NR_Y then list.Concat(taicpu.op_none(A_TAY)) else list.Concat(taicpu.op_reg(A_STA,reg2)); end else if reg1=NR_X then begin if reg2=NR_A then list.Concat(taicpu.op_none(A_TXA)) else if reg2=NR_Y then begin getcpuregister(list,NR_A); list.Concat(taicpu.op_none(A_TXA)); list.Concat(taicpu.op_none(A_TAY)); ungetcpuregister(list,NR_A); end else list.Concat(taicpu.op_reg(A_STX,reg2)); end else if reg1=NR_Y then begin if reg2=NR_A then list.Concat(taicpu.op_none(A_TYA)) else if reg2=NR_Y then begin getcpuregister(list,NR_A); list.Concat(taicpu.op_none(A_TYA)); list.Concat(taicpu.op_none(A_TAX)); ungetcpuregister(list,NR_A); end else list.Concat(taicpu.op_reg(A_STY,reg2)); end else if reg2=NR_A then list.Concat(taicpu.op_reg(A_LDA,reg1)) else if reg2=NR_X then list.Concat(taicpu.op_reg(A_LDX,reg1)) else if reg2=NR_Y then list.Concat(taicpu.op_reg(A_LDY,reg1)) else begin getcpuregister(list,NR_A); list.Concat(taicpu.op_reg(A_LDA,reg1)); list.Concat(taicpu.op_reg(A_STA,reg2)); ungetcpuregister(list,NR_A); end; //instr:=taicpu.op_reg_reg(A_LD,reg2,reg1); //list.Concat(instr); { Notify the register allocator that we have written a move instruction so it can try to eliminate it. } //add_move_instruction(instr); end; procedure tcg64fmos6502.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64); begin list.Concat(tai_comment.Create(strpnew('TODO: a_op64_reg_reg '+topcg2str(Op)+' '+tcgsize2str(size)+' '+std_regname(regsrc.reghi)+':'+std_regname(regsrc.reglo)+' '+std_regname(regdst.reghi)+':'+std_regname(regdst.reglo)))); if not(size in [OS_S64,OS_64]) then internalerror(2012102402); tcgmos6502(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi); end; procedure tcg64fmos6502.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64); begin list.Concat(tai_comment.Create(strpnew('TODO: a_op64_const_reg '+topcg2str(Op)+' '+tcgsize2str(size)+' '+tostr(value)+' '+std_regname(reg.reghi)+':'+std_regname(reg.reglo)))); tcgmos6502(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi); end; procedure create_codegen; begin cg:=tcgmos6502.create; cg64:=tcg64fmos6502.create; end; end.