cgcpu.pas 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993
  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. { tcgz80 }
  29. tcgz80 = class(tcg)
  30. { true, if the next arithmetic operation should modify the flags }
  31. cgsetflags : boolean;
  32. procedure init_register_allocators;override;
  33. procedure done_register_allocators;override;
  34. function getaddressregister(list:TAsmList):TRegister;override;
  35. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
  36. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  37. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  38. procedure a_load_reg_cgpara(list : TAsmList; size : tcgsize;r : tregister; const cgpara : tcgpara);override;
  39. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  40. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  41. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  42. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override;
  43. { move instructions }
  44. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  45. procedure a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);override;
  46. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  47. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  48. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  49. { fpu move instructions }
  50. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  51. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  52. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  53. { comparison operations }
  54. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  55. l : tasmlabel);override;
  56. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  57. procedure a_jmp_name(list : TAsmList;const s : string); override;
  58. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  59. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  60. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  61. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  62. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  63. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  64. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  65. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  66. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  67. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  68. procedure g_save_registers(list : TAsmList);override;
  69. procedure g_restore_registers(list : TAsmList);override;
  70. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  71. procedure fixref(list : TAsmList;var ref : treference);
  72. function normalize_ref(list : TAsmList;ref : treference;
  73. tmpreg : tregister) : treference;
  74. procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  75. procedure a_adjust_sp(list: TAsmList; value: longint);
  76. protected
  77. procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  78. procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister);
  79. procedure maybegetcpuregister(list : tasmlist; reg : tregister);
  80. end;
  81. tcg64fz80 = class(tcg64f32)
  82. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  83. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  84. end;
  85. function GetByteLoc(const loc : tlocation;nr : byte) : tlocation;
  86. procedure create_codegen;
  87. const
  88. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_LD,A_ADD,A_AND,A_NONE,
  89. A_NONE,A_NONE,A_NONE,A_NEG,A_CPL,A_OR,
  90. A_SRA,A_SLA,A_SRL,A_SUB,A_XOR,A_RLCA,A_RRCA);
  91. implementation
  92. uses
  93. globals,verbose,systems,cutils,
  94. fmodule,
  95. symconst,symsym,symtable,
  96. tgobj,rgobj,
  97. procinfo,cpupi,
  98. paramgr;
  99. procedure tcgz80.init_register_allocators;
  100. begin
  101. inherited init_register_allocators;
  102. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  103. [RS_A,RS_B,RS_C,RS_D,RS_E,RS_H,RS_L],first_int_imreg,[]);
  104. end;
  105. procedure tcgz80.done_register_allocators;
  106. begin
  107. rg[R_INTREGISTER].free;
  108. // rg[R_ADDRESSREGISTER].free;
  109. inherited done_register_allocators;
  110. end;
  111. function tcgz80.getaddressregister(list: TAsmList): TRegister;
  112. begin
  113. Result:=getintregister(list,OS_ADDR);
  114. end;
  115. procedure tcgz80.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  116. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  117. var
  118. ref : treference;
  119. begin
  120. paramanager.allocparaloc(list,paraloc);
  121. case paraloc^.loc of
  122. LOC_REGISTER,LOC_CREGISTER:
  123. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  124. LOC_REFERENCE,LOC_CREFERENCE:
  125. begin
  126. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,ctempposinvalid,2,[]);
  127. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  128. end;
  129. else
  130. internalerror(2002071004);
  131. end;
  132. end;
  133. var
  134. i, i2 : longint;
  135. hp : PCGParaLocation;
  136. begin
  137. { if use_push(cgpara) then
  138. begin
  139. if tcgsize2size[cgpara.Size] > 2 then
  140. begin
  141. if tcgsize2size[cgpara.Size] <> 4 then
  142. internalerror(2013031101);
  143. if cgpara.location^.Next = nil then
  144. begin
  145. if tcgsize2size[cgpara.location^.size] <> 4 then
  146. internalerror(2013031101);
  147. end
  148. else
  149. begin
  150. if tcgsize2size[cgpara.location^.size] <> 2 then
  151. internalerror(2013031101);
  152. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  153. internalerror(2013031101);
  154. if cgpara.location^.Next^.Next <> nil then
  155. internalerror(2013031101);
  156. end;
  157. if tcgsize2size[cgpara.size]>cgpara.alignment then
  158. pushsize:=cgpara.size
  159. else
  160. pushsize:=int_cgsize(cgpara.alignment);
  161. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  162. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  163. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  164. end
  165. else
  166. begin
  167. cgpara.check_simple_location;
  168. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  169. pushsize:=cgpara.location^.size
  170. else
  171. pushsize:=int_cgsize(cgpara.alignment);
  172. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  173. end;
  174. end
  175. else }
  176. begin
  177. if not(tcgsize2size[cgpara.Size] in [1..4]) then
  178. internalerror(2014011101);
  179. hp:=cgpara.location;
  180. i:=0;
  181. while i<tcgsize2size[cgpara.Size] do
  182. begin
  183. if not(assigned(hp)) then
  184. internalerror(2014011102);
  185. inc(i, tcgsize2size[hp^.Size]);
  186. if hp^.Loc=LOC_REGISTER then
  187. begin
  188. load_para_loc(r,hp);
  189. hp:=hp^.Next;
  190. r:=GetNextReg(r);
  191. end
  192. else
  193. begin
  194. load_para_loc(r,hp);
  195. for i2:=1 to tcgsize2size[hp^.Size] do
  196. r:=GetNextReg(r);
  197. hp:=hp^.Next;
  198. end;
  199. end;
  200. if assigned(hp) then
  201. internalerror(2014011103);
  202. end;
  203. end;
  204. procedure tcgz80.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
  205. var
  206. i : longint;
  207. hp : PCGParaLocation;
  208. ref: treference;
  209. begin
  210. if not(tcgsize2size[paraloc.Size] in [1..4]) then
  211. internalerror(2014011101);
  212. hp:=paraloc.location;
  213. i:=1;
  214. while i<=tcgsize2size[paraloc.Size] do
  215. begin
  216. if not(assigned(hp)) then
  217. internalerror(2014011105);
  218. //paramanager.allocparaloc(list,hp);
  219. case hp^.loc of
  220. LOC_REGISTER,LOC_CREGISTER:
  221. begin
  222. if (tcgsize2size[hp^.size]<>1) or
  223. (hp^.shiftval<>0) then
  224. internalerror(2015041101);
  225. a_load_const_reg(list,hp^.size,(a shr (8*(i-1))) and $ff,hp^.register);
  226. inc(i,tcgsize2size[hp^.size]);
  227. hp:=hp^.Next;
  228. end;
  229. LOC_REFERENCE,LOC_CREFERENCE:
  230. begin
  231. reference_reset(ref,paraloc.alignment,[]);
  232. ref.base:=hp^.reference.index;
  233. ref.offset:=hp^.reference.offset;
  234. a_load_const_ref(list,hp^.size,a shr (8*(i-1)),ref);
  235. inc(i,tcgsize2size[hp^.size]);
  236. hp:=hp^.Next;
  237. end;
  238. else
  239. internalerror(2002071004);
  240. end;
  241. end;
  242. end;
  243. procedure tcgz80.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  244. var
  245. tmpref, ref: treference;
  246. location: pcgparalocation;
  247. sizeleft: tcgint;
  248. begin
  249. location := paraloc.location;
  250. tmpref := r;
  251. sizeleft := paraloc.intsize;
  252. while assigned(location) do
  253. begin
  254. paramanager.allocparaloc(list,location);
  255. case location^.loc of
  256. LOC_REGISTER,LOC_CREGISTER:
  257. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  258. LOC_REFERENCE:
  259. begin
  260. reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,paraloc.alignment,[]);
  261. { doubles in softemu mode have a strange order of registers and references }
  262. if location^.size=OS_32 then
  263. g_concatcopy(list,tmpref,ref,4)
  264. else
  265. begin
  266. g_concatcopy(list,tmpref,ref,sizeleft);
  267. if assigned(location^.next) then
  268. internalerror(2005010710);
  269. end;
  270. end;
  271. LOC_VOID:
  272. begin
  273. // nothing to do
  274. end;
  275. else
  276. internalerror(2002081103);
  277. end;
  278. inc(tmpref.offset,tcgsize2size[location^.size]);
  279. dec(sizeleft,tcgsize2size[location^.size]);
  280. location := location^.next;
  281. end;
  282. end;
  283. procedure tcgz80.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  284. var
  285. tmpreg: tregister;
  286. begin
  287. tmpreg:=getaddressregister(list);
  288. a_loadaddr_ref_reg(list,r,tmpreg);
  289. a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc);
  290. end;
  291. procedure tcgz80.a_call_name(list : TAsmList;const s : string; weak: boolean);
  292. var
  293. sym: TAsmSymbol;
  294. begin
  295. if weak then
  296. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)
  297. else
  298. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  299. list.concat(taicpu.op_sym(A_CALL,sym));
  300. include(current_procinfo.flags,pi_do_call);
  301. end;
  302. procedure tcgz80.a_call_reg(list : TAsmList;reg: tregister);
  303. var
  304. l : TAsmLabel;
  305. ref : treference;
  306. begin
  307. current_asmdata.getjumplabel(l);
  308. reference_reset(ref,0,[]);
  309. ref.symbol:=l;
  310. list.concat(taicpu.op_ref_reg(A_LD,ref,reg));
  311. list.concat(tai_const.Create_8bit($CD));
  312. list.concat(tai_label.Create(l));
  313. include(current_procinfo.flags,pi_do_call);
  314. end;
  315. procedure tcgz80.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  316. begin
  317. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  318. internalerror(2012102403);
  319. a_op_const_reg_internal(list,Op,size,a,reg,NR_NO);
  320. end;
  321. procedure tcgz80.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister);
  322. begin
  323. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  324. internalerror(2012102401);
  325. a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO);
  326. end;
  327. procedure tcgz80.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  328. var
  329. countreg,
  330. tmpreg,tmpreg2: tregister;
  331. i : integer;
  332. instr : taicpu;
  333. paraloc1,paraloc2,paraloc3 : TCGPara;
  334. l1,l2 : tasmlabel;
  335. pd : tprocdef;
  336. procedure NextSrcDst;
  337. begin
  338. if i=5 then
  339. begin
  340. dst:=dsthi;
  341. src:=srchi;
  342. end
  343. else
  344. begin
  345. dst:=GetNextReg(dst);
  346. src:=GetNextReg(src);
  347. end;
  348. end;
  349. { iterates TmpReg through all registers of dst }
  350. procedure NextTmp;
  351. begin
  352. if i=5 then
  353. tmpreg:=dsthi
  354. else
  355. tmpreg:=GetNextReg(tmpreg);
  356. end;
  357. begin
  358. case op of
  359. OP_ADD:
  360. begin
  361. getcpuregister(list,NR_A);
  362. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  363. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,src));
  364. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  365. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  366. begin
  367. for i:=2 to tcgsize2size[size] do
  368. begin
  369. NextSrcDst;
  370. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  371. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,src));
  372. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  373. end;
  374. end;
  375. ungetcpuregister(list,NR_A);
  376. end;
  377. OP_SUB:
  378. begin
  379. getcpuregister(list,NR_A);
  380. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  381. list.concat(taicpu.op_reg_reg(A_SUB,NR_A,src));
  382. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  383. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  384. begin
  385. for i:=2 to tcgsize2size[size] do
  386. begin
  387. NextSrcDst;
  388. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  389. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,src));
  390. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  391. end;
  392. end;
  393. ungetcpuregister(list,NR_A);
  394. end;
  395. OP_NEG:
  396. begin
  397. getcpuregister(list,NR_A);
  398. if tcgsize2size[size]>=2 then
  399. begin
  400. tmpreg:=GetNextReg(src);
  401. tmpreg2:=GetNextReg(dst);
  402. for i:=2 to tcgsize2size[size] do
  403. begin
  404. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
  405. list.concat(taicpu.op_none(A_CPL));
  406. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  407. if i<>tcgsize2size[size] then
  408. begin
  409. if i=5 then
  410. begin
  411. tmpreg:=srchi;
  412. tmpreg2:=dsthi;
  413. end
  414. else
  415. begin
  416. tmpreg:=GetNextReg(tmpreg);
  417. tmpreg2:=GetNextReg(tmpreg2);
  418. end;
  419. end;
  420. end;
  421. end;
  422. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  423. list.concat(taicpu.op_none(A_NEG));
  424. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  425. if tcgsize2size[size]>=2 then
  426. begin
  427. tmpreg2:=GetNextReg(dst);
  428. for i:=2 to tcgsize2size[size] do
  429. begin
  430. a_load_reg_reg(list,OS_8,OS_8,tmpreg2,NR_A);
  431. list.concat(taicpu.op_reg_const(A_SBC,NR_A,-1));
  432. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  433. if i<>tcgsize2size[size] then
  434. begin
  435. if i=5 then
  436. begin
  437. tmpreg2:=dsthi;
  438. end
  439. else
  440. begin
  441. tmpreg2:=GetNextReg(tmpreg2);
  442. end;
  443. end;
  444. end;
  445. end;
  446. ungetcpuregister(list,NR_A);
  447. end;
  448. OP_NOT:
  449. begin
  450. getcpuregister(list,NR_A);
  451. for i:=1 to tcgsize2size[size] do
  452. begin
  453. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  454. list.concat(taicpu.op_none(A_CPL));
  455. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  456. if i<>tcgsize2size[size] then
  457. NextSrcDst;
  458. end;
  459. ungetcpuregister(list,NR_A);
  460. end;
  461. OP_MUL,OP_IMUL:
  462. { special stuff, needs separate handling inside code
  463. generator }
  464. internalerror(2017032604);
  465. OP_DIV,OP_IDIV:
  466. { special stuff, needs separate handling inside code
  467. generator }
  468. internalerror(2017032604);
  469. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  470. begin
  471. //current_asmdata.getjumplabel(l1);
  472. //current_asmdata.getjumplabel(l2);
  473. //countreg:=getintregister(list,OS_8);
  474. //a_load_reg_reg(list,size,OS_8,src,countreg);
  475. //list.concat(taicpu.op_reg(A_TST,countreg));
  476. //a_jmp_flags(list,F_EQ,l2);
  477. //cg.a_label(list,l1);
  478. //case op of
  479. // OP_SHR:
  480. // list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  481. // OP_SHL:
  482. // list.concat(taicpu.op_reg(A_LSL,dst));
  483. // OP_SAR:
  484. // list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  485. // OP_ROR:
  486. // begin
  487. // { load carry? }
  488. // if not(size in [OS_8,OS_S8]) then
  489. // begin
  490. // list.concat(taicpu.op_none(A_CLC));
  491. // list.concat(taicpu.op_reg_const(A_SBRC,src,0));
  492. // list.concat(taicpu.op_none(A_SEC));
  493. // end;
  494. // list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  495. // end;
  496. // OP_ROL:
  497. // begin
  498. // { load carry? }
  499. // if not(size in [OS_8,OS_S8]) then
  500. // begin
  501. // list.concat(taicpu.op_none(A_CLC));
  502. // list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1),7));
  503. // list.concat(taicpu.op_none(A_SEC));
  504. // end;
  505. // list.concat(taicpu.op_reg(A_ROL,dst))
  506. // end;
  507. // else
  508. // internalerror(2011030901);
  509. //end;
  510. //if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  511. // begin
  512. // for i:=2 to tcgsize2size[size] do
  513. // begin
  514. // case op of
  515. // OP_ROR,
  516. // OP_SHR:
  517. // list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  518. // OP_ROL,
  519. // OP_SHL:
  520. // list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(dst,dsthi,i-1)));
  521. // OP_SAR:
  522. // list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  523. // else
  524. // internalerror(2011030902);
  525. // end;
  526. // end;
  527. // end;
  528. //
  529. //list.concat(taicpu.op_reg(A_DEC,countreg));
  530. //a_jmp_flags(list,F_NE,l1);
  531. //// keep registers alive
  532. //list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  533. //cg.a_label(list,l2);
  534. end;
  535. OP_AND,OP_OR,OP_XOR:
  536. begin
  537. getcpuregister(list,NR_A);
  538. for i:=1 to tcgsize2size[size] do
  539. begin
  540. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  541. list.concat(taicpu.op_reg_reg(topcg2asmop[op],NR_A,src));
  542. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  543. if i<>tcgsize2size[size] then
  544. NextSrcDst;
  545. end;
  546. ungetcpuregister(list,NR_A);
  547. end;
  548. else
  549. internalerror(2011022004);
  550. end;
  551. end;
  552. procedure tcgz80.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
  553. size: TCGSize; a: tcgint; reg, reghi: TRegister);
  554. var
  555. mask : qword;
  556. shift : byte;
  557. i,j : byte;
  558. tmpreg : tregister;
  559. tmpreg64 : tregister64;
  560. procedure NextReg;
  561. begin
  562. if i=5 then
  563. reg:=reghi
  564. else
  565. reg:=GetNextReg(reg);
  566. end;
  567. var
  568. curvalue : byte;
  569. begin
  570. optimize_op_const(size,op,a);
  571. mask:=$ff;
  572. shift:=0;
  573. case op of
  574. OP_NONE:
  575. begin
  576. { Opcode is optimized away }
  577. end;
  578. OP_MOVE:
  579. begin
  580. { Optimized, replaced with a simple load }
  581. a_load_const_reg(list,size,a,reg);
  582. end;
  583. OP_OR:
  584. begin
  585. //for i:=1 to tcgsize2size[size] do
  586. // begin
  587. // if ((qword(a) and mask) shr shift)<>0 then
  588. // list.concat(taicpu.op_reg_const(A_ORI,reg,(qword(a) and mask) shr shift));
  589. // NextReg;
  590. // mask:=mask shl 8;
  591. // inc(shift,8);
  592. // end;
  593. end;
  594. OP_AND:
  595. begin
  596. //for i:=1 to tcgsize2size[size] do
  597. // begin
  598. // if ((qword(a) and mask) shr shift)=0 then
  599. // list.concat(taicpu.op_reg_reg(A_MOV,reg,NR_R1))
  600. // else
  601. // list.concat(taicpu.op_reg_const(A_ANDI,reg,(qword(a) and mask) shr shift));
  602. // NextReg;
  603. // mask:=mask shl 8;
  604. // inc(shift,8);
  605. // end;
  606. end;
  607. OP_SUB:
  608. begin
  609. //if ((a and mask)=1) and (tcgsize2size[size]=1) then
  610. // list.concat(taicpu.op_reg(A_DEC,reg))
  611. //else
  612. // list.concat(taicpu.op_reg_const(A_SUBI,reg,a and mask));
  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. // NextReg;
  618. // mask:=mask shl 8;
  619. // inc(shift,8);
  620. // curvalue:=(qword(a) and mask) shr shift;
  621. // { decrease pressure on upper half of registers by using SBC ...,R1 instead
  622. // of SBCI ...,0 }
  623. // if curvalue=0 then
  624. // list.concat(taicpu.op_reg_reg(A_SBC,reg,NR_R1))
  625. // else
  626. // list.concat(taicpu.op_reg_const(A_SBCI,reg,curvalue));
  627. // end;
  628. // end;
  629. end;
  630. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  631. begin
  632. //if a*tcgsize2size[size]<=8 then
  633. // begin
  634. // for j:=1 to a do
  635. // begin
  636. // case op of
  637. // OP_SHR:
  638. // list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  639. // OP_SHL:
  640. // list.concat(taicpu.op_reg(A_LSL,reg));
  641. // OP_SAR:
  642. // list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  643. // OP_ROR:
  644. // begin
  645. // { load carry? }
  646. // if not(size in [OS_8,OS_S8]) then
  647. // begin
  648. // list.concat(taicpu.op_none(A_CLC));
  649. // list.concat(taicpu.op_reg_const(A_SBRC,reg,0));
  650. // list.concat(taicpu.op_none(A_SEC));
  651. // end;
  652. // list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  653. // end;
  654. // OP_ROL:
  655. // begin
  656. // { load carry? }
  657. // if not(size in [OS_8,OS_S8]) then
  658. // begin
  659. // list.concat(taicpu.op_none(A_CLC));
  660. // list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1),7));
  661. // list.concat(taicpu.op_none(A_SEC));
  662. // end;
  663. // list.concat(taicpu.op_reg(A_ROL,reg))
  664. // end;
  665. // else
  666. // internalerror(2011030901);
  667. // end;
  668. // if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  669. // begin
  670. // for i:=2 to tcgsize2size[size] do
  671. // begin
  672. // case op of
  673. // OP_ROR,
  674. // OP_SHR:
  675. // list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  676. // OP_ROL,
  677. // OP_SHL:
  678. // list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(reg,reghi,i-1)));
  679. // OP_SAR:
  680. // list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  681. // else
  682. // internalerror(2011030902);
  683. // end;
  684. // end;
  685. // end;
  686. // end;
  687. // end
  688. //else
  689. // begin
  690. // tmpreg:=getintregister(list,size);
  691. // a_load_const_reg(list,size,a,tmpreg);
  692. // a_op_reg_reg(list,op,size,tmpreg,reg);
  693. // end;
  694. end;
  695. OP_ADD:
  696. begin
  697. //curvalue:=a and mask;
  698. //if curvalue=0 then
  699. // list.concat(taicpu.op_reg_reg(A_ADD,reg,NR_R1))
  700. //else if (curvalue=1) and (tcgsize2size[size]=1) then
  701. // list.concat(taicpu.op_reg(A_INC,reg))
  702. //else
  703. // begin
  704. // tmpreg:=getintregister(list,OS_8);
  705. // a_load_const_reg(list,OS_8,curvalue,tmpreg);
  706. // list.concat(taicpu.op_reg_reg(A_ADD,reg,tmpreg));
  707. // end;
  708. //if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  709. // begin
  710. // for i:=2 to tcgsize2size[size] do
  711. // begin
  712. // NextReg;
  713. // mask:=mask shl 8;
  714. // inc(shift,8);
  715. // curvalue:=(qword(a) and mask) shr shift;
  716. // { decrease pressure on upper half of registers by using ADC ...,R1 instead
  717. // of ADD ...,0 }
  718. // if curvalue=0 then
  719. // list.concat(taicpu.op_reg_reg(A_ADC,reg,NR_R1))
  720. // else
  721. // begin
  722. // tmpreg:=getintregister(list,OS_8);
  723. // a_load_const_reg(list,OS_8,curvalue,tmpreg);
  724. // list.concat(taicpu.op_reg_reg(A_ADC,reg,tmpreg));
  725. // end;
  726. // end;
  727. // end;
  728. end;
  729. else
  730. begin
  731. if size in [OS_64,OS_S64] then
  732. begin
  733. tmpreg64.reglo:=getintregister(list,OS_32);
  734. tmpreg64.reghi:=getintregister(list,OS_32);
  735. cg64.a_load64_const_reg(list,a,tmpreg64);
  736. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  737. end
  738. else
  739. begin
  740. {$if 0}
  741. { code not working yet }
  742. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  743. begin
  744. tmpreg:=reg;
  745. for i:=1 to 4 do
  746. begin
  747. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
  748. tmpreg:=GetNextReg(tmpreg);
  749. end;
  750. end
  751. else
  752. {$endif}
  753. begin
  754. tmpreg:=getintregister(list,size);
  755. a_load_const_reg(list,size,a,tmpreg);
  756. a_op_reg_reg(list,op,size,tmpreg,reg);
  757. end;
  758. end;
  759. end;
  760. end;
  761. end;
  762. procedure tcgz80.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  763. var
  764. mask : qword;
  765. shift : byte;
  766. i : byte;
  767. begin
  768. mask:=$ff;
  769. shift:=0;
  770. for i:=tcgsize2size[size] downto 1 do
  771. begin
  772. list.Concat(taicpu.op_reg_const(A_LD,reg,(qword(a) and mask) shr shift));
  773. if i<>1 then
  774. begin
  775. mask:=mask shl 8;
  776. inc(shift,8);
  777. reg:=GetNextReg(reg);
  778. end;
  779. end;
  780. end;
  781. procedure tcgz80.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
  782. var
  783. mask : qword;
  784. shift : byte;
  785. href: treference;
  786. i: Integer;
  787. begin
  788. mask:=$ff;
  789. shift:=0;
  790. href:=ref;
  791. if (href.base=NR_NO) and (href.index<>NR_NO) then
  792. begin
  793. href.base:=href.index;
  794. href.index:=NR_NO;
  795. end;
  796. if not assigned(href.symbol) and
  797. ((href.base=NR_IX) or (href.base=NR_IY) or
  798. ((href.base=NR_HL) and (size in [OS_8,OS_S8]) and (href.offset=0))) then
  799. begin
  800. for i:=tcgsize2size[size] downto 1 do
  801. begin
  802. list.Concat(taicpu.op_ref_const(A_LD,href,(qword(a) and mask) shr shift));
  803. if i<>1 then
  804. begin
  805. mask:=mask shl 8;
  806. inc(shift,8);
  807. inc(href.offset);
  808. end;
  809. end;
  810. end
  811. else
  812. inherited;
  813. end;
  814. procedure tcgz80.maybegetcpuregister(list:tasmlist;reg : tregister);
  815. begin
  816. { allocate the register only, if a cpu register is passed }
  817. if getsupreg(reg)<first_int_imreg then
  818. getcpuregister(list,reg);
  819. end;
  820. function tcgz80.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
  821. var
  822. tmpref : treference;
  823. l : tasmlabel;
  824. begin
  825. Result:=ref;
  826. //
  827. // if ref.addressmode<>AM_UNCHANGED then
  828. // internalerror(2011021701);
  829. //
  830. // { Be sure to have a base register }
  831. // if (ref.base=NR_NO) then
  832. // begin
  833. // { only symbol+offset? }
  834. // if ref.index=NR_NO then
  835. // exit;
  836. // ref.base:=ref.index;
  837. // ref.index:=NR_NO;
  838. // end;
  839. //
  840. // { can we take advantage of adiw/sbiw? }
  841. // if (current_settings.cputype>=cpu_avr2) and not(assigned(ref.symbol)) and (ref.offset<>0) and (ref.offset>=-63) and (ref.offset<=63) and
  842. // ((tmpreg=NR_R24) or (tmpreg=NR_R26) or (tmpreg=NR_R28) or (tmpreg=NR_R30)) and (ref.base<>NR_NO) then
  843. // begin
  844. // maybegetcpuregister(list,tmpreg);
  845. // emit_mov(list,tmpreg,ref.base);
  846. // maybegetcpuregister(list,GetNextReg(tmpreg));
  847. // emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  848. // if ref.index<>NR_NO then
  849. // begin
  850. // list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  851. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  852. // end;
  853. // if ref.offset>0 then
  854. // list.concat(taicpu.op_reg_const(A_ADIW,tmpreg,ref.offset))
  855. // else
  856. // list.concat(taicpu.op_reg_const(A_SBIW,tmpreg,-ref.offset));
  857. // ref.offset:=0;
  858. // ref.base:=tmpreg;
  859. // ref.index:=NR_NO;
  860. // end
  861. // else if assigned(ref.symbol) or (ref.offset<>0) then
  862. // begin
  863. // reference_reset(tmpref,0,[]);
  864. // tmpref.symbol:=ref.symbol;
  865. // tmpref.offset:=ref.offset;
  866. // if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  867. // tmpref.refaddr:=addr_lo8_gs
  868. // else
  869. // tmpref.refaddr:=addr_lo8;
  870. // maybegetcpuregister(list,tmpreg);
  871. // list.concat(taicpu.op_reg_ref(A_LDI,tmpreg,tmpref));
  872. //
  873. // if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  874. // tmpref.refaddr:=addr_hi8_gs
  875. // else
  876. // tmpref.refaddr:=addr_hi8;
  877. // maybegetcpuregister(list,GetNextReg(tmpreg));
  878. // list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(tmpreg),tmpref));
  879. //
  880. // if (ref.base<>NR_NO) then
  881. // begin
  882. // list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.base));
  883. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.base)));
  884. // end;
  885. // if (ref.index<>NR_NO) then
  886. // begin
  887. // list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  888. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  889. // end;
  890. // ref.symbol:=nil;
  891. // ref.offset:=0;
  892. // ref.base:=tmpreg;
  893. // ref.index:=NR_NO;
  894. // end
  895. // else if (ref.base<>NR_NO) and (ref.index<>NR_NO) then
  896. // begin
  897. // maybegetcpuregister(list,tmpreg);
  898. // emit_mov(list,tmpreg,ref.base);
  899. // maybegetcpuregister(list,GetNextReg(tmpreg));
  900. // emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  901. // list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  902. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  903. // ref.base:=tmpreg;
  904. // ref.index:=NR_NO;
  905. // end
  906. // else if (ref.base<>NR_NO) then
  907. // begin
  908. // maybegetcpuregister(list,tmpreg);
  909. // emit_mov(list,tmpreg,ref.base);
  910. // maybegetcpuregister(list,GetNextReg(tmpreg));
  911. // emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  912. // ref.base:=tmpreg;
  913. // ref.index:=NR_NO;
  914. // end
  915. // else if (ref.index<>NR_NO) then
  916. // begin
  917. // maybegetcpuregister(list,tmpreg);
  918. // emit_mov(list,tmpreg,ref.index);
  919. // maybegetcpuregister(list,GetNextReg(tmpreg));
  920. // emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.index));
  921. // ref.base:=tmpreg;
  922. // ref.index:=NR_NO;
  923. // end;
  924. Result:=ref;
  925. end;
  926. procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  927. var
  928. href : treference;
  929. i : integer;
  930. begin
  931. href:=Ref;
  932. { ensure, href.base contains a valid register if there is any register used }
  933. if href.base=NR_NO then
  934. begin
  935. href.base:=href.index;
  936. href.index:=NR_NO;
  937. end;
  938. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  939. internalerror(2011021307);
  940. if fromsize=tosize then
  941. begin
  942. getcpuregister(list,NR_A);
  943. for i:=tcgsize2size[fromsize] downto 1 do
  944. begin
  945. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  946. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  947. if i<>1 then
  948. begin
  949. inc(href.offset);
  950. reg:=GetNextReg(reg);
  951. end;
  952. end;
  953. ungetcpuregister(list,NR_A);
  954. end
  955. else
  956. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_load_reg_ref')));
  957. end;
  958. procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  959. const Ref : treference;reg : tregister);
  960. var
  961. href : treference;
  962. i : integer;
  963. begin
  964. href:=Ref;
  965. { ensure, href.base contains a valid register if there is any register used }
  966. if href.base=NR_NO then
  967. begin
  968. href.base:=href.index;
  969. href.index:=NR_NO;
  970. end;
  971. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  972. internalerror(2011021307);
  973. if tosize=fromsize then
  974. begin
  975. getcpuregister(list,NR_A);
  976. for i:=tcgsize2size[fromsize] downto 1 do
  977. begin
  978. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  979. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  980. if i<>1 then
  981. begin
  982. inc(href.offset);
  983. reg:=GetNextReg(reg);
  984. end;
  985. end;
  986. ungetcpuregister(list,NR_A);
  987. end
  988. else
  989. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_load_ref_reg')));
  990. //conv_done:=false;
  991. //if tosize<>fromsize then
  992. // begin
  993. // conv_done:=true;
  994. // if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  995. // fromsize:=tosize;
  996. // case fromsize of
  997. // OS_8:
  998. // begin
  999. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1000. // for i:=2 to tcgsize2size[tosize] do
  1001. // begin
  1002. // reg:=GetNextReg(reg);
  1003. // emit_mov(list,reg,NR_R1);
  1004. // end;
  1005. // end;
  1006. // OS_S8:
  1007. // begin
  1008. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1009. // tmpreg:=reg;
  1010. //
  1011. // if tcgsize2size[tosize]>1 then
  1012. // begin
  1013. // reg:=GetNextReg(reg);
  1014. // emit_mov(list,reg,NR_R1);
  1015. // list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1016. // list.concat(taicpu.op_reg(A_COM,reg));
  1017. // tmpreg:=reg;
  1018. // for i:=3 to tcgsize2size[tosize] do
  1019. // begin
  1020. // reg:=GetNextReg(reg);
  1021. // emit_mov(list,reg,tmpreg);
  1022. // end;
  1023. // end;
  1024. // end;
  1025. // OS_16:
  1026. // begin
  1027. // if not(QuickRef) then
  1028. // href.addressmode:=AM_POSTINCREMENT;
  1029. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1030. //
  1031. // if QuickRef then
  1032. // inc(href.offset);
  1033. // href.addressmode:=AM_UNCHANGED;
  1034. //
  1035. // reg:=GetNextReg(reg);
  1036. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1037. //
  1038. // for i:=3 to tcgsize2size[tosize] do
  1039. // begin
  1040. // reg:=GetNextReg(reg);
  1041. // emit_mov(list,reg,NR_R1);
  1042. // end;
  1043. // end;
  1044. // OS_S16:
  1045. // begin
  1046. // if not(QuickRef) then
  1047. // href.addressmode:=AM_POSTINCREMENT;
  1048. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1049. // if QuickRef then
  1050. // inc(href.offset);
  1051. // href.addressmode:=AM_UNCHANGED;
  1052. //
  1053. // reg:=GetNextReg(reg);
  1054. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1055. // tmpreg:=reg;
  1056. //
  1057. // reg:=GetNextReg(reg);
  1058. // emit_mov(list,reg,NR_R1);
  1059. // list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1060. // list.concat(taicpu.op_reg(A_COM,reg));
  1061. // tmpreg:=reg;
  1062. // for i:=4 to tcgsize2size[tosize] do
  1063. // begin
  1064. // reg:=GetNextReg(reg);
  1065. // emit_mov(list,reg,tmpreg);
  1066. // end;
  1067. // end;
  1068. // else
  1069. // conv_done:=false;
  1070. // end;
  1071. // end;
  1072. //if not conv_done then
  1073. // begin
  1074. // for i:=1 to tcgsize2size[fromsize] do
  1075. // begin
  1076. // if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1077. // href.addressmode:=AM_POSTINCREMENT
  1078. // else
  1079. // href.addressmode:=AM_UNCHANGED;
  1080. //
  1081. // list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1082. //
  1083. // if QuickRef then
  1084. // inc(href.offset);
  1085. //
  1086. // reg:=GetNextReg(reg);
  1087. // end;
  1088. // end;
  1089. //
  1090. //if not(QuickRef) then
  1091. // begin
  1092. // ungetcpuregister(list,href.base);
  1093. // ungetcpuregister(list,GetNextReg(href.base));
  1094. // end;
  1095. end;
  1096. procedure tcgz80.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1097. var
  1098. conv_done: boolean;
  1099. tmpreg : tregister;
  1100. i : integer;
  1101. begin
  1102. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1103. internalerror(2011021310);
  1104. if tosize=fromsize then
  1105. begin
  1106. if reg1<>reg2 then
  1107. for i:=tcgsize2size[fromsize] downto 1 do
  1108. begin
  1109. emit_mov(list,reg2,reg1);
  1110. if i<>1 then
  1111. begin
  1112. reg1:=GetNextReg(reg1);
  1113. reg2:=GetNextReg(reg2);
  1114. end;
  1115. end;
  1116. end
  1117. else
  1118. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_load_reg_reg')));
  1119. end;
  1120. procedure tcgz80.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1121. begin
  1122. internalerror(2012010702);
  1123. end;
  1124. procedure tcgz80.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1125. begin
  1126. internalerror(2012010703);
  1127. end;
  1128. procedure tcgz80.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1129. begin
  1130. internalerror(2012010704);
  1131. end;
  1132. { comparison operations }
  1133. procedure tcgz80.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1134. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1135. var
  1136. swapped : boolean;
  1137. tmpreg : tregister;
  1138. i : byte;
  1139. begin
  1140. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_cmp_const_reg_label')));
  1141. //if a=0 then
  1142. // begin
  1143. // swapped:=false;
  1144. // { swap parameters? }
  1145. // case cmp_op of
  1146. // OC_GT:
  1147. // begin
  1148. // swapped:=true;
  1149. // cmp_op:=OC_LT;
  1150. // end;
  1151. // OC_LTE:
  1152. // begin
  1153. // swapped:=true;
  1154. // cmp_op:=OC_GTE;
  1155. // end;
  1156. // OC_BE:
  1157. // begin
  1158. // swapped:=true;
  1159. // cmp_op:=OC_AE;
  1160. // end;
  1161. // OC_A:
  1162. // begin
  1163. // swapped:=true;
  1164. // cmp_op:=OC_B;
  1165. // end;
  1166. // end;
  1167. //
  1168. // if swapped then
  1169. // list.concat(taicpu.op_reg_reg(A_CP,NR_R1,reg))
  1170. // else
  1171. // list.concat(taicpu.op_reg_reg(A_CP,reg,NR_R1));
  1172. //
  1173. // for i:=2 to tcgsize2size[size] do
  1174. // begin
  1175. // reg:=GetNextReg(reg);
  1176. // if swapped then
  1177. // list.concat(taicpu.op_reg_reg(A_CPC,NR_R1,reg))
  1178. // else
  1179. // list.concat(taicpu.op_reg_reg(A_CPC,reg,NR_R1));
  1180. // end;
  1181. //
  1182. // a_jmp_cond(list,cmp_op,l);
  1183. // end
  1184. //else
  1185. // inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
  1186. end;
  1187. procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1188. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1189. var
  1190. swapped : boolean;
  1191. tmpreg : tregister;
  1192. i : byte;
  1193. begin
  1194. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_cmp_reg_reg_label')));
  1195. //swapped:=false;
  1196. //{ swap parameters? }
  1197. //case cmp_op of
  1198. // OC_GT:
  1199. // begin
  1200. // swapped:=true;
  1201. // cmp_op:=OC_LT;
  1202. // end;
  1203. // OC_LTE:
  1204. // begin
  1205. // swapped:=true;
  1206. // cmp_op:=OC_GTE;
  1207. // end;
  1208. // OC_BE:
  1209. // begin
  1210. // swapped:=true;
  1211. // cmp_op:=OC_AE;
  1212. // end;
  1213. // OC_A:
  1214. // begin
  1215. // swapped:=true;
  1216. // cmp_op:=OC_B;
  1217. // end;
  1218. //end;
  1219. //if swapped then
  1220. // begin
  1221. // tmpreg:=reg1;
  1222. // reg1:=reg2;
  1223. // reg2:=tmpreg;
  1224. // end;
  1225. //list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1226. //
  1227. //for i:=2 to tcgsize2size[size] do
  1228. // begin
  1229. // reg1:=GetNextReg(reg1);
  1230. // reg2:=GetNextReg(reg2);
  1231. // list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1232. // end;
  1233. //
  1234. //a_jmp_cond(list,cmp_op,l);
  1235. end;
  1236. procedure tcgz80.a_jmp_name(list : TAsmList;const s : string);
  1237. var
  1238. ai : taicpu;
  1239. begin
  1240. ai:=taicpu.op_sym(A_JP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1241. ai.is_jmp:=true;
  1242. list.concat(ai);
  1243. end;
  1244. procedure tcgz80.a_jmp_always(list : TAsmList;l: tasmlabel);
  1245. var
  1246. ai : taicpu;
  1247. begin
  1248. ai:=taicpu.op_sym(A_JP,l);
  1249. ai.is_jmp:=true;
  1250. list.concat(ai);
  1251. end;
  1252. procedure tcgz80.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1253. var
  1254. ai : taicpu;
  1255. begin
  1256. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_jmp_flags')));
  1257. // ai:=setcondition(taicpu.op_sym(A_BRxx,l),flags_to_cond(f));
  1258. ai.is_jmp:=true;
  1259. list.concat(ai);
  1260. end;
  1261. procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1262. var
  1263. l : TAsmLabel;
  1264. tmpflags : TResFlags;
  1265. begin
  1266. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_flags2reg')));
  1267. current_asmdata.getjumplabel(l);
  1268. {
  1269. if flags_to_cond(f) then
  1270. begin
  1271. tmpflags:=f;
  1272. inverse_flags(tmpflags);
  1273. emit_mov(reg,NR_R1);
  1274. a_jmp_flags(list,tmpflags,l);
  1275. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1276. end
  1277. else
  1278. }
  1279. begin
  1280. //list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1281. //a_jmp_flags(list,f,l);
  1282. //emit_mov(list,reg,NR_R1);
  1283. end;
  1284. cg.a_label(list,l);
  1285. end;
  1286. procedure tcgz80.g_stackpointer_alloc(list: TAsmList; localsize: longint);
  1287. begin
  1288. if localsize>0 then
  1289. begin
  1290. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize));
  1291. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
  1292. list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
  1293. end;
  1294. end;
  1295. procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
  1296. var
  1297. i : integer;
  1298. begin
  1299. //case value of
  1300. // 0:
  1301. // ;
  1302. // {-14..-1:
  1303. // begin
  1304. // if ((-value) mod 2)<>0 then
  1305. // list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1306. // for i:=1 to (-value) div 2 do
  1307. // list.concat(taicpu.op_const(A_RCALL,0));
  1308. // end;
  1309. // 1..7:
  1310. // begin
  1311. // for i:=1 to value do
  1312. // list.concat(taicpu.op_reg(A_POP,NR_R0));
  1313. // end;}
  1314. // else
  1315. // begin
  1316. // list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1317. // list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1318. // // get SREG
  1319. // list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1320. //
  1321. // // block interrupts
  1322. // list.concat(taicpu.op_none(A_CLI));
  1323. //
  1324. // // write high SP
  1325. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1326. //
  1327. // // release interrupts
  1328. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1329. //
  1330. // // write low SP
  1331. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1332. // end;
  1333. //end;
  1334. end;
  1335. procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1336. var
  1337. regsize,stackmisalignment: longint;
  1338. begin
  1339. regsize:=0;
  1340. stackmisalignment:=0;
  1341. { save old framepointer }
  1342. if not nostackframe then
  1343. begin
  1344. { return address }
  1345. inc(stackmisalignment,2);
  1346. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  1347. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1348. begin
  1349. { push <frame_pointer> }
  1350. inc(stackmisalignment,2);
  1351. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  1352. list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG));
  1353. { Return address and FP are both on stack }
  1354. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2);
  1355. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2));
  1356. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  1357. begin
  1358. list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0));
  1359. list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG))
  1360. end
  1361. else
  1362. begin
  1363. internalerror(2020040301);
  1364. (*push_regs;
  1365. gen_load_frame_for_exceptfilter(list);
  1366. { Need only as much stack space as necessary to do the calls.
  1367. Exception filters don't have own local vars, and temps are 'mapped'
  1368. to the parent procedure.
  1369. maxpushedparasize is already aligned at least on x86_64. }
  1370. localsize:=current_procinfo.maxpushedparasize;*)
  1371. end;
  1372. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  1373. end
  1374. else
  1375. begin
  1376. CGmessage(cg_d_stackframe_omited);
  1377. end;
  1378. { allocate stackframe space }
  1379. if (localsize<>0) or
  1380. ((target_info.stackalign>sizeof(pint)) and
  1381. (stackmisalignment <> 0) and
  1382. ((pi_do_call in current_procinfo.flags) or
  1383. (po_assembler in current_procinfo.procdef.procoptions))) then
  1384. begin
  1385. if target_info.stackalign>sizeof(pint) then
  1386. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  1387. g_stackpointer_alloc(list,localsize);
  1388. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1389. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
  1390. current_procinfo.final_localsize:=localsize;
  1391. end
  1392. end;
  1393. end;
  1394. procedure tcgz80.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1395. var
  1396. regs : tcpuregisterset;
  1397. reg : TSuperRegister;
  1398. LocalSize : longint;
  1399. begin
  1400. { every byte counts for Z80, so if a subroutine is marked as non-returning, we do
  1401. not generate any exit code, so we really trust the noreturn directive
  1402. }
  1403. if po_noreturn in current_procinfo.procdef.procoptions then
  1404. exit;
  1405. { remove stackframe }
  1406. if not nostackframe then
  1407. begin
  1408. stacksize:=current_procinfo.calc_stackframe_size;
  1409. if (target_info.stackalign>4) and
  1410. ((stacksize <> 0) or
  1411. (pi_do_call in current_procinfo.flags) or
  1412. { can't detect if a call in this case -> use nostackframe }
  1413. { if you (think you) know what you are doing }
  1414. (po_assembler in current_procinfo.procdef.procoptions)) then
  1415. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1416. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1417. begin
  1418. internalerror(2020040302);
  1419. {if (stacksize<>0) then
  1420. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);}
  1421. end
  1422. else
  1423. begin
  1424. list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  1425. list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG));
  1426. end;
  1427. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1428. end;
  1429. list.concat(taicpu.op_none(A_RET));
  1430. end;
  1431. procedure tcgz80.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1432. var
  1433. tmpref : treference;
  1434. begin
  1435. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_loadaddr_ref_reg')));
  1436. // if ref.addressmode<>AM_UNCHANGED then
  1437. // internalerror(2011021701);
  1438. //
  1439. //if assigned(ref.symbol) or (ref.offset<>0) then
  1440. // begin
  1441. // reference_reset(tmpref,0,[]);
  1442. // tmpref.symbol:=ref.symbol;
  1443. // tmpref.offset:=ref.offset;
  1444. //
  1445. // if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1446. // tmpref.refaddr:=addr_lo8_gs
  1447. // else
  1448. // tmpref.refaddr:=addr_lo8;
  1449. // list.concat(taicpu.op_reg_ref(A_LDI,r,tmpref));
  1450. //
  1451. // if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1452. // tmpref.refaddr:=addr_hi8_gs
  1453. // else
  1454. // tmpref.refaddr:=addr_hi8;
  1455. // list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(r),tmpref));
  1456. //
  1457. // if (ref.base<>NR_NO) then
  1458. // begin
  1459. // list.concat(taicpu.op_reg_reg(A_ADD,r,ref.base));
  1460. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.base)));
  1461. // end;
  1462. // if (ref.index<>NR_NO) then
  1463. // begin
  1464. // list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  1465. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  1466. // end;
  1467. // end
  1468. //else if (ref.base<>NR_NO)then
  1469. // begin
  1470. // emit_mov(list,r,ref.base);
  1471. // emit_mov(list,GetNextReg(r),GetNextReg(ref.base));
  1472. // if (ref.index<>NR_NO) then
  1473. // begin
  1474. // list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  1475. // list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  1476. // end;
  1477. // end
  1478. //else if (ref.index<>NR_NO) then
  1479. // begin
  1480. // emit_mov(list,r,ref.index);
  1481. // emit_mov(list,GetNextReg(r),GetNextReg(ref.index));
  1482. // end;
  1483. end;
  1484. procedure tcgz80.fixref(list : TAsmList;var ref : treference);
  1485. begin
  1486. internalerror(2011021320);
  1487. end;
  1488. procedure tcgz80.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  1489. var
  1490. paraloc1,paraloc2,paraloc3 : TCGPara;
  1491. pd : tprocdef;
  1492. begin
  1493. pd:=search_system_proc('MOVE');
  1494. paraloc1.init;
  1495. paraloc2.init;
  1496. paraloc3.init;
  1497. {$warning TODO: implement!!!}
  1498. //paramanager.getintparaloc(list,pd,1,paraloc1);
  1499. //paramanager.getintparaloc(list,pd,2,paraloc2);
  1500. //paramanager.getintparaloc(list,pd,3,paraloc3);
  1501. a_load_const_cgpara(list,OS_SINT,len,paraloc3);
  1502. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  1503. a_loadaddr_ref_cgpara(list,source,paraloc1);
  1504. paramanager.freecgpara(list,paraloc3);
  1505. paramanager.freecgpara(list,paraloc2);
  1506. paramanager.freecgpara(list,paraloc1);
  1507. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1508. a_call_name_static(list,'FPC_MOVE');
  1509. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1510. paraloc3.done;
  1511. paraloc2.done;
  1512. paraloc1.done;
  1513. end;
  1514. procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  1515. var
  1516. countreg,tmpreg : tregister;
  1517. srcref,dstref : treference;
  1518. copysize,countregsize : tcgsize;
  1519. l : TAsmLabel;
  1520. i : longint;
  1521. SrcQuickRef, DestQuickRef : Boolean;
  1522. begin
  1523. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_concatcopy')));
  1524. //if len>16 then
  1525. // begin
  1526. // current_asmdata.getjumplabel(l);
  1527. //
  1528. // reference_reset(srcref,source.alignment,source.volatility);
  1529. // reference_reset(dstref,dest.alignment,source.volatility);
  1530. // srcref.base:=NR_R30;
  1531. // srcref.addressmode:=AM_POSTINCREMENT;
  1532. // dstref.base:=NR_R26;
  1533. // dstref.addressmode:=AM_POSTINCREMENT;
  1534. //
  1535. // copysize:=OS_8;
  1536. // if len<256 then
  1537. // countregsize:=OS_8
  1538. // else if len<65536 then
  1539. // countregsize:=OS_16
  1540. // else
  1541. // internalerror(2011022007);
  1542. // countreg:=getintregister(list,countregsize);
  1543. // a_load_const_reg(list,countregsize,len,countreg);
  1544. // a_loadaddr_ref_reg(list,source,NR_R30);
  1545. //
  1546. // { only base or index register in dest? }
  1547. // if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
  1548. // ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
  1549. // begin
  1550. // if dest.base<>NR_NO then
  1551. // tmpreg:=dest.base
  1552. // else if dest.index<>NR_NO then
  1553. // tmpreg:=dest.index
  1554. // else
  1555. // internalerror(2016112001);
  1556. // end
  1557. // else
  1558. // begin
  1559. // tmpreg:=getaddressregister(list);
  1560. // a_loadaddr_ref_reg(list,dest,tmpreg);
  1561. // end;
  1562. //
  1563. // { X is used for spilling code so we can load it
  1564. // only by a push/pop sequence, this can be
  1565. // optimized later on by the peephole optimizer
  1566. // }
  1567. // list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  1568. // list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  1569. // list.concat(taicpu.op_reg(A_POP,NR_R27));
  1570. // list.concat(taicpu.op_reg(A_POP,NR_R26));
  1571. // cg.a_label(list,l);
  1572. // list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  1573. // list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  1574. // list.concat(taicpu.op_reg(A_DEC,countreg));
  1575. // a_jmp_flags(list,F_NE,l);
  1576. // // keep registers alive
  1577. // list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1578. // end
  1579. //else
  1580. // begin
  1581. // SrcQuickRef:=false;
  1582. // DestQuickRef:=false;
  1583. // if not((source.addressmode=AM_UNCHANGED) and
  1584. // (source.symbol=nil) and
  1585. // ((source.base=NR_R28) or
  1586. // (source.base=NR_R30)) and
  1587. // (source.Index=NR_NO) and
  1588. // (source.Offset in [0..64-len])) and
  1589. // not((source.Base=NR_NO) and (source.Index=NR_NO)) then
  1590. // srcref:=normalize_ref(list,source,NR_R30)
  1591. // else
  1592. // begin
  1593. // SrcQuickRef:=true;
  1594. // srcref:=source;
  1595. // end;
  1596. //
  1597. // if not((dest.addressmode=AM_UNCHANGED) and
  1598. // (dest.symbol=nil) and
  1599. // ((dest.base=NR_R28) or
  1600. // (dest.base=NR_R30)) and
  1601. // (dest.Index=NR_No) and
  1602. // (dest.Offset in [0..64-len])) and
  1603. // not((dest.Base=NR_NO) and (dest.Index=NR_NO)) then
  1604. // begin
  1605. // if not(SrcQuickRef) then
  1606. // begin
  1607. // { only base or index register in dest? }
  1608. // if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
  1609. // ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
  1610. // begin
  1611. // if dest.base<>NR_NO then
  1612. // tmpreg:=dest.base
  1613. // else if dest.index<>NR_NO then
  1614. // tmpreg:=dest.index
  1615. // else
  1616. // internalerror(2016112002);
  1617. // end
  1618. // else
  1619. // tmpreg:=getaddressregister(list);
  1620. //
  1621. // dstref:=normalize_ref(list,dest,tmpreg);
  1622. //
  1623. // { X is used for spilling code so we can load it
  1624. // only by a push/pop sequence, this can be
  1625. // optimized later on by the peephole optimizer
  1626. // }
  1627. // list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  1628. // list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  1629. // list.concat(taicpu.op_reg(A_POP,NR_R27));
  1630. // list.concat(taicpu.op_reg(A_POP,NR_R26));
  1631. // dstref.base:=NR_R26;
  1632. // end
  1633. // else
  1634. // dstref:=normalize_ref(list,dest,NR_R30);
  1635. // end
  1636. // else
  1637. // begin
  1638. // DestQuickRef:=true;
  1639. // dstref:=dest;
  1640. // end;
  1641. //
  1642. // for i:=1 to len do
  1643. // begin
  1644. // if not(SrcQuickRef) and (i<len) then
  1645. // srcref.addressmode:=AM_POSTINCREMENT
  1646. // else
  1647. // srcref.addressmode:=AM_UNCHANGED;
  1648. //
  1649. // if not(DestQuickRef) and (i<len) then
  1650. // dstref.addressmode:=AM_POSTINCREMENT
  1651. // else
  1652. // dstref.addressmode:=AM_UNCHANGED;
  1653. //
  1654. // list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  1655. // list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  1656. //
  1657. // if SrcQuickRef then
  1658. // inc(srcref.offset);
  1659. // if DestQuickRef then
  1660. // inc(dstref.offset);
  1661. // end;
  1662. // if not(SrcQuickRef) then
  1663. // begin
  1664. // ungetcpuregister(list,srcref.base);
  1665. // ungetcpuregister(list,GetNextReg(srcref.base));
  1666. // end;
  1667. // end;
  1668. end;
  1669. procedure tcgz80.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1670. var
  1671. hl : tasmlabel;
  1672. ai : taicpu;
  1673. cond : TAsmCond;
  1674. begin
  1675. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck')));
  1676. //if not(cs_check_overflow in current_settings.localswitches) then
  1677. // exit;
  1678. //current_asmdata.getjumplabel(hl);
  1679. //if not ((def.typ=pointerdef) or
  1680. // ((def.typ=orddef) and
  1681. // (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1682. // pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1683. // cond:=C_VC
  1684. //else
  1685. // cond:=C_CC;
  1686. //ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1687. //ai.SetCondition(cond);
  1688. //ai.is_jmp:=true;
  1689. //list.concat(ai);
  1690. //
  1691. //a_call_name(list,'FPC_OVERFLOW',false);
  1692. //a_label(list,hl);
  1693. end;
  1694. procedure tcgz80.g_save_registers(list: TAsmList);
  1695. begin
  1696. { this is done by the entry code }
  1697. end;
  1698. procedure tcgz80.g_restore_registers(list: TAsmList);
  1699. begin
  1700. { this is done by the exit code }
  1701. end;
  1702. procedure tcgz80.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1703. var
  1704. ai1,ai2 : taicpu;
  1705. hl : TAsmLabel;
  1706. begin
  1707. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_jmp_cond')));
  1708. //ai1:=Taicpu.Op_sym(A_BRxx,l);
  1709. //ai1.is_jmp:=true;
  1710. //hl:=nil;
  1711. //case cond of
  1712. // OC_EQ:
  1713. // ai1.SetCondition(C_EQ);
  1714. // OC_GT:
  1715. // begin
  1716. // { emulate GT }
  1717. // current_asmdata.getjumplabel(hl);
  1718. // ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1719. // ai2.SetCondition(C_EQ);
  1720. // ai2.is_jmp:=true;
  1721. // list.concat(ai2);
  1722. //
  1723. // ai1.SetCondition(C_GE);
  1724. // end;
  1725. // OC_LT:
  1726. // ai1.SetCondition(C_LT);
  1727. // OC_GTE:
  1728. // ai1.SetCondition(C_GE);
  1729. // OC_LTE:
  1730. // begin
  1731. // { emulate LTE }
  1732. // ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1733. // ai2.SetCondition(C_EQ);
  1734. // ai2.is_jmp:=true;
  1735. // list.concat(ai2);
  1736. //
  1737. // ai1.SetCondition(C_LT);
  1738. // end;
  1739. // OC_NE:
  1740. // ai1.SetCondition(C_NE);
  1741. // OC_BE:
  1742. // begin
  1743. // { emulate BE }
  1744. // ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1745. // ai2.SetCondition(C_EQ);
  1746. // ai2.is_jmp:=true;
  1747. // list.concat(ai2);
  1748. //
  1749. // ai1.SetCondition(C_LO);
  1750. // end;
  1751. // OC_B:
  1752. // ai1.SetCondition(C_LO);
  1753. // OC_AE:
  1754. // ai1.SetCondition(C_SH);
  1755. // OC_A:
  1756. // begin
  1757. // { emulate A (unsigned GT) }
  1758. // current_asmdata.getjumplabel(hl);
  1759. // ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1760. // ai2.SetCondition(C_EQ);
  1761. // ai2.is_jmp:=true;
  1762. // list.concat(ai2);
  1763. //
  1764. // ai1.SetCondition(C_SH);
  1765. // end;
  1766. // else
  1767. // internalerror(2011082501);
  1768. //end;
  1769. //list.concat(ai1);
  1770. //if assigned(hl) then
  1771. // a_label(list,hl);
  1772. end;
  1773. procedure tcgz80.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  1774. var
  1775. instr: taicpu;
  1776. begin
  1777. instr:=taicpu.op_reg_reg(A_LD,reg2,reg1);
  1778. list.Concat(instr);
  1779. { Notify the register allocator that we have written a move instruction so
  1780. it can try to eliminate it. }
  1781. add_move_instruction(instr);
  1782. end;
  1783. procedure tcg64fz80.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1784. begin
  1785. if not(size in [OS_S64,OS_64]) then
  1786. internalerror(2012102402);
  1787. tcgz80(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  1788. end;
  1789. procedure tcg64fz80.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1790. begin
  1791. tcgz80(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  1792. end;
  1793. function GetByteLoc(const loc : tlocation; nr : byte) : tlocation;
  1794. var
  1795. i : Integer;
  1796. begin
  1797. Result:=loc;
  1798. Result.size:=OS_8;
  1799. case loc.loc of
  1800. LOC_REFERENCE,LOC_CREFERENCE:
  1801. inc(Result.reference.offset,nr);
  1802. LOC_REGISTER,LOC_CREGISTER:
  1803. begin
  1804. if nr>=4 then
  1805. Result.register:=Result.register64.reghi;
  1806. nr:=nr mod 4;
  1807. for i:=1 to nr do
  1808. Result.register:=GetNextReg(Result.register);
  1809. end;
  1810. LOC_CONSTANT:
  1811. if loc.size in [OS_64,OS_S64] then
  1812. Result.value:=(Result.value64 shr (nr*8)) and $ff
  1813. else
  1814. Result.value:=(Result.value shr (nr*8)) and $ff;
  1815. else
  1816. Internalerror(2019020902);
  1817. end;
  1818. end;
  1819. procedure create_codegen;
  1820. begin
  1821. cg:=tcgz80.create;
  1822. cg64:=tcg64fz80.create;
  1823. end;
  1824. end.