├── .gitignore
├── .gitmodules
├── Keil2GCC.cbp
├── Keil2GCC.dsp
├── Keil2GCC.dsw
├── Keil2GCC.sln
├── Keil2GCC.vcproj
├── KeilToARMGCC.cpp
├── KeilToARMGCC.h
├── KeilToGCC.cpp
├── README.md
└── Readme before using.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.d
3 | *.log
4 | *.patch
5 | *.depend
6 | *.layout
7 | Debug
8 | Release
9 | lib
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "PersistenceLibrary"]
2 | path = PersistenceLibrary
3 | url = https://github.com/embedded-tools/PersistenceLibrary.git
4 |
--------------------------------------------------------------------------------
/Keil2GCC.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/Keil2GCC.dsp:
--------------------------------------------------------------------------------
1 | # Microsoft Developer Studio Project File - Name="Keil2GCCConvertor" - Package Owner=<4>
2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00
3 | # ** DO NOT EDIT **
4 |
5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103
6 |
7 | CFG=Keil2GCCConvertor - Win32 Debug
8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE,
9 | !MESSAGE use the Export Makefile command and run
10 | !MESSAGE
11 | !MESSAGE NMAKE /f "Keil2GCC.mak".
12 | !MESSAGE
13 | !MESSAGE You can specify a configuration when running NMAKE
14 | !MESSAGE by defining the macro CFG on the command line. For example:
15 | !MESSAGE
16 | !MESSAGE NMAKE /f "Keil2GCC.mak" CFG="Keil2GCCConvertor - Win32 Debug"
17 | !MESSAGE
18 | !MESSAGE Possible choices for configuration are:
19 | !MESSAGE
20 | !MESSAGE "Keil2GCCConvertor - Win32 Release" (based on "Win32 (x86) Console Application")
21 | !MESSAGE "Keil2GCCConvertor - Win32 Debug" (based on "Win32 (x86) Console Application")
22 | !MESSAGE
23 |
24 | # Begin Project
25 | # PROP AllowPerConfigDependencies 0
26 | # PROP Scc_ProjName ""
27 | # PROP Scc_LocalPath ""
28 | CPP=cl.exe
29 | RSC=rc.exe
30 |
31 | !IF "$(CFG)" == "Keil2GCCConvertor - Win32 Release"
32 |
33 | # PROP BASE Use_MFC 0
34 | # PROP BASE Use_Debug_Libraries 0
35 | # PROP BASE Output_Dir "Release"
36 | # PROP BASE Intermediate_Dir "Release"
37 | # PROP BASE Target_Dir ""
38 | # PROP Use_MFC 0
39 | # PROP Use_Debug_Libraries 0
40 | # PROP Output_Dir "Release"
41 | # PROP Intermediate_Dir "Release"
42 | # PROP Target_Dir ""
43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
45 | # ADD BASE RSC /l 0x409 /d "NDEBUG"
46 | # ADD RSC /l 0x409 /d "NDEBUG"
47 | BSC32=bscmake.exe
48 | # ADD BASE BSC32 /nologo
49 | # ADD BSC32 /nologo
50 | LINK32=link.exe
51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
53 |
54 | !ELSEIF "$(CFG)" == "Keil2GCCConvertor - Win32 Debug"
55 |
56 | # PROP BASE Use_MFC 0
57 | # PROP BASE Use_Debug_Libraries 1
58 | # PROP BASE Output_Dir "Debug"
59 | # PROP BASE Intermediate_Dir "Debug"
60 | # PROP BASE Target_Dir ""
61 | # PROP Use_MFC 0
62 | # PROP Use_Debug_Libraries 1
63 | # PROP Output_Dir "Debug"
64 | # PROP Intermediate_Dir "Debug"
65 | # PROP Ignore_Export_Lib 0
66 | # PROP Target_Dir ""
67 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
68 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
69 | # SUBTRACT CPP /YX /Yc /Yu
70 | # ADD BASE RSC /l 0x409 /d "_DEBUG"
71 | # ADD RSC /l 0x409 /d "_DEBUG"
72 | BSC32=bscmake.exe
73 | # ADD BASE BSC32 /nologo
74 | # SUBTRACT BSC32 /nologo
75 | LINK32=link.exe
76 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
77 | # ADD LINK32 BasicTypesD.lib FileUtilsD.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
78 |
79 | !ENDIF
80 |
81 | # Begin Target
82 |
83 | # Name "Keil2GCCConvertor - Win32 Release"
84 | # Name "Keil2GCCConvertor - Win32 Debug"
85 | # Begin Group "Source Files"
86 |
87 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
88 | # Begin Source File
89 |
90 | SOURCE=.\KeilToARMGCC.cpp
91 | # End Source File
92 | # End Group
93 | # Begin Group "Header Files"
94 |
95 | # PROP Default_Filter "h;hpp;hxx;hm;inl"
96 | # Begin Source File
97 |
98 | SOURCE=.\KeilToARMGCC.h
99 | # End Source File
100 | # End Group
101 | # Begin Group "Resource Files"
102 |
103 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
104 | # End Group
105 | # Begin Source File
106 |
107 | SOURCE=.\ReadMe.txt
108 | # End Source File
109 | # End Target
110 | # End Project
111 |
--------------------------------------------------------------------------------
/Keil2GCC.dsw:
--------------------------------------------------------------------------------
1 | Microsoft Developer Studio Workspace File, Format Version 6.00
2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
3 |
4 | ###############################################################################
5 |
6 | Project: "Keil2GCCConvertor"=".\Keil2GCC.dsp" - Package Owner=<4>
7 |
8 | Package=<5>
9 | {{{
10 | }}}
11 |
12 | Package=<4>
13 | {{{
14 | }}}
15 |
16 | ###############################################################################
17 |
18 | Global:
19 |
20 | Package=<5>
21 | {{{
22 | }}}
23 |
24 | Package=<3>
25 | {{{
26 | }}}
27 |
28 | ###############################################################################
29 |
30 |
--------------------------------------------------------------------------------
/Keil2GCC.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Keil2GCC", "Keil2GCC.vcproj", "{A94CAB0E-8882-4378-AB57-7EEDE180FF35}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Win32 = Debug|Win32
9 | Release|Win32 = Release|Win32
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {A94CAB0E-8882-4378-AB57-7EEDE180FF35}.Debug|Win32.ActiveCfg = Debug|Win32
13 | {A94CAB0E-8882-4378-AB57-7EEDE180FF35}.Debug|Win32.Build.0 = Debug|Win32
14 | {A94CAB0E-8882-4378-AB57-7EEDE180FF35}.Release|Win32.ActiveCfg = Release|Win32
15 | {A94CAB0E-8882-4378-AB57-7EEDE180FF35}.Release|Win32.Build.0 = Release|Win32
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Keil2GCC.vcproj:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
26 |
29 |
32 |
35 |
38 |
41 |
53 |
56 |
59 |
62 |
71 |
74 |
77 |
80 |
83 |
86 |
89 |
92 |
93 |
101 |
104 |
107 |
110 |
113 |
116 |
128 |
131 |
134 |
137 |
148 |
151 |
154 |
157 |
160 |
163 |
166 |
169 |
170 |
171 |
172 |
173 |
174 |
179 |
182 |
183 |
186 |
187 |
188 |
193 |
196 |
197 |
198 |
203 |
204 |
207 |
208 |
209 |
210 |
211 |
212 |
--------------------------------------------------------------------------------
/KeilToARMGCC.cpp:
--------------------------------------------------------------------------------
1 | #include "KeilToARMGCC.h"
2 | #include "TFilePath.h"
3 | #include "StringUtils.h"
4 | #include "TTextFile.h"
5 | #include "TXmlDoc.h"
6 | #include "TXmlTagDynamicPool.h"
7 | #include "TRandom.h"
8 | #ifdef WIN32
9 | #include
10 | #else
11 | #include
12 | #include
13 | #include
14 | #endif
15 | #include
16 |
17 | KeilToARMGCC::KeilToARMGCC()
18 | {
19 | m_stackSize = 0;
20 | m_heapSize = 0;
21 | m_useFPU = false;
22 | m_fpuVersion = 0;
23 | m_fileHandle = 0;
24 | m_state = kcsVectors;
25 | }
26 |
27 | void KeilToARMGCC::SetState (KeilConversionState state)
28 | {
29 | m_state = state;
30 | }
31 |
32 | void KeilToARMGCC::ScanLibs(const char* makefilePath, const char* relativePath)
33 | {
34 | #ifdef WIN32
35 | WIN32_FIND_DATAA findData;
36 | HANDLE hFindHandle;
37 | char filter [512];
38 | char subpath[512];
39 |
40 | sprintf(filter, "%s%s*.*", makefilePath, relativePath+2);
41 |
42 | hFindHandle = FindFirstFileA(filter, &findData);
43 | if (hFindHandle==INVALID_HANDLE_VALUE)
44 | {
45 | return;
46 | }
47 |
48 | TFilePath filename;
49 | TFilePath fileExt;
50 | TFilePath filedir;
51 | while(true)
52 | {
53 |
54 | if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
55 | {
56 | if (findData.cFileName[0]!='.')
57 | {
58 | if (relativePath==NULL)
59 | {
60 | sprintf(subpath, "%s\\", findData.cFileName );
61 | } else {
62 | sprintf(subpath, "%s%s\\", relativePath, findData.cFileName );
63 | }
64 | printf(" %s\r\n", subpath);
65 |
66 | ScanLibs(makefilePath, subpath);
67 | }
68 | } else
69 | {
70 | filename = relativePath;
71 | filename += findData.cFileName;
72 | filename.ChangeSeparator('/');
73 | filedir = filename.ExtractFileDirectory();
74 | fileExt = filename.ExtractFileExt();
75 | if (filedir.LastChar()=='/')
76 | {
77 | filedir.SetLength(filedir.Length()-1);
78 | }
79 | if ((fileExt==".c") || (fileExt==".cpp"))
80 | {
81 | printf(" %s\r\n", filename);
82 | if (m_srcList.IndexOf(filename)==-1)
83 | {
84 | m_srcList.Add(filename);
85 | }
86 | }
87 | if (fileExt==".h")
88 | {
89 | printf(" %s\r\n", filename);
90 | if (m_incList.IndexOf(filedir)==-1)
91 | {
92 | m_incList.Add(filedir);
93 | }
94 | }
95 | }
96 | if (!FindNextFileA(hFindHandle, &findData)) break;
97 | }
98 | FindClose(hFindHandle);
99 | #else
100 | struct dirent *findData = nullptr;
101 | DIR *hFindHandle = nullptr;
102 | char filter [512];
103 | char subpath[512];
104 |
105 | sprintf(filter, "%s%s*.*", makefilePath, relativePath+2);
106 |
107 | hFindHandle = opendir(filter);
108 | if (hFindHandle == nullptr)
109 | {
110 | return;
111 | }
112 |
113 | TFilePath filename;
114 | TFilePath fileExt;
115 | TFilePath filedir;
116 | while((findData = readdir(hFindHandle)) != nullptr)
117 | {
118 | if (findData->d_type == DT_DIR)
119 | {
120 | if (findData->d_name[0]!='.')
121 | {
122 | if (relativePath==NULL)
123 | {
124 | sprintf(subpath, "%s\\", findData->d_name );
125 | } else {
126 | sprintf(subpath, "%s%s\\", relativePath, findData->d_name );
127 | }
128 | printf(" %s\r\n", subpath);
129 |
130 | ScanLibs(makefilePath, subpath);
131 | }
132 | } else
133 | {
134 | filename = relativePath;
135 | filename += findData->d_name;
136 | filename.ChangeSeparator('/');
137 | filedir = filename.ExtractFileDirectory();
138 | fileExt = filename.ExtractFileExt();
139 | if (filedir.LastChar()=='/')
140 | {
141 | filedir.SetLength(filedir.Length()-1);
142 | }
143 | if ((fileExt==".c") || (fileExt==".cpp"))
144 | {
145 | printf(" %s\r\n", filename);
146 | if (m_srcList.IndexOf(filename)==-1)
147 | {
148 | m_srcList.Add(filename);
149 | }
150 | } else if (fileExt==".h")
151 | {
152 | printf(" %s\r\n", filename);
153 | if (m_incList.IndexOf(filedir)==-1)
154 | {
155 | m_incList.Add(filedir);
156 | }
157 | }
158 | }
159 | }
160 | closedir(hFindHandle);
161 | #endif
162 | }
163 |
164 | void KeilToARMGCC::DoConversion(const char* uv4ProjectFile,
165 | int keilTargetIndex,
166 | const char* targetDirectory,
167 | bool forceSoftFPU,
168 | bool scanlibs)
169 | {
170 | bool res;
171 | bool noErrors = true;
172 |
173 | TFilePath projectFile, projectPath;
174 | projectFile.SetLength(512);
175 | #ifdef WIN32
176 | GetFullPathNameA(uv4ProjectFile, 512, (LPSTR)projectFile.ToPChar(), NULL);
177 | #else
178 | realpath(uv4ProjectFile, (char *)projectFile.ToPChar());
179 | #endif
180 | projectFile.SetLength(strlen(projectFile.ToPChar()));
181 |
182 | projectPath = projectFile;
183 | projectPath.ChangeFileName("");
184 |
185 | TFilePath targetFile = projectPath + targetDirectory;
186 | TFilePath targetPath = targetFile.ExtractFileDirectory();
187 | if (targetFile==targetPath)
188 | {
189 | //target file does not contain filename, just a directory
190 | //in such case is necessary to add a filename
191 | targetFile += "makefile";
192 | }
193 |
194 | res = ParseKeilProjectSettings(projectFile, keilTargetIndex, targetDirectory, forceSoftFPU);
195 | if (!res)
196 | {
197 | printf("\r\nKeil project parsing failed\r\n");
198 | return;
199 | }
200 | if (m_stackSize==0) m_stackSize = 512;
201 | if (m_heapSize==0) m_heapSize = 512;
202 |
203 | if (scanlibs)
204 | {
205 | printf("\r\nSearching for source codes in directories:\r\n");
206 | printf(" .\\\r\n");
207 | ScanLibs(targetPath, ".\\");
208 | printf("All files added to makefile file list.\r\n");
209 | }
210 | m_incList.Sort();
211 | m_srcList.Sort();
212 |
213 | TString deviceName = m_cpuType;
214 | deviceName.LowerCase();
215 | for(int i = 0; i='a')&&(deviceName[i]<='z')) continue;
218 | if ((deviceName[i]>='A')&&(deviceName[i]<='Z')) continue;
219 | if ((deviceName[i]>='0')&&(deviceName[i]<='9')) continue;
220 | deviceName[i]='_';
221 | }
222 |
223 | //is startup file a gcc version?
224 | bool gcc = m_startupFile.Contains("/gcc/") || m_startupFile.Contains("/gcc_");
225 | if (!gcc)
226 | {
227 | //new startup file is generated from
228 | //previously parsed irq handlers
229 | m_startupFile = "gcc_startupfile_";
230 | m_startupFile += deviceName;
231 | m_startupFile += ".s";
232 |
233 | res = CreateStartupFile(targetPath + m_startupFile);
234 | if (!res)
235 | {
236 | printf("\r\nStartup file creating failed\r\n");
237 | noErrors = false;
238 | }
239 | }
240 |
241 | m_ldScriptFile = "gcc_linkerfile_";
242 | m_ldScriptFile += deviceName;
243 | m_ldScriptFile += ".ld";
244 |
245 | res = CreateLDScript(targetPath + m_ldScriptFile);
246 | if (!res)
247 | {
248 | printf("\r\nLD file creating failed\r\n");
249 | noErrors = false;
250 | }
251 |
252 | res = CreateJLinkFile(targetPath + "flash.jlink");
253 | if (!res)
254 | {
255 | printf("\r\nJLink file not created\r\n");
256 | noErrors = false;
257 | }
258 |
259 | res = CreateMakeFile(targetFile);
260 | if (!res)
261 | {
262 | printf("\r\nMakefile not created\r\n");
263 | noErrors = false;
264 | }
265 | if (noErrors)
266 | {
267 | printf("\r\nARMGCC makefile created successfully.\r\n");
268 | } else {
269 | printf("\r\nARMGCC makefile created with errors, errors need to be fixed manually.\r\n");
270 | }
271 | }
272 |
273 |
274 | bool KeilToARMGCC::ParseKeilProjectSettings(const char* keilProjectFile, int keilTargetIndex, const char* targetFile, bool forceSoftFPU)
275 | {
276 | int i1, i2, i3;
277 |
278 | TTextFile textfile;
279 | TString line;
280 |
281 | TXMLTagDynamicPool xmlPool;
282 | TXMLDoc keilProjectXml;
283 | keilProjectXml.SetPool(&xmlPool);
284 |
285 | TFilePath targetPath = targetFile;
286 | targetPath = targetPath.ExtractFileDirectory();
287 | targetPath.ChangeSeparator('/');
288 |
289 | bool res = keilProjectXml.LoadFromFile(keilProjectFile);
290 | if (!res)
291 | {
292 | printf("Project file can not be loaded.\r\n");
293 | return false;
294 | }
295 |
296 | TXMLTag* header = keilProjectXml.Header();
297 |
298 |
299 | TXMLTag* root = keilProjectXml.Root();
300 | if (root==NULL)
301 | {
302 | printf("Project file has no xml root.\r\n");
303 | return false;
304 | }
305 |
306 | TXMLTag* targets = root->SelectNode("Targets");
307 | if (targets==NULL)
308 | {
309 | printf("Embedded target not found\r\n");
310 | return false;
311 | }
312 |
313 | TXMLTagList* targetList = targets->SelectNodes("Target");
314 |
315 | TXMLTag* target = targetList->First();
316 | if (target==NULL)
317 | {
318 | printf("Embedded target not found\r\n");
319 | return false;
320 | }
321 |
322 | TXMLTag* targetNameTag = target->SelectNode("TargetName");
323 | if (targetNameTag)
324 | {
325 | m_targetName = targetNameTag->GetValue();
326 | } else {
327 | m_targetName = "NotNamed";
328 | }
329 |
330 | for(int i = 0; i='a') && (m_targetName[i]<='z')) continue;
333 | if ((m_targetName[i]>='A') && (m_targetName[i]<='Z')) continue;
334 | if ((m_targetName[i]>='0') && (m_targetName[i]<='9')) continue;
335 | m_targetName[i] = '_';
336 | }
337 |
338 | //include paths
339 | TXMLTag* variousControlsTag = target->SelectNode("TargetOption/TargetArmAds/Cads/VariousControls");
340 | if (variousControlsTag)
341 | {
342 | int separatorPosition = 0;
343 | TXMLTag* defineTag = variousControlsTag->SelectNode("Define");
344 | if (defineTag)
345 | {
346 | TString defines = defineTag->GetValue();
347 | TString define;
348 | while(true)
349 | {
350 | separatorPosition = defines.IndexOf(',');
351 | if (separatorPosition==-1)
352 | {
353 | separatorPosition = defines.IndexOf(';');
354 | if (separatorPosition==-1)
355 | {
356 | separatorPosition = defines.IndexOf(' ');
357 | }
358 | }
359 | if (separatorPosition>=0)
360 | {
361 | define.CopyFrom(defines.ToPChar(), separatorPosition);
362 | define.Trim();
363 | m_defineList.Add(define);
364 | defines.Delete(0, separatorPosition+1);
365 | } else break;
366 | }
367 | if (defines.Length()>0)
368 | {
369 | defines.Trim();
370 | m_defineList.Add(defines);
371 | }
372 | }
373 | separatorPosition = 0;
374 | TXMLTag* includeTag = variousControlsTag->SelectNode("IncludePath");
375 |
376 | TFilePath target = targetFile;
377 | target.ChangeSeparator('/');
378 | if (includeTag)
379 | {
380 | TString includes = includeTag->GetValue();
381 | TString include;
382 | TString tmp;
383 | while(true)
384 | {
385 | separatorPosition = includes.IndexOf(';');
386 | if (separatorPosition>=0)
387 | {
388 | include.CopyFrom(includes.ToPChar(), separatorPosition);
389 | include.Trim();
390 | tmp = targetPath + include;
391 | if ((tmp.LastChar()=='\\') || (tmp.LastChar()=='/'))
392 | {
393 | tmp.SetLength(tmp.Length()-1);
394 | }
395 | int n = tmp.IndexOf("portable/RVDS");
396 | if (n>0)
397 | {
398 | for(int i = n+10; i0)
412 | {
413 | includes.Trim();
414 | m_incList.Add(targetPath + includes);
415 | }
416 | }
417 | }
418 |
419 | //cpu name
420 | TXMLTag* deviceTag = target->SelectNode("TargetOption/TargetCommonOption/Device");
421 | if (deviceTag)
422 | {
423 | m_cpuType = deviceTag->GetValue();
424 | } else {
425 | printf("CPU Type not found\r\n");
426 | }
427 |
428 | TXMLTag* vendorTag = target->SelectNode("TargetOption/TargetCommonOption/Vendor");
429 | if (vendorTag)
430 | {
431 | m_cpuVendor = vendorTag->GetValue();
432 | } else {
433 | printf("CPU Vendor not found\r\n");
434 | }
435 |
436 | //fpu present
437 | TXMLTag* cpuTag = target->SelectNode("TargetOption/TargetCommonOption/Cpu");
438 | if (!cpuTag)
439 | {
440 | printf("CPU info not found\r\n");
441 | return false;
442 | }
443 |
444 | TString cpuValue = cpuTag->GetValue();
445 |
446 |
447 | //cpu type
448 | i1 = cpuValue.IndexOf("CPUTYPE");
449 | i1 = cpuValue.IndexOf('"', i1);
450 | i2 = cpuValue.IndexOf(")",i1);
451 | if ((i1>0) && (i2>i1))
452 | {
453 | m_cpuPlatform.CopyFrom(cpuValue.ToPChar()+i1+1, i2-i1-2);
454 | m_cpuPlatform.LowerCase();
455 | }
456 |
457 | m_fpuPresent = false;
458 | m_fpuVersion = 0;
459 | if (m_cpuPlatform.Contains("cortex-m4"))
460 | {
461 | m_fpuPresent = true;
462 | m_fpuVersion = 4;
463 | }
464 | if (m_cpuPlatform.Contains("cortex-m7"))
465 | {
466 | m_fpuPresent = true;
467 | m_fpuVersion = 5;
468 | }
469 | if (m_cpuPlatform.Contains("cortex-h7"))
470 | {
471 | m_fpuPresent = true;
472 | m_fpuVersion = 5;
473 | }
474 | if (forceSoftFPU)
475 | {
476 | m_fpuPresent = false;
477 | }
478 |
479 | MemoryFragment memFragment;
480 | memset(&memFragment, 0, sizeof(memFragment));
481 |
482 | TXMLTag* armAds = target->SelectNode("TargetOption/TargetArmAds/ArmAdsMisc");
483 |
484 | //rom
485 | i1 = cpuValue.IndexOf("IROM(");
486 | i2 = cpuValue.IndexOf("-",i1+5);
487 | i3 = cpuValue.IndexOf(")",i1+5);
488 | if ((i2==-1) || (i2>i3))
489 | {
490 | i2 = cpuValue.IndexOf(',', i1+5);
491 | }
492 | if ((i1>0) && (i2>i1) && (i3>i2))
493 | {
494 | i1+=5;
495 | memFragment.beginAddress = HexToULongInt(cpuValue.ToPChar()+i1, i2-i1);
496 | memFragment.endAddress = HexToULongInt(cpuValue.ToPChar()+i2+1, i3-i2-1);
497 | m_romFragments.Add(memFragment);
498 | } else {
499 | //alternative way how to find ROM address and size (MDK v5)
500 | if (armAds)
501 | {
502 | if (FindMdk5IRom(armAds, memFragment.beginAddress, memFragment.endAddress))
503 | {
504 | m_romFragments.Add(memFragment);
505 | }
506 | }
507 | if (m_romFragments.Count()==0)
508 | {
509 | memFragment.beginAddress = 0x8100000;
510 | memFragment.endAddress = memFragment.beginAddress + 0x8000;
511 | m_romFragments.Add(memFragment);
512 | printf("ROM address not found, inserted address 0x8100000 and size 0x8000 instead\r\n");
513 | }
514 | }
515 |
516 | //ram
517 | i1 = cpuValue.IndexOf("IRAM(");
518 | i1 = cpuValue.IndexOf("(",i1);
519 | i2 = cpuValue.IndexOf("-",i1);
520 | i3 = cpuValue.IndexOf(")",i1);
521 | if ((i2==-1) || (i2>i3))
522 | {
523 | i2 = cpuValue.IndexOf(',', i1);
524 | }
525 | if ((i1>0) && (i2>i1) && (i3>i2))
526 | {
527 | i1++;
528 | memFragment.beginAddress = HexToULongInt(cpuValue.ToPChar()+i1, i2-i1);
529 | memFragment.endAddress = HexToULongInt(cpuValue.ToPChar()+i2+1, i3-i2-1);
530 | m_ramFragments.Add(memFragment);
531 | } else {
532 | if (armAds)
533 | {
534 | if (FindMdk5IRam1(armAds, memFragment.beginAddress, memFragment.endAddress))
535 | {
536 | m_ramFragments.Add(memFragment);
537 | }
538 | }
539 | if (m_ramFragments.Count()==0)
540 | {
541 | memFragment.beginAddress = 0x8200000;
542 | memFragment.endAddress = memFragment.beginAddress + 0x4000;
543 | m_ramFragments.Add(memFragment);
544 | printf("RAM address not found, inserted address 0x8200000 and size 0x4000 instead\r\n");
545 | }
546 | }
547 |
548 | //ccm ram
549 | i1 = cpuValue.IndexOf("IRAM2");
550 | i1 = cpuValue.IndexOf("(",i1);
551 | i2 = cpuValue.IndexOf("-",i1);
552 | i3 = cpuValue.IndexOf(")",i1);
553 | if ((i2==-1) || (i2>i3))
554 | {
555 | i2 = cpuValue.IndexOf(',', i1);
556 | }
557 | if ((i1>0) && (i2>i1) && (i3>i2))
558 | {
559 | i1++;
560 | memFragment.beginAddress = HexToULongInt(cpuValue.ToPChar()+i1, i2-i1);
561 | memFragment.endAddress = HexToULongInt(cpuValue.ToPChar()+i2+1, i3-i2-1);
562 | m_ramFragments.Add(memFragment);
563 | } else {
564 | if (armAds)
565 | {
566 | if (FindMdk5IRam2(armAds, memFragment.beginAddress, memFragment.endAddress))
567 | {
568 | m_ramFragments.Add(memFragment);
569 | }
570 | }
571 | }
572 |
573 | //cpu clock
574 | i1 = cpuValue.IndexOf("CLOCK");
575 | i1 = cpuValue.IndexOf("(",i1);
576 | i2 = cpuValue.IndexOf(")",i1);
577 | if ((i1>0) && (i2>i1))
578 | {
579 | i1++;
580 | m_cpuClock = StrToULongInt(cpuValue.ToPChar()+i1, (unsigned short)(i2-i1));
581 | } else{
582 | printf("Clock frequency not found\r\n");
583 | }
584 |
585 | TXMLTag* groupsTag = target->SelectNode("Groups");
586 | TXMLTagList* groupTagList = groupsTag->SelectNodes("Group");
587 | TFilePath filename;
588 | TString fileExt;
589 |
590 | for(TXMLTag* groupTag = groupTagList->First(); groupTag!=NULL; groupTag=groupTagList->Next())
591 | {
592 | TXMLTag* filesTag = groupTag->SelectNode("Files");
593 | if (filesTag == NULL) continue;
594 |
595 | TXMLTagList* fileTagList = filesTag->SelectNodes("File");
596 | if (fileTagList==NULL) continue;
597 |
598 | for(TXMLTag* fileTag = fileTagList->First(); fileTag!=NULL; fileTag=fileTagList->Next())
599 | {
600 | TXMLTag* fileNameTag = fileTag->SelectNode("FileName");
601 | TXMLTag* filePathTag = fileTag->SelectNode("FilePath");
602 | if (fileNameTag && filePathTag)
603 | {
604 | filename = filePathTag->GetValue();
605 | filename.DeleteDoubleSlash();
606 | filename.Trim();
607 | if (filename.Contains("startup_"))
608 | {
609 | if (m_startupFile.Length()>0)
610 | {
611 | printf("Project definition contains more startup files!");
612 | }
613 | if (filename.Contains("/arm/"))
614 | {
615 | //startup file is designed for keil uvision
616 | //checks if gcc version is present
617 | TString gccRelativePath = filename;
618 | int n = gccRelativePath.IndexOf("/arm/");
619 | if (n>0)
620 | {
621 | gccRelativePath[n+1] = 'g';
622 | gccRelativePath[n+2] = 'c';
623 | gccRelativePath[n+3] = 'c';
624 | }
625 | TFilePath gccfile = targetPath + gccRelativePath;
626 | FILE* file = fopen(gccfile.ToPChar(), "rb");
627 | if (file)
628 | {
629 | fclose(file);
630 | //gcc version exists
631 | filename = gccfile;
632 | }
633 | }
634 | m_startupFile = filename;
635 |
636 | } else {
637 | fileExt = filename.ExtractFileExt();
638 | fileExt.LowerCase();
639 | if ((fileExt==".c") || (fileExt==".cpp"))
640 | {
641 | TFilePath file = targetPath + filename;
642 | int n = file.IndexOf("portable/RVDS");
643 | if (n>0)
644 | {
645 | for(int i = n+10; iSelectNode("Ro1Chk");
734 | romAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT1");
735 | result = ReadMemoryBlock(romEnabledTag, romAddressTag, startAddress, endAddress);
736 | if (!result)
737 | {
738 | romEnabledTag = xmlTag->SelectNode("Ro2Chk");
739 | romAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT2");
740 | result = ReadMemoryBlock(romEnabledTag, romAddressTag, startAddress, endAddress);
741 | }
742 | if (!result)
743 | {
744 | romEnabledTag = xmlTag->SelectNode("Ro3Chk");
745 | romAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT3");
746 | result = ReadMemoryBlock(romEnabledTag, romAddressTag, startAddress, endAddress);
747 | }
748 | if (!result)
749 | {
750 | romEnabledTag = xmlTag->SelectNode("Ir1Chk");
751 | romAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT4");
752 | result = ReadMemoryBlock(romEnabledTag, romAddressTag, startAddress, endAddress);
753 | }
754 | if (!result)
755 | {
756 | romEnabledTag = xmlTag->SelectNode("Ir2Chk");
757 | romAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT5");
758 | result = ReadMemoryBlock(romEnabledTag, romAddressTag, startAddress, endAddress);
759 | }
760 | return result;
761 | }
762 |
763 | bool KeilToARMGCC::FindMdk5IRam1(TXMLTag* xmlTag, unsigned long &startAddress, unsigned long& endAddress)
764 | {
765 | return FindMdk5IRam(xmlTag, 0, startAddress, endAddress);
766 | }
767 |
768 | bool KeilToARMGCC::FindMdk5IRam2(TXMLTag* xmlTag, unsigned long &startAddress, unsigned long& endAddress)
769 | {
770 | return FindMdk5IRam(xmlTag, 1, startAddress, endAddress);
771 | }
772 |
773 | bool KeilToARMGCC::FindMdk5IRam(TXMLTag* xmlTag, unsigned long memoryIndex, unsigned long& startAddress, unsigned long& endAddress)
774 | {
775 | TXMLTag* ramEnabledTag = NULL;
776 | TXMLTag* ramAddressTag = NULL;
777 |
778 | for(int i = 0; i<5; i++)
779 | {
780 | switch(i)
781 | {
782 | case 0:
783 | {
784 | ramEnabledTag = xmlTag->SelectNode("Ra1Chk");
785 | ramAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT6");
786 | }
787 | break;
788 |
789 | case 1:
790 | {
791 | ramEnabledTag = xmlTag->SelectNode("Ra2Chk");
792 | ramAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT7");
793 | }
794 | break;
795 |
796 | case 2:
797 | {
798 | ramEnabledTag = xmlTag->SelectNode("Ra3Chk");
799 | ramAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT8");
800 | }
801 | break;
802 |
803 | case 3:
804 | {
805 | ramEnabledTag = xmlTag->SelectNode("Im1Chk");
806 | ramAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT9");
807 | }
808 | break;
809 |
810 | case 4:
811 | {
812 | ramEnabledTag = xmlTag->SelectNode("Im2Chk");
813 | ramAddressTag = xmlTag->SelectNode("OnChipMemories/OCR_RVCT10");
814 | }
815 | break;
816 | }
817 | if ((ramEnabledTag) && (ramAddressTag))
818 | {
819 | if (ReadMemoryBlock(ramEnabledTag, ramAddressTag, startAddress, endAddress))
820 | {
821 | if (memoryIndex==0) return true;
822 | memoryIndex--;
823 | }
824 | }
825 | }
826 | return false;
827 | }
828 |
829 | bool KeilToARMGCC::ReadMemoryBlock(TXMLTag* ramEnabledTag, TXMLTag* ramAddressTag, unsigned long& startAddress, unsigned long& endAddress)
830 | {
831 | startAddress = -1;
832 | endAddress = 0;
833 | int blockLength = -1;
834 | const char* enabled = ramEnabledTag->GetValue();
835 | if (enabled)
836 | {
837 | if (enabled[0]!='0')
838 | {
839 | TXMLTag* startAddressTag = ramAddressTag->SelectNode("StartAddress");
840 | if (startAddressTag)
841 | {
842 | startAddress = HexToULongInt(startAddressTag->GetValue());
843 | }
844 | TXMLTag* sizeTag = ramAddressTag->SelectNode("Size");
845 | if (sizeTag)
846 | {
847 | blockLength = HexToULongInt(sizeTag->GetValue());
848 | }
849 | if ((startAddress>=0) && (blockLength>0))
850 | {
851 | endAddress = startAddress + blockLength;
852 | return true;
853 | }
854 | }
855 | }
856 | return false;
857 | }
858 |
859 |
860 | bool KeilToARMGCC::CreateStartupFile(const char* startUpFileName)
861 | {
862 | int i;
863 | TString irq;
864 |
865 | m_fileHandle = fopen(startUpFileName, "wb");
866 | if (m_fileHandle==NULL)
867 | {
868 | return false;
869 | }
870 |
871 | WriteLine("/** Header file generated by Keil2GCC converter.\r\n");
872 | WriteLine(" * \r\n");
873 | WriteLine(" * GENERATED STARTUP FILE WITH ISR VECTORS IS PROVIDED \"AS IS\" AND ANY EXPRESS\r\n");
874 | WriteLine(" * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n");
875 | WriteLine(" * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\n");
876 | WriteLine(" * ARE DISCLAIMED.\r\n");
877 | WriteLine("*/\r\n");
878 | WriteLine("\r\n");
879 | WriteLine(" .syntax unified\r\n");
880 | WriteLine(" .cpu "); WriteLine(m_cpuPlatform.ToPChar()); WriteLine("\r\n");
881 | WriteLine(" .fpu softvfp\r\n");
882 | WriteLine(" .thumb\r\n");
883 | WriteLine("\r\n");
884 | WriteLine(".global g_pfnVectors\r\n"\
885 | ".global Default_Handler\r\n"\
886 | "\r\n"\
887 | "/* start address for the initialization values of the .data section.\r\n"\
888 | "defined in linker script */\r\n"\
889 | ".word _sidata\r\n"\
890 | "/* start address for the .data section. defined in linker script */\r\n"\
891 | ".word _sdata\r\n"\
892 | "/* end address for the .data section. defined in linker script */\r\n"\
893 | ".word _edata\r\n"\
894 | "/* start address for the .bss section. defined in linker script */\r\n"\
895 | ".word _sbss\r\n"\
896 | "/* end address for the .bss section. defined in linker script */\r\n"\
897 | ".word _ebss\r\n"\
898 | "/* stack used for SystemInit_ExtMemCtl; always internal RAM used */\r\n"\
899 | "\r\n"\
900 | "/**\r\n"\
901 | " * @brief This is the code that gets called when the processor first\r\n"\
902 | " * starts execution following a reset event. Only the absolutely\r\n"\
903 | " * necessary set is performed, after which the application\r\n"\
904 | " * supplied main() routine is called.\r\n"\
905 | " * @param None\r\n"\
906 | " * @retval : None\r\n"\
907 | "*/\r\n"\
908 | "\r\n"
909 | );
910 |
911 | WriteLine(" .section .text.Reset_Handler\r\n");
912 | WriteLine(" .weak Reset_Handler\r\n");
913 | WriteLine(" .type Reset_Handler, %function\r\n");
914 | WriteLine("Reset_Handler:\r\n");
915 | WriteLine("/* Disable all interrupts.*/\r\n");
916 | WriteLine(" cpsid i\r\n");
917 | WriteLine("\r\n");
918 | WriteLine("/* Set stack pointer */\r\n");
919 | if (m_cpuPlatform=="cortex-m0")
920 | {
921 | WriteLine(" ldr r0, =_estack\r\n");
922 | WriteLine(" mov sp, r0\r\n");
923 | } else {
924 | WriteLine(" ldr sp, =_estack\r\n");
925 | }
926 | WriteLine("\r\n");
927 | WriteLine("/* Copy the data segment initializers from flash to SRAM */\r\n");
928 | WriteLine(" movs r1, #0\r\n");
929 | WriteLine(" b LoopCopyDataInit\r\n");
930 | WriteLine("\r\n");
931 | WriteLine("CopyDataInit:\r\n");
932 | WriteLine(" ldr r3, =_sidata\r\n");
933 | WriteLine(" ldr r3, [r3, r1]\r\n");
934 | WriteLine(" str r3, [r0, r1]\r\n");
935 | WriteLine(" adds r1, r1, #4\r\n");
936 | WriteLine("\r\n");
937 | WriteLine("LoopCopyDataInit:\r\n");
938 | WriteLine(" ldr r0, =_sdata\r\n");
939 | WriteLine(" ldr r3, =_edata\r\n");
940 | WriteLine(" adds r2, r0, r1\r\n");
941 | WriteLine(" cmp r2, r3\r\n");
942 | WriteLine(" bcc CopyDataInit\r\n");
943 | WriteLine(" ldr r2, =_sbss\r\n");
944 | WriteLine(" b LoopFillZerobss\r\n");
945 | WriteLine("/* Zero fill the bss segment. */\r\n");
946 | WriteLine("FillZerobss:\r\n");
947 | WriteLine(" movs r3, #0\r\n");
948 | if (m_cpuPlatform=="cortex-m0")
949 | {
950 | WriteLine(" str r3,[r2]\r\n");
951 | WriteLine(" adds r2, r2, #4\r\n");
952 | } else {
953 | WriteLine(" str r3, [r2], #4\r\n");
954 | }
955 | WriteLine("\r\n");
956 | WriteLine("LoopFillZerobss:\r\n");
957 | WriteLine(" ldr r3, = _ebss\r\n");
958 | WriteLine(" cmp r2, r3\r\n");
959 | WriteLine(" bcc FillZerobss\r\n");
960 | WriteLine("\r\n");
961 | WriteLine("/* Call the clock system intitialization function.*/\r\n");
962 | WriteLine(" bl SystemInit\r\n");
963 | WriteLine("/* Call static constructors */\r\n");
964 | WriteLine(" bl __libc_init_array\r\n");
965 | WriteLine("/* Enable all interrupts.*/\r\n");
966 | WriteLine(" cpsie i\r\n");
967 | WriteLine("/* Call the application's entry point.*/\r\n");
968 | WriteLine(" bl main\r\n");
969 | WriteLine(" bx lr\r\n");
970 | WriteLine(" .size Reset_Handler, .-Reset_Handler\r\n");
971 | WriteLine("\r\n");
972 | WriteLine("/**\r\n");
973 | WriteLine("* @brief This is the code that gets called when the processor receives an\r\n");
974 | WriteLine("* unexpected interrupt. This simply enters an infinite loop, preserving\r\n");
975 | WriteLine("* the system state for examination by a debugger.\r\n");
976 | WriteLine("*\r\n");
977 | WriteLine("* @param None\r\n");
978 | WriteLine("* @retval : None\r\n");
979 | WriteLine("*/\r\n");
980 | WriteLine(" .section .text.Default_Handler,\"ax\",%progbits\r\n");
981 | WriteLine("Default_Handler:\r\n");
982 | WriteLine("Infinite_Loop:\r\n");
983 | WriteLine(" b Infinite_Loop\r\n");
984 | WriteLine(" .size Default_Handler, .-Default_Handler\r\n");
985 | WriteLine("/******************************************************************************\r\n");
986 | WriteLine("*\r\n");
987 | WriteLine("* The minimal vector table for a ");
988 | WriteLine(m_cpuPlatform);
989 | WriteLine(". Note that the proper constructs\r\n");
990 | WriteLine("* must be placed on this to ensure that it ends up at physical address\r\n");
991 | WriteLine("* 0x0000.0000.\r\n");
992 | WriteLine("*\r\n");
993 | WriteLine("******************************************************************************/\r\n");
994 | WriteLine(" .section .isr_vector,\"a\",%progbits\r\n");
995 | WriteLine(" .type g_pfnVectors, %object\r\n");
996 | WriteLine(" .size g_pfnVectors, .-g_pfnVectors\r\n");
997 | WriteLine("\r\n");
998 | WriteLine("g_pfnVectors:\r\n");
999 | WriteLine(" .word \t_estack\r\n");
1000 | for(i = 0; i0)
1225 | {
1226 | WriteLine("_estack = 0x");
1227 | WriteHex(m_ramFragments[0].endAddress+1);
1228 | WriteLine(";\t/* end of RAM */\r\n");
1229 | }
1230 | WriteLine("/* Generate a link error if heap and stack don't fit into RAM */\r\n");
1231 | WriteLine("_Min_Heap_Size = 0x"); WriteHex(m_heapSize); WriteLine("; /* required amount of heap */\r\n");
1232 | WriteLine("_Min_Stack_Size = 0x"); WriteHex(m_stackSize); WriteLine("; /* required amount of stack */ \r\n");
1233 | WriteLine("\r\n");
1234 | WriteLine("/* Specify the memory areas */\r\n");
1235 | WriteLine("MEMORY\r\n");
1236 | WriteLine("{\r\n");
1237 | if(m_romFragments.Count()>0)
1238 | {
1239 | WriteLine("FLASH (rx)\t:ORIGIN = 0x");
1240 | WriteHex(m_romFragments[0].beginAddress);
1241 | WriteLine(", LENGTH = ");
1242 | WriteInt((m_romFragments[0].endAddress-m_romFragments[0].beginAddress+1)/1024);
1243 | WriteLine("K\r\n");
1244 | }
1245 | if(m_ramFragments.Count()>0)
1246 | {
1247 | WriteLine("RAM (xrw)\t:ORIGIN = 0x");
1248 | WriteHex(m_ramFragments[0].beginAddress);
1249 | WriteLine(", LENGTH = ");
1250 | WriteInt((m_ramFragments[0].endAddress - m_ramFragments[0].beginAddress+1)/1024);
1251 | WriteLine("K\r\n");
1252 | }
1253 | for(int i = 1; iFLASH\r\n");
1273 | WriteLine("\r\n");
1274 | WriteLine(" .descriptor :\r\n");
1275 | WriteLine(" {\r\n");
1276 | WriteLine(" . = ALIGN(128);\r\n");
1277 | WriteLine(" KEEP(*(.descriptor)) /* Startup code */\r\n");
1278 | WriteLine(" } >FLASH\r\n");
1279 | WriteLine("\r\n");
1280 | WriteLine(" /* The program code and other data goes into FLASH */\r\n");
1281 | WriteLine(" .text :\r\n");
1282 | WriteLine(" {\r\n");
1283 | WriteLine(" . = ALIGN(4);\r\n");
1284 | WriteLine(" *(.text) /* .text sections (code) */\r\n");
1285 | WriteLine(" *(.text*) /* .text* sections (code) */\r\n");
1286 | WriteLine(" *(.glue_7) /* glue arm to thumb code */\r\n");
1287 | WriteLine(" *(.glue_7t) /* glue thumb to arm code */\r\n");
1288 | WriteLine(" *(.eh_frame)\r\n");
1289 | WriteLine("\r\n");
1290 | WriteLine(" KEEP (*(.init))\r\n");
1291 | WriteLine(" KEEP (*(.fini))\r\n");
1292 | WriteLine("\r\n");
1293 | WriteLine(" . = ALIGN(4);\r\n");
1294 | WriteLine(" _etext = .; /* define a global symbols at end of code */\r\n");
1295 | WriteLine(" } >FLASH\r\n");
1296 | WriteLine("\r\n");
1297 | WriteLine(" /* Constant data goes into FLASH */\r\n");
1298 | WriteLine(" .rodata :\r\n");
1299 | WriteLine(" {\r\n");
1300 | WriteLine(" . = ALIGN(4);\r\n");
1301 | WriteLine(" *(.rodata) /* .rodata sections (constants, strings, etc.) */\r\n");
1302 | WriteLine(" *(.rodata*) /* .rodata* sections (constants, strings, etc.) */\r\n");
1303 | WriteLine(" . = ALIGN(4);\r\n");
1304 | WriteLine(" } >FLASH\r\n");
1305 | WriteLine("\r\n");
1306 | WriteLine(" .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH\r\n");
1307 | WriteLine(" .ARM : {\r\n");
1308 | WriteLine(" __exidx_start = .;\r\n");
1309 | WriteLine(" *(.ARM.exidx*)\r\n");
1310 | WriteLine(" __exidx_end = .;\r\n");
1311 | WriteLine(" } >FLASH\r\n");
1312 | WriteLine("\r\n");
1313 | WriteLine(" .preinit_array :\r\n");
1314 | WriteLine(" {\r\n");
1315 | WriteLine(" PROVIDE_HIDDEN (__preinit_array_start = .);\r\n");
1316 | WriteLine(" KEEP (*(.preinit_array*))\r\n");
1317 | WriteLine(" PROVIDE_HIDDEN (__preinit_array_end = .);\r\n");
1318 | WriteLine(" } >FLASH\r\n");
1319 | WriteLine(" .init_array :\r\n");
1320 | WriteLine(" {\r\n");
1321 | WriteLine(" PROVIDE_HIDDEN (__init_array_start = .);\r\n");
1322 | WriteLine(" KEEP (*(SORT(.init_array.*)))\r\n");
1323 | WriteLine(" KEEP (*(.init_array*))\r\n");
1324 | WriteLine(" PROVIDE_HIDDEN (__init_array_end = .);\r\n");
1325 | WriteLine(" } >FLASH\r\n");
1326 | WriteLine(" .fini_array :\r\n");
1327 | WriteLine(" {\r\n");
1328 | WriteLine(" PROVIDE_HIDDEN (__fini_array_start = .);\r\n");
1329 | WriteLine(" KEEP (*(SORT(.fini_array.*)))\r\n");
1330 | WriteLine(" KEEP (*(.fini_array*))\r\n");
1331 | WriteLine(" PROVIDE_HIDDEN (__fini_array_end = .);\r\n");
1332 | WriteLine(" } >FLASH\r\n");
1333 | WriteLine("\r\n");
1334 | WriteLine(" /* used by the startup to initialize data */\r\n");
1335 | WriteLine(" _sidata = LOADADDR(.data);\r\n");
1336 | WriteLine("\r\n");
1337 | WriteLine(" /* Initialized data sections goes into RAM, load LMA copy after code */\r\n");
1338 | WriteLine(" .data :\r\n");
1339 | WriteLine(" {\r\n");
1340 | WriteLine(" . = ALIGN(4);\r\n");
1341 | WriteLine(" _sdata = .; /* create a global symbol at data start */\r\n");
1342 | WriteLine(" *(.data) /* .data sections */\r\n");
1343 | WriteLine(" *(.data*) /* .data* sections */\r\n");
1344 | WriteLine("\r\n");
1345 | WriteLine(" . = ALIGN(4);\r\n");
1346 | WriteLine(" _edata = .; /* define a global symbol at data end */\r\n");
1347 | WriteLine(" } >RAM AT> FLASH\r\n");
1348 | WriteLine("\r\n");
1349 | if (m_ramFragments.Count()>1)
1350 | {
1351 | WriteLine(" _siccmram = LOADADDR(.ccmram);\r\n");
1352 | WriteLine("\r\n");
1353 | WriteLine(" /* CCM-RAM section \r\n");
1354 | WriteLine(" * \r\n");
1355 | WriteLine(" * IMPORTANT NOTE! \r\n");
1356 | WriteLine(" * If initialized variables will be placed in this section,\r\n");
1357 | WriteLine(" * the startup code needs to be modified to copy the init-values.\r\n");
1358 | WriteLine(" */\r\n");
1359 | WriteLine(" .ccmram :\r\n");
1360 | WriteLine(" {\r\n");
1361 | WriteLine(" . = ALIGN(4);\r\n");
1362 | WriteLine(" _sccmram = .; /* create a global symbol at ccmram start */\r\n");
1363 | WriteLine(" *(.ccmram)\r\n");
1364 | WriteLine(" *(.ccmram*)\r\n");
1365 | WriteLine("\r\n");
1366 | WriteLine(" . = ALIGN(4);\r\n");
1367 | WriteLine(" _eccmram = .; /* create a global symbol at ccmram end */\r\n");
1368 | WriteLine(" } >CCMRAM AT> FLASH\r\n");
1369 | WriteLine("\r\n");
1370 | }
1371 | WriteLine("\r\n");
1372 | WriteLine(" /* Uninitialized data section */\r\n");
1373 | WriteLine(" . = ALIGN(4);\r\n");
1374 | WriteLine(" .bss :\r\n");
1375 | WriteLine(" {\r\n");
1376 | WriteLine(" /* This is used by the startup in order to initialize the .bss secion */\r\n");
1377 | WriteLine(" _sbss = .; /* define a global symbol at bss start */\r\n");
1378 | WriteLine(" __bss_start__ = _sbss;\r\n");
1379 | WriteLine(" *(.bss)\r\n");
1380 | WriteLine(" *(.bss*)\r\n");
1381 | WriteLine(" *(COMMON)\r\n");
1382 | WriteLine("\r\n");
1383 | WriteLine(" . = ALIGN(4);\r\n");
1384 | WriteLine(" _ebss = .; /* define a global symbol at bss end */\r\n");
1385 | WriteLine(" __bss_end__ = _ebss;\r\n");
1386 | WriteLine(" } >RAM\r\n");
1387 | WriteLine("\r\n");
1388 | WriteLine(" /* User_heap_stack section, used to check that there is enough RAM left */\r\n");
1389 | WriteLine(" ._user_heap_stack :\r\n");
1390 | WriteLine(" {\r\n");
1391 | WriteLine(" . = ALIGN(8);\r\n");
1392 | WriteLine(" PROVIDE ( end = . );\r\n");
1393 | WriteLine(" PROVIDE ( _end = . );\r\n");
1394 | WriteLine(" . = . + _Min_Heap_Size;\r\n");
1395 | WriteLine(" . = . + _Min_Stack_Size;\r\n");
1396 | WriteLine(" . = ALIGN(8);\r\n");
1397 | WriteLine(" } >RAM\r\n");
1398 | WriteLine("\r\n");
1399 | WriteLine("\r\n");
1400 | WriteLine(" /* Remove information from the standard libraries */\r\n");
1401 | WriteLine(" /DISCARD/ :\r\n");
1402 | WriteLine(" {\r\n");
1403 | WriteLine(" libnosys.a ( * )\r\n");
1404 | WriteLine(" libc.a ( * )\r\n");
1405 | WriteLine(" libm.a ( * )\r\n");
1406 | WriteLine(" libgcc.a ( * )\r\n");
1407 | WriteLine(" }\r\n");
1408 | WriteLine("\r\n");
1409 | WriteLine(" .ARM.attributes 0 : { *(.ARM.attributes) }\r\n");
1410 | WriteLine("}\r\n");
1411 | fclose(m_fileHandle);
1412 | m_fileHandle = NULL;
1413 |
1414 | return true;
1415 | }
1416 |
1417 | bool KeilToARMGCC::CreateJLinkFile(const char* jlinkFileName)
1418 | {
1419 | m_fileHandle = fopen(jlinkFileName, "wb");
1420 | if (m_fileHandle==NULL)
1421 | {
1422 | return false;
1423 | }
1424 |
1425 | WriteLine("si 1\r\n");
1426 | WriteLine("speed 2000\r\n");
1427 | WriteLine("r\r\n");
1428 | WriteLine("h\r\n");
1429 | WriteLine("loadbin ");
1430 | WriteLine(m_targetName);
1431 | WriteLine(".bin,0x");
1432 | if (m_romFragments.Count()==0)
1433 | {
1434 | return false;
1435 | }
1436 | WriteHex( m_romFragments[0].beginAddress);
1437 | WriteLine("\r\n");
1438 | WriteLine("r\r\n");
1439 | WriteLine("exit\r\n");
1440 |
1441 | return true;
1442 | }
1443 |
1444 | void KeilToARMGCC::WriteLine(const char* text)
1445 | {
1446 | if (text==NULL) return;
1447 |
1448 | fwrite(text, 1, strlen(text), m_fileHandle);
1449 | }
1450 |
1451 | void KeilToARMGCC::WriteInt(int number)
1452 | {
1453 | char num[12];
1454 | ULongIntToStr(number, num, 12);
1455 | fwrite(num, 1, strlen(num), m_fileHandle);
1456 | }
1457 |
1458 | void KeilToARMGCC::WriteHex(int number)
1459 | {
1460 | char hex[12];
1461 | ULongIntToHex(number, hex, 12);
1462 | fwrite(hex, 1, strlen(hex), m_fileHandle);
1463 | }
1464 |
1465 | void KeilToARMGCC::ParseLine(TString& line)
1466 | {
1467 | switch(m_state)
1468 | {
1469 | case kcsHeader:
1470 | {
1471 | if ( (line.IndexOf("Stack_Size")==0) ||
1472 | (line.IndexOf("Heap_Size")==0) )
1473 | {
1474 | SetState(kcsParams);
1475 | ParseLine(line);
1476 | };
1477 | if ( (line.IndexOf("__Vectors")==0))
1478 | {
1479 | SetState(kcsVectors);
1480 | ParseLine(line);
1481 | }
1482 | }
1483 | break;
1484 |
1485 | case kcsParams:
1486 | {
1487 | if (line.IndexOf("__Vectors")==0)
1488 | {
1489 | SetState(kcsVectors);
1490 | ParseLine(line);
1491 | } else {
1492 | ParseParams(line);
1493 | }
1494 | }
1495 | break;
1496 |
1497 | case kcsVectors:
1498 | {
1499 | if (line.IndexOf("Reset_Handler")==0)
1500 | {
1501 | SetState(kcsEnd);
1502 | } else
1503 | {
1504 | ParseVectors(line);
1505 |
1506 | }
1507 | }
1508 | break;
1509 |
1510 | case kcsEnd:
1511 | {
1512 | //do nothing
1513 | }
1514 | break;
1515 | }
1516 | }
1517 |
1518 | void KeilToARMGCC::ParseParams(TString& line)
1519 | {
1520 | TString sizeString;
1521 | short i;
1522 |
1523 | i = line.IndexOf("Stack_Size");
1524 | if (i==0)
1525 | {
1526 | i = line.IndexOf("EQU");
1527 | if (i>0)
1528 | {
1529 | sizeString.CopyFrom(line.ToPChar()+i+3);
1530 | sizeString.Trim();
1531 | m_stackSize = HexToULongInt(sizeString);
1532 | }
1533 | }
1534 | i = line.IndexOf("Heap_Size");
1535 | if (i==0)
1536 | {
1537 | i = line.IndexOf("EQU");
1538 | TString sizeString;
1539 | if (i>0)
1540 | {
1541 | sizeString.CopyFrom(line.ToPChar()+i+3);
1542 | sizeString.Trim();
1543 | m_heapSize = HexToULongInt(sizeString.ToPChar());
1544 | }
1545 | }
1546 | }
1547 |
1548 | void KeilToARMGCC::ParseVectors(TString& line)
1549 | {
1550 | TString irqName;
1551 |
1552 | long i1,i2;
1553 |
1554 | i1 = line.IndexOf("DCD");
1555 | if (i1==-1) return;
1556 |
1557 | i2 = line.IndexOf(";");
1558 | if (i2==-1)
1559 | {
1560 | i2 = line.Length();
1561 | }
1562 | if (i2
5 | *
6 | * https://github.com/embedded-tools/keil2gcc
7 | *
8 | * Permission to use, copy, modify, distribute and sell this software
9 | * and its documentation for any purpose is hereby granted without fee,
10 | * provided that the above copyright notice appear in all copies and
11 | * that both that copyright notice and this permission notice appear
12 | * in supporting documentation.
13 | * It is provided "as is" without express or implied warranty.
14 | *
15 | */
16 |
17 | #ifndef KEIL2GCC___H
18 | #define KEIL2GCC___H
19 |
20 | #include "TString.h"
21 | #include "TStringList.h"
22 | #include "TXmlTag.h"
23 | #include "TList.h"
24 |
25 | enum KeilConversionState
26 | {
27 | kcsHeader,
28 | kcsParams,
29 | kcsVectors,
30 | kcsEnd
31 | };
32 |
33 | struct MemoryFragment
34 | {
35 | unsigned long beginAddress;
36 | unsigned long endAddress;
37 | };
38 |
39 | class KeilToARMGCC
40 | {
41 | private:
42 | KeilConversionState m_state;
43 | FILE* m_fileHandle;
44 |
45 | int m_stackSize;
46 | int m_heapSize;
47 | bool m_useFPU;
48 | int m_fpuVersion;
49 |
50 | TStringList m_irqList;
51 | TStringList m_incList;
52 | TStringList m_srcList;
53 | TStringList m_defineList;
54 |
55 | TString m_targetName;
56 | TString m_startupFile;
57 | TString m_ldScriptFile;
58 | TString m_eclipseFile;
59 |
60 | TString m_cpuType;
61 | TString m_cpuPlatform;
62 | TString m_cpuVendor;
63 | unsigned long m_cpuClock;
64 | bool m_fpuPresent;
65 |
66 | TList m_romFragments;
67 | TList m_ramFragments;
68 |
69 | TString m_cflags;
70 | TString m_defines;
71 | TString m_newStartupFile;
72 | TString m_systemFile;
73 |
74 | void SetState (KeilConversionState state);
75 |
76 | void WriteLine(const char* text);
77 | void WriteInt(int number);
78 | void WriteHex(int number);
79 |
80 | bool CreateStartupFile(const char* vectorFileName);
81 | bool CreateMakeFile(const char* makeFileName);
82 | bool CreateJLinkFile(const char* jlinkFileName);
83 | bool CreateLDScript(const char* ldScriptFileName);
84 |
85 | void ParseLine(TString& line);
86 | void ParseParams(TString& line);
87 | void ParseVectors(TString& line);
88 |
89 | void ScanLibs(const char* makefilePath, const char* relativePath);
90 |
91 | bool FindMdk5IRom(TXMLTag* xmlTag, unsigned long& startAddress, unsigned long& endAddress);
92 | bool FindMdk5IRam1(TXMLTag* xmlTag, unsigned long &startAddress, unsigned long& endAddress);
93 | bool FindMdk5IRam2(TXMLTag* xmlTag, unsigned long &startAddress, unsigned long& endAddress);
94 | bool FindMdk5IRam(TXMLTag* xmlTag, unsigned long memoryIndex, unsigned long& startAddress, unsigned long& endAddress);
95 | bool ReadMemoryBlock(TXMLTag* ramEnabledTag, TXMLTag* ramAddressTag, unsigned long& startAddress, unsigned long& endAddress);
96 |
97 | public:
98 | KeilToARMGCC();
99 | bool ParseKeilProjectSettings(const char* keilProjectFile,
100 | int keilTargetIndex,
101 | const char* targetDirectory,
102 | bool forceSoftFPU);
103 |
104 | void DoConversion(const char* uv4ProjectFile,
105 | int keilTargetIndex,
106 | const char* targetDirectory,
107 | bool forceSoftFPU,
108 | bool scanlibs);
109 |
110 | };
111 |
112 |
113 | #endif
114 |
--------------------------------------------------------------------------------
/KeilToGCC.cpp:
--------------------------------------------------------------------------------
1 | // Keil2EclipseConvertor.cpp : Defines the entry point for the console application.
2 | //
3 | #include "TStringList.h"
4 | #include "TFilePath.h"
5 | #include "KeilToARMGCC.h"
6 | #include "TString.h"
7 |
8 |
9 | int main(int argc, char* argv[])
10 | {
11 | if (argc<=1)
12 | {
13 | printf("\r\nKeil MDK to ARM GCC makefile converter v1.07\r\n");
14 | printf("(c) 2017-2020 Ondrej Sterba, osterba@atlas.cz \r\n");
15 | printf("\r\n");
16 | printf("Usage: keil2gcc uv_project_file [-soft] [-scanlibs] [makefile_name]\r\n");
17 | printf("\r\n");
18 | printf("Options:\r\n");
19 | printf(" -soft Force using software emulated FPU\r\n");
20 | printf(" -scanlibs Scans subdirectories for source codes not included in project file\r\n");
21 | printf(" makefile_name optional - makefile path relative to uv_project_file, default value is '.\\makefile'\r\n");
22 | printf("\r\n");
23 | return -1;
24 | }
25 |
26 | bool forceSoftFPU = false;
27 | bool scanLibs = false;
28 |
29 | TString uv4ProjectFile = argv[1];
30 | TFilePath targetFile = "./";
31 | if (argc>=3)
32 | {
33 | TString lastArg = argv[argc-1];
34 | if (lastArg.Length()>0)
35 | {
36 | if (lastArg[0]!='-')
37 | {
38 | targetFile = lastArg;
39 | }
40 | }
41 | }
42 | targetFile.ChangeSeparator('/');
43 | for(int i = 1; i
2 |
3 | This utility goes through Keil project file and creates:
4 | -makefile with list of all source files included into project
5 | -it sets proper C/C++ compiler flags that fit to selected MCU
6 | -it inserts clean command + install command to makefile
7 | -it generates JLink script for installing compiled firmware to MCU (see makefile install command)
8 | -it generates *.ld file
9 | -it generates *.s file
10 | -*.s file contains some additional instructions to make sure that stack pointer is always set to correct value
11 | (even after calling entry point by boot loader)
12 |
13 |
14 | It has been tested with these MCU types:
15 |
16 | -STM 32F010
17 | -STM 32F103
18 | -STM 32F205
19 | -STM 32F207
20 | -STM 32F429
21 | -NXP LCP11C24
22 |
23 | For these MCUs is generated correct S (startup) file and LD file. For other MCUs can happen that generated S file or LD file is not 100% correct (although I hope it will not happen). In such case try to get original S file or LD file from your MCU manufacter and you can send me the correct file.
24 |
25 | This utility is also demostrating how easy is to do such things with PersistantLibrary (see https://github.com/embedded-tools/PersistenceLibrary )
26 |
27 | Binary files:
28 |
29 | 1.03 - not available anymore
30 | 1.04 - https://keil2gcc.bbot.cz/file/keil2gcc_1.04.zip (added -scanlib feature)
31 | 1.05 - https://keil2gcc.bbot.cz/file/keil2gcc_1.05.zip (support for Keil v5 added)
32 | 1.06 - https://keil2gcc.bbot.cz/file/keil2gcc_1.06.zip (minor bug fixes)
33 | 1.07 - https://keil2gcc.bbot.cz/file/keil2gcc_1.07.zip (checks for presence of original gcc startup file by manufacturer - tested with some waveshare dev kits)
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Readme before using.txt:
--------------------------------------------------------------------------------
1 | Converts Keil MDK-ARM 4 project (generated by STMCube) to ARM GCC makefile.
2 | Supports ARM Cortex MCUs (M0, M3, M4) by ST and NXP.
3 | Tested with:
4 | NXP LCP11C24
5 | ST STM32F010
6 | ST STM32F103
7 | ST STM32F207
8 | ST STM32F429
9 |
10 | Usage: keil2gcc uv4_project_file [-soft] [-scanlibs] [makefile_name]
11 |
12 | Options:
13 | -soft Force using software emulated FPU
14 | -scanlibs Scans subdirectories for not included source codes and headers
15 | makefile_name Optional, default value is '.\makefile'
16 |
17 | Example:
18 |
19 | Keil2GCC.exe d:\YourKeilProject\YourProject.uvproj
20 | Keil2GCC.exe d:\YourSTMCubeProject\MDK-ARM\TestF103.uvproj ..\makefile
21 |
--------------------------------------------------------------------------------