t_oric.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. {
  2. Copyright (c) 2025 by Nikolay Nikolov
  3. This unit implements support import, export, link routines
  4. for the Oric-1 / Oric Atmos / Oric NOVA 64 / Pravetz 8D Target
  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 t_oric;
  19. {$i fpcdefs.inc}
  20. interface
  21. implementation
  22. uses
  23. SysUtils,
  24. cutils,cfileutl,cclasses,
  25. globtype,globals,systems,verbose,comphook,cscript,fmodule,i_oric,link,
  26. cpuinfo,ogbase,ogrel,owar;
  27. const
  28. DefaultOrigin=$400;
  29. type
  30. { sdld - the sdld linker from the SDCC project ( http://sdcc.sourceforge.net/ ) }
  31. { vlink - the vlink linker by Frank Wille (http://sun.hasenbraten.de/vlink/ ) }
  32. TLinkerOric=class(texternallinker)
  33. private
  34. FOrigin: Word;
  35. Function WriteResponseFile_Sdld: Boolean;
  36. Function WriteResponseFile_Vlink: Boolean;
  37. procedure SetDefaultInfo_Sdld;
  38. procedure SetDefaultInfo_Vlink;
  39. function MakeExecutable_Sdld: boolean;
  40. function MakeExecutable_Vlink: boolean;
  41. public
  42. procedure SetDefaultInfo; override;
  43. function MakeExecutable: boolean; override;
  44. procedure InitSysInitUnitName; override;
  45. function postprocessexecutable(const fn : string;isdll:boolean): boolean;
  46. end;
  47. // { TInternalLinkerOric }
  48. //
  49. // TInternalLinkerOric=class(tinternallinker)
  50. // private
  51. // FOrigin: Word;
  52. // protected
  53. // procedure DefaultLinkScript;override;
  54. // public
  55. // constructor create;override;
  56. // procedure InitSysInitUnitName;override;
  57. // function MakeExecutable: boolean; override;
  58. // function postprocessexecutable(const fn : string): boolean;
  59. // end;
  60. {*****************************************************************************
  61. TLinkerZXSpectrum
  62. *****************************************************************************}
  63. function TLinkerOric.WriteResponseFile_Sdld: Boolean;
  64. Var
  65. linkres : TLinkRes;
  66. s : TCmdStr;
  67. prtobj: string[80];
  68. begin
  69. result:=False;
  70. prtobj:='prt0';
  71. { Open link.res file }
  72. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  73. { Write the origin (i.e. the program load address) }
  74. LinkRes.Add('-b _CODE='+tostr(FOrigin));
  75. if not (target_info.system in systems_internal_sysinit) and (prtobj <> '') then
  76. begin
  77. s:=FindObjectFile(prtobj,'',false);
  78. LinkRes.AddFileName(s);
  79. end;
  80. while not ObjectFiles.Empty do
  81. begin
  82. s:=ObjectFiles.GetFirst;
  83. if s<>'' then
  84. begin
  85. if not(cs_link_on_target in current_settings.globalswitches) then
  86. s:=FindObjectFile(s,'',false);
  87. LinkRes.AddFileName((maybequoted(s)));
  88. end;
  89. end;
  90. { Write staticlibraries }
  91. if not StaticLibFiles.Empty then
  92. begin
  93. while not StaticLibFiles.Empty do
  94. begin
  95. S:=StaticLibFiles.GetFirst;
  96. LinkRes.Add('-l'+maybequoted(s));
  97. end;
  98. end;
  99. { Write and Close response }
  100. linkres.writetodisk;
  101. linkres.free;
  102. result:=True;
  103. end;
  104. function TLinkerOric.WriteResponseFile_Vlink: Boolean;
  105. Var
  106. linkres : TLinkRes;
  107. s : TCmdStr;
  108. prtobj: string[80];
  109. begin
  110. result:=false;
  111. prtobj:='prt0';
  112. { Open link.res file }
  113. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
  114. if (source_info.dirsep <> '/') then
  115. LinkRes.fForceUseForwardSlash:=true;
  116. LinkRes.Add('INPUT (');
  117. if not (target_info.system in systems_internal_sysinit) and (prtobj <> '') then
  118. begin
  119. s:=FindObjectFile(prtobj,'',false);
  120. LinkRes.AddFileName(maybequoted(s));
  121. end;
  122. while not ObjectFiles.Empty do
  123. begin
  124. s:=ObjectFiles.GetFirst;
  125. if s<>'' then
  126. begin
  127. s:=FindObjectFile(s,'',false);
  128. LinkRes.AddFileName(maybequoted(s));
  129. end;
  130. end;
  131. while not StaticLibFiles.Empty do
  132. begin
  133. S:=StaticLibFiles.GetFirst;
  134. LinkRes.AddFileName(maybequoted(s));
  135. end;
  136. LinkRes.Add(')');
  137. with LinkRes do
  138. begin
  139. Add('');
  140. Add('SECTIONS');
  141. Add('{');
  142. Add(' . = 0x'+hexstr(FOrigin,4)+';');
  143. Add(' .text : { *(.text .text.* _CODE _CODE.* ) }');
  144. Add(' .data : { *(.data .data.* .rodata .rodata.* .fpc.* ) }');
  145. Add(' .bss : { *(_BSS _BSS.*) *(.bss .bss.*) *(_BSSEND _BSSEND.*) *(_HEAP _HEAP.*) *(.stack .stack.*) *(_STACK _STACK.*) }');
  146. Add('}');
  147. end;
  148. { Write and Close response }
  149. linkres.writetodisk;
  150. linkres.free;
  151. result:=true;
  152. end;
  153. procedure TLinkerOric.SetDefaultInfo_Sdld;
  154. const
  155. ExeName='sdld';
  156. begin
  157. if ImageBaseSetExplicity then
  158. FOrigin:=ImageBase
  159. else
  160. FOrigin:=DefaultOrigin;
  161. with Info do
  162. begin
  163. ExeCmd[1]:=ExeName+' -n $OPT -i $MAP $EXE -f $RES'
  164. end;
  165. end;
  166. procedure TLinkerOric.SetDefaultInfo_Vlink;
  167. const
  168. ExeName='vlink';
  169. begin
  170. if ImageBaseSetExplicity then
  171. FOrigin:=ImageBase
  172. else
  173. FOrigin:=DefaultOrigin;
  174. with Info do
  175. begin
  176. ExeCmd[1]:=ExeName+' -bihex $GCSECTIONS -e $STARTSYMBOL $STRIP $OPT $MAP -o $EXE -T $RES'
  177. end;
  178. end;
  179. procedure TLinkerOric.SetDefaultInfo;
  180. begin
  181. if not (cs_link_vlink in current_settings.globalswitches) then
  182. SetDefaultInfo_Sdld
  183. else
  184. SetDefaultInfo_Vlink;
  185. end;
  186. function TLinkerOric.MakeExecutable_Sdld: boolean;
  187. var
  188. binstr,
  189. cmdstr,
  190. mapstr: TCmdStr;
  191. success : boolean;
  192. StaticStr,
  193. //GCSectionsStr,
  194. DynLinkStr,
  195. StripStr,
  196. FixedExeFileName: string;
  197. begin
  198. { for future use }
  199. StaticStr:='';
  200. StripStr:='';
  201. mapstr:='';
  202. DynLinkStr:='';
  203. FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
  204. if (cs_link_map in current_settings.globalswitches) then
  205. mapstr:='-mw';
  206. { Write used files and libraries }
  207. WriteResponseFile_Sdld();
  208. { Call linker }
  209. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  210. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  211. Replace(cmdstr,'$EXE',FixedExeFileName);
  212. Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  213. Replace(cmdstr,'$STATIC',StaticStr);
  214. Replace(cmdstr,'$STRIP',StripStr);
  215. Replace(cmdstr,'$MAP',mapstr);
  216. //Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  217. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  218. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  219. { Remove ReponseFile }
  220. if success and not(cs_link_nolink in current_settings.globalswitches) then
  221. DeleteFile(outputexedir+Info.ResName);
  222. { Post process }
  223. if success and not(cs_link_nolink in current_settings.globalswitches) then
  224. success:=PostProcessExecutable(FixedExeFileName,false);
  225. result:=success; { otherwise a recursive call to link method }
  226. end;
  227. function TLinkerOric.MakeExecutable_Vlink: boolean;
  228. var
  229. binstr,
  230. cmdstr: TCmdStr;
  231. success: boolean;
  232. GCSectionsStr,
  233. StripStr,
  234. StartSymbolStr,
  235. MapStr,
  236. FixedExeFilename: string;
  237. begin
  238. GCSectionsStr:='-gc-all -mtype';
  239. StripStr:='';
  240. MapStr:='';
  241. StartSymbolStr:='start';
  242. FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
  243. if (cs_link_map in current_settings.globalswitches) then
  244. MapStr:='-M'+maybequoted(ScriptFixFileName(current_module.mapfilename));
  245. { Write used files and libraries }
  246. WriteResponseFile_Vlink();
  247. { Call linker }
  248. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  249. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  250. Replace(cmdstr,'$EXE',FixedExeFileName);
  251. Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
  252. Replace(cmdstr,'$MAP',MapStr);
  253. Replace(cmdstr,'$STRIP',StripStr);
  254. Replace(cmdstr,'$STARTSYMBOL',StartSymbolStr);
  255. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  256. success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
  257. { Remove ReponseFile }
  258. if success and not(cs_link_nolink in current_settings.globalswitches) then
  259. DeleteFile(outputexedir+Info.ResName);
  260. { Post process }
  261. if success and not(cs_link_nolink in current_settings.globalswitches) then
  262. success:=PostProcessExecutable(FixedExeFileName,false);
  263. result:=success;
  264. end;
  265. function TLinkerOric.MakeExecutable: boolean;
  266. begin
  267. if not (cs_link_vlink in current_settings.globalswitches) then
  268. result:=MakeExecutable_Sdld
  269. else
  270. result:=MakeExecutable_Vlink;
  271. end;
  272. procedure TLinkerOric.InitSysInitUnitName;
  273. begin
  274. sysinitunit:='si_prc';
  275. end;
  276. function TLinkerOric.postprocessexecutable(const fn: string; isdll: boolean): boolean;
  277. begin
  278. result:=DoExec(FindUtil(utilsprefix+'ihxutil'),' -t bin '+fn+' '+maybequoted(ScriptFixFileName(current_module.exefilename)),true,false);
  279. end;
  280. {*****************************************************************************
  281. TInternalLinkerOric
  282. *****************************************************************************}
  283. //procedure TInternalLinkerOric.DefaultLinkScript;
  284. // var
  285. // s : TCmdStr;
  286. // prtobj: string[80];
  287. // begin
  288. // prtobj:='prt0';
  289. //
  290. // if not (target_info.system in systems_internal_sysinit) and (prtobj <> '') then
  291. // LinkScript.Concat('READOBJECT ' + maybequoted(FindObjectFile(prtobj,'',false)));
  292. //
  293. // while not ObjectFiles.Empty do
  294. // begin
  295. // s:=ObjectFiles.GetFirst;
  296. // if s<>'' then
  297. // begin
  298. // if not(cs_link_on_target in current_settings.globalswitches) then
  299. // s:=FindObjectFile(s,'',false);
  300. // LinkScript.Concat('READOBJECT ' + maybequoted(s));
  301. // end;
  302. // end;
  303. //
  304. // LinkScript.Concat('GROUP');
  305. // { Write staticlibraries }
  306. // if not StaticLibFiles.Empty then
  307. // begin
  308. // while not StaticLibFiles.Empty do
  309. // begin
  310. // S:=StaticLibFiles.GetFirst;
  311. // if s<>'' then
  312. // LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  313. // end;
  314. // end;
  315. // LinkScript.Concat('ENDGROUP');
  316. //
  317. // LinkScript.Concat('IMAGEBASE '+tostr(FOrigin));
  318. //
  319. // LinkScript.Concat('EXESECTION .text');
  320. // LinkScript.Concat(' OBJSECTION _CODE');
  321. // LinkScript.Concat('ENDEXESECTION');
  322. // LinkScript.Concat('EXESECTION .data');
  323. // LinkScript.Concat(' OBJSECTION _DATA');
  324. // LinkScript.Concat('ENDEXESECTION');
  325. // LinkScript.Concat('EXESECTION .bss');
  326. // LinkScript.Concat(' OBJSECTION _BSS');
  327. // LinkScript.Concat(' OBJSECTION _BSSEND');
  328. // LinkScript.Concat(' OBJSECTION _HEAP');
  329. // LinkScript.Concat(' OBJSECTION _STACK');
  330. // LinkScript.Concat('ENDEXESECTION');
  331. //
  332. // LinkScript.Concat('ENTRYNAME start');
  333. // end;
  334. //
  335. //constructor TInternalLinkerOric.create;
  336. // begin
  337. // inherited create;
  338. // CArObjectReader:=TArObjectReader;
  339. // CExeOutput:=TZXSpectrumIntelHexExeOutput;
  340. // CObjInput:=TRelObjInput;
  341. // if ImageBaseSetExplicity then
  342. // FOrigin:=ImageBase
  343. // else
  344. // FOrigin:=DefaultOrigin;
  345. // end;
  346. //
  347. //procedure TInternalLinkerOric.InitSysInitUnitName;
  348. // begin
  349. // sysinitunit:='si_prc';
  350. // end;
  351. //
  352. //function TInternalLinkerOric.MakeExecutable: boolean;
  353. // begin
  354. // result:=inherited;
  355. // { Post process }
  356. // if result and not(cs_link_nolink in current_settings.globalswitches) then
  357. // result:=PostProcessExecutable(current_module.exefilename);
  358. // end;
  359. //
  360. //function TInternalLinkerOric.postprocessexecutable(const fn: string): boolean;
  361. // var
  362. // exitcode: longint;
  363. // FoundBin: ansistring;
  364. // Found: Boolean;
  365. // utilexe: TCmdStr;
  366. // begin
  367. // result:=false;
  368. //
  369. // utilexe:=utilsprefix+'ihxutil';
  370. // FoundBin:='';
  371. // Found:=false;
  372. // if utilsdirectory<>'' then
  373. // Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  374. // if (not Found) then
  375. // Found:=FindExe(utilexe,false,Foundbin);
  376. //
  377. // if Found then
  378. // begin
  379. // Message1(exec_t_using_util,FoundBin);
  380. // exitcode:=RequotedExecuteProcess(foundbin,' '+fn);
  381. // result:=exitcode<>0;
  382. // end
  383. // else
  384. // begin
  385. // Message1(exec_e_util_not_found,utilexe);
  386. // end;
  387. // end;
  388. {*****************************************************************************
  389. Initialize
  390. *****************************************************************************}
  391. initialization
  392. {$ifdef mos6502}
  393. //RegisterLinker(ld_int_oric,TInternalLinkerOric);
  394. RegisterLinker(ld_oric,TLinkerOric);
  395. RegisterTarget(system_mos6502_oric_info);
  396. {$endif mos6502}
  397. end.