diff --git a/compiler/avr/cgcpu.pas b/compiler/avr/cgcpu.pas index 34c440407c..bb2cbc5a33 100644 --- a/compiler/avr/cgcpu.pas +++ b/compiler/avr/cgcpu.pas @@ -120,6 +120,7 @@ unit cgcpu; 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 maybegetcpuregister(list : tasmlist; reg : tregister); + function addr_is_io_register(const addr: integer): boolean; end; tcg64favr = class(tcg64f32) @@ -1084,6 +1085,14 @@ unit cgcpu; getcpuregister(list,reg); end; + { Returns true if dataspace address falls in I/O register range } + function tcgavr.addr_is_io_register(const addr: integer): boolean; + begin + result := (not(current_settings.cputype in [cpu_avrxmega3,cpu_avrtiny]) and (addr>31)) or + ((current_settings.cputype in [cpu_avrxmega3,cpu_avrtiny]) and (addr>=0)) and + (addr cpu_avrxmega3) and - (fromsize in [OS_16, OS_S16]) and QuickRef and (href.offset > 31) and - (href.offset < cpuinfo.embedded_controllers[current_settings.controllertype].srambase) then + (fromsize in [OS_16, OS_S16]) and QuickRef and addr_is_io_register(href.offset) then begin tmpreg:=GetNextReg(reg); href.addressmode:=AM_UNCHANGED; @@ -2601,16 +2609,14 @@ unit cgcpu; end; // CC - // If dest is an ioreg (31 < offset < srambase) and size = 16 bit then + // If dest is an ioreg and size = 16 bit then // write high byte first, then low byte // but not for avrxmega3 if (len = 2) and DestQuickRef and (current_settings.cputype <> cpu_avrxmega3) and - (dest.offset > 31) and - (dest.offset < cpuinfo.embedded_controllers[current_settings.controllertype].srambase) then + addr_is_io_register(dest.offset) then begin // If src is also a 16 bit ioreg then read low byte then high byte - if SrcQuickRef and (srcref.offset > 31) - and (srcref.offset < cpuinfo.embedded_controllers[current_settings.controllertype].srambase) then + if SrcQuickRef and addr_is_io_register(srcref.offset) then begin // First read source into temp registers tmpreg:=getintregister(list, OS_16); @@ -2627,8 +2633,20 @@ unit cgcpu; end else begin - srcref.addressmode:=AM_UNCHANGED; - inc(srcref.offset); + { avrtiny doesn't have LDD instruction, so use + predecrement version of LD with pre-incremented pointer } + if current_settings.cputype = cpu_avrtiny then + begin + srcref.addressmode:=AM_PREDRECEMENT; + list.concat(taicpu.op_reg_const(A_SUBI,srcref.base,-2)); + list.concat(taicpu.op_reg_const(A_SBCI,GetNextReg(srcref.base),$FF)); + end + else + begin + srcref.addressmode:=AM_UNCHANGED; + inc(srcref.offset); + end; + dstref.addressmode:=AM_UNCHANGED; inc(dstref.offset); @@ -2637,12 +2655,15 @@ unit cgcpu; list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,GetDefaultTmpReg)); cg.ungetcpuregister(list,GetDefaultTmpReg); - if not(SrcQuickRef) then + if not(SrcQuickRef) and (current_settings.cputype <> cpu_avrtiny) then srcref.addressmode:=AM_POSTINCREMENT + else if current_settings.cputype = cpu_avrtiny then + srcref.addressmode:=AM_PREDRECEMENT else srcref.addressmode:=AM_UNCHANGED; - dec(srcref.offset); + if current_settings.cputype <> cpu_avrtiny then + dec(srcref.offset); dec(dstref.offset); cg.getcpuregister(list,GetDefaultTmpReg);