cgcpu.pas 81 KB

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