cgcpu.pas 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509
  1. {
  2. Copyright (c) 2008 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the Z80
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tregisterlist = array of tregister;
  29. { tcgz80 }
  30. tcgz80 = class(tcg)
  31. { true, if the next arithmetic operation should modify the flags }
  32. cgsetflags : boolean;
  33. procedure init_register_allocators;override;
  34. procedure done_register_allocators;override;
  35. procedure getcpuregisters(list:TAsmList;regs:tregisterlist);
  36. procedure ungetcpuregisters(list:TAsmList;regs:tregisterlist);
  37. function getaddressregister(list:TAsmList):TRegister;override;
  38. function GetOffsetReg(const r: TRegister;ofs : shortint): TRegister;override;
  39. function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): TRegister;override;
  40. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
  41. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);override;
  42. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  43. procedure a_load_reg_cgpara(list : TAsmList; size : tcgsize;r : tregister; const cgpara : tcgpara);override;
  44. procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const cgpara : TCGPara);override;
  45. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  46. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  47. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  48. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override;
  49. { move instructions }
  50. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  51. procedure a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);override;
  52. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  53. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  54. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  55. { fpu move instructions }
  56. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  57. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  58. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  59. { comparison operations }
  60. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  61. l : tasmlabel);override;
  62. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  63. procedure a_jmp_name(list : TAsmList;const s : string); override;
  64. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  65. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  66. { Z80-specific unsigned comparison code generation jmp helper }
  67. procedure a_jmp_unsigned_cmp_3way(list : TAsmList;onbelow,onequal,onabove: tasmlabel);
  68. { Z80-specific signed comparison code generation jmp helper. Should follow a SUB instruction,
  69. and the A register must still contain the result. }
  70. procedure a_jmp_signed_cmp_3way(list : TAsmList;onless,onequal,ongreater: tasmlabel);
  71. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  72. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  73. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  74. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  75. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  76. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  77. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  78. procedure g_save_registers(list : TAsmList);override;
  79. procedure g_restore_registers(list : TAsmList);override;
  80. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  81. function normalize_ref(list : TAsmList;ref : treference; const refopertypes:trefoperandtypes; out allocatedregs:tregisterlist) : treference;
  82. procedure adjust_normalized_ref(list: TAsmList;var ref: treference; value: longint);
  83. procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  84. procedure a_adjust_sp(list: TAsmList; value: longint);
  85. protected
  86. procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  87. procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister);
  88. procedure maybegetcpuregister(list : tasmlist; reg : tregister);
  89. end;
  90. tcg64fz80 = class(tcg64f32)
  91. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  92. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  93. end;
  94. function GetByteLoc(const loc : tlocation;nr : byte) : tlocation;
  95. procedure create_codegen;
  96. const
  97. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_LD,A_ADD,A_AND,A_NONE,
  98. A_NONE,A_NONE,A_NONE,A_NEG,A_CPL,A_OR,
  99. A_SRA,A_SLA,A_SRL,A_SUB,A_XOR,A_RLCA,A_RRCA);
  100. implementation
  101. uses
  102. globals,verbose,systems,cutils,
  103. fmodule,
  104. symconst,symsym,symtable,
  105. tgobj,rgobj,
  106. procinfo,cpupi,
  107. paramgr;
  108. function use_push(const cgpara:tcgpara):boolean;
  109. begin
  110. result:=(not paramanager.use_fixed_stack) and
  111. assigned(cgpara.location) and
  112. (cgpara.location^.loc=LOC_REFERENCE) and
  113. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  114. end;
  115. procedure tcgz80.init_register_allocators;
  116. begin
  117. inherited init_register_allocators;
  118. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  119. [RS_A,RS_B,RS_C,RS_D,RS_E,RS_H,RS_L],first_int_imreg,[]);
  120. end;
  121. procedure tcgz80.done_register_allocators;
  122. begin
  123. rg[R_INTREGISTER].free;
  124. // rg[R_ADDRESSREGISTER].free;
  125. inherited done_register_allocators;
  126. end;
  127. procedure tcgz80.getcpuregisters(list: TAsmList; regs: tregisterlist);
  128. var
  129. r: tregister;
  130. begin
  131. for r in regs do
  132. getcpuregister(list,r);
  133. end;
  134. procedure tcgz80.ungetcpuregisters(list: TAsmList; regs: tregisterlist);
  135. var
  136. r: tregister;
  137. begin
  138. for r in regs do
  139. ungetcpuregister(list,r);
  140. end;
  141. function tcgz80.getaddressregister(list: TAsmList): TRegister;
  142. begin
  143. Result:=getintregister(list,OS_ADDR);
  144. end;
  145. function tcgz80.GetOffsetReg(const r: TRegister; ofs: shortint): TRegister;
  146. var
  147. i: Integer;
  148. begin
  149. result:=r;
  150. for i:=1 to ofs do
  151. result:=GetNextReg(result);
  152. end;
  153. function tcgz80.GetOffsetReg64(const r, rhi: TRegister; ofs: shortint): TRegister;
  154. var
  155. i: Integer;
  156. begin
  157. if ofs>=4 then
  158. begin
  159. result:=rhi;
  160. dec(ofs,4);
  161. end
  162. else
  163. result:=r;
  164. for i:=1 to ofs do
  165. result:=GetNextReg(result);
  166. end;
  167. procedure tcgz80.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  168. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  169. var
  170. ref : treference;
  171. begin
  172. paramanager.allocparaloc(list,paraloc);
  173. case paraloc^.loc of
  174. LOC_REGISTER,LOC_CREGISTER:
  175. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  176. LOC_REFERENCE,LOC_CREFERENCE:
  177. begin
  178. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,ctempposinvalid,2,[]);
  179. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  180. end;
  181. else
  182. internalerror(2002071004);
  183. end;
  184. end;
  185. var
  186. i, i2 : longint;
  187. hp : PCGParaLocation;
  188. begin
  189. if use_push(cgpara) then
  190. begin
  191. case tcgsize2size[cgpara.Size] of
  192. 1:
  193. begin
  194. cgpara.check_simple_location;
  195. getcpuregister(list,NR_A);
  196. a_load_reg_reg(list,OS_8,OS_8,r,NR_A);
  197. list.concat(taicpu.op_reg(A_PUSH,NR_AF));
  198. list.concat(taicpu.op_reg(A_INC,NR_SP));
  199. ungetcpuregister(list,NR_A);
  200. end;
  201. 2:
  202. begin
  203. cgpara.check_simple_location;
  204. getcpuregister(list,NR_L);
  205. a_load_reg_reg(list,OS_8,OS_8,r,NR_L);
  206. getcpuregister(list,NR_H);
  207. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H);
  208. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  209. getcpuregister(list,NR_H);
  210. getcpuregister(list,NR_L);
  211. end;
  212. 4:
  213. begin
  214. cgpara.check_simple_location;
  215. getcpuregister(list,NR_L);
  216. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(GetNextReg(r)),NR_L);
  217. getcpuregister(list,NR_H);
  218. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(GetNextReg(GetNextReg(r))),NR_H);
  219. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  220. getcpuregister(list,NR_H);
  221. getcpuregister(list,NR_L);
  222. getcpuregister(list,NR_L);
  223. a_load_reg_reg(list,OS_8,OS_8,r,NR_L);
  224. getcpuregister(list,NR_H);
  225. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H);
  226. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  227. getcpuregister(list,NR_H);
  228. getcpuregister(list,NR_L);
  229. end;
  230. else
  231. internalerror(2020040801);
  232. end;
  233. { if tcgsize2size[cgpara.Size] > 2 then
  234. begin
  235. if tcgsize2size[cgpara.Size] <> 4 then
  236. internalerror(2013031101);
  237. if cgpara.location^.Next = nil then
  238. begin
  239. if tcgsize2size[cgpara.location^.size] <> 4 then
  240. internalerror(2013031101);
  241. end
  242. else
  243. begin
  244. if tcgsize2size[cgpara.location^.size] <> 2 then
  245. internalerror(2013031101);
  246. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  247. internalerror(2013031101);
  248. if cgpara.location^.Next^.Next <> nil then
  249. internalerror(2013031101);
  250. end;
  251. if tcgsize2size[cgpara.size]>cgpara.alignment then
  252. pushsize:=cgpara.size
  253. else
  254. pushsize:=int_cgsize(cgpara.alignment);
  255. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  256. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  257. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  258. end
  259. else
  260. begin
  261. cgpara.check_simple_location;
  262. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  263. pushsize:=cgpara.location^.size
  264. else
  265. pushsize:=int_cgsize(cgpara.alignment);
  266. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  267. end;}
  268. end
  269. else
  270. begin
  271. if not(tcgsize2size[cgpara.Size] in [1..4]) then
  272. internalerror(2014011101);
  273. hp:=cgpara.location;
  274. i:=0;
  275. while i<tcgsize2size[cgpara.Size] do
  276. begin
  277. if not(assigned(hp)) then
  278. internalerror(2014011102);
  279. inc(i, tcgsize2size[hp^.Size]);
  280. if hp^.Loc=LOC_REGISTER then
  281. begin
  282. load_para_loc(r,hp);
  283. hp:=hp^.Next;
  284. r:=GetNextReg(r);
  285. end
  286. else
  287. begin
  288. load_para_loc(r,hp);
  289. for i2:=1 to tcgsize2size[hp^.Size] do
  290. r:=GetNextReg(r);
  291. hp:=hp^.Next;
  292. end;
  293. end;
  294. if assigned(hp) then
  295. internalerror(2014011103);
  296. end;
  297. end;
  298. procedure tcgz80.a_loadfpu_ref_cgpara(list: TAsmList; size: tcgsize; const ref: treference; const cgpara: TCGPara);
  299. var
  300. href: treference;
  301. curloc: PCGParaLocation;
  302. i: Integer;
  303. begin
  304. case cgpara.location^.loc of
  305. LOC_REGISTER,LOC_CREGISTER:
  306. begin
  307. case size of
  308. OS_F32:
  309. begin
  310. curloc:=cgpara.location;
  311. href:=ref;
  312. for i:=1 to 4 do
  313. begin
  314. if not assigned(curloc) then
  315. internalerror(2020042303);
  316. if not (curloc^.Loc in [LOC_REGISTER,LOC_CREGISTER]) then
  317. internalerror(2020042304);
  318. a_load_ref_reg(list,OS_8,OS_8,href,curloc^.register);
  319. curloc:=curloc^.Next;
  320. end;
  321. if assigned(curloc) then
  322. internalerror(2020042305);
  323. end;
  324. else
  325. internalerror(2020042302);
  326. end;
  327. end;
  328. else
  329. inherited;
  330. end;
  331. end;
  332. procedure tcgz80.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
  333. var
  334. i : longint;
  335. hp : PCGParaLocation;
  336. ref: treference;
  337. begin
  338. if not(tcgsize2size[paraloc.Size] in [1..4]) then
  339. internalerror(2014011101);
  340. if use_push(paraloc) then
  341. begin
  342. case tcgsize2size[paraloc.Size] of
  343. 1:
  344. begin
  345. getcpuregister(list,NR_A);
  346. a_load_const_reg(list,OS_8,a,NR_A);
  347. list.Concat(taicpu.op_reg(A_PUSH,NR_AF));
  348. list.Concat(taicpu.op_reg(A_INC,NR_SP));
  349. ungetcpuregister(list,NR_A);
  350. end;
  351. 2:
  352. begin
  353. getcpuregister(list,NR_IY);
  354. list.Concat(taicpu.op_reg_const(A_LD,NR_IY,a));
  355. list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
  356. ungetcpuregister(list,NR_IY);
  357. end;
  358. 4:
  359. begin
  360. getcpuregister(list,NR_IY);
  361. list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a shr 16)));
  362. list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
  363. list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a)));
  364. list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
  365. ungetcpuregister(list,NR_IY);
  366. end;
  367. else
  368. internalerror(2020040701);
  369. end;
  370. end
  371. else
  372. begin
  373. hp:=paraloc.location;
  374. i:=1;
  375. while i<=tcgsize2size[paraloc.Size] do
  376. begin
  377. if not(assigned(hp)) then
  378. internalerror(2014011105);
  379. //paramanager.allocparaloc(list,hp);
  380. case hp^.loc of
  381. LOC_REGISTER,LOC_CREGISTER:
  382. begin
  383. if (tcgsize2size[hp^.size]<>1) or
  384. (hp^.shiftval<>0) then
  385. internalerror(2015041101);
  386. a_load_const_reg(list,hp^.size,(a shr (8*(i-1))) and $ff,hp^.register);
  387. inc(i,tcgsize2size[hp^.size]);
  388. hp:=hp^.Next;
  389. end;
  390. LOC_REFERENCE,LOC_CREFERENCE:
  391. begin
  392. reference_reset(ref,paraloc.alignment,[]);
  393. ref.base:=hp^.reference.index;
  394. ref.offset:=hp^.reference.offset;
  395. a_load_const_ref(list,hp^.size,a shr (8*(i-1)),ref);
  396. inc(i,tcgsize2size[hp^.size]);
  397. hp:=hp^.Next;
  398. end;
  399. else
  400. internalerror(2002071004);
  401. end;
  402. end;
  403. end;
  404. end;
  405. procedure tcgz80.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);
  406. procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
  407. var
  408. pushsize : tcgsize;
  409. opsize : topsize;
  410. tmpreg : tregister;
  411. href,tmpref: treference;
  412. begin
  413. if not assigned(paraloc) then
  414. exit;
  415. if (paraloc^.loc<>LOC_REFERENCE) or
  416. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  417. (tcgsize2size[paraloc^.size]>4) then
  418. internalerror(200501162);
  419. { Pushes are needed in reverse order, add the size of the
  420. current location to the offset where to load from. This
  421. prevents wrong calculations for the last location when
  422. the size is not a power of 2 }
  423. if assigned(paraloc^.next) then
  424. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  425. { Push the data starting at ofs }
  426. href:=r;
  427. inc(href.offset,ofs);
  428. {if tcgsize2size[paraloc^.size]>cgpara.alignment then}
  429. pushsize:=paraloc^.size
  430. {else
  431. pushsize:=int_cgsize(cgpara.alignment)};
  432. {Writeln(pushsize);}
  433. case tcgsize2size[pushsize] of
  434. 1:
  435. begin
  436. tmpreg:=getintregister(list,OS_8);
  437. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  438. getcpuregister(list,NR_A);
  439. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
  440. list.concat(taicpu.op_reg(A_PUSH,NR_AF));
  441. list.concat(taicpu.op_reg(A_INC,NR_SP));
  442. ungetcpuregister(list,NR_A);
  443. end;
  444. 2:
  445. begin
  446. tmpreg:=getintregister(list,OS_16);
  447. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  448. getcpuregister(list,NR_L);
  449. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
  450. getcpuregister(list,NR_H);
  451. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
  452. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  453. ungetcpuregister(list,NR_H);
  454. ungetcpuregister(list,NR_L);
  455. end;
  456. 4:
  457. begin
  458. tmpreg:=getintregister(list,OS_16);
  459. inc(href.offset,2);
  460. a_load_ref_reg(list,OS_16,OS_16,href,tmpreg);
  461. getcpuregister(list,NR_L);
  462. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
  463. getcpuregister(list,NR_H);
  464. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
  465. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  466. ungetcpuregister(list,NR_H);
  467. ungetcpuregister(list,NR_L);
  468. dec(href.offset,2);
  469. a_load_ref_reg(list,OS_16,OS_16,href,tmpreg);
  470. getcpuregister(list,NR_L);
  471. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
  472. getcpuregister(list,NR_H);
  473. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
  474. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  475. ungetcpuregister(list,NR_H);
  476. ungetcpuregister(list,NR_L);
  477. end;
  478. else
  479. internalerror(2020040803);
  480. end;
  481. //if tcgsize2size[paraloc^.size]<cgpara.alignment then
  482. // begin
  483. // tmpreg:=getintregister(list,pushsize);
  484. // a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  485. // list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  486. // end
  487. //else
  488. // begin
  489. // make_simple_ref(list,href);
  490. // if tcgsize2size[pushsize] > 2 then
  491. // begin
  492. // tmpref := href;
  493. // Inc(tmpref.offset, 2);
  494. // list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[int_cgsize(tcgsize2size[pushsize]-2)],tmpref));
  495. // end;
  496. // list.concat(taicpu.op_ref(A_PUSH,opsize,href));
  497. // end;
  498. end;
  499. var
  500. tmpref, ref, href: treference;
  501. location: pcgparalocation;
  502. sizeleft: tcgint;
  503. len: tcgint;
  504. begin
  505. { cgpara.size=OS_NO requires a copy on the stack }
  506. if use_push(cgpara) then
  507. begin
  508. { Record copy? }
  509. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  510. begin
  511. cgpara.check_simple_location;
  512. len:=align(cgpara.intsize,cgpara.alignment);
  513. g_stackpointer_alloc(list,len);
  514. reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]);
  515. g_concatcopy(list,r,href,len);
  516. end
  517. else
  518. begin
  519. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  520. internalerror(200501161);
  521. { We need to push the data in reverse order,
  522. therefor we use a recursive algorithm }
  523. pushdata(cgpara.location,0);
  524. end
  525. end
  526. else
  527. begin
  528. location := cgpara.location;
  529. tmpref := r;
  530. sizeleft := cgpara.intsize;
  531. while assigned(location) do
  532. begin
  533. paramanager.allocparaloc(list,location);
  534. case location^.loc of
  535. LOC_REGISTER,LOC_CREGISTER:
  536. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  537. LOC_REFERENCE:
  538. begin
  539. reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  540. { doubles in softemu mode have a strange order of registers and references }
  541. if location^.size=OS_32 then
  542. g_concatcopy(list,tmpref,ref,4)
  543. else
  544. begin
  545. g_concatcopy(list,tmpref,ref,sizeleft);
  546. if assigned(location^.next) then
  547. internalerror(2005010710);
  548. end;
  549. end;
  550. LOC_VOID:
  551. begin
  552. // nothing to do
  553. end;
  554. else
  555. internalerror(2002081103);
  556. end;
  557. inc(tmpref.offset,tcgsize2size[location^.size]);
  558. dec(sizeleft,tcgsize2size[location^.size]);
  559. location := location^.next;
  560. end;
  561. end;
  562. end;
  563. procedure tcgz80.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  564. var
  565. tmpreg: tregister;
  566. begin
  567. tmpreg:=getaddressregister(list);
  568. a_loadaddr_ref_reg(list,r,tmpreg);
  569. a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc);
  570. end;
  571. procedure tcgz80.a_call_name(list : TAsmList;const s : string; weak: boolean);
  572. var
  573. sym: TAsmSymbol;
  574. begin
  575. if weak then
  576. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)
  577. else
  578. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  579. list.concat(taicpu.op_sym(A_CALL,sym));
  580. include(current_procinfo.flags,pi_do_call);
  581. end;
  582. procedure tcgz80.a_call_reg(list : TAsmList;reg: tregister);
  583. var
  584. l : TAsmLabel;
  585. ref : treference;
  586. begin
  587. { HACK: at this point all registers are allocated, due to the way the
  588. calling convention works, but we need to free some registers, in order
  589. for the following code to work, so we do it here }
  590. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  591. getcpuregister(list,NR_L);
  592. a_load_reg_reg(list,OS_8,OS_8,reg,NR_L);
  593. getcpuregister(list,NR_H);
  594. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(reg),NR_H);
  595. current_asmdata.getjumplabel(l);
  596. reference_reset(ref,0,[]);
  597. ref.symbol:=l;
  598. list.concat(taicpu.op_ref_reg(A_LD,ref,NR_HL));
  599. ungetcpuregister(list,NR_H);
  600. ungetcpuregister(list,NR_L);
  601. { allocate them again, right before the actual call instruction }
  602. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  603. list.concat(tai_const.Create_8bit($CD)); { $CD is the opcode of the call instruction }
  604. list.concat(tai_label.Create(l));
  605. list.concat(tai_const.Create_16bit(0));
  606. include(current_procinfo.flags,pi_do_call);
  607. end;
  608. procedure tcgz80.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  609. begin
  610. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  611. internalerror(2012102403);
  612. a_op_const_reg_internal(list,Op,size,a,reg,NR_NO);
  613. end;
  614. procedure tcgz80.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister);
  615. begin
  616. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  617. internalerror(2012102401);
  618. a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO);
  619. end;
  620. procedure tcgz80.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  621. var
  622. i : integer;
  623. procedure NextSrcDst;
  624. begin
  625. if i=5 then
  626. begin
  627. dst:=dsthi;
  628. src:=srchi;
  629. end
  630. else
  631. begin
  632. dst:=GetNextReg(dst);
  633. src:=GetNextReg(src);
  634. end;
  635. end;
  636. var
  637. tmpreg,tmpreg2: tregister;
  638. instr : taicpu;
  639. l1,l2 : tasmlabel;
  640. begin
  641. case op of
  642. OP_ADD:
  643. begin
  644. getcpuregister(list,NR_A);
  645. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  646. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,src));
  647. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  648. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  649. begin
  650. for i:=2 to tcgsize2size[size] do
  651. begin
  652. NextSrcDst;
  653. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  654. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,src));
  655. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  656. end;
  657. end;
  658. ungetcpuregister(list,NR_A);
  659. end;
  660. OP_SUB:
  661. begin
  662. getcpuregister(list,NR_A);
  663. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  664. list.concat(taicpu.op_reg_reg(A_SUB,NR_A,src));
  665. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  666. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  667. begin
  668. for i:=2 to tcgsize2size[size] do
  669. begin
  670. NextSrcDst;
  671. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  672. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,src));
  673. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  674. end;
  675. end;
  676. ungetcpuregister(list,NR_A);
  677. end;
  678. OP_NEG:
  679. begin
  680. getcpuregister(list,NR_A);
  681. if tcgsize2size[size]>=2 then
  682. begin
  683. tmpreg:=GetNextReg(src);
  684. tmpreg2:=GetNextReg(dst);
  685. for i:=2 to tcgsize2size[size] do
  686. begin
  687. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
  688. list.concat(taicpu.op_none(A_CPL));
  689. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  690. if i<>tcgsize2size[size] then
  691. begin
  692. if i=4 then
  693. begin
  694. tmpreg:=srchi;
  695. tmpreg2:=dsthi;
  696. end
  697. else
  698. begin
  699. tmpreg:=GetNextReg(tmpreg);
  700. tmpreg2:=GetNextReg(tmpreg2);
  701. end;
  702. end;
  703. end;
  704. end;
  705. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  706. list.concat(taicpu.op_none(A_NEG));
  707. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  708. if tcgsize2size[size]>=2 then
  709. begin
  710. tmpreg2:=GetNextReg(dst);
  711. for i:=2 to tcgsize2size[size] do
  712. begin
  713. a_load_reg_reg(list,OS_8,OS_8,tmpreg2,NR_A);
  714. list.concat(taicpu.op_reg_const(A_SBC,NR_A,-1));
  715. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  716. if i<>tcgsize2size[size] then
  717. begin
  718. if i=4 then
  719. begin
  720. tmpreg2:=dsthi;
  721. end
  722. else
  723. begin
  724. tmpreg2:=GetNextReg(tmpreg2);
  725. end;
  726. end;
  727. end;
  728. end;
  729. ungetcpuregister(list,NR_A);
  730. end;
  731. OP_NOT:
  732. begin
  733. getcpuregister(list,NR_A);
  734. for i:=1 to tcgsize2size[size] do
  735. begin
  736. if i<>1 then
  737. NextSrcDst;
  738. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  739. list.concat(taicpu.op_none(A_CPL));
  740. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  741. end;
  742. ungetcpuregister(list,NR_A);
  743. end;
  744. OP_MUL,OP_IMUL:
  745. begin
  746. { special stuff, needs separate handling inside code
  747. generator }
  748. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_op_reg_reg_internal OP_MUL/OP_IMUL')));
  749. {internalerror(2017032604);}
  750. end;
  751. OP_DIV,OP_IDIV:
  752. { special stuff, needs separate handling inside code
  753. generator }
  754. internalerror(2017032604);
  755. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  756. begin
  757. current_asmdata.getjumplabel(l1);
  758. current_asmdata.getjumplabel(l2);
  759. getcpuregister(list,NR_B);
  760. emit_mov(list,NR_B,src);
  761. list.concat(taicpu.op_reg(A_INC,NR_B));
  762. list.concat(taicpu.op_reg(A_DEC,NR_B));
  763. a_jmp_flags(list,F_E,l2);
  764. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  765. case op of
  766. OP_ROL:
  767. begin
  768. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  769. list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  770. end;
  771. OP_ROR:
  772. begin
  773. list.concat(taicpu.op_reg(A_RLC,dst));
  774. list.concat(taicpu.op_reg(A_RRC,dst));
  775. end;
  776. else
  777. ;
  778. end;
  779. cg.a_label(list,l1);
  780. case op of
  781. OP_SHL:
  782. list.concat(taicpu.op_reg(A_SLA,dst));
  783. OP_SHR:
  784. list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  785. OP_SAR:
  786. list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  787. OP_ROL:
  788. if size in [OS_8,OS_S8] then
  789. list.concat(taicpu.op_reg(A_RLC,dst))
  790. else
  791. list.concat(taicpu.op_reg(A_RL,dst));
  792. OP_ROR:
  793. if size in [OS_8,OS_S8] then
  794. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)))
  795. else
  796. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  797. else
  798. internalerror(2020040903);
  799. end;
  800. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  801. begin
  802. for i:=2 to tcgsize2size[size] do
  803. begin
  804. case op of
  805. OP_ROR,
  806. OP_SHR,
  807. OP_SAR:
  808. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  809. OP_ROL,
  810. OP_SHL:
  811. list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(dst,dsthi,i-1)));
  812. else
  813. internalerror(2020040904);
  814. end;
  815. end;
  816. end;
  817. instr:=taicpu.op_sym(A_DJNZ,l1);
  818. instr.is_jmp:=true;
  819. list.concat(instr);
  820. ungetcpuregister(list,NR_B);
  821. cg.a_label(list,l2);
  822. end;
  823. OP_AND,OP_OR,OP_XOR:
  824. begin
  825. getcpuregister(list,NR_A);
  826. for i:=1 to tcgsize2size[size] do
  827. begin
  828. if i<>1 then
  829. NextSrcDst;
  830. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  831. list.concat(taicpu.op_reg_reg(topcg2asmop[op],NR_A,src));
  832. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  833. end;
  834. ungetcpuregister(list,NR_A);
  835. end;
  836. else
  837. internalerror(2011022004);
  838. end;
  839. end;
  840. procedure tcgz80.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
  841. size: TCGSize; a: tcgint; reg, reghi: TRegister);
  842. var
  843. i : byte;
  844. procedure NextReg;
  845. begin
  846. if i=4 then
  847. reg:=reghi
  848. else
  849. reg:=GetNextReg(reg);
  850. end;
  851. var
  852. mask : qword;
  853. shift : byte;
  854. curvalue : byte;
  855. tmpop: TAsmOp;
  856. l1: TAsmLabel;
  857. instr: taicpu;
  858. tmpreg : tregister;
  859. tmpreg64 : tregister64;
  860. begin
  861. optimize_op_const(size,op,a);
  862. mask:=$ff;
  863. shift:=0;
  864. case op of
  865. OP_NONE:
  866. begin
  867. { Opcode is optimized away }
  868. end;
  869. OP_MOVE:
  870. begin
  871. { Optimized, replaced with a simple load }
  872. a_load_const_reg(list,size,a,reg);
  873. end;
  874. OP_AND:
  875. begin
  876. curvalue:=a and mask;
  877. for i:=1 to tcgsize2size[size] do
  878. begin
  879. case curvalue of
  880. 0:
  881. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  882. $ff:
  883. {nothing};
  884. else
  885. begin
  886. getcpuregister(list,NR_A);
  887. emit_mov(list,NR_A,reg);
  888. list.concat(taicpu.op_reg_const(A_AND,NR_A,curvalue));
  889. emit_mov(list,reg,NR_A);
  890. ungetcpuregister(list,NR_A);
  891. end;
  892. end;
  893. if i<>tcgsize2size[size] then
  894. begin
  895. NextReg;
  896. mask:=mask shl 8;
  897. inc(shift,8);
  898. curvalue:=(qword(a) and mask) shr shift;
  899. end;
  900. end;
  901. end;
  902. OP_OR:
  903. begin
  904. curvalue:=a and mask;
  905. for i:=1 to tcgsize2size[size] do
  906. begin
  907. case curvalue of
  908. 0:
  909. {nothing};
  910. $ff:
  911. list.concat(taicpu.op_reg_const(A_LD,reg,$ff));
  912. else
  913. begin
  914. getcpuregister(list,NR_A);
  915. emit_mov(list,NR_A,reg);
  916. list.concat(taicpu.op_reg_const(A_OR,NR_A,curvalue));
  917. emit_mov(list,reg,NR_A);
  918. ungetcpuregister(list,NR_A);
  919. end;
  920. end;
  921. if i<>tcgsize2size[size] then
  922. begin
  923. NextReg;
  924. mask:=mask shl 8;
  925. inc(shift,8);
  926. curvalue:=(qword(a) and mask) shr shift;
  927. end;
  928. end;
  929. end;
  930. OP_XOR:
  931. begin
  932. curvalue:=a and mask;
  933. for i:=1 to tcgsize2size[size] do
  934. begin
  935. case curvalue of
  936. 0:
  937. {nothing};
  938. $ff:
  939. begin
  940. getcpuregister(list,NR_A);
  941. emit_mov(list,NR_A,reg);
  942. list.concat(taicpu.op_none(A_CPL));
  943. emit_mov(list,reg,NR_A);
  944. ungetcpuregister(list,NR_A);
  945. end;
  946. else
  947. begin
  948. getcpuregister(list,NR_A);
  949. emit_mov(list,NR_A,reg);
  950. list.concat(taicpu.op_reg_const(A_XOR,NR_A,curvalue));
  951. emit_mov(list,reg,NR_A);
  952. ungetcpuregister(list,NR_A);
  953. end;
  954. end;
  955. if i<>tcgsize2size[size] then
  956. begin
  957. NextReg;
  958. mask:=mask shl 8;
  959. inc(shift,8);
  960. curvalue:=(qword(a) and mask) shr shift;
  961. end;
  962. end;
  963. end;
  964. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  965. begin
  966. if size in [OS_64,OS_S64] then
  967. a:=a and 63
  968. else
  969. a:=a and 31;
  970. if a<>0 then
  971. begin
  972. if a>1 then
  973. begin
  974. current_asmdata.getjumplabel(l1);
  975. getcpuregister(list,NR_B);
  976. list.concat(taicpu.op_reg_const(A_LD,NR_B,a));
  977. end;
  978. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  979. case op of
  980. OP_ROL:
  981. begin
  982. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  983. list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  984. end;
  985. OP_ROR:
  986. begin
  987. list.concat(taicpu.op_reg(A_RLC,reg));
  988. list.concat(taicpu.op_reg(A_RRC,reg));
  989. end;
  990. else
  991. ;
  992. end;
  993. if a>1 then
  994. cg.a_label(list,l1);
  995. case op of
  996. OP_SHL:
  997. list.concat(taicpu.op_reg(A_SLA,reg));
  998. OP_SHR:
  999. list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  1000. OP_SAR:
  1001. list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  1002. OP_ROL:
  1003. if size in [OS_8,OS_S8] then
  1004. list.concat(taicpu.op_reg(A_RLC,reg))
  1005. else
  1006. list.concat(taicpu.op_reg(A_RL,reg));
  1007. OP_ROR:
  1008. if size in [OS_8,OS_S8] then
  1009. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)))
  1010. else
  1011. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  1012. else
  1013. internalerror(2020040903);
  1014. end;
  1015. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  1016. begin
  1017. for i:=2 to tcgsize2size[size] do
  1018. begin
  1019. case op of
  1020. OP_ROR,
  1021. OP_SHR,
  1022. OP_SAR:
  1023. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  1024. OP_ROL,
  1025. OP_SHL:
  1026. list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(reg,reghi,i-1)));
  1027. else
  1028. internalerror(2020040904);
  1029. end;
  1030. end;
  1031. end;
  1032. if a>1 then
  1033. begin
  1034. instr:=taicpu.op_sym(A_DJNZ,l1);
  1035. instr.is_jmp:=true;
  1036. list.concat(instr);
  1037. ungetcpuregister(list,NR_B);
  1038. end;
  1039. end;
  1040. end;
  1041. OP_ADD:
  1042. begin
  1043. curvalue:=a and mask;
  1044. tmpop:=A_NONE;
  1045. for i:=1 to tcgsize2size[size] do
  1046. begin
  1047. if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
  1048. tmpop:=A_INC
  1049. else if (tmpop=A_NONE) and (curvalue<>0) then
  1050. tmpop:=A_ADD
  1051. else if tmpop=A_ADD then
  1052. tmpop:=A_ADC;
  1053. case tmpop of
  1054. A_NONE:
  1055. {nothing};
  1056. A_INC:
  1057. list.concat(taicpu.op_reg(tmpop,reg));
  1058. A_ADD,A_ADC:
  1059. begin
  1060. getcpuregister(list,NR_A);
  1061. emit_mov(list,NR_A,reg);
  1062. list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
  1063. emit_mov(list,reg,NR_A);
  1064. ungetcpuregister(list,NR_A);
  1065. end;
  1066. else
  1067. internalerror(2020040901);
  1068. end;
  1069. if i<>tcgsize2size[size] then
  1070. begin
  1071. NextReg;
  1072. mask:=mask shl 8;
  1073. inc(shift,8);
  1074. curvalue:=(qword(a) and mask) shr shift;
  1075. end;
  1076. end;
  1077. end;
  1078. OP_SUB:
  1079. begin
  1080. curvalue:=a and mask;
  1081. tmpop:=A_NONE;
  1082. for i:=1 to tcgsize2size[size] do
  1083. begin
  1084. if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
  1085. tmpop:=A_DEC
  1086. else if (tmpop=A_NONE) and (curvalue<>0) then
  1087. tmpop:=A_SUB
  1088. else if tmpop=A_SUB then
  1089. tmpop:=A_SBC;
  1090. case tmpop of
  1091. A_NONE:
  1092. {nothing};
  1093. A_DEC:
  1094. list.concat(taicpu.op_reg(tmpop,reg));
  1095. A_SUB,A_SBC:
  1096. begin
  1097. getcpuregister(list,NR_A);
  1098. emit_mov(list,NR_A,reg);
  1099. list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
  1100. emit_mov(list,reg,NR_A);
  1101. ungetcpuregister(list,NR_A);
  1102. end;
  1103. else
  1104. internalerror(2020040902);
  1105. end;
  1106. if i<>tcgsize2size[size] then
  1107. begin
  1108. NextReg;
  1109. mask:=mask shl 8;
  1110. inc(shift,8);
  1111. curvalue:=(qword(a) and mask) shr shift;
  1112. end;
  1113. end;
  1114. end;
  1115. else
  1116. begin
  1117. if size in [OS_64,OS_S64] then
  1118. begin
  1119. tmpreg64.reglo:=getintregister(list,OS_32);
  1120. tmpreg64.reghi:=getintregister(list,OS_32);
  1121. cg64.a_load64_const_reg(list,a,tmpreg64);
  1122. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  1123. end
  1124. else
  1125. begin
  1126. {$if 0}
  1127. { code not working yet }
  1128. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  1129. begin
  1130. tmpreg:=reg;
  1131. for i:=1 to 4 do
  1132. begin
  1133. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
  1134. tmpreg:=GetNextReg(tmpreg);
  1135. end;
  1136. end
  1137. else
  1138. {$endif}
  1139. begin
  1140. tmpreg:=getintregister(list,size);
  1141. a_load_const_reg(list,size,a,tmpreg);
  1142. a_op_reg_reg(list,op,size,tmpreg,reg);
  1143. end;
  1144. end;
  1145. end;
  1146. end;
  1147. end;
  1148. procedure tcgz80.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  1149. var
  1150. mask : qword;
  1151. shift : byte;
  1152. i : byte;
  1153. begin
  1154. mask:=$ff;
  1155. shift:=0;
  1156. for i:=tcgsize2size[size] downto 1 do
  1157. begin
  1158. list.Concat(taicpu.op_reg_const(A_LD,reg,(qword(a) and mask) shr shift));
  1159. if i<>1 then
  1160. begin
  1161. mask:=mask shl 8;
  1162. inc(shift,8);
  1163. reg:=GetNextReg(reg);
  1164. end;
  1165. end;
  1166. end;
  1167. procedure tcgz80.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
  1168. var
  1169. mask : qword;
  1170. shift : byte;
  1171. href: treference;
  1172. i: Integer;
  1173. begin
  1174. mask:=$ff;
  1175. shift:=0;
  1176. href:=ref;
  1177. if (href.base=NR_NO) and (href.index<>NR_NO) then
  1178. begin
  1179. href.base:=href.index;
  1180. href.index:=NR_NO;
  1181. end;
  1182. if is_ref_in_opertypes(href,[OT_REF_IX_d,OT_REF_IY_d]) or
  1183. (is_ref_hl(href) and (size in [OS_8,OS_S8])) then
  1184. begin
  1185. for i:=tcgsize2size[size] downto 1 do
  1186. begin
  1187. list.Concat(taicpu.op_ref_const(A_LD,href,(qword(a) and mask) shr shift));
  1188. if i<>1 then
  1189. begin
  1190. mask:=mask shl 8;
  1191. inc(shift,8);
  1192. inc(href.offset);
  1193. end;
  1194. end;
  1195. end
  1196. else
  1197. inherited;
  1198. end;
  1199. procedure tcgz80.maybegetcpuregister(list:tasmlist;reg : tregister);
  1200. begin
  1201. { allocate the register only, if a cpu register is passed }
  1202. if getsupreg(reg)<first_int_imreg then
  1203. getcpuregister(list,reg);
  1204. end;
  1205. function tcgz80.normalize_ref(list: TAsmList; ref: treference;
  1206. const refopertypes: trefoperandtypes; out allocatedregs: tregisterlist): treference;
  1207. var
  1208. tmpref : treference;
  1209. l : tasmlabel;
  1210. begin
  1211. SetLength(allocatedregs,0);
  1212. if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then
  1213. begin
  1214. ref.base:=ref.index;
  1215. ref.index:=NR_NO;
  1216. end;
  1217. if is_ref_in_opertypes(ref,refopertypes) then
  1218. begin
  1219. Result:=ref;
  1220. exit;
  1221. end;
  1222. { can we use the HL register? }
  1223. if OT_REF_HL in refopertypes then
  1224. begin
  1225. SetLength(allocatedregs,2);
  1226. allocatedregs[0]:=NR_H;
  1227. allocatedregs[1]:=NR_L;
  1228. getcpuregisters(list,allocatedregs);
  1229. if assigned(ref.symbol) then
  1230. begin
  1231. reference_reset(tmpref,0,[]);
  1232. tmpref.symbol:=ref.symbol;
  1233. tmpref.offset:=ref.offset;
  1234. tmpref.refaddr:=addr_full;
  1235. list.concat(taicpu.op_reg_ref(A_LD,NR_HL,tmpref));
  1236. end
  1237. else
  1238. list.concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
  1239. if (ref.base=NR_IX) or (ref.base=NR_IY) then
  1240. begin
  1241. getcpuregister(list,NR_D);
  1242. getcpuregister(list,NR_E);
  1243. list.concat(taicpu.op_reg(A_PUSH,ref.base));
  1244. list.concat(taicpu.op_reg(A_POP,NR_DE));
  1245. list.concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_DE));
  1246. ungetcpuregister(list,NR_E);
  1247. ungetcpuregister(list,NR_D);
  1248. end
  1249. else if ref.base<>NR_NO then
  1250. begin
  1251. getcpuregister(list,NR_A);
  1252. emit_mov(list,NR_A,NR_L);
  1253. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.base));
  1254. emit_mov(list,NR_L,NR_A);
  1255. emit_mov(list,NR_A,NR_H);
  1256. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.base)));
  1257. emit_mov(list,NR_H,NR_A);
  1258. ungetcpuregister(list,NR_A);
  1259. end;
  1260. if ref.index<>NR_NO then
  1261. begin
  1262. if ref.scalefactor>1 then
  1263. internalerror(2020042002);
  1264. getcpuregister(list,NR_A);
  1265. emit_mov(list,NR_A,NR_L);
  1266. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index));
  1267. emit_mov(list,NR_L,NR_A);
  1268. emit_mov(list,NR_A,NR_H);
  1269. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index)));
  1270. emit_mov(list,NR_H,NR_A);
  1271. ungetcpuregister(list,NR_A);
  1272. end;
  1273. reference_reset_base(result,NR_HL,0,ctempposinvalid,0,[]);
  1274. end
  1275. else
  1276. internalerror(2020042001);
  1277. end;
  1278. procedure tcgz80.adjust_normalized_ref(list: TAsmList; var ref: treference; value: longint);
  1279. var
  1280. i: Integer;
  1281. begin
  1282. if is_ref_addr16(ref) then
  1283. Inc(ref.offset,value)
  1284. else if is_ref_hl(ref) then
  1285. begin
  1286. if value>0 then
  1287. for i:=1 to value do
  1288. list.concat(taicpu.op_reg(A_INC,NR_HL))
  1289. else
  1290. for i:=-1 downto value do
  1291. list.concat(taicpu.op_reg(A_DEC,NR_HL));
  1292. end
  1293. else if is_ref_ix_d(ref) then
  1294. begin
  1295. if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
  1296. inc(ref.offset,value)
  1297. else
  1298. begin
  1299. { todo: IX is the frame pointer, we cannot change it, so we }
  1300. { think of another mechanism to deal with this situation }
  1301. internalerror(2020042101);
  1302. //if value>0 then
  1303. // for i:=1 to value do
  1304. // list.concat(taicpu.op_reg(A_INC,NR_IX))
  1305. //else
  1306. // for i:=-1 downto value do
  1307. // list.concat(taicpu.op_reg(A_DEC,NR_IX));
  1308. end;
  1309. end
  1310. else if is_ref_iy_d(ref) then
  1311. begin
  1312. if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
  1313. inc(ref.offset,value)
  1314. else
  1315. if value>0 then
  1316. for i:=1 to value do
  1317. list.concat(taicpu.op_reg(A_INC,NR_IY))
  1318. else
  1319. for i:=-1 downto value do
  1320. list.concat(taicpu.op_reg(A_DEC,NR_IY));
  1321. end;
  1322. end;
  1323. procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  1324. var
  1325. href : treference;
  1326. i : integer;
  1327. regsused: tregisterlist;
  1328. begin
  1329. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1330. internalerror(2011021307);
  1331. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1332. internalerror(2020040802);
  1333. href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
  1334. if (tcgsize2size[fromsize]=tcgsize2size[tosize]) or (fromsize in [OS_8,OS_16,OS_32]) then
  1335. begin
  1336. getcpuregister(list,NR_A);
  1337. for i:=1 to tcgsize2size[fromsize] do
  1338. begin
  1339. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1340. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1341. if i<>tcgsize2size[fromsize] then
  1342. reg:=GetNextReg(reg);
  1343. if i<>tcgsize2size[tosize] then
  1344. adjust_normalized_ref(list,href,1);
  1345. end;
  1346. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1347. begin
  1348. if i=(tcgsize2size[fromsize]+1) then
  1349. list.concat(taicpu.op_reg_const(A_LD,NR_A,0));
  1350. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1351. if i<>tcgsize2size[tosize] then
  1352. begin
  1353. adjust_normalized_ref(list,href,1);
  1354. reg:=GetNextReg(reg);
  1355. end;
  1356. end;
  1357. ungetcpuregister(list,NR_A);
  1358. end
  1359. else
  1360. begin
  1361. getcpuregister(list,NR_A);
  1362. for i:=1 to tcgsize2size[fromsize] do
  1363. begin
  1364. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1365. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1366. if i<>tcgsize2size[fromsize] then
  1367. reg:=GetNextReg(reg);
  1368. if i<>tcgsize2size[tosize] then
  1369. adjust_normalized_ref(list,href,1);
  1370. end;
  1371. list.concat(taicpu.op_none(A_RLA));
  1372. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1373. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1374. begin
  1375. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1376. if i<>tcgsize2size[tosize] then
  1377. begin
  1378. adjust_normalized_ref(list,href,1);
  1379. reg:=GetNextReg(reg);
  1380. end;
  1381. end;
  1382. ungetcpuregister(list,NR_A);
  1383. end;
  1384. ungetcpuregisters(list,regsused);
  1385. end;
  1386. procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1387. const Ref : treference;reg : tregister);
  1388. var
  1389. href : treference;
  1390. i : integer;
  1391. regsused: tregisterlist;
  1392. begin
  1393. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1394. internalerror(2011021307);
  1395. if tcgsize2size[fromsize]>=tcgsize2size[tosize] then
  1396. fromsize:=tosize;
  1397. href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
  1398. if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then
  1399. begin
  1400. getcpuregister(list,NR_A);
  1401. for i:=1 to tcgsize2size[fromsize] do
  1402. begin
  1403. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1404. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1405. if i<>tcgsize2size[fromsize] then
  1406. adjust_normalized_ref(list,href,1);
  1407. if i<>tcgsize2size[tosize] then
  1408. reg:=GetNextReg(reg);
  1409. end;
  1410. ungetcpuregisters(list,regsused);
  1411. ungetcpuregister(list,NR_A);
  1412. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1413. begin
  1414. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  1415. if i<>tcgsize2size[tosize] then
  1416. reg:=GetNextReg(reg);
  1417. end;
  1418. end
  1419. else
  1420. begin
  1421. getcpuregister(list,NR_A);
  1422. for i:=1 to tcgsize2size[fromsize] do
  1423. begin
  1424. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1425. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1426. if i<>tcgsize2size[fromsize] then
  1427. adjust_normalized_ref(list,href,1);
  1428. if i<>tcgsize2size[tosize] then
  1429. reg:=GetNextReg(reg);
  1430. end;
  1431. ungetcpuregisters(list,regsused);
  1432. list.concat(taicpu.op_none(A_RLA));
  1433. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1434. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1435. begin
  1436. emit_mov(list,reg,NR_A);
  1437. if i<>tcgsize2size[tosize] then
  1438. reg:=GetNextReg(reg);
  1439. end;
  1440. ungetcpuregister(list,NR_A);
  1441. end;
  1442. end;
  1443. procedure tcgz80.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1444. var
  1445. conv_done: boolean;
  1446. tmpreg : tregister;
  1447. i : integer;
  1448. begin
  1449. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1450. internalerror(2011021310);
  1451. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1452. fromsize:=tosize;
  1453. if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then
  1454. begin
  1455. if reg1<>reg2 then
  1456. for i:=1 to tcgsize2size[fromsize] do
  1457. begin
  1458. emit_mov(list,reg2,reg1);
  1459. if i<>tcgsize2size[fromsize] then
  1460. reg1:=GetNextReg(reg1);
  1461. if i<>tcgsize2size[tosize] then
  1462. reg2:=GetNextReg(reg2);
  1463. end
  1464. else
  1465. for i:=1 to tcgsize2size[fromsize] do
  1466. if i<>tcgsize2size[tosize] then
  1467. reg2:=GetNextReg(reg2);
  1468. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1469. begin
  1470. list.Concat(taicpu.op_reg_const(A_LD,reg2,0));
  1471. if i<>tcgsize2size[tosize] then
  1472. reg2:=GetNextReg(reg2);
  1473. end
  1474. end
  1475. else
  1476. begin
  1477. if reg1<>reg2 then
  1478. for i:=1 to tcgsize2size[fromsize]-1 do
  1479. begin
  1480. emit_mov(list,reg2,reg1);
  1481. reg1:=GetNextReg(reg1);
  1482. reg2:=GetNextReg(reg2);
  1483. end
  1484. else
  1485. for i:=1 to tcgsize2size[fromsize]-1 do
  1486. reg2:=GetNextReg(reg2);
  1487. emit_mov(list,reg2,reg1);
  1488. getcpuregister(list,NR_A);
  1489. emit_mov(list,NR_A,reg2);
  1490. reg2:=GetNextReg(reg2);
  1491. list.concat(taicpu.op_none(A_RLA));
  1492. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1493. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1494. begin
  1495. emit_mov(list,reg2,NR_A);
  1496. if i<>tcgsize2size[tosize] then
  1497. reg2:=GetNextReg(reg2);
  1498. end;
  1499. ungetcpuregister(list,NR_A);
  1500. end;
  1501. end;
  1502. procedure tcgz80.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1503. begin
  1504. internalerror(2012010702);
  1505. end;
  1506. procedure tcgz80.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1507. begin
  1508. internalerror(2012010703);
  1509. end;
  1510. procedure tcgz80.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1511. begin
  1512. internalerror(2012010704);
  1513. end;
  1514. { comparison operations }
  1515. procedure tcgz80.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1516. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1517. var
  1518. swapped : boolean;
  1519. tmpreg : tregister;
  1520. i : byte;
  1521. tmpl: TAsmLabel;
  1522. begin
  1523. if size in [OS_8,OS_S8]then
  1524. begin
  1525. if cmp_op in [OC_EQ,OC_NE,OC_B,OC_AE] then
  1526. begin
  1527. getcpuregister(list,NR_A);
  1528. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1529. list.concat(taicpu.op_reg_const(A_CP,NR_A,a));
  1530. case cmp_op of
  1531. OC_EQ:
  1532. a_jmp_flags(list,F_E,l);
  1533. OC_NE:
  1534. a_jmp_flags(list,F_NE,l);
  1535. OC_B:
  1536. a_jmp_flags(list,F_C,l);
  1537. OC_AE:
  1538. a_jmp_flags(list,F_NC,l);
  1539. else
  1540. internalerror(2020042206);
  1541. end;
  1542. ungetcpuregister(list,NR_A);
  1543. end
  1544. else if cmp_op in [OC_A,OC_BE] then
  1545. begin
  1546. getcpuregister(list,NR_A);
  1547. a_load_const_reg(list,OS_8,a,NR_A);
  1548. list.concat(taicpu.op_reg_reg(A_CP,NR_A,reg));
  1549. case cmp_op of
  1550. OC_A:
  1551. a_jmp_flags(list,F_C,l);
  1552. OC_BE:
  1553. a_jmp_flags(list,F_NC,l);
  1554. else
  1555. internalerror(2020042206);
  1556. end;
  1557. ungetcpuregister(list,NR_A);
  1558. end
  1559. else if cmp_op in [OC_LT,OC_GTE] then
  1560. begin
  1561. getcpuregister(list,NR_A);
  1562. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1563. list.concat(taicpu.op_reg_const(A_SUB,NR_A,a));
  1564. current_asmdata.getjumplabel(tmpl);
  1565. a_jmp_flags(list,F_PO,tmpl);
  1566. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1567. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1568. case cmp_op of
  1569. OC_LT:
  1570. a_jmp_flags(list,F_M,l);
  1571. OC_GTE:
  1572. a_jmp_flags(list,F_P,l);
  1573. else
  1574. internalerror(2020042206);
  1575. end;
  1576. ungetcpuregister(list,NR_A);
  1577. end
  1578. else if cmp_op in [OC_GT,OC_LTE] then
  1579. begin
  1580. getcpuregister(list,NR_A);
  1581. a_load_const_reg(list,OS_8,a,NR_A);
  1582. list.concat(taicpu.op_reg_reg(A_SUB,NR_A,reg));
  1583. current_asmdata.getjumplabel(tmpl);
  1584. a_jmp_flags(list,F_PO,tmpl);
  1585. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1586. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1587. case cmp_op of
  1588. OC_GT:
  1589. a_jmp_flags(list,F_M,l);
  1590. OC_LTE:
  1591. a_jmp_flags(list,F_P,l);
  1592. else
  1593. internalerror(2020042206);
  1594. end;
  1595. ungetcpuregister(list,NR_A);
  1596. end;
  1597. end
  1598. else if cmp_op in [OC_EQ,OC_NE] then
  1599. begin
  1600. if cmp_op=OC_EQ then
  1601. current_asmdata.getjumplabel(tmpl);
  1602. for i:=0 to tcgsize2size[size]-1 do
  1603. begin
  1604. a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A);
  1605. list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i))));
  1606. case cmp_op of
  1607. OC_EQ:
  1608. if i<>(tcgsize2size[size]-1) then
  1609. a_jmp_flags(list,F_NE,tmpl)
  1610. else
  1611. a_jmp_flags(list,F_E,l);
  1612. OC_NE:
  1613. a_jmp_flags(list,F_NE,l);
  1614. else
  1615. internalerror(2020042206);
  1616. end;
  1617. end;
  1618. if cmp_op=OC_EQ then
  1619. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1620. end
  1621. else if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE,OC_BE,OC_B,OC_AE,OC_A] then
  1622. begin
  1623. getcpuregister(list,NR_A);
  1624. current_asmdata.getjumplabel(tmpl);
  1625. for i:=tcgsize2size[size]-1 downto 0 do
  1626. begin
  1627. a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A);
  1628. list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i))));
  1629. if (i=(tcgsize2size[size]-1)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then
  1630. case cmp_op of
  1631. OC_GTE,
  1632. OC_GT:
  1633. a_jmp_signed_cmp_3way(list,tmpl,nil,l);
  1634. OC_LT,
  1635. OC_LTE:
  1636. a_jmp_signed_cmp_3way(list,l,nil,tmpl);
  1637. else
  1638. internalerror(2020042206);
  1639. end
  1640. else if i<>0 then
  1641. case cmp_op of
  1642. OC_AE,
  1643. OC_A,
  1644. OC_GTE,
  1645. OC_GT:
  1646. a_jmp_unsigned_cmp_3way(list,tmpl,nil,l);
  1647. OC_BE,
  1648. OC_B,
  1649. OC_LT,
  1650. OC_LTE:
  1651. a_jmp_unsigned_cmp_3way(list,l,nil,tmpl);
  1652. else
  1653. internalerror(2020042206);
  1654. end
  1655. else
  1656. case cmp_op of
  1657. OC_A,
  1658. OC_GT:
  1659. a_jmp_unsigned_cmp_3way(list,nil,nil,l);
  1660. OC_B,
  1661. OC_LT:
  1662. a_jmp_unsigned_cmp_3way(list,l,nil,nil);
  1663. OC_AE,
  1664. OC_GTE:
  1665. a_jmp_unsigned_cmp_3way(list,nil,l,l);
  1666. OC_BE,
  1667. OC_LTE:
  1668. a_jmp_unsigned_cmp_3way(list,l,l,nil);
  1669. else
  1670. internalerror(2020042206);
  1671. end;
  1672. end;
  1673. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1674. ungetcpuregister(list,NR_A);
  1675. end
  1676. else
  1677. internalerror(2020042205);
  1678. end;
  1679. procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1680. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1681. var
  1682. swapped : boolean;
  1683. tmpreg : tregister;
  1684. i : byte;
  1685. begin
  1686. internalerror(2020042301);
  1687. //swapped:=false;
  1688. //{ swap parameters? }
  1689. //case cmp_op of
  1690. // OC_GT:
  1691. // begin
  1692. // swapped:=true;
  1693. // cmp_op:=OC_LT;
  1694. // end;
  1695. // OC_LTE:
  1696. // begin
  1697. // swapped:=true;
  1698. // cmp_op:=OC_GTE;
  1699. // end;
  1700. // OC_BE:
  1701. // begin
  1702. // swapped:=true;
  1703. // cmp_op:=OC_AE;
  1704. // end;
  1705. // OC_A:
  1706. // begin
  1707. // swapped:=true;
  1708. // cmp_op:=OC_B;
  1709. // end;
  1710. //end;
  1711. //if swapped then
  1712. // begin
  1713. // tmpreg:=reg1;
  1714. // reg1:=reg2;
  1715. // reg2:=tmpreg;
  1716. // end;
  1717. //list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1718. //
  1719. //for i:=2 to tcgsize2size[size] do
  1720. // begin
  1721. // reg1:=GetNextReg(reg1);
  1722. // reg2:=GetNextReg(reg2);
  1723. // list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1724. // end;
  1725. //
  1726. //a_jmp_cond(list,cmp_op,l);
  1727. end;
  1728. procedure tcgz80.a_jmp_name(list : TAsmList;const s : string);
  1729. var
  1730. ai : taicpu;
  1731. begin
  1732. ai:=taicpu.op_sym(A_JP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1733. ai.is_jmp:=true;
  1734. list.concat(ai);
  1735. end;
  1736. procedure tcgz80.a_jmp_always(list : TAsmList;l: tasmlabel);
  1737. var
  1738. ai : taicpu;
  1739. begin
  1740. ai:=taicpu.op_sym(A_JP,l);
  1741. ai.is_jmp:=true;
  1742. list.concat(ai);
  1743. end;
  1744. procedure tcgz80.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1745. var
  1746. ai : taicpu;
  1747. begin
  1748. ai:=taicpu.op_cond_sym(A_JP,flags_to_cond(f),l);
  1749. ai.is_jmp:=true;
  1750. list.concat(ai);
  1751. end;
  1752. procedure tcgz80.a_jmp_unsigned_cmp_3way(list: TAsmList; onbelow, onequal, onabove: tasmlabel);
  1753. var
  1754. skiplabel: TAsmLabel;
  1755. begin
  1756. if (onbelow= nil) and (onequal= nil) and (onabove= nil) then
  1757. {nothing}
  1758. else if (onbelow= nil) and (onequal= nil) and (onabove<>nil) then
  1759. begin
  1760. current_asmdata.getjumplabel(skiplabel);
  1761. a_jmp_flags(list,F_E,skiplabel);
  1762. a_jmp_flags(list,F_NC,onabove);
  1763. cg.a_label(list,skiplabel);
  1764. end
  1765. else if (onbelow= nil) and (onequal<>nil) and (onabove= nil) then
  1766. a_jmp_flags(list,F_E,onequal)
  1767. else if (onbelow= nil) and (onequal<>nil) and (onabove<>nil) then
  1768. begin
  1769. if onequal<>onabove then
  1770. a_jmp_flags(list,F_E,onequal);
  1771. a_jmp_flags(list,F_NC,onabove);
  1772. end
  1773. else if (onbelow<>nil) and (onequal= nil) and (onabove= nil) then
  1774. a_jmp_flags(list,F_C,onbelow)
  1775. else if (onbelow<>nil) and (onequal= nil) and (onabove<>nil) then
  1776. begin
  1777. if onbelow<>onabove then
  1778. a_jmp_flags(list,F_C,onbelow);
  1779. a_jmp_flags(list,F_NE,onabove);
  1780. end
  1781. else if (onbelow<>nil) and (onequal<>nil) and (onabove= nil) then
  1782. begin
  1783. a_jmp_flags(list,F_C,onbelow);
  1784. a_jmp_flags(list,F_E,onequal);
  1785. end
  1786. else if (onbelow<>nil) and (onequal<>nil) and (onabove<>nil) then
  1787. begin
  1788. if (onbelow=onequal) and (onequal=onabove) then
  1789. a_jmp_always(list,onbelow)
  1790. else if onequal=onabove then
  1791. begin
  1792. a_jmp_flags(list,F_C,onbelow);
  1793. a_jmp_always(list,onabove);
  1794. end
  1795. else if onbelow=onequal then
  1796. begin
  1797. a_jmp_flags(list,F_C,onbelow);
  1798. a_jmp_flags(list,F_E,onequal);
  1799. a_jmp_always(list,onabove);
  1800. end
  1801. else if onbelow=onabove then
  1802. begin
  1803. a_jmp_flags(list,F_E,onequal);
  1804. a_jmp_always(list,onabove);
  1805. end
  1806. else
  1807. begin
  1808. { the generic case - all 3 are different labels }
  1809. a_jmp_flags(list,F_C,onbelow);
  1810. a_jmp_flags(list,F_E,onequal);
  1811. a_jmp_always(list,onabove);
  1812. end;
  1813. end
  1814. else
  1815. begin
  1816. { Shouldn't happen! All possible combinations are handled by the above code. }
  1817. internalerror(2020042201);
  1818. end;
  1819. end;
  1820. procedure tcgz80.a_jmp_signed_cmp_3way(list: TAsmList; onless, onequal, ongreater: tasmlabel);
  1821. var
  1822. l, skiplabel: TAsmLabel;
  1823. begin
  1824. if (onless= nil) and (onequal= nil) and (ongreater= nil) then
  1825. {nothing}
  1826. else if (onless= nil) and (onequal= nil) and (ongreater<>nil) then
  1827. begin
  1828. current_asmdata.getjumplabel(skiplabel);
  1829. a_jmp_flags(list,F_E,skiplabel);
  1830. current_asmdata.getjumplabel(l);
  1831. a_jmp_flags(list,F_PO,l);
  1832. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1833. cg.a_label(current_asmdata.CurrAsmList,l);
  1834. a_jmp_flags(list,F_P,ongreater);
  1835. cg.a_label(list,skiplabel);
  1836. end
  1837. else if (onless= nil) and (onequal<>nil) and (ongreater= nil) then
  1838. a_jmp_flags(list,F_E,onequal)
  1839. else if (onless= nil) and (onequal<>nil) and (ongreater<>nil) then
  1840. begin
  1841. if onequal<>ongreater then
  1842. a_jmp_flags(list,F_E,onequal);
  1843. current_asmdata.getjumplabel(l);
  1844. a_jmp_flags(list,F_PO,l);
  1845. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1846. cg.a_label(current_asmdata.CurrAsmList,l);
  1847. a_jmp_flags(list,F_P,ongreater);
  1848. end
  1849. else if (onless<>nil) and (onequal= nil) and (ongreater= nil) then
  1850. begin
  1851. current_asmdata.getjumplabel(l);
  1852. a_jmp_flags(list,F_PO,l);
  1853. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1854. cg.a_label(current_asmdata.CurrAsmList,l);
  1855. a_jmp_flags(list,F_M,onless);
  1856. end
  1857. else if (onless<>nil) and (onequal= nil) and (ongreater<>nil) then
  1858. begin
  1859. if onless=ongreater then
  1860. a_jmp_flags(list,F_NE,onless)
  1861. else
  1862. begin
  1863. current_asmdata.getjumplabel(skiplabel);
  1864. a_jmp_flags(list,F_E,skiplabel);
  1865. current_asmdata.getjumplabel(l);
  1866. a_jmp_flags(list,F_PO,l);
  1867. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1868. cg.a_label(current_asmdata.CurrAsmList,l);
  1869. a_jmp_flags(list,F_M,onless);
  1870. a_jmp_always(list,ongreater);
  1871. cg.a_label(list,skiplabel);
  1872. end;
  1873. end
  1874. else if (onless<>nil) and (onequal<>nil) and (ongreater= nil) then
  1875. begin
  1876. a_jmp_flags(list,F_E,onequal);
  1877. current_asmdata.getjumplabel(l);
  1878. a_jmp_flags(list,F_PO,l);
  1879. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1880. cg.a_label(current_asmdata.CurrAsmList,l);
  1881. a_jmp_flags(list,F_M,onless);
  1882. end
  1883. else if (onless<>nil) and (onequal<>nil) and (ongreater<>nil) then
  1884. begin
  1885. if (onless=onequal) and (onequal=ongreater) then
  1886. a_jmp_always(list,onless)
  1887. else if onequal=ongreater then
  1888. begin
  1889. current_asmdata.getjumplabel(l);
  1890. a_jmp_flags(list,F_PO,l);
  1891. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1892. cg.a_label(current_asmdata.CurrAsmList,l);
  1893. a_jmp_flags(list,F_M,onless);
  1894. a_jmp_always(list,ongreater);
  1895. end
  1896. else if onless=onequal then
  1897. begin
  1898. a_jmp_flags(list,F_E,onequal);
  1899. current_asmdata.getjumplabel(l);
  1900. a_jmp_flags(list,F_PO,l);
  1901. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1902. cg.a_label(current_asmdata.CurrAsmList,l);
  1903. a_jmp_flags(list,F_M,onless);
  1904. a_jmp_always(list,ongreater);
  1905. end
  1906. else if onless=ongreater then
  1907. begin
  1908. a_jmp_flags(list,F_E,onequal);
  1909. a_jmp_always(list,ongreater);
  1910. end
  1911. else
  1912. begin
  1913. { the generic case - all 3 are different labels }
  1914. a_jmp_flags(list,F_E,onequal);
  1915. current_asmdata.getjumplabel(l);
  1916. a_jmp_flags(list,F_PO,l);
  1917. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1918. cg.a_label(current_asmdata.CurrAsmList,l);
  1919. a_jmp_flags(list,F_M,onless);
  1920. a_jmp_always(list,ongreater);
  1921. end;
  1922. end
  1923. else
  1924. begin
  1925. { Shouldn't happen! All possible combinations are handled by the above code. }
  1926. internalerror(2020042204);
  1927. end;
  1928. end;
  1929. procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1930. var
  1931. l : TAsmLabel;
  1932. tmpflags : TResFlags;
  1933. begin
  1934. if f in [F_C,F_NC] then
  1935. begin
  1936. a_load_const_reg(list,size,0,reg);
  1937. if f=F_NC then
  1938. list.concat(taicpu.op_none(A_CCF));
  1939. list.concat(taicpu.op_reg(A_RL,reg));
  1940. end
  1941. else
  1942. begin
  1943. current_asmdata.getjumplabel(l);
  1944. a_load_const_reg(list,size,0,reg);
  1945. tmpflags:=f;
  1946. inverse_flags(tmpflags);
  1947. a_jmp_flags(list,tmpflags,l);
  1948. list.concat(taicpu.op_reg(A_INC,reg));
  1949. cg.a_label(list,l);
  1950. end;
  1951. end;
  1952. procedure tcgz80.g_stackpointer_alloc(list: TAsmList; localsize: longint);
  1953. begin
  1954. if localsize>0 then
  1955. begin
  1956. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize));
  1957. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
  1958. list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
  1959. end;
  1960. end;
  1961. procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
  1962. var
  1963. i : integer;
  1964. begin
  1965. //case value of
  1966. // 0:
  1967. // ;
  1968. // {-14..-1:
  1969. // begin
  1970. // if ((-value) mod 2)<>0 then
  1971. // list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1972. // for i:=1 to (-value) div 2 do
  1973. // list.concat(taicpu.op_const(A_RCALL,0));
  1974. // end;
  1975. // 1..7:
  1976. // begin
  1977. // for i:=1 to value do
  1978. // list.concat(taicpu.op_reg(A_POP,NR_R0));
  1979. // end;}
  1980. // else
  1981. // begin
  1982. // list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1983. // list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1984. // // get SREG
  1985. // list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1986. //
  1987. // // block interrupts
  1988. // list.concat(taicpu.op_none(A_CLI));
  1989. //
  1990. // // write high SP
  1991. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1992. //
  1993. // // release interrupts
  1994. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1995. //
  1996. // // write low SP
  1997. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1998. // end;
  1999. //end;
  2000. end;
  2001. procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  2002. var
  2003. regsize,stackmisalignment: longint;
  2004. begin
  2005. regsize:=0;
  2006. stackmisalignment:=0;
  2007. { save old framepointer }
  2008. if not nostackframe then
  2009. begin
  2010. { return address }
  2011. inc(stackmisalignment,2);
  2012. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  2013. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  2014. begin
  2015. { push <frame_pointer> }
  2016. inc(stackmisalignment,2);
  2017. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  2018. list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG));
  2019. { Return address and FP are both on stack }
  2020. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2);
  2021. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2));
  2022. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  2023. begin
  2024. list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0));
  2025. list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG))
  2026. end
  2027. else
  2028. begin
  2029. internalerror(2020040301);
  2030. (*push_regs;
  2031. gen_load_frame_for_exceptfilter(list);
  2032. { Need only as much stack space as necessary to do the calls.
  2033. Exception filters don't have own local vars, and temps are 'mapped'
  2034. to the parent procedure.
  2035. maxpushedparasize is already aligned at least on x86_64. }
  2036. localsize:=current_procinfo.maxpushedparasize;*)
  2037. end;
  2038. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  2039. end
  2040. else
  2041. begin
  2042. CGmessage(cg_d_stackframe_omited);
  2043. end;
  2044. { allocate stackframe space }
  2045. if (localsize<>0) or
  2046. ((target_info.stackalign>sizeof(pint)) and
  2047. (stackmisalignment <> 0) and
  2048. ((pi_do_call in current_procinfo.flags) or
  2049. (po_assembler in current_procinfo.procdef.procoptions))) then
  2050. begin
  2051. if target_info.stackalign>sizeof(pint) then
  2052. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  2053. g_stackpointer_alloc(list,localsize);
  2054. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  2055. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
  2056. current_procinfo.final_localsize:=localsize;
  2057. end
  2058. end;
  2059. end;
  2060. procedure tcgz80.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  2061. var
  2062. regs : tcpuregisterset;
  2063. reg : TSuperRegister;
  2064. LocalSize : longint;
  2065. begin
  2066. { every byte counts for Z80, so if a subroutine is marked as non-returning, we do
  2067. not generate any exit code, so we really trust the noreturn directive
  2068. }
  2069. if po_noreturn in current_procinfo.procdef.procoptions then
  2070. exit;
  2071. { remove stackframe }
  2072. if not nostackframe then
  2073. begin
  2074. stacksize:=current_procinfo.calc_stackframe_size;
  2075. if (target_info.stackalign>4) and
  2076. ((stacksize <> 0) or
  2077. (pi_do_call in current_procinfo.flags) or
  2078. { can't detect if a call in this case -> use nostackframe }
  2079. { if you (think you) know what you are doing }
  2080. (po_assembler in current_procinfo.procdef.procoptions)) then
  2081. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  2082. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  2083. begin
  2084. internalerror(2020040302);
  2085. {if (stacksize<>0) then
  2086. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);}
  2087. end
  2088. else
  2089. begin
  2090. list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  2091. list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG));
  2092. end;
  2093. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  2094. end;
  2095. list.concat(taicpu.op_none(A_RET));
  2096. end;
  2097. procedure tcgz80.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  2098. var
  2099. tmpref : treference;
  2100. begin
  2101. if assigned(ref.symbol) then
  2102. begin
  2103. reference_reset(tmpref,0,[]);
  2104. tmpref.symbol:=ref.symbol;
  2105. tmpref.offset:=ref.offset;
  2106. tmpref.refaddr:=addr_lo8;
  2107. list.concat(taicpu.op_reg_ref(A_LD,r,tmpref));
  2108. tmpref.refaddr:=addr_hi8;
  2109. list.concat(taicpu.op_reg_ref(A_LD,GetNextReg(r),tmpref));
  2110. if (ref.base<>NR_NO) then
  2111. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  2112. if (ref.index<>NR_NO) then
  2113. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2114. end
  2115. else if ref.base=NR_IX then
  2116. begin
  2117. list.concat(taicpu.op_reg(A_PUSH,NR_IX));
  2118. getcpuregister(list,NR_H);
  2119. getcpuregister(list,NR_L);
  2120. list.concat(taicpu.op_reg(A_POP,NR_HL));
  2121. emit_mov(list,r,NR_L);
  2122. ungetcpuregister(list,NR_L);
  2123. emit_mov(list,GetNextReg(r),NR_H);
  2124. ungetcpuregister(list,NR_H);
  2125. if (ref.index<>NR_NO) then
  2126. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2127. if ref.offset<>0 then
  2128. a_op_const_reg(list,OP_ADD,OS_16,ref.offset,r);
  2129. end
  2130. else if (ref.base=NR_SP) or (ref.base=NR_BC) or (ref.base=NR_DE) then
  2131. begin
  2132. getcpuregister(list,NR_H);
  2133. getcpuregister(list,NR_L);
  2134. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
  2135. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,ref.base));
  2136. emit_mov(list,r,NR_L);
  2137. ungetcpuregister(list,NR_L);
  2138. emit_mov(list,GetNextReg(r),NR_H);
  2139. ungetcpuregister(list,NR_H);
  2140. if (ref.index<>NR_NO) then
  2141. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2142. end
  2143. else
  2144. begin
  2145. a_load_const_reg(list,OS_16,ref.offset,r);
  2146. if (ref.base<>NR_NO) then
  2147. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  2148. if (ref.index<>NR_NO) then
  2149. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2150. end;
  2151. end;
  2152. procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  2153. var
  2154. tmpreg,srcreg,dstreg: tregister;
  2155. srcref,dstref : treference;
  2156. i: Integer;
  2157. begin
  2158. if (len<=2) and
  2159. is_ref_in_opertypes(source,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) and
  2160. is_ref_in_opertypes(dest,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
  2161. begin
  2162. srcref:=source;
  2163. dstref:=dest;
  2164. tmpreg:=getintregister(list,OS_8);
  2165. for i:=1 to len do
  2166. begin
  2167. list.concat(taicpu.op_reg_ref(A_LD,tmpreg,srcref));
  2168. list.concat(taicpu.op_ref_reg(A_LD,dstref,tmpreg));
  2169. if i<>len then
  2170. begin
  2171. adjust_normalized_ref(list,srcref,1);
  2172. adjust_normalized_ref(list,dstref,1);
  2173. end;
  2174. end;
  2175. end
  2176. else
  2177. begin
  2178. srcreg:=getintregister(list,OS_16);
  2179. a_loadaddr_ref_reg(list,source,srcreg);
  2180. dstreg:=getintregister(list,OS_16);
  2181. a_loadaddr_ref_reg(list,dest,dstreg);
  2182. getcpuregister(list,NR_L);
  2183. a_load_reg_reg(list,OS_8,OS_8,srcreg,NR_L);
  2184. getcpuregister(list,NR_H);
  2185. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(srcreg),NR_H);
  2186. getcpuregister(list,NR_E);
  2187. a_load_reg_reg(list,OS_8,OS_8,dstreg,NR_E);
  2188. getcpuregister(list,NR_D);
  2189. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(dstreg),NR_D);
  2190. getcpuregister(list,NR_B);
  2191. getcpuregister(list,NR_C);
  2192. list.concat(taicpu.op_reg_const(A_LD,NR_BC,len));
  2193. list.concat(taicpu.op_none(A_LDIR));
  2194. ungetcpuregister(list,NR_B);
  2195. ungetcpuregister(list,NR_C);
  2196. ungetcpuregister(list,NR_D);
  2197. ungetcpuregister(list,NR_E);
  2198. ungetcpuregister(list,NR_H);
  2199. ungetcpuregister(list,NR_L);
  2200. end;
  2201. end;
  2202. procedure tcgz80.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  2203. var
  2204. hl : tasmlabel;
  2205. ai : taicpu;
  2206. cond : TAsmCond;
  2207. begin
  2208. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck')));
  2209. //if not(cs_check_overflow in current_settings.localswitches) then
  2210. // exit;
  2211. //current_asmdata.getjumplabel(hl);
  2212. //if not ((def.typ=pointerdef) or
  2213. // ((def.typ=orddef) and
  2214. // (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2215. // pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2216. // cond:=C_VC
  2217. //else
  2218. // cond:=C_CC;
  2219. //ai:=Taicpu.Op_Sym(A_BRxx,hl);
  2220. //ai.SetCondition(cond);
  2221. //ai.is_jmp:=true;
  2222. //list.concat(ai);
  2223. //
  2224. //a_call_name(list,'FPC_OVERFLOW',false);
  2225. //a_label(list,hl);
  2226. end;
  2227. procedure tcgz80.g_save_registers(list: TAsmList);
  2228. begin
  2229. { this is done by the entry code }
  2230. end;
  2231. procedure tcgz80.g_restore_registers(list: TAsmList);
  2232. begin
  2233. { this is done by the exit code }
  2234. end;
  2235. procedure tcgz80.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2236. begin
  2237. case cond of
  2238. OC_EQ:
  2239. a_jmp_unsigned_cmp_3way(list,nil,l,nil);
  2240. OC_NE:
  2241. a_jmp_unsigned_cmp_3way(list,l,nil,l);
  2242. OC_A:
  2243. a_jmp_unsigned_cmp_3way(list,nil,nil,l);
  2244. OC_B:
  2245. a_jmp_unsigned_cmp_3way(list,l,nil,nil);
  2246. OC_AE:
  2247. a_jmp_unsigned_cmp_3way(list,nil,l,l);
  2248. OC_BE:
  2249. a_jmp_unsigned_cmp_3way(list,l,l,nil);
  2250. OC_GT:
  2251. a_jmp_signed_cmp_3way(list,nil,nil,l);
  2252. OC_LT:
  2253. a_jmp_signed_cmp_3way(list,l,nil,nil);
  2254. OC_GTE:
  2255. a_jmp_signed_cmp_3way(list,nil,l,l);
  2256. OC_LTE:
  2257. a_jmp_signed_cmp_3way(list,l,l,nil);
  2258. else
  2259. internalerror(2011082501);
  2260. end;
  2261. end;
  2262. procedure tcgz80.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  2263. var
  2264. instr: taicpu;
  2265. begin
  2266. instr:=taicpu.op_reg_reg(A_LD,reg2,reg1);
  2267. list.Concat(instr);
  2268. { Notify the register allocator that we have written a move instruction so
  2269. it can try to eliminate it. }
  2270. add_move_instruction(instr);
  2271. end;
  2272. procedure tcg64fz80.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2273. begin
  2274. if not(size in [OS_S64,OS_64]) then
  2275. internalerror(2012102402);
  2276. tcgz80(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  2277. end;
  2278. procedure tcg64fz80.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2279. begin
  2280. tcgz80(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  2281. end;
  2282. function GetByteLoc(const loc : tlocation; nr : byte) : tlocation;
  2283. var
  2284. i : Integer;
  2285. begin
  2286. Result:=loc;
  2287. Result.size:=OS_8;
  2288. case loc.loc of
  2289. LOC_REFERENCE,LOC_CREFERENCE:
  2290. inc(Result.reference.offset,nr);
  2291. LOC_REGISTER,LOC_CREGISTER:
  2292. begin
  2293. if nr>=4 then
  2294. Result.register:=Result.register64.reghi;
  2295. nr:=nr mod 4;
  2296. for i:=1 to nr do
  2297. Result.register:=GetNextReg(Result.register);
  2298. end;
  2299. LOC_CONSTANT:
  2300. if loc.size in [OS_64,OS_S64] then
  2301. Result.value:=(Result.value64 shr (nr*8)) and $ff
  2302. else
  2303. Result.value:=(Result.value shr (nr*8)) and $ff;
  2304. else
  2305. Internalerror(2019020902);
  2306. end;
  2307. end;
  2308. procedure create_codegen;
  2309. begin
  2310. cg:=tcgz80.create;
  2311. cg64:=tcg64fz80.create;
  2312. end;
  2313. end.