cg68kcal.pas 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate m68k assembler for in call nodes
  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 cg68kcal;
  19. interface
  20. uses
  21. symtable,tree;
  22. { save the size of pushed parameter }
  23. var
  24. pushedparasize : longint;
  25. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  26. push_from_left_to_right : boolean);
  27. procedure secondcalln(var p : ptree);
  28. procedure secondprocinline(var p : ptree);
  29. implementation
  30. uses
  31. globtype,systems,
  32. cobjects,verbose,globals,
  33. aasm,types,
  34. hcodegen,temp_gen,pass_2,
  35. m68k,cga68k,tgen68k,cg68kld;
  36. {*****************************************************************************
  37. SecondCallParaN
  38. *****************************************************************************}
  39. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  40. push_from_left_to_right : boolean);
  41. procedure maybe_push_open_array_high;
  42. var
  43. r : preference;
  44. begin
  45. { open array ? }
  46. { defcoll^.data can be nil for read/write }
  47. if assigned(defcoll^.data) and
  48. is_open_array(defcoll^.data) then
  49. begin
  50. inc(pushedparasize,4);
  51. { push high }
  52. if is_open_array(p^.left^.resulttype) then
  53. begin
  54. new(r);
  55. reset_reference(r^);
  56. r^.base:=highframepointer;
  57. r^.offset:=highoffset+4;
  58. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_SPPUSH)));
  59. end
  60. else
  61. push_int(parraydef(p^.left^.resulttype)^.highrange-parraydef(p^.left^.resulttype)^.lowrange);
  62. end;
  63. end;
  64. var
  65. size : longint;
  66. stackref : treference;
  67. otlabel,hlabel,oflabel : plabel;
  68. { temporary variables: }
  69. reg : tregister;
  70. tempdeftype : tdeftype;
  71. tempreference : treference;
  72. r : preference;
  73. s : topsize;
  74. op : tasmop;
  75. begin
  76. { push from left to right if specified }
  77. if push_from_left_to_right and assigned(p^.right) then
  78. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right);
  79. otlabel:=truelabel;
  80. oflabel:=falselabel;
  81. getlabel(truelabel);
  82. getlabel(falselabel);
  83. secondpass(p^.left);
  84. { in codegen.handleread.. defcoll^.data is set to nil }
  85. if assigned(defcoll^.data) and
  86. (defcoll^.data^.deftype=formaldef) then
  87. begin
  88. { allow @var }
  89. if p^.left^.treetype=addrn then
  90. begin
  91. { allways a register }
  92. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,p^.left^.location.register,R_SPPUSH)));
  93. ungetregister32(p^.left^.location.register);
  94. end
  95. else
  96. begin
  97. if (p^.left^.location.loc<>LOC_REFERENCE) and
  98. (p^.left^.location.loc<>LOC_MEM) then
  99. CGMessage(type_e_mismatch)
  100. else
  101. begin
  102. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  103. del_reference(p^.left^.location.reference);
  104. end;
  105. end;
  106. inc(pushedparasize,4);
  107. end
  108. { handle call by reference parameter }
  109. else if (defcoll^.paratyp=vs_var) then
  110. begin
  111. if (p^.left^.location.loc<>LOC_REFERENCE) then
  112. CGMessage(cg_e_var_must_be_reference);
  113. maybe_push_open_array_high;
  114. inc(pushedparasize,4);
  115. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  116. del_reference(p^.left^.location.reference);
  117. end
  118. else
  119. begin
  120. tempdeftype:=p^.resulttype^.deftype;
  121. if tempdeftype=filedef then
  122. CGMessage(cg_e_file_must_call_by_reference);
  123. if (defcoll^.paratyp=vs_const) and
  124. dont_copy_const_param(p^.resulttype) then
  125. begin
  126. maybe_push_open_array_high;
  127. inc(pushedparasize,4);
  128. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  129. del_reference(p^.left^.location.reference);
  130. end
  131. else
  132. case p^.left^.location.loc of
  133. LOC_REGISTER,
  134. LOC_CREGISTER : begin
  135. { HERE IS A BIG PROBLEM }
  136. { --> We *MUST* know the data size to push }
  137. { for the moment, we can say that the savesize }
  138. { indicates the parameter size to push, but }
  139. { that is CERTAINLY NOT TRUE! }
  140. { CAN WE USE LIKE LOC_MEM OR LOC_REFERENCE?? }
  141. case integer(p^.left^.resulttype^.savesize) of
  142. 1 : Begin
  143. { A byte sized value normally increments }
  144. { the SP by 2, BUT because how memory has }
  145. { been setup OR because of GAS, a byte sized }
  146. { push CRASHES the Amiga, therefore, we do it }
  147. { by hand instead. }
  148. { PUSH A WORD SHIFTED LEFT 8 }
  149. reg := getregister32;
  150. emit_reg_reg(A_MOVE, S_B, p^.left^.location.register, reg);
  151. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_W,
  152. 8, reg)));
  153. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,
  154. reg,R_SPPUSH)));
  155. { offset will be TWO greater }
  156. inc(pushedparasize,2);
  157. ungetregister32(reg);
  158. ungetregister32(p^.left^.location.register);
  159. end;
  160. 2 :
  161. Begin
  162. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,
  163. p^.left^.location.register,R_SPPUSH)));
  164. inc(pushedparasize,2);
  165. ungetregister32(p^.left^.location.register);
  166. end;
  167. 4 : Begin
  168. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  169. p^.left^.location.register,R_SPPUSH)));
  170. inc(pushedparasize,4);
  171. ungetregister32(p^.left^.location.register);
  172. end;
  173. else
  174. Begin
  175. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  176. p^.left^.location.register,R_SPPUSH)));
  177. inc(pushedparasize,4);
  178. ungetregister32(p^.left^.location.register);
  179. end;
  180. end; { end case }
  181. end;
  182. LOC_FPU : begin
  183. size:=pfloatdef(p^.left^.resulttype)^.size;
  184. inc(pushedparasize,size);
  185. { how now how long a FPU is !! }
  186. if (size > 0) and (size < 9) then
  187. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,S_L,size,R_SP)))
  188. else
  189. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBA,
  190. S_L,size,R_SP)));
  191. new(r);
  192. reset_reference(r^);
  193. r^.base:=R_SP;
  194. s:=getfloatsize(pfloatdef(p^.left^.resulttype)^.typ);
  195. if (cs_fp_emulation in aktmoduleswitches) or (s=S_FS) then
  196. begin
  197. { when in emulation mode... }
  198. { only single supported!!! }
  199. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,
  200. p^.left^.location.fpureg,r)));
  201. end
  202. else
  203. { convert back from extended to normal type }
  204. exprasmlist^.concat(new(pai68k,op_reg_ref(A_FMOVE,s,
  205. p^.left^.location.fpureg,r)));
  206. end;
  207. LOC_REFERENCE,LOC_MEM :
  208. begin
  209. tempreference:=p^.left^.location.reference;
  210. del_reference(p^.left^.location.reference);
  211. case p^.resulttype^.deftype of
  212. enumdef,
  213. orddef : begin
  214. case p^.resulttype^.size of
  215. 4 : begin
  216. emit_push_mem(tempreference);
  217. inc(pushedparasize,4);
  218. end;
  219. 1 : Begin
  220. { We push a BUT, the SP is incremented by 2 }
  221. { as specified in the Motorola Prog's Ref Manual }
  222. { Therefore offet increments BY 2!!! }
  223. { BUG??? ... }
  224. { SWAP OPERANDS: }
  225. if tempreference.isintvalue then
  226. Begin
  227. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_W,
  228. tempreference.offset shl 8,R_SPPUSH)));
  229. end
  230. else
  231. Begin
  232. { A byte sized value normally increments }
  233. { the SP by 2, BUT because how memory has }
  234. { been setup OR because of GAS, a byte sized }
  235. { push CRASHES the Amiga, therefore, we do it }
  236. { by hand instead. }
  237. { PUSH A WORD SHIFTED LEFT 8 }
  238. reg:=getregister32;
  239. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,
  240. newreference(tempreference),reg)));
  241. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_W,
  242. 8, reg)));
  243. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,
  244. reg,R_SPPUSH)));
  245. ungetregister32(reg);
  246. { exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,
  247. newreference(tempreference),R_SPPUSH))); }
  248. end;
  249. inc(pushedparasize,2);
  250. end;
  251. 2 : begin
  252. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,
  253. newreference(tempreference),R_SPPUSH)));
  254. inc(pushedparasize,2);
  255. end;
  256. end;
  257. end;
  258. floatdef : begin
  259. case pfloatdef(p^.resulttype)^.typ of
  260. f32bit,
  261. s32real :
  262. begin
  263. emit_push_mem(tempreference);
  264. inc(pushedparasize,4);
  265. end;
  266. s64real:
  267. {s64bit }
  268. begin
  269. inc(tempreference.offset,4);
  270. emit_push_mem(tempreference);
  271. dec(tempreference.offset,4);
  272. emit_push_mem(tempreference);
  273. inc(pushedparasize,8);
  274. end;
  275. {$ifdef use48}
  276. s48real : begin
  277. end;
  278. {$endif}
  279. s80real : begin
  280. CGMessage(cg_f_extended_cg68k_not_supported);
  281. { inc(tempreference.offset,6);
  282. emit_push_mem(tempreference);
  283. dec(tempreference.offset,4);
  284. emit_push_mem(tempreference);
  285. dec(tempreference.offset,2);
  286. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,
  287. newreference(tempreference),R_SPPUSH)));
  288. inc(pushedparasize,extended_size);}
  289. end;
  290. end;
  291. end;
  292. pointerdef,procvardef,
  293. classrefdef: begin
  294. emit_push_mem(tempreference);
  295. inc(pushedparasize,4);
  296. end;
  297. arraydef,recorddef,stringdef,setdef,objectdef :
  298. begin
  299. if ((p^.resulttype^.deftype=setdef) and
  300. (psetdef(p^.resulttype)^.settype=smallset)) then
  301. begin
  302. emit_push_mem(tempreference);
  303. inc(pushedparasize,4);
  304. end
  305. else
  306. begin
  307. size:=p^.resulttype^.size;
  308. { Alignment }
  309. {
  310. if (size>=4) and ((size and 3)<>0) then
  311. inc(size,4-(size and 3))
  312. else if (size>=2) and ((size and 1)<>0) then
  313. inc(size,2-(size and 1))
  314. else
  315. if size=1 then size:=2;
  316. }
  317. { create stack space }
  318. if (size > 0) and (size < 9) then
  319. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,S_L,size,R_SP)))
  320. else
  321. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBA,
  322. S_L,size,R_SP)));
  323. inc(pushedparasize,size);
  324. { create stack reference }
  325. stackref.symbol := nil;
  326. clear_reference(stackref);
  327. stackref.base:=R_SP;
  328. { produce copy }
  329. if p^.resulttype^.deftype=stringdef then
  330. begin
  331. copystring(stackref,p^.left^.location.reference,
  332. pstringdef(p^.resulttype)^.len);
  333. end
  334. else
  335. begin
  336. concatcopy(p^.left^.location.reference,
  337. stackref,p^.resulttype^.size,true);
  338. end;
  339. end;
  340. end;
  341. else CGMessage(cg_e_illegal_expression);
  342. end;
  343. end;
  344. LOC_JUMP : begin
  345. getlabel(hlabel);
  346. inc(pushedparasize,2);
  347. emitl(A_LABEL,truelabel);
  348. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_W,1 shl 8,R_SPPUSH)));
  349. emitl(A_JMP,hlabel);
  350. emitl(A_LABEL,falselabel);
  351. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_W,0,R_SPPUSH)));
  352. emitl(A_LABEL,hlabel);
  353. end;
  354. LOC_FLAGS : begin
  355. exprasmlist^.concat(new(pai68k,op_reg(flag_2_set[p^.left^.location.resflags],S_B,
  356. R_D0)));
  357. exprasmlist^.concat(new(pai68k,op_reg(A_NEG, S_B, R_D0)));
  358. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_W,$ff, R_D0)));
  359. inc(pushedparasize,2);
  360. { ----------------- HACK ----------------------- }
  361. { HERE IS THE BYTE SIZED PUSH HACK ONCE AGAIN }
  362. { SHIFT LEFT THE BYTE TO MAKE IT WORK! }
  363. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_W,8, R_D0)));
  364. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,R_D0,R_SPPUSH)));
  365. end;
  366. end;
  367. end;
  368. freelabel(truelabel);
  369. freelabel(falselabel);
  370. truelabel:=otlabel;
  371. falselabel:=oflabel;
  372. { push from right to left }
  373. if not push_from_left_to_right and assigned(p^.right) then
  374. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right);
  375. end;
  376. {*****************************************************************************
  377. SecondCallN
  378. *****************************************************************************}
  379. procedure secondcalln(var p : ptree);
  380. var
  381. unusedregisters : tregisterset;
  382. pushed : tpushed;
  383. funcretref : treference;
  384. hregister : tregister;
  385. oldpushedparasize : longint;
  386. { true if a5 must be loaded again after the subroutine }
  387. loada5 : boolean;
  388. { true if a virtual method must be called directly }
  389. no_virtual_call : boolean;
  390. { true if we produce a con- or destrutor in a call }
  391. is_con_or_destructor : boolean;
  392. { true if a constructor is called again }
  393. extended_new : boolean;
  394. { adress returned from an I/O-error }
  395. iolabel : plabel;
  396. { lexlevel count }
  397. i : longint;
  398. { help reference pointer }
  399. r : preference;
  400. pp,params : ptree;
  401. { temp register allocation }
  402. reg: tregister;
  403. { help reference pointer }
  404. ref: preference;
  405. label
  406. dont_call;
  407. begin
  408. extended_new:=false;
  409. iolabel:=nil;
  410. loada5:=true;
  411. no_virtual_call:=false;
  412. unusedregisters:=unused;
  413. if not assigned(p^.procdefinition) then
  414. exit;
  415. { only if no proc var }
  416. if not(assigned(p^.right)) then
  417. is_con_or_destructor:=((p^.procdefinition^.options and poconstructor)<>0)
  418. or ((p^.procdefinition^.options and podestructor)<>0);
  419. { proc variables destroy all registers }
  420. if (p^.right=nil) and
  421. { virtual methods too }
  422. ((p^.procdefinition^.options and povirtualmethod)=0) then
  423. begin
  424. if ((p^.procdefinition^.options and poiocheck)<>0) and
  425. ((aktprocsym^.definition^.options and poiocheck)=0) and
  426. (cs_check_io in aktlocalswitches) then
  427. begin
  428. getlabel(iolabel);
  429. emitl(A_LABEL,iolabel);
  430. end
  431. else iolabel:=nil;
  432. { save all used registers }
  433. pushusedregisters(pushed,p^.procdefinition^.usedregisters);
  434. { give used registers through }
  435. usedinproc:=usedinproc or p^.procdefinition^.usedregisters;
  436. end
  437. else
  438. begin
  439. pushusedregisters(pushed,$ffff);
  440. usedinproc:=$ffff;
  441. { no IO check for methods and procedure variables }
  442. iolabel:=nil;
  443. end;
  444. { generate the code for the parameter and push them }
  445. oldpushedparasize:=pushedparasize;
  446. pushedparasize:=0;
  447. if (p^.resulttype<>pdef(voiddef)) and
  448. ret_in_param(p^.resulttype) then
  449. begin
  450. funcretref.symbol:=nil;
  451. {$ifdef test_dest_loc}
  452. if dest_loc_known and (dest_loc_tree=p) and
  453. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  454. begin
  455. funcretref:=dest_loc.reference;
  456. if assigned(dest_loc.reference.symbol) then
  457. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  458. in_dest_loc:=true;
  459. end
  460. else
  461. {$endif test_dest_loc}
  462. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  463. end;
  464. if assigned(p^.left) then
  465. begin
  466. pushedparasize:=0;
  467. { be found elsewhere }
  468. if assigned(p^.right) then
  469. secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1,
  470. (p^.procdefinition^.options and poleftright)<>0)
  471. else
  472. secondcallparan(p^.left,p^.procdefinition^.para1,
  473. (p^.procdefinition^.options and poleftright)<>0);
  474. end;
  475. params:=p^.left;
  476. p^.left:=nil;
  477. if ret_in_param(p^.resulttype) then
  478. begin
  479. emitpushreferenceaddr(exprasmlist,funcretref);
  480. inc(pushedparasize,4);
  481. end;
  482. { overloaded operator have no symtable }
  483. if (p^.right=nil) then
  484. begin
  485. { push self }
  486. if assigned(p^.symtable) and
  487. (p^.symtable^.symtabletype=withsymtable) then
  488. begin
  489. { dirty trick to avoid the secondcall below }
  490. p^.methodpointer:=genzeronode(callparan);
  491. p^.methodpointer^.location.loc:=LOC_REGISTER;
  492. p^.methodpointer^.location.register:=R_A5;
  493. { change dispose type !! }
  494. p^.disposetyp:=dt_mbleft_and_method;
  495. { make a reference }
  496. new(r);
  497. reset_reference(r^);
  498. r^.offset:=p^.symtable^.datasize;
  499. r^.base:=procinfo.framepointer;
  500. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  501. end;
  502. { push self }
  503. if assigned(p^.symtable) and
  504. ((p^.symtable^.symtabletype=objectsymtable) or
  505. (p^.symtable^.symtabletype=withsymtable)) then
  506. begin
  507. if assigned(p^.methodpointer) then
  508. begin
  509. case p^.methodpointer^.treetype of
  510. typen : begin
  511. { direct call to inherited method }
  512. if (p^.procdefinition^.options and poabstractmethod)<>0 then
  513. begin
  514. CGMessage(cg_e_cant_call_abstract_method);
  515. goto dont_call;
  516. end;
  517. { generate no virtual call }
  518. no_virtual_call:=true;
  519. if (p^.symtableprocentry^.properties and sp_static)<>0 then
  520. begin
  521. { well lets put the VMT address directly into a5 }
  522. { it is kind of dirty but that is the simplest }
  523. { way to accept virtual static functions (PM) }
  524. loada5:=true;
  525. exprasmlist^.concat(new(pai68k,op_csymbol_reg(A_MOVE,S_L,
  526. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0),R_A5)));
  527. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  528. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  529. end
  530. else
  531. { this is a member call, so A5 isn't modfied }
  532. loada5:=false;
  533. if not(is_con_or_destructor and
  534. pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  535. assigned(aktprocsym) and
  536. ((aktprocsym^.definition^.options and
  537. (poconstructor or podestructor))<>0)) then
  538. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  539. { if an inherited con- or destructor should be }
  540. { called in a con- or destructor then a warning }
  541. { will be made }
  542. { con- and destructors need a pointer to the vmt }
  543. if is_con_or_destructor and
  544. ((pobjectdef(p^.methodpointer^.resulttype)^.options and oo_is_class)=0) and
  545. assigned(aktprocsym) then
  546. begin
  547. if not ((aktprocsym^.definition^.options
  548. and (poconstructor or podestructor))<>0) then
  549. CGMessage(cg_w_member_cd_call_from_method);
  550. end;
  551. { con- and destructors need a pointer to the vmt }
  552. if is_con_or_destructor then
  553. begin
  554. { classes need the mem ! }
  555. if ((pobjectdef(p^.methodpointer^.resulttype)^.options and
  556. oo_is_class)=0) then
  557. push_int(0)
  558. else
  559. begin
  560. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,
  561. S_L,newcsymbol(pobjectdef(p^.methodpointer^.
  562. resulttype)^.vmt_mangledname,0))));
  563. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.
  564. vmt_mangledname,EXT_NEAR);
  565. end;
  566. end;
  567. end;
  568. hnewn : begin
  569. { extended syntax of new }
  570. { A5 must be zero }
  571. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,0,R_A5)));
  572. emit_reg_reg(A_MOVE,S_L,R_A5, R_SPPUSH);
  573. { insert the vmt }
  574. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  575. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  576. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  577. extended_new:=true;
  578. end;
  579. hdisposen : begin
  580. secondpass(p^.methodpointer);
  581. { destructor with extended syntax called from dispose }
  582. { hdisposen always deliver LOC_REFRENZ }
  583. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  584. newreference(p^.methodpointer^.location.reference),R_A5)));
  585. del_reference(p^.methodpointer^.location.reference);
  586. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  587. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  588. newcsymbol(pobjectdef
  589. (p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  590. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  591. end;
  592. else
  593. begin
  594. { call to a instance member }
  595. if (p^.symtable^.symtabletype<>withsymtable) then
  596. begin
  597. secondpass(p^.methodpointer);
  598. case p^.methodpointer^.location.loc of
  599. LOC_REGISTER :
  600. begin
  601. ungetregister32(p^.methodpointer^.location.register);
  602. emit_reg_reg(A_MOVE,S_L,p^.methodpointer^.location.register,R_A5);
  603. end;
  604. else
  605. begin
  606. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  607. pobjectdef(p^.methodpointer^.resulttype)^.isclass then
  608. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  609. newreference(p^.methodpointer^.location.reference),R_A5)))
  610. else
  611. Begin
  612. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  613. newreference(p^.methodpointer^.location.reference),R_A5)));
  614. end;
  615. del_reference(p^.methodpointer^.location.reference);
  616. end;
  617. end;
  618. end;
  619. { when calling a class method, we have
  620. to load ESI with the VMT !
  621. But that's wrong, if we call a class method via self
  622. }
  623. if ((p^.procdefinition^.options and poclassmethod)<>0)
  624. and not(p^.methodpointer^.treetype=selfn) then
  625. begin
  626. { class method needs current VMT }
  627. new(r);
  628. reset_reference(r^);
  629. r^.base:=R_A5;
  630. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  631. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  632. end;
  633. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  634. if is_con_or_destructor then
  635. begin
  636. { classes don't get a VMT pointer pushed }
  637. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  638. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  639. begin
  640. if ((p^.procdefinition^.options and poconstructor)<>0) then
  641. begin
  642. { it's no bad idea, to insert the VMT }
  643. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  644. newcsymbol(pobjectdef(
  645. p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  646. concat_external(pobjectdef(
  647. p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  648. end
  649. { destructors haven't to dispose the instance, if this is }
  650. { a direct call }
  651. else
  652. push_int(0);
  653. end;
  654. end;
  655. end;
  656. end;
  657. end
  658. else
  659. begin
  660. if ((p^.procdefinition^.options and poclassmethod)<>0) and
  661. not(
  662. assigned(aktprocsym) and
  663. ((aktprocsym^.definition^.options and poclassmethod)<>0)
  664. ) then
  665. begin
  666. { class method needs current VMT }
  667. new(r);
  668. reset_reference(r^);
  669. r^.base:=R_A5;
  670. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  671. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  672. end
  673. else
  674. begin
  675. { member call, A5 isn't modified }
  676. loada5:=false;
  677. end;
  678. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  679. { but a con- or destructor here would probably almost }
  680. { always be placed wrong }
  681. if is_con_or_destructor then
  682. begin
  683. CGMessage(cg_w_member_cd_call_from_method);
  684. { not insert VMT pointer } { VMT-Zeiger nicht eintragen }
  685. push_int(0);
  686. end;
  687. end;
  688. end;
  689. { push base pointer ?}
  690. if (lexlevel>=normal_function_level) and assigned(pprocdef(p^.procdefinition)^.parast) and
  691. ((p^.procdefinition^.parast^.symtablelevel)>normal_function_level) then
  692. begin
  693. { if we call a nested function in a method, we must }
  694. { push also SELF! }
  695. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  696. { access }
  697. {
  698. begin
  699. loadesi:=false;
  700. exprasmlist^.concat(new(pai68k,op_reg(A_PUSH,S_L,R_ESI)));
  701. end;
  702. }
  703. if lexlevel=(p^.procdefinition^.parast^.symtablelevel) then
  704. begin
  705. new(r);
  706. reset_reference(r^);
  707. r^.offset:=procinfo.framepointer_offset;
  708. r^.base:=procinfo.framepointer;
  709. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_SPPUSH)))
  710. end
  711. { this is only true if the difference is one !!
  712. but it cannot be more !! }
  713. else if lexlevel=(p^.procdefinition^.parast^.symtablelevel)-1 then
  714. begin
  715. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,procinfo.framepointer,R_SPPUSH)))
  716. end
  717. else if lexlevel>(p^.procdefinition^.parast^.symtablelevel) then
  718. begin
  719. hregister:=getaddressreg;
  720. new(r);
  721. reset_reference(r^);
  722. r^.offset:=procinfo.framepointer_offset;
  723. r^.base:=procinfo.framepointer;
  724. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,hregister)));
  725. for i:=(p^.procdefinition^.parast^.symtablelevel) to lexlevel-1 do
  726. begin
  727. new(r);
  728. reset_reference(r^);
  729. {we should get the correct frame_pointer_offset at each level
  730. how can we do this !!! }
  731. r^.offset:=procinfo.framepointer_offset;
  732. r^.base:=hregister;
  733. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,hregister)));
  734. end;
  735. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,hregister,R_SPPUSH)));
  736. ungetregister32(hregister);
  737. end
  738. else
  739. internalerror(25000);
  740. end;
  741. { exported methods should be never called direct }
  742. if (p^.procdefinition^.options and poexports)<>0 then
  743. CGMessage(cg_e_dont_call_exported_direct);
  744. if ((p^.procdefinition^.options and povirtualmethod)<>0) and
  745. not(no_virtual_call) then
  746. begin
  747. { static functions contain the vmt_address in ESI }
  748. { also class methods }
  749. if assigned(aktprocsym) then
  750. begin
  751. if ((aktprocsym^.properties and sp_static)<>0) or
  752. ((aktprocsym^.definition^.options and poclassmethod)<>0) or
  753. ((p^.procdefinition^.options and postaticmethod)<>0) or
  754. { A5 is already loaded }
  755. ((p^.procdefinition^.options and poclassmethod)<>0)then
  756. begin
  757. new(r);
  758. reset_reference(r^);
  759. r^.base:=R_a5;
  760. end
  761. else
  762. begin
  763. new(r);
  764. reset_reference(r^);
  765. r^.base:=R_a5;
  766. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  767. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  768. new(r);
  769. reset_reference(r^);
  770. r^.base:=R_a0;
  771. end;
  772. end
  773. else
  774. begin
  775. new(r);
  776. reset_reference(r^);
  777. r^.base:=R_a5;
  778. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  779. new(r);
  780. reset_reference(r^);
  781. r^.base:=R_a0;
  782. end;
  783. if p^.procdefinition^.extnumber=-1 then
  784. internalerror($Da);
  785. r^.offset:=p^.procdefinition^.extnumber*4+12;
  786. if (cs_check_range in aktlocalswitches) then
  787. begin
  788. { If the base is already A0, the no instruction will }
  789. { be emitted! }
  790. emit_reg_reg(A_MOVE,S_L,r^.base,R_A0);
  791. emitcall('FPC_CHECK_OBJECT',true);
  792. end;
  793. { This was wrong we must then load the address into the }
  794. { register a0 and/or a5 }
  795. { Because doing an indirect call with offset is NOT }
  796. { allowed on the m68k! }
  797. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(r^),R_A0)));
  798. { clear the reference }
  799. reset_reference(r^);
  800. r^.base := R_A0;
  801. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,r)));
  802. end
  803. else if (p^.procdefinition^.options and popalmossyscall)<>0 then
  804. begin
  805. exprasmlist^.concat(new(pai68k,op_const(A_TRAP,S_NO,15)));
  806. exprasmlist^.concat(new(pai_const,init_16bit(p^.procdefinition^.extnumber)));
  807. end
  808. else
  809. emitcall(p^.procdefinition^.mangledname,
  810. (p^.symtableproc^.symtabletype=unitsymtable) or
  811. ((p^.symtableproc^.symtabletype=objectsymtable) and
  812. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable))or
  813. ((p^.symtableproc^.symtabletype=withsymtable) and
  814. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable)));
  815. if ((p^.procdefinition^.options and poclearstack)<>0) then
  816. begin
  817. if (pushedparasize > 0) and (pushedparasize < 9) then
  818. { restore the stack, to its initial value }
  819. exprasmlist^.concat(new(pai68k,op_const_reg(A_ADDQ,S_L,pushedparasize,R_SP)))
  820. else
  821. { restore the stack, to its initial value }
  822. exprasmlist^.concat(new(pai68k,op_const_reg(A_ADDA,S_L,pushedparasize,R_SP)));
  823. end;
  824. end
  825. else
  826. begin
  827. secondpass(p^.right);
  828. case p^.right^.location.loc of
  829. LOC_REGISTER,
  830. LOC_CREGISTER : begin
  831. if p^.right^.location.register in [R_D0..R_D7] then
  832. begin
  833. reg := getaddressreg;
  834. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,reg);
  835. new(ref);
  836. reset_reference(ref^);
  837. ref^.base := reg;
  838. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  839. ungetregister(reg);
  840. end
  841. else
  842. begin
  843. new(ref);
  844. reset_reference(ref^);
  845. ref^.base := p^.right^.location.register;
  846. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  847. end;
  848. ungetregister32(p^.right^.location.register);
  849. end
  850. else
  851. begin
  852. if assigned(p^.right^.location.reference.symbol) then
  853. { Here we have a symbolic name to the routine, so solve }
  854. { problem by loading the address first, and then emitting }
  855. { the call. }
  856. begin
  857. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  858. newreference(p^.right^.location.reference),R_A1)));
  859. new(ref);
  860. reset_reference(ref^);
  861. ref^.base := R_A1;
  862. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  863. end
  864. else
  865. begin
  866. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  867. newreference(p^.right^.location.reference),R_A1)));
  868. new(ref);
  869. reset_reference(ref^);
  870. ref^.base := R_A1;
  871. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  872. end;
  873. del_reference(p^.right^.location.reference);
  874. end;
  875. end;
  876. end;
  877. dont_call:
  878. pushedparasize:=oldpushedparasize;
  879. unused:=unusedregisters;
  880. { handle function results }
  881. if p^.resulttype<>pdef(voiddef) then
  882. begin
  883. { a contructor could be a function with boolean result }
  884. if (p^.right=nil) and
  885. ((p^.procdefinition^.options and poconstructor)<>0) and
  886. { quick'n'dirty check if it is a class or an object }
  887. (p^.resulttype^.deftype=orddef) then
  888. begin
  889. p^.location.loc:=LOC_FLAGS;
  890. p^.location.resflags:=F_NE;
  891. if extended_new then
  892. begin
  893. {$ifdef test_dest_loc}
  894. if dest_loc_known and (dest_loc_tree=p) then
  895. mov_reg_to_dest(p,S_L,R_EAX)
  896. else
  897. {$endif test_dest_loc}
  898. hregister:=getregister32;
  899. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  900. p^.location.register:=hregister;
  901. end;
  902. end
  903. { structed results are easy to handle.... }
  904. else if ret_in_param(p^.resulttype) then
  905. begin
  906. p^.location.loc:=LOC_MEM;
  907. stringdispose(p^.location.reference.symbol);
  908. p^.location.reference:=funcretref;
  909. end
  910. else
  911. begin
  912. if (p^.resulttype^.deftype=orddef) then
  913. begin
  914. p^.location.loc:=LOC_REGISTER;
  915. case porddef(p^.resulttype)^.typ of
  916. s32bit,u32bit :
  917. begin
  918. hregister:=getregister32;
  919. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  920. p^.location.register:=hregister;
  921. end;
  922. uchar,u8bit,bool8bit,s8bit :
  923. begin
  924. hregister:=getregister32;
  925. emit_reg_reg(A_MOVE,S_B,R_D0,hregister);
  926. p^.location.register:=hregister;
  927. end;
  928. s16bit,u16bit :
  929. begin
  930. hregister:=getregister32;
  931. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  932. p^.location.register:=hregister;
  933. end;
  934. else internalerror(7);
  935. end
  936. end
  937. else if (p^.resulttype^.deftype=floatdef) then
  938. case pfloatdef(p^.resulttype)^.typ of
  939. f32bit :
  940. begin
  941. p^.location.loc:=LOC_REGISTER;
  942. hregister:=getregister32;
  943. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  944. p^.location.register:=hregister;
  945. end;
  946. s32real : Begin
  947. p^.location.loc:=LOC_FPU;
  948. hregister:=getregister32;
  949. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  950. p^.location.fpureg:=hregister;
  951. end;
  952. s64bit,s64real,s80real: begin
  953. if cs_fp_emulation in aktmoduleswitches then
  954. begin
  955. p^.location.loc:=LOC_FPU;
  956. hregister:=getregister32;
  957. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  958. p^.location.fpureg:=hregister;
  959. end
  960. else
  961. begin
  962. { TRUE FPU mode }
  963. p^.location.loc:=LOC_FPU;
  964. { on exit of function result in R_FP0 }
  965. p^.location.fpureg:=R_FP0;
  966. end;
  967. end;
  968. else
  969. begin
  970. p^.location.loc:=LOC_FPU;
  971. p^.location.fpureg:=R_FP0;
  972. end;
  973. end {end case }
  974. else
  975. begin
  976. p^.location.loc:=LOC_REGISTER;
  977. hregister:=getregister32;
  978. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  979. p^.location.register:=hregister;
  980. end;
  981. end;
  982. end;
  983. { perhaps i/o check ? }
  984. if iolabel<>nil then
  985. begin
  986. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,newcsymbol(lab2str(iolabel),0))));
  987. emitcall('FPC_IOCHECK',true);
  988. end;
  989. { restore registers }
  990. popusedregisters(pushed);
  991. { at last, restore instance pointer (SELF) }
  992. if loada5 then
  993. maybe_loada5;
  994. pp:=params;
  995. while assigned(pp) do
  996. begin
  997. if assigned(pp^.left) then
  998. if (pp^.left^.location.loc=LOC_REFERENCE) or
  999. (pp^.left^.location.loc=LOC_MEM) then
  1000. ungetiftemp(pp^.left^.location.reference);
  1001. pp:=pp^.right;
  1002. end;
  1003. disposetree(params);
  1004. end;
  1005. {*****************************************************************************
  1006. SecondProcInlineN
  1007. *****************************************************************************}
  1008. procedure secondprocinline(var p : ptree);
  1009. begin
  1010. InternalError(132421);
  1011. end;
  1012. end.
  1013. {
  1014. $Log$
  1015. Revision 1.17 1998-12-11 00:02:58 peter
  1016. + globtype,tokens,version unit splitted from globals
  1017. Revision 1.16 1998/11/13 15:40:15 pierre
  1018. + added -Se in Makefile cvstest target
  1019. + lexlevel cleanup
  1020. normal_function_level main_program_level and unit_init_level defined
  1021. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1022. (test added in code !)
  1023. * -Un option was wrong
  1024. * _FAIL and _SELF only keyword inside
  1025. constructors and methods respectively
  1026. Revision 1.15 1998/11/12 11:19:41 pierre
  1027. * fix for first line of function break
  1028. Revision 1.14 1998/10/21 15:12:51 pierre
  1029. * bug fix for IOCHECK inside a procedure with iocheck modifier
  1030. * removed the GPF for unexistant overloading
  1031. (firstcall was called with procedinition=nil !)
  1032. * changed typen to what Florian proposed
  1033. gentypenode(p : pdef) sets the typenodetype field
  1034. and resulttype is only set if inside bt_type block !
  1035. Revision 1.13 1998/10/20 08:06:45 pierre
  1036. * several memory corruptions due to double freemem solved
  1037. => never use p^.loc.location:=p^.left^.loc.location;
  1038. + finally I added now by default
  1039. that ra386dir translates global and unit symbols
  1040. + added a first field in tsymtable and
  1041. a nextsym field in tsym
  1042. (this allows to obtain ordered type info for
  1043. records and objects in gdb !)
  1044. Revision 1.12 1998/10/19 08:54:53 pierre
  1045. * wrong stabs info corrected once again !!
  1046. + variable vmt offset with vmt field only if required
  1047. implemented now !!!
  1048. Revision 1.11 1998/10/16 13:12:46 pierre
  1049. * added vmt_offsets in destructors code also !!!
  1050. * vmt_offset code for m68k
  1051. Revision 1.10 1998/10/15 12:41:16 pierre
  1052. * last memory leaks found when compiler
  1053. a native atari compiler fixed
  1054. Revision 1.9 1998/10/14 11:28:16 florian
  1055. * emitpushreferenceaddress gets now the asmlist as parameter
  1056. * m68k version compiles with -duseansistrings
  1057. Revision 1.8 1998/10/13 16:50:04 pierre
  1058. * undid some changes of Peter that made the compiler wrong
  1059. for m68k (I had to reinsert some ifdefs)
  1060. * removed several memory leaks under m68k
  1061. * removed the meory leaks for assembler readers
  1062. * cross compiling shoud work again better
  1063. ( crosscompiling sysamiga works
  1064. but as68k still complain about some code !)
  1065. Revision 1.7 1998/10/13 08:19:27 pierre
  1066. + source_os is now set correctly for cross-processor compilers
  1067. (tos contains all target_infos and
  1068. we use CPU86 and CPU68 conditionnals to
  1069. get the source operating system
  1070. this only works if you do not undefine
  1071. the source target !!)
  1072. * several cg68k memory leaks fixed
  1073. + started to change the code so that it should be possible to have
  1074. a complete compiler (both for m68k and i386 !!)
  1075. Revision 1.6 1998/09/20 12:26:38 peter
  1076. * merged fixes
  1077. Revision 1.5 1998/09/17 09:42:22 peter
  1078. + pass_2 for cg386
  1079. * Message() -> CGMessage() for pass_1/pass_2
  1080. Revision 1.4 1998/09/14 10:43:55 peter
  1081. * all internal RTL functions start with FPC_
  1082. Revision 1.3.2.1 1998/09/20 12:20:09 peter
  1083. * Fixed stack not on 4 byte boundary when doing a call
  1084. Revision 1.3 1998/09/04 08:41:43 peter
  1085. * updated some error CGMessages
  1086. Revision 1.2 1998/09/01 12:47:59 peter
  1087. * use pdef^.size instead of orddef^.typ
  1088. Revision 1.1 1998/09/01 09:07:09 peter
  1089. * m68k fixes, splitted cg68k like cgi386
  1090. }