cgcpu.pas 92 KB

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