├── .gitignore ├── LICENSE ├── README.md ├── SConstruct ├── coremark ├── README.md ├── SConscript ├── core_list_join.c ├── core_main.c ├── core_matrix.c ├── core_portme.c ├── core_portme.h ├── core_state.c ├── core_util.c ├── coremark.h └── main.c ├── cxx ├── SConscript ├── crt │ ├── SConscript │ ├── crt.cpp │ └── crt.h ├── cxx.cpp ├── cxx.h └── main.c ├── devicetest ├── SConscript ├── device_test.c └── main.c ├── hello ├── SConscript └── main.c ├── lib ├── SConscript └── lib.c ├── md5 ├── SConscript ├── main.c ├── md5.c └── md5.h ├── memperf ├── LICENSE ├── README.md ├── SConscript ├── main.c ├── mem_perf.c ├── portme.c └── portme.h ├── tools ├── __init__.py ├── host │ ├── building.py │ └── rtthread │ │ ├── SConscript │ │ ├── finsh.h │ │ ├── rthw.h │ │ ├── rtthread.c │ │ └── rtthread.h ├── ua.def └── ua.py └── ymodem ├── SConscript ├── tofile.c ├── ymodem.c └── ymodem.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | *.mo 7 | *.pyc 8 | 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | 13 | # Libraries 14 | *.lib 15 | *.a 16 | *.la 17 | *.lo 18 | 19 | # Shared objects (inc. Windows DLLs) 20 | *.dll 21 | *.so 22 | *.so.* 23 | *.dylib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | *.i*86 30 | *.x86_64 31 | *.hex 32 | 33 | .sconsign.dblite 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Applications of RT-Thread RTOS # 2 | 3 | ## Introduction ## 4 | 5 | The user application is the application layer of RT-Thread RTOS. The developer can 6 | develop his/her application out of RT-Thread RTOS firmware environment. 7 | 8 | There are two mode for RT-Thread Applications, 9 | 10 | * Standalone Application 11 | * Shared Library 12 | 13 | The standalone application has a main() function as the program entry. It more like 14 | a program in the PC/Linux. 15 | 16 | The shared library is compose of functions, and provide these APIs to other programs. 17 | 18 | ## Build Application ## 19 | 20 | First of all, these programs must base on RT-Thread RTOS environment, and run inside. 21 | In the RT-Thread RTOS, the module option must be enable in rtconfig.h File: 22 | 23 | #define RT_USING_MODULE 24 | 25 | And provide the flags for Application building in rtconfig.py file (since RT-Thread 2.1.x, 26 | these flags will be gradually added to each BSP): 27 | 28 | * M_CFLAGS - User Application C/C++ compiler flags 29 | * M_LFLAGS - User Application link flags 30 | 31 | And Provide the ENV variable `BSP_ROOT` which points to your board support package 32 | directory. 33 | 34 | Windows: 35 | 36 | set BSP_ROOT=your_bsp_directory 37 | 38 | Linux: 39 | 40 | export BSP_ROOT=your_bsp_directory 41 | 42 | And to run the command under your BSP directory: 43 | 44 | scons --target=ua -s 45 | 46 | To generate the information for User Application, such as the header file search path, 47 | the macro defined in the RT-Thread RTOS etc. 48 | 49 | Finally, you can build the user application in `rtthread-apps` directory, for example: 50 | 51 | scons --app=hello 52 | 53 | To build `hello` program. 54 | 55 | scons --lib=libtar 56 | 57 | To build a shared library. 58 | 59 | ## A Simple Application ## 60 | 61 | This is a simple application of `Hello World`: 62 | 63 | #include 64 | 65 | int main(int argc, char **argv) 66 | { 67 | printf("Hello World!\n"); 68 | return 0; 69 | } 70 | 71 | It's just like the `Hello World` program in the PC/Linux. Beside that, the user 72 | application can use the most of APIs of RT-Thread, for example: 73 | 74 | #include 75 | 76 | void my_thread_entry(void* parameter) 77 | { 78 | int index; 79 | 80 | while (1) 81 | { 82 | rt_kprintf("index => %d\n", index ++); 83 | rt_thread_delay(RT_TICK_PER_SECOND); 84 | } 85 | } 86 | 87 | int my_thread_init(void) 88 | { 89 | rt_thread_t tid; 90 | 91 | tid = rt_thread_create("tMyTask', my_thread_entry, RT_NULL, 92 | 2048, 20, 20); 93 | if (tid != RT_NULL) rt_thread_startup(tid); 94 | 95 | return 0; 96 | } 97 | 98 | This example will create a sub-thread, which named as 'tMyTask'. 99 | 100 | ## Build the POSIX application in the host ## 101 | 102 | If you didn't set RTT_ROOT/BSP_ROOT, The command ```scons --app=hello``` will 103 | build the program in host environment, for example, build it as a Linux program. 104 | 105 | Therefore, only POSIX application can be built like that. 106 | 107 | ## License ## 108 | 109 | All of user application are standalone program, if there is no special explanation, 110 | the license of these program is [GPLv2](LICENSE). While the license of RT-Thread RTOS is GPLv2+. 111 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | # File : SConstruct.py 2 | # Building Script for User Applications 3 | # This file is part of RT-Thread RTOS 4 | # COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License along 17 | # with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | # 20 | # Change Logs: 21 | # Date Author Notes 22 | # 2015-02-07 Bernard The firstly version 23 | # 2018-04-15 Bernard Add the build option for library 24 | # 25 | 26 | import os 27 | 28 | from tools.ua import BuildApplication 29 | from tools.ua import BuildLibrary 30 | 31 | AddOption('--app', 32 | dest='app', 33 | nargs=1, type='string', 34 | action='store', 35 | metavar='DIR', 36 | help='application to be built') 37 | 38 | AddOption('--lib', 39 | dest='lib', 40 | nargs=1, type='string', 41 | action='store', 42 | metavar='DIR', 43 | help='library to be built') 44 | 45 | app = GetOption('app') 46 | lib = GetOption('lib') 47 | 48 | if app == None and lib == None: 49 | print("none application or library, please use ") 50 | print(" scons --app=your_app") 51 | print(" scons --lib=your_lib") 52 | exit(0) 53 | 54 | else: 55 | if app: 56 | BuildApplication(app + '/' + app + '.mo', app +'/SConscript') 57 | 58 | if lib: 59 | BuildLibrary(lib + '/' + lib + '.so', lib +'/SConscript') 60 | -------------------------------------------------------------------------------- /coremark/README.md: -------------------------------------------------------------------------------- 1 | # Coremark 2 | 3 | RT-Thread 上的 MCU/CPU 性能测试小工具,在 menuconfig 里选中软件包后,在 msh 中输入: 4 | 5 | ``` 6 | msh> core_mark 7 | ``` 8 | 9 | 就可以看到跑分结果了,例如: 10 | 11 | ### STM32F103RC (72MHZ) ARMCC -O3 -Otime 跑分 135: 12 | 13 | ``` 14 | \ | / 15 | - RT - Thread Operating System 16 | / | \ 4.0.2 build Oct 13 2019 17 | 2006 - 2019 Copyright by rt-thread team 18 | msh > 19 | msh >core_mark 20 | Benchmark started, please make sure it runs for at least 10s. 21 | 22 | 2K performance run parameters for coremark. 23 | CoreMark Size : 666 24 | Total ticks : 17776 25 | Total time (secs): 17.776000 26 | Iterations/Sec : 135.013501 27 | Iterations : 2400 28 | Compiler version : Please put compiler version here (e.g. gcc 4.1) 29 | Compiler flags : 30 | Memory location : STACK 31 | seedcrc : 0xe9f5 32 | [0]crclist : 0xe714 33 | [0]crcmatrix : 0x1fd7 34 | [0]crcstate : 0x8e3a 35 | [0]crcfinal : 0x382f 36 | Correct operation validated. See README.md for run and reporting rules. 37 | CoreMark 1.0 : 135.013501 / Please put compiler version here (e.g. gcc 4.1) / STACK 38 | ``` 39 | 40 | ### GD32VF103 (108MHz) GCC -Os 跑分 327: 41 | 42 | ``` 43 | \ | / 44 | - RT - Thread Operating System 45 | / | \ 4.0.2 build Oct 13 2019 46 | 2006 - 2019 Copyright by rt-thread team 47 | msh > 48 | msh >core_mark 49 | Benchmark started, please make sure it runs for at least 10s. 50 | 51 | 2K performance run parameters for coremark. 52 | CoreMark Size : 666 53 | Total ticks : 1178 54 | Total time (secs): 11 55 | Iterations/Sec : 327 56 | Iterations : 3600 57 | Compiler version : GCC8.2.0 58 | Compiler flags : 59 | Memory location : STACK 60 | seedcrc : 0xe9f5 61 | [0]crclist : 0xe714 62 | [0]crcmatrix : 0x1fd7 63 | [0]crcstate : 0x8e3a 64 | [0]crcfinal : 0x4bfc 65 | Correct operation validated. See README.md for run and reporting rules. 66 | CoreMark 1.0 : 327 / GCC8.2.0 / STACK 67 | ``` 68 | 69 | 更多测试结果可以在这里看到: 70 | 71 | **https://www.eembc.org/coremark/scores.php** 72 | 73 | ## 注意事项 74 | 75 | - 如果结果希望以小数形式打印,默认会选择 libc 依赖 76 | - 测试程序需要运行至少 10s,如果 MCU 性能太强劲一下就结束了,可以适当增加迭代次数 77 | 78 | --------------------------- 79 | 80 | # Introduction 81 | 82 | CoreMark's primary goals are simplicity and providing a method for testing only a processor's core features. For more information about EEMBC's comprehensive embedded benchmark suites, please see www.eembc.org. 83 | 84 | For a more compute-intensive version of CoreMark that uses larger datasets and execution loops taken from common applications, please check out EEMBC's [CoreMark-PRO](https://www.github.com/eembc/coremark-pro) benchmark, also on GitHub. 85 | 86 | # Building and Running 87 | 88 | To build and run the benchmark, type 89 | 90 | `> make` 91 | 92 | Full results are available in the files `run1.log` and `run2.log`. CoreMark result can be found in `run1.log`. 93 | 94 | ## Cross Compiling 95 | 96 | For cross compile platforms please adjust `core_portme.mak`, `core_portme.h` (and possibly `core_portme.c`) according to the specific platform used. When porting to a new platform, it is recommended to copy one of the default port folders (e.g. `mkdir && cp linux/* `), adjust the porting files, and run: 97 | ~~~ 98 | % make PORT_DIR= 99 | ~~~ 100 | 101 | ## Make Targets 102 | `run` - Default target, creates `run1.log` and `run2.log`. 103 | `run1.log` - Run the benchmark with performance parameters, and output to `run1.log` 104 | `run2.log` - Run the benchmark with validation parameters, and output to `run2.log` 105 | `run3.log` - Run the benchmark with profile generation parameters, and output to `run3.log` 106 | `compile` - compile the benchmark executable 107 | `link` - link the benchmark executable 108 | `check` - test MD5 of sources that may not be modified 109 | `clean` - clean temporary files 110 | 111 | ### Make flag: `ITERATIONS` 112 | By default, the benchmark will run between 10-100 seconds. To override, use `ITERATIONS=N` 113 | ~~~ 114 | % make ITERATIONS=10 115 | ~~~ 116 | Will run the benchmark for 10 iterations. It is recommended to set a specific number of iterations in certain situations e.g.: 117 | 118 | * Running with a simulator 119 | * Measuring power/energy 120 | * Timing cannot be restarted 121 | 122 | Minimum required run time: **Results are only valid for reporting if the benchmark ran for at least 10 secs!** 123 | 124 | ### Make flag: `XCFLAGS` 125 | To add compiler flags from the command line, use `XCFLAGS` e.g.: 126 | 127 | ~~~ 128 | % make XCFLAGS="-g -DMULTITHREAD=4 -DUSE_FORK=1" 129 | ~~~ 130 | 131 | ### Make flag: `CORE_DEBUG` 132 | 133 | Define to compile for a debug run if you get incorrect CRC. 134 | 135 | ~~~ 136 | % make XCFLAGS="-DCORE_DEBUG=1" 137 | ~~~ 138 | 139 | ### Make flag: `REBUILD` 140 | 141 | Force a rebuild of the executable. 142 | 143 | ## Systems Without `make` 144 | The following files need to be compiled: 145 | * `core_list_join.c` 146 | * `core_main.c` 147 | * `core_matrix.c` 148 | * `core_state.c` 149 | * `core_util.c` 150 | * `PORT_DIR/core_portme.c` 151 | 152 | For example: 153 | ~~~ 154 | % gcc -O2 -o coremark.exe core_list_join.c core_main.c core_matrix.c core_state.c core_util.c simple/core_portme.c -DPERFORMANCE_RUN=1 -DITERATIONS=1000 155 | % ./coremark.exe > run1.log 156 | ~~~ 157 | The above will compile the benchmark for a performance run and 1000 iterations. Output is redirected to `run1.log`. 158 | 159 | # Parallel Execution 160 | Use `XCFLAGS=-DMULTITHREAD=N` where N is number of threads to run in parallel. Several implementations are available to execute in multiple contexts, or you can implement your own in `core_portme.c`. 161 | 162 | ~~~ 163 | % make XCFLAGS="-DMULTITHREAD=4 -DUSE_PTHREAD" 164 | ~~~ 165 | 166 | Above will compile the benchmark for execution on 4 cores, using POSIX Threads API. 167 | 168 | # Run Parameters for the Benchmark Executable 169 | CoreMark's executable takes several parameters as follows (but only if `main()` accepts arguments): 170 | 1st - A seed value used for initialization of data. 171 | 2nd - A seed value used for initialization of data. 172 | 3rd - A seed value used for initialization of data. 173 | 4th - Number of iterations (0 for auto : default value) 174 | 5th - Reserved for internal use. 175 | 6th - Reserved for internal use. 176 | 7th - For malloc users only, ovreride the size of the input data buffer. 177 | 178 | The run target from make will run coremark with 2 different data initialization seeds. 179 | 180 | ## Alternative parameters: 181 | If not using `malloc` or command line arguments are not supported, the buffer size 182 | for the algorithms must be defined via the compiler define `TOTAL_DATA_SIZE`. 183 | `TOTAL_DATA_SIZE` must be set to 2000 bytes (default) for standard runs. 184 | The default for such a target when testing different configurations could be: 185 | 186 | ~~~ 187 | % make XCFLAGS="-DTOTAL_DATA_SIZE=6000 -DMAIN_HAS_NOARGC=1" 188 | ~~~ 189 | 190 | # Submitting Results 191 | 192 | CoreMark results can be submitted on the web. Open a web browser and go to the [submission page](https://www.eembc.org/coremark/submit.php). After registering an account you may enter a score. 193 | 194 | # Run Rules 195 | What is and is not allowed. 196 | 197 | ## Required 198 | 1. The benchmark needs to run for at least 10 seconds. 199 | 2. All validation must succeed for seeds `0,0,0x66` and `0x3415,0x3415,0x66`, buffer size of 2000 bytes total. 200 | * If not using command line arguments to main: 201 | ~~~ 202 | % make XCFLAGS="-DPERFORMANCE_RUN=1" REBUILD=1 run1.log 203 | % make XCFLAGS="-DVALIDATION_RUN=1" REBUILD=1 run2.log 204 | ~~~ 205 | 3. If using profile guided optimization, profile must be generated using seeds of `8,8,8`, and buffer size of 1200 bytes total. 206 | ~~~ 207 | % make XCFLAGS="-DTOTAL_DATA_SIZE=1200 -DPROFILE_RUN=1" REBUILD=1 run3.log 208 | ~~~ 209 | 4. All source files must be compiled with the same flags. 210 | 5. All data type sizes must match size in bits such that: 211 | * `ee_u8` is an unsigned 8-bit datatype. 212 | * `ee_s16` is a signed 16-bit datatype. 213 | * `ee_u16` is an unsigned 16-bit datatype. 214 | * `ee_s32` is a signed 32-bit datatype. 215 | * `ee_u32` is an unsigned 32-bit datatype. 216 | 217 | ## Allowed 218 | 219 | 1. Changing number of iterations 220 | 2. Changing toolchain and build/load/run options 221 | 3. Changing method of acquiring a data memory block 222 | 5. Changing the method of acquiring seed values 223 | 6. Changing implementation `in core_portme.c` 224 | 7. Changing configuration values in `core_portme.h` 225 | 8. Changing `core_portme.mak` 226 | 227 | ## NOT ALLOWED 228 | 1. Changing of source file other then `core_portme*` (use `make check` to validate) 229 | 230 | # Reporting rules 231 | Use the following syntax to report results on a data sheet: 232 | 233 | CoreMark 1.0 : N / C [/ P] [/ M] 234 | 235 | N - Number of iterations per second with seeds 0,0,0x66,size=2000) 236 | 237 | C - Compiler version and flags 238 | 239 | P - Parameters such as data and code allocation specifics 240 | 241 | * This parameter *may* be omitted if all data was allocated on the heap in RAM. 242 | * This parameter *may not* be omitted when reporting CoreMark/MHz 243 | 244 | M - Type of parallel execution (if used) and number of contexts 245 | * This parameter may be omitted if parallel execution was not used. 246 | 247 | e.g.: 248 | 249 | ~~~ 250 | CoreMark 1.0 : 128 / GCC 4.1.2 -O2 -fprofile-use / Heap in TCRAM / FORK:2 251 | ~~~ 252 | or 253 | ~~~ 254 | CoreMark 1.0 : 1400 / GCC 3.4 -O4 255 | ~~~ 256 | 257 | If reporting scaling results, the results must be reported as follows: 258 | 259 | CoreMark/MHz 1.0 : N / C / P [/ M] 260 | 261 | P - When reporting scaling results, memory parameter must also indicate memory frequency:core frequency ratio. 262 | 1. If the core has cache and cache frequency to core frequency ratio is configurable, that must also be included. 263 | 264 | e.g.: 265 | 266 | ~~~ 267 | CoreMark/MHz 1.0 : 1.47 / GCC 4.1.2 -O2 / DDR3(Heap) 30:1 Memory 1:1 Cache 268 | ~~~ 269 | 270 | # Log File Format 271 | The log files have the following format 272 | 273 | ~~~ 274 | 2K performance run parameters for coremark. (Run type) 275 | CoreMark Size : 666 (Buffer size) 276 | Total ticks : 25875 (platform dependent value) 277 | Total time (secs) : 25.875000 (actual time in seconds) 278 | Iterations/Sec : 3864.734300 (Performance value to report) 279 | Iterations : 100000 (number of iterations used) 280 | Compiler version : GCC3.4.4 (Compiler and version) 281 | Compiler flags : -O2 (Compiler and linker flags) 282 | Memory location : Code in flash, data in on chip RAM 283 | seedcrc : 0xe9f5 (identifier for the input seeds) 284 | [0]crclist : 0xe714 (validation for list part) 285 | [0]crcmatrix : 0x1fd7 (validation for matrix part) 286 | [0]crcstate : 0x8e3a (validation for state part) 287 | [0]crcfinal : 0x33ff (iteration dependent output) 288 | Correct operation validated. See README.md for run and reporting rules. (*Only when run is successful*) 289 | CoreMark 1.0 : 6508.490622 / GCC3.4.4 -O2 / Heap (*Only on a successful performance run*) 290 | ~~~ 291 | 292 | # Theory of Operation 293 | 294 | This section describes the initial goals of CoreMark and their implementation. 295 | 296 | ## Small and easy to understand 297 | 298 | * X number of source code lines for timed portion of the benchmark. 299 | * Meaningful names for variables and functions. 300 | * Comments for each block of code more than 10 lines long. 301 | 302 | ## Portability 303 | 304 | A thin abstraction layer will be provided for I/O and timing in a separate file. All I/O and timing of the benchmark will be done through this layer. 305 | 306 | ### Code / data size 307 | 308 | * Compile with gcc on x86 and make sure all sizes are according to requirements. 309 | * If dynamic memory allocation is used, take total memory allocated into account as well. 310 | * Avoid recursive functions and keep track of stack usage. 311 | * Use the same memory block as data site for all algorithms, and initialize the data before each algorithm – while this means that initialization with data happens during the timed portion, it will only happen once during the timed portion and so have negligible effect on the results. 312 | 313 | ## Controlled output 314 | 315 | This may be the most difficult goal. Compilers are constantly improving and getting better at analyzing code. To create work that cannot be computed at compile time and must be computed at run time, we will rely on two assumptions: 316 | 317 | * Some system functions (e.g. time, scanf) and parameters cannot be computed at compile time. In most cases, marking a variable volatile means the compiler is force to read this variable every time it is read. This will be used to introduce a factor into the input that cannot be precomputed at compile time. Since the results are input dependent, that will make sure that computation has to happen at run time. 318 | 319 | * Either a system function or I/O (e.g. scanf) or command line parameters or volatile variables will be used before the timed portion to generate data which is not available at compile time. Specific method used is not relevant as long as it can be controlled, and that it cannot be computed or eliminated by the compiler at compile time. E.g. if the clock() functions is a compiler stub, it may not be used. The derived values will be reported on the output so that verification can be done on a different machine. 320 | 321 | * We cannot rely on command line parameters since some embedded systems do not have the capability to provide command line parameters. All 3 methods above will be implemented (time based, scanf and command line parameters) and all 3 are valid if the compiler cannot determine the value at compile time. 322 | 323 | * It is important to note that The actual values that are to be supplied at run time will be standardized. The methodology is not intended to provide random data, but simply to provide controlled data that cannot be precomputed at compile time. 324 | 325 | * Printed results must be valid at run time. This will be used to make sure the computation has been executed. 326 | 327 | * Some embedded systems do not provide “printf” or other I/O functionality. All I/O will be done through a thin abstraction interface to allow execution on such systems (e.g. allow output via JTAG). 328 | 329 | ## Key Algorithms 330 | 331 | ### Linked List 332 | 333 | The following linked list structure will be used: 334 | 335 | ~~~ 336 | typedef struct list_data_s { 337 | ee_s16 data16; 338 | ee_s16 idx; 339 | } list_data; 340 | 341 | typedef struct list_head_s { 342 | struct list_head_s *next; 343 | struct list_data_s *info; 344 | } list_head; 345 | ~~~ 346 | 347 | While adding a level of indirection accessing the data, this structure is realistic and used in many embedded applications for small to medium lists. 348 | 349 | The list itself will be initialized on a block of memory that will be passed in to the initialization function. While in general linked lists use malloc for new nodes, embedded applications sometime control the memory for small data structures such as arrays and lists directly to avoid the overhead of system calls, so this approach is realistic. 350 | 351 | The linked list will be initialized such that 1/4 of the list pointers point to sequential areas in memory, and 3/4 of the list pointers are distributed in a non sequential manner. This is done to emulate a linked list that had add/remove happen for a while disrupting the neat order, and then a series of adds that are likely to come from sequential memory locations. 352 | 353 | For the benchmark itself: 354 | - Multiple find operations are going to be performed. These find operations may result in the whole list being traversed. The result of each find will become part of the output chain. 355 | - The list will be sorted using merge sort based on the data16 value, and then derive CRC of the data16 item in order for part of the list. The CRC will become part of the output chain. 356 | - The list will be sorted again using merge sort based on the idx value. This sort will guarantee that the list is returned to the primary state before leaving the function, so that multiple iterations of the function will have the same result. CRC of the data16 for part of the list will again be calculated and become part of the output chain. 357 | 358 | The actual `data16` in each cell will be pseudo random based on a single 16b input that cannot be determined at compile time. In addition, the part of the list which is used for CRC will also be passed to the function, and determined based on an input that cannot be determined at run time. 359 | 360 | ### Matrix Multiply 361 | 362 | This very simple algorithm forms the basis of many more complex algorithms. The tight inner loop is the focus of many optimizations (compiler as well as hardware based) and is thus relevant for embedded processing. 363 | 364 | The total available data space will be divided to 3 parts: 365 | 1. NxN matrix A. 366 | 2. NxN matrix B. 367 | 3. NxN matrix C. 368 | 369 | E.g. for 2K we will have 3 12x12 matrices (assuming data type of 32b 12(len)*12(wid)*4(size)*3(num) =1728 bytes). 370 | 371 | Matrix A will be initialized with small values (upper 3/4 of the bits all zero). 372 | Matrix B will be initialized with medium values (upper half of the bits all zero). 373 | Matrix C will be used for the result. 374 | 375 | For the benchmark itself: 376 | - Multiple A by a constant into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. 377 | - Multiple A by column X of B into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. 378 | - Multiple A by B into C, add the upper bits of each of the values in the result matrix. The result will become part of the output chain. 379 | 380 | The actual values for A and B must be derived based on input that is not available at compile time. 381 | 382 | ### State Machine 383 | 384 | This part of the code needs to exercise switch and if statements. As such, we will use a small Moore state machine. In particular, this will be a state machine that identifies string input as numbers and divides them according to format. 385 | 386 | The state machine will parse the input string until either a “,” separator or end of input is encountered. An invalid number will cause the state machine to return invalid state and a valid number will cause the state machine to return with type of number format (int/float/scientific). 387 | 388 | This code will perform a realistic task, be small enough to easily understand, and exercise the required functionality. The other option used in embedded systems is a mealy based state machine, which is driven by a table. The table then determines the number of states and complexity of transitions. This approach, however, tests mainly the load/store and function call mechanisms and less the handling of branches. If analysis of the final results shows that the load/store functionality of the processor is not exercised thoroughly, it may be a good addition to the benchmark (codesize allowing). 389 | 390 | For input, the memory block will be initialized with comma separated values of mixed formats, as well as invalid inputs. 391 | 392 | For the benchmark itself: 393 | - Invoke the state machine on all of the input and count final states and state transitions. CRC of all final states and transitions will become part of the output chain. 394 | - Modify the input at intervals (inject errors) and repeat the state machine operation. 395 | - Modify the input back to original form. 396 | 397 | The actual input must be initialized based on data that cannot be determined at compile time. In addition the intervals for modification of the input and the actual modification must be based on input that cannot be determined at compile time. 398 | 399 | # Validation 400 | 401 | This release was tested on the following platforms: 402 | * x86 cygwin and gcc 3.4 (Quad, dual and single core systems) 403 | * x86 linux (Ubuntu/Fedora) and gcc (4.2/4.1) (Quad and single core systems) 404 | * MIPS64 BE linux and gcc 3.4 16 cores system 405 | * MIPS32 BE linux with CodeSourcery compiler 4.2-177 on Malta/Linux with a 1004K 3-core system 406 | * PPC simulator with gcc 4.2.2 (No OS) 407 | * PPC 64b BE linux (yellowdog) with gcc 3.4 and 4.1 (Dual core system) 408 | * BF533 with VDSP50 409 | * Renesas R8C/H8 MCU with HEW 4.05 410 | * NXP LPC1700 armcc v4.0.0.524 411 | * NEC 78K with IAR v4.61 412 | * ARM simulator with armcc v4 413 | 414 | # Memory Analysis 415 | 416 | Valgrind 3.4.0 used and no errors reported. 417 | 418 | # Balance Analysis 419 | 420 | Number of instructions executed for each function tested with cachegrind and found balanced with gcc and -O0. 421 | 422 | # Statistics 423 | 424 | Lines: 425 | ~~~ 426 | Lines Blank Cmnts Source AESL 427 | ===== ===== ===== ===== ========== ======================================= 428 | 469 66 170 251 627.5 core_list_join.c (C) 429 | 330 18 54 268 670.0 core_main.c (C) 430 | 256 32 80 146 365.0 core_matrix.c (C) 431 | 240 16 51 186 465.0 core_state.c (C) 432 | 165 11 20 134 335.0 core_util.c (C) 433 | 150 23 36 98 245.0 coremark.h (C) 434 | 1610 166 411 1083 2707.5 ----- Benchmark ----- (6 files) 435 | 293 15 74 212 530.0 linux/core_portme.c (C) 436 | 235 30 104 104 260.0 linux/core_portme.h (C) 437 | 528 45 178 316 790.0 ----- Porting ----- (2 files) 438 | 439 | * For comparison, here are the stats for Dhrystone 440 | Lines Blank Cmnts Source AESL 441 | ===== ===== ===== ===== ========== ======================================= 442 | 311 15 242 54 135.0 dhry.h (C) 443 | 789 132 119 553 1382.5 dhry_1.c (C) 444 | 186 26 68 107 267.5 dhry_2.c (C) 445 | 1286 173 429 714 1785.0 ----- C ----- (3 files) 446 | ~~~ 447 | 448 | # Credits 449 | Many thanks to all of the individuals who helped with the development or testing of CoreMark including (Sorted by company name; note that company names may no longer be accurate as this was written in 2009). 450 | * Alan Anderson, ADI 451 | * Adhikary Rajiv, ADI 452 | * Elena Stohr, ARM 453 | * Ian Rickards, ARM 454 | * Andrew Pickard, ARM 455 | * Trent Parker, CAVIUM 456 | * Shay Gal-On, EEMBC 457 | * Markus Levy, EEMBC 458 | * Peter Torelli, EEMBC 459 | * Ron Olson, IBM 460 | * Eyal Barzilay, MIPS 461 | * Jens Eltze, NEC 462 | * Hirohiko Ono, NEC 463 | * Ulrich Drees, NEC 464 | * Frank Roscheda, NEC 465 | * Rob Cosaro, NXP 466 | * Shumpei Kawasaki, RENESAS 467 | 468 | # Legal 469 | Please refer to LICENSE.md in this reposity for a description of your rights to use this code. 470 | 471 | # Copyright 472 | Copyright © 2009 EEMBC All rights reserved. 473 | CoreMark is a trademark of EEMBC and EEMBC is a registered trademark of the Embedded Microprocessor Benchmark Consortium. 474 | 475 | -------------------------------------------------------------------------------- /coremark/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | import rtconfig 3 | 4 | # get current directory 5 | cwd = GetCurrentDir() 6 | # The set of source files associated with this SConscript file. 7 | src = Glob('*.c') 8 | 9 | path = [cwd + '/'] 10 | 11 | LOCAL_CCFLAGS = '' 12 | 13 | group = DefineGroup('coremark', src, depend = [''], CPPPATH = path, LOCAL_CCFLAGS = LOCAL_CCFLAGS) 14 | 15 | Return('group') 16 | -------------------------------------------------------------------------------- /coremark/core_list_join.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* 21 | Topic: Description 22 | Benchmark using a linked list. 23 | 24 | Linked list is a common data structure used in many applications. 25 | 26 | For our purposes, this will excercise the memory units of the processor. 27 | In particular, usage of the list pointers to find and alter data. 28 | 29 | We are not using Malloc since some platforms do not support this library. 30 | 31 | Instead, the memory block being passed in is used to create a list, 32 | and the benchmark takes care not to add more items then can be 33 | accomodated by the memory block. The porting layer will make sure 34 | that we have a valid memory block. 35 | 36 | All operations are done in place, without using any extra memory. 37 | 38 | The list itself contains list pointers and pointers to data items. 39 | Data items contain the following: 40 | 41 | idx - An index that captures the initial order of the list. 42 | data - Variable data initialized based on the input parameters. The 16b are divided as follows: 43 | o Upper 8b are backup of original data. 44 | o Bit 7 indicates if the lower 7 bits are to be used as is or calculated. 45 | o Bits 0-2 indicate type of operation to perform to get a 7b value. 46 | o Bits 3-6 provide input for the operation. 47 | 48 | */ 49 | 50 | /* local functions */ 51 | 52 | list_head *core_list_find(list_head *list,list_data *info); 53 | list_head *core_list_reverse(list_head *list); 54 | list_head *core_list_remove(list_head *item); 55 | list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified); 56 | list_head *core_list_insert_new(list_head *insert_point 57 | , list_data *info, list_head **memblock, list_data **datablock 58 | , list_head *memblock_end, list_data *datablock_end); 59 | typedef ee_s32(*list_cmp)(list_data *a, list_data *b, core_results *res); 60 | list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res); 61 | 62 | ee_s16 calc_func(ee_s16 *pdata, core_results *res) { 63 | ee_s16 data=*pdata; 64 | ee_s16 retval; 65 | ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ 66 | if (optype) /* if cached, use cache */ 67 | return (data & 0x007f); 68 | else { /* otherwise calculate and cache the result */ 69 | ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ 70 | ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ 71 | dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ 72 | switch (flag) { 73 | case 0: 74 | if (dtype<0x22) /* set min period for bit corruption */ 75 | dtype=0x22; 76 | retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); 77 | if (res->crcstate==0) 78 | res->crcstate=retval; 79 | break; 80 | case 1: 81 | retval=core_bench_matrix(&(res->mat),dtype,res->crc); 82 | if (res->crcmatrix==0) 83 | res->crcmatrix=retval; 84 | break; 85 | default: 86 | retval=data; 87 | break; 88 | } 89 | res->crc=crcu16(retval,res->crc); 90 | retval &= 0x007f; 91 | *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ 92 | return retval; 93 | } 94 | } 95 | /* Function: cmp_complex 96 | Compare the data item in a list cell. 97 | 98 | Can be used by mergesort. 99 | */ 100 | ee_s32 cmp_complex(list_data *a, list_data *b, core_results *res) { 101 | ee_s16 val1=calc_func(&(a->data16),res); 102 | ee_s16 val2=calc_func(&(b->data16),res); 103 | return val1 - val2; 104 | } 105 | 106 | /* Function: cmp_idx 107 | Compare the idx item in a list cell, and regen the data. 108 | 109 | Can be used by mergesort. 110 | */ 111 | ee_s32 cmp_idx(list_data *a, list_data *b, core_results *res) { 112 | if (res==NULL) { 113 | a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8)); 114 | b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8)); 115 | } 116 | return a->idx - b->idx; 117 | } 118 | 119 | void copy_info(list_data *to,list_data *from) { 120 | to->data16=from->data16; 121 | to->idx=from->idx; 122 | } 123 | 124 | /* Benchmark for linked list: 125 | - Try to find multiple data items. 126 | - List sort 127 | - Operate on data from list (crc) 128 | - Single remove/reinsert 129 | * At the end of this function, the list is back to original state 130 | */ 131 | ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx) { 132 | ee_u16 retval=0; 133 | ee_u16 found=0,missed=0; 134 | list_head *list=res->list; 135 | ee_s16 find_num=res->seed3; 136 | list_head *this_find; 137 | list_head *finder, *remover; 138 | list_data info; 139 | ee_s16 i; 140 | 141 | info.idx=finder_idx; 142 | /* find values in the list, and change the list each time (reverse and cache if value found) */ 143 | for (i=0; inext->info->data16 >> 8) & 1; 150 | } 151 | else { 152 | found++; 153 | if (this_find->info->data16 & 0x1) /* use found value */ 154 | retval+=(this_find->info->data16 >> 9) & 1; 155 | /* and cache next item at the head of the list (if any) */ 156 | if (this_find->next != NULL) { 157 | finder = this_find->next; 158 | this_find->next = finder->next; 159 | finder->next=list->next; 160 | list->next=finder; 161 | } 162 | } 163 | if (info.idx>=0) 164 | info.idx++; 165 | #if CORE_DEBUG 166 | ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); 167 | #endif 168 | } 169 | retval+=found*4-missed; 170 | /* sort the list by data content and remove one item*/ 171 | if (finder_idx>0) 172 | list=core_list_mergesort(list,cmp_complex,res); 173 | remover=core_list_remove(list->next); 174 | /* CRC data content of list from location of index N forward, and then undo remove */ 175 | finder=core_list_find(list,&info); 176 | if (!finder) 177 | finder=list->next; 178 | while (finder) { 179 | retval=crc16(list->info->data16,retval); 180 | finder=finder->next; 181 | } 182 | #if CORE_DEBUG 183 | ee_printf("List sort 1: %04x\n",retval); 184 | #endif 185 | remover=core_list_undo_remove(remover,list->next); 186 | /* sort the list by index, in effect returning the list to original state */ 187 | list=core_list_mergesort(list,cmp_idx,NULL); 188 | /* CRC data content of list */ 189 | finder=list->next; 190 | while (finder) { 191 | retval=crc16(list->info->data16,retval); 192 | finder=finder->next; 193 | } 194 | #if CORE_DEBUG 195 | ee_printf("List sort 2: %04x\n",retval); 196 | #endif 197 | return retval; 198 | } 199 | /* Function: core_list_init 200 | Initialize list with data. 201 | 202 | Parameters: 203 | blksize - Size of memory to be initialized. 204 | memblock - Pointer to memory block. 205 | seed - Actual values chosen depend on the seed parameter. 206 | The seed parameter MUST be supplied from a source that cannot be determined at compile time 207 | 208 | Returns: 209 | Pointer to the head of the list. 210 | 211 | */ 212 | list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) { 213 | /* calculated pointers for the list */ 214 | ee_u32 per_item=16+sizeof(struct list_data_s); 215 | ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */ 216 | list_head *memblock_end=memblock+size; 217 | list_data *datablock=(list_data *)(memblock_end); 218 | list_data *datablock_end=datablock+size; 219 | /* some useful variables */ 220 | ee_u32 i; 221 | list_head *finder,*list=memblock; 222 | list_data info; 223 | 224 | /* create a fake items for the list head and tail */ 225 | list->next=NULL; 226 | list->info=datablock; 227 | list->info->idx=0x0000; 228 | list->info->data16=(ee_s16)0x8080; 229 | memblock++; 230 | datablock++; 231 | info.idx=0x7fff; 232 | info.data16=(ee_s16)0xffff; 233 | core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end); 234 | 235 | /* then insert size items */ 236 | for (i=0; inext; 244 | i=1; 245 | while (finder->next!=NULL) { 246 | if (iinfo->idx=i++; 248 | else { 249 | ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */ 250 | finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */ 251 | } 252 | finder=finder->next; 253 | } 254 | list = core_list_mergesort(list,cmp_idx,NULL); 255 | #if CORE_DEBUG 256 | ee_printf("Initialized list:\n"); 257 | finder=list; 258 | while (finder) { 259 | ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16); 260 | finder=finder->next; 261 | } 262 | ee_printf("\n"); 263 | #endif 264 | return list; 265 | } 266 | 267 | /* Function: core_list_insert 268 | Insert an item to the list 269 | 270 | Parameters: 271 | insert_point - where to insert the item. 272 | info - data for the cell. 273 | memblock - pointer for the list header 274 | datablock - pointer for the list data 275 | memblock_end - end of region for list headers 276 | datablock_end - end of region for list data 277 | 278 | Returns: 279 | Pointer to new item. 280 | */ 281 | list_head *core_list_insert_new(list_head *insert_point, list_data *info, list_head **memblock, list_data **datablock 282 | , list_head *memblock_end, list_data *datablock_end) { 283 | list_head *newitem; 284 | 285 | if ((*memblock+1) >= memblock_end) 286 | return NULL; 287 | if ((*datablock+1) >= datablock_end) 288 | return NULL; 289 | 290 | newitem=*memblock; 291 | (*memblock)++; 292 | newitem->next=insert_point->next; 293 | insert_point->next=newitem; 294 | 295 | newitem->info=*datablock; 296 | (*datablock)++; 297 | copy_info(newitem->info,info); 298 | 299 | return newitem; 300 | } 301 | 302 | /* Function: core_list_remove 303 | Remove an item from the list. 304 | 305 | Operation: 306 | For a singly linked list, remove by copying the data from the next item 307 | over to the current cell, and unlinking the next item. 308 | 309 | Note: 310 | since there is always a fake item at the end of the list, no need to check for NULL. 311 | 312 | Returns: 313 | Removed item. 314 | */ 315 | list_head *core_list_remove(list_head *item) { 316 | list_data *tmp; 317 | list_head *ret=item->next; 318 | /* swap data pointers */ 319 | tmp=item->info; 320 | item->info=ret->info; 321 | ret->info=tmp; 322 | /* and eliminate item */ 323 | item->next=item->next->next; 324 | ret->next=NULL; 325 | return ret; 326 | } 327 | 328 | /* Function: core_list_undo_remove 329 | Undo a remove operation. 330 | 331 | Operation: 332 | Since we want each iteration of the benchmark to be exactly the same, 333 | we need to be able to undo a remove. 334 | Link the removed item back into the list, and switch the info items. 335 | 336 | Parameters: 337 | item_removed - Return value from the 338 | item_modified - List item that was modified during 339 | 340 | Returns: 341 | The item that was linked back to the list. 342 | 343 | */ 344 | list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified) { 345 | list_data *tmp; 346 | /* swap data pointers */ 347 | tmp=item_removed->info; 348 | item_removed->info=item_modified->info; 349 | item_modified->info=tmp; 350 | /* and insert item */ 351 | item_removed->next=item_modified->next; 352 | item_modified->next=item_removed; 353 | return item_removed; 354 | } 355 | 356 | /* Function: core_list_find 357 | Find an item in the list 358 | 359 | Operation: 360 | Find an item by idx (if not 0) or specific data value 361 | 362 | Parameters: 363 | list - list head 364 | info - idx or data to find 365 | 366 | Returns: 367 | Found item, or NULL if not found. 368 | */ 369 | list_head *core_list_find(list_head *list,list_data *info) { 370 | if (info->idx>=0) { 371 | while (list && (list->info->idx != info->idx)) 372 | list=list->next; 373 | return list; 374 | } else { 375 | while (list && ((list->info->data16 & 0xff) != info->data16)) 376 | list=list->next; 377 | return list; 378 | } 379 | } 380 | /* Function: core_list_reverse 381 | Reverse a list 382 | 383 | Operation: 384 | Rearrange the pointers so the list is reversed. 385 | 386 | Parameters: 387 | list - list head 388 | info - idx or data to find 389 | 390 | Returns: 391 | Found item, or NULL if not found. 392 | */ 393 | 394 | list_head *core_list_reverse(list_head *list) { 395 | list_head *next=NULL, *tmp; 396 | while (list) { 397 | tmp=list->next; 398 | list->next=next; 399 | next=list; 400 | list=tmp; 401 | } 402 | return next; 403 | } 404 | /* Function: core_list_mergesort 405 | Sort the list in place without recursion. 406 | 407 | Description: 408 | Use mergesort, as for linked list this is a realistic solution. 409 | Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm. 410 | The sort can either return the list to original order (by idx) , 411 | or use the data item to invoke other other algorithms and change the order of the list. 412 | 413 | Parameters: 414 | list - list to be sorted. 415 | cmp - cmp function to use 416 | 417 | Returns: 418 | New head of the list. 419 | 420 | Note: 421 | We have a special header for the list that will always be first, 422 | but the algorithm could theoretically modify where the list starts. 423 | 424 | */ 425 | list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) { 426 | list_head *p, *q, *e, *tail; 427 | ee_s32 insize, nmerges, psize, qsize, i; 428 | 429 | insize = 1; 430 | 431 | while (1) { 432 | p = list; 433 | list = NULL; 434 | tail = NULL; 435 | 436 | nmerges = 0; /* count number of merges we do in this pass */ 437 | 438 | while (p) { 439 | nmerges++; /* there exists a merge to be done */ 440 | /* step `insize' places along from p */ 441 | q = p; 442 | psize = 0; 443 | for (i = 0; i < insize; i++) { 444 | psize++; 445 | q = q->next; 446 | if (!q) break; 447 | } 448 | 449 | /* if q hasn't fallen off end, we have two lists to merge */ 450 | qsize = insize; 451 | 452 | /* now we have two lists; merge them */ 453 | while (psize > 0 || (qsize > 0 && q)) { 454 | 455 | /* decide whether next element of merge comes from p or q */ 456 | if (psize == 0) { 457 | /* p is empty; e must come from q. */ 458 | e = q; q = q->next; qsize--; 459 | } else if (qsize == 0 || !q) { 460 | /* q is empty; e must come from p. */ 461 | e = p; p = p->next; psize--; 462 | } else if (cmp(p->info,q->info,res) <= 0) { 463 | /* First element of p is lower (or same); e must come from p. */ 464 | e = p; p = p->next; psize--; 465 | } else { 466 | /* First element of q is lower; e must come from q. */ 467 | e = q; q = q->next; qsize--; 468 | } 469 | 470 | /* add the next element to the merged list */ 471 | if (tail) { 472 | tail->next = e; 473 | } else { 474 | list = e; 475 | } 476 | tail = e; 477 | } 478 | 479 | /* now p has stepped `insize' places along, and q has too */ 480 | p = q; 481 | } 482 | 483 | tail->next = NULL; 484 | 485 | /* If we have done only one merge, we're finished. */ 486 | if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ 487 | return list; 488 | 489 | /* Otherwise repeat, merging lists twice the size */ 490 | insize *= 2; 491 | } 492 | #if COMPILER_REQUIRES_SORT_RETURN 493 | return list; 494 | #endif 495 | } 496 | -------------------------------------------------------------------------------- /coremark/core_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* File: core_main.c 20 | This file contains the framework to acquire a block of memory, seed initial parameters, tun t he benchmark and report the results. 21 | */ 22 | #include "coremark.h" 23 | #include 24 | /* Function: iterate 25 | Run the benchmark for a specified number of iterations. 26 | 27 | Operation: 28 | For each type of benchmarked algorithm: 29 | a - Initialize the data block for the algorithm. 30 | b - Execute the algorithm N times. 31 | 32 | Returns: 33 | NULL. 34 | */ 35 | static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0,(ee_u16)0x3340,(ee_u16)0x6a79,(ee_u16)0xe714,(ee_u16)0xe3c1}; 36 | static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52,(ee_u16)0x1199,(ee_u16)0x5608,(ee_u16)0x1fd7,(ee_u16)0x0747}; 37 | static ee_u16 state_known_crc[] = {(ee_u16)0x5e47,(ee_u16)0x39bf,(ee_u16)0xe5a4,(ee_u16)0x8e3a,(ee_u16)0x8d84}; 38 | void *iterate(void *pres) { 39 | ee_u32 i; 40 | ee_u16 crc; 41 | core_results *res=(core_results *)pres; 42 | ee_u32 iterations=res->iterations; 43 | res->crc=0; 44 | res->crclist=0; 45 | res->crcmatrix=0; 46 | res->crcstate=0; 47 | 48 | for (i=0; icrc=crcu16(crc,res->crc); 51 | crc=core_bench_list(res,-1); 52 | res->crc=crcu16(crc,res->crc); 53 | if (i==0) res->crclist=res->crc; 54 | } 55 | return NULL; 56 | } 57 | 58 | #if (SEED_METHOD==SEED_ARG) 59 | ee_s32 get_seed_args(int i, int argc, char *argv[]); 60 | #define get_seed(x) (ee_s16)get_seed_args(x,argc,argv) 61 | #define get_seed_32(x) get_seed_args(x,argc,argv) 62 | #else /* via function or volatile */ 63 | ee_s32 get_seed_32(int i); 64 | #define get_seed(x) (ee_s16)get_seed_32(x) 65 | #endif 66 | 67 | #if (MEM_METHOD==MEM_STATIC) 68 | ee_u8 static_memblk[TOTAL_DATA_SIZE]; 69 | #endif 70 | char *mem_name[3] = {"Static","Heap","Stack"}; 71 | /* Function: main 72 | Main entry routine for the benchmark. 73 | This function is responsible for the following steps: 74 | 75 | 1 - Initialize input seeds from a source that cannot be determined at compile time. 76 | 2 - Initialize memory block for use. 77 | 3 - Run and time the benchmark. 78 | 4 - Report results, testing the validity of the output if the seeds are known. 79 | 80 | Arguments: 81 | 1 - first seed : Any value 82 | 2 - second seed : Must be identical to first for iterations to be identical 83 | 3 - third seed : Any value, should be at least an order of magnitude less then the input size, but bigger then 32. 84 | 4 - Iterations : Special, if set to 0, iterations will be automatically determined such that the benchmark will run between 10 to 100 secs 85 | 86 | */ 87 | 88 | #if MAIN_HAS_NOARGC 89 | MAIN_RETURN_TYPE core_mark(void) { 90 | int argc=0; 91 | char *argv[1]; 92 | #else 93 | MAIN_RETURN_TYPE core_mark(int argc, char *argv[]) { 94 | #endif 95 | ee_u16 i,j=0,num_algorithms=0; 96 | ee_s16 known_id=-1,total_errors=0; 97 | ee_u16 seedcrc=0; 98 | CORE_TICKS total_time; 99 | core_results results[MULTITHREAD]; 100 | #if (MEM_METHOD==MEM_STACK) 101 | ee_u8 stack_memblock[TOTAL_DATA_SIZE*MULTITHREAD]; 102 | #endif 103 | /* first call any initializations needed */ 104 | portable_init(&(results[0].port), &argc, argv); 105 | /* First some checks to make sure benchmark will run ok */ 106 | if (sizeof(struct list_head_s)>128) { 107 | ee_printf("list_head structure too big for comparable data!\n"); 108 | return MAIN_RETURN_VAL; 109 | } 110 | results[0].seed1=get_seed(1); 111 | results[0].seed2=get_seed(2); 112 | results[0].seed3=get_seed(3); 113 | results[0].iterations=get_seed_32(4); 114 | #if CORE_DEBUG 115 | results[0].iterations=1; 116 | #endif 117 | results[0].execs=get_seed_32(5); 118 | if (results[0].execs==0) { /* if not supplied, execute all algorithms */ 119 | results[0].execs=ALL_ALGORITHMS_MASK; 120 | } 121 | /* put in some default values based on one seed only for easy testing */ 122 | if ((results[0].seed1==0) && (results[0].seed2==0) && (results[0].seed3==0)) { /* validation run */ 123 | results[0].seed1=0; 124 | results[0].seed2=0; 125 | results[0].seed3=0x66; 126 | } 127 | if ((results[0].seed1==1) && (results[0].seed2==0) && (results[0].seed3==0)) { /* perfromance run */ 128 | results[0].seed1=0x3415; 129 | results[0].seed2=0x3415; 130 | results[0].seed3=0x66; 131 | } 132 | #if (MEM_METHOD==MEM_STATIC) 133 | results[0].memblock[0]=(void *)static_memblk; 134 | results[0].size=TOTAL_DATA_SIZE; 135 | results[0].err=0; 136 | #if (MULTITHREAD>1) 137 | #error "Cannot use a static data area with multiple contexts!" 138 | #endif 139 | #elif (MEM_METHOD==MEM_MALLOC) 140 | for (i=0 ; i1) 217 | if (default_num_contexts>MULTITHREAD) { 218 | default_num_contexts=MULTITHREAD; 219 | } 220 | for (i=0 ; i=0) { 265 | for (i=0 ; i 0) 292 | ee_printf("Iterations/Sec : %f\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); 293 | #else 294 | ee_printf("Total time (secs): %d\n",time_in_secs(total_time)); 295 | if (time_in_secs(total_time) > 0) 296 | ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); 297 | #endif 298 | if (time_in_secs(total_time) < 10) { 299 | ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); 300 | total_errors++; 301 | } 302 | 303 | ee_printf("Iterations : %lu\n", (long unsigned) default_num_contexts*results[0].iterations); 304 | ee_printf("Compiler version : %s\n",COMPILER_VERSION); 305 | ee_printf("Compiler flags : %s\n",COMPILER_FLAGS); 306 | #if (MULTITHREAD>1) 307 | ee_printf("Parallel %s : %d\n",PARALLEL_METHOD,default_num_contexts); 308 | #endif 309 | ee_printf("Memory location : %s\n",MEM_LOCATION); 310 | /* output for verification */ 311 | ee_printf("seedcrc : 0x%04x\n",seedcrc); 312 | if (results[0].execs & ID_LIST) 313 | for (i=0 ; i1) 335 | ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); 336 | #endif 337 | ee_printf("\n"); 338 | } 339 | #else 340 | if (known_id==3) { 341 | ee_printf("CoreMark 1.0 : %d / %s %s",default_num_contexts*results[0].iterations/time_in_secs(total_time),COMPILER_VERSION,COMPILER_FLAGS); 342 | #if defined(MEM_LOCATION) && !defined(MEM_LOCATION_UNSPEC) 343 | ee_printf(" / %s",MEM_LOCATION); 344 | #else 345 | ee_printf(" / %s",mem_name[MEM_METHOD]); 346 | #endif 347 | 348 | #if (MULTITHREAD>1) 349 | ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); 350 | #endif 351 | ee_printf("\n"); 352 | } 353 | #endif 354 | } 355 | if (total_errors>0) 356 | ee_printf("Errors detected\n"); 357 | if (total_errors<0) 358 | ee_printf("Cannot validate operation for these seed values, please compare with results on a known platform.\n"); 359 | 360 | #if (MEM_METHOD==MEM_MALLOC) 361 | for (i=0 ; i>(from)) & (~(0xffffffff << (to)))) 48 | 49 | #if CORE_DEBUG 50 | void printmat(MATDAT *A, ee_u32 N, char *name) { 51 | ee_u32 i,j; 52 | ee_printf("Matrix %s [%dx%d]:\n",name,N,N); 53 | for (i=0; i N times, 79 | changing the matrix values slightly by a constant amount each time. 80 | */ 81 | ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) { 82 | ee_u32 N=p->N; 83 | MATRES *C=p->C; 84 | MATDAT *A=p->A; 85 | MATDAT *B=p->B; 86 | MATDAT val=(MATDAT)seed; 87 | 88 | crc=crc16(matrix_test(N,C,A,B,val),crc); 89 | 90 | return crc; 91 | } 92 | 93 | /* Function: matrix_test 94 | Perform matrix manipulation. 95 | 96 | Parameters: 97 | N - Dimensions of the matrix. 98 | C - memory for result matrix. 99 | A - input matrix 100 | B - operator matrix (not changed during operations) 101 | 102 | Returns: 103 | A CRC value that captures all results calculated in the function. 104 | In particular, crc of the value calculated on the result matrix 105 | after each step by . 106 | 107 | Operation: 108 | 109 | 1 - Add a constant value to all elements of a matrix. 110 | 2 - Multiply a matrix by a constant. 111 | 3 - Multiply a matrix by a vector. 112 | 4 - Multiply a matrix by a matrix. 113 | 5 - Add a constant value to all elements of a matrix. 114 | 115 | After the last step, matrix A is back to original contents. 116 | */ 117 | ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) { 118 | ee_u16 crc=0; 119 | MATDAT clipval=matrix_big(val); 120 | 121 | matrix_add_const(N,A,val); /* make sure data changes */ 122 | #if CORE_DEBUG 123 | printmat(A,N,"matrix_add_const"); 124 | #endif 125 | matrix_mul_const(N,C,A,val); 126 | crc=crc16(matrix_sum(N,C,clipval),crc); 127 | #if CORE_DEBUG 128 | printmatC(C,N,"matrix_mul_const"); 129 | #endif 130 | matrix_mul_vect(N,C,A,B); 131 | crc=crc16(matrix_sum(N,C,clipval),crc); 132 | #if CORE_DEBUG 133 | printmatC(C,N,"matrix_mul_vect"); 134 | #endif 135 | matrix_mul_matrix(N,C,A,B); 136 | crc=crc16(matrix_sum(N,C,clipval),crc); 137 | #if CORE_DEBUG 138 | printmatC(C,N,"matrix_mul_matrix"); 139 | #endif 140 | matrix_mul_matrix_bitextract(N,C,A,B); 141 | crc=crc16(matrix_sum(N,C,clipval),crc); 142 | #if CORE_DEBUG 143 | printmatC(C,N,"matrix_mul_matrix_bitextract"); 144 | #endif 145 | 146 | matrix_add_const(N,A,-val); /* return matrix to initial value */ 147 | return crc; 148 | } 149 | 150 | /* Function : matrix_init 151 | Initialize the memory block for matrix benchmarking. 152 | 153 | Parameters: 154 | blksize - Size of memory to be initialized. 155 | memblk - Pointer to memory block. 156 | seed - Actual values chosen depend on the seed parameter. 157 | p - pointers to containing initialized matrixes. 158 | 159 | Returns: 160 | Matrix dimensions. 161 | 162 | Note: 163 | The seed parameter MUST be supplied from a source that cannot be determined at compile time 164 | */ 165 | ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) { 166 | ee_u32 N=0; 167 | MATDAT *A; 168 | MATDAT *B; 169 | ee_s32 order=1; 170 | MATDAT val; 171 | ee_u32 i=0,j=0; 172 | if (seed==0) 173 | seed=1; 174 | while (jA=A; 196 | p->B=B; 197 | p->C=(MATRES *)align_mem(B+N*N); 198 | p->N=N; 199 | #if CORE_DEBUG 200 | printmat(A,N,"A"); 201 | printmat(B,N,"B"); 202 | #endif 203 | return N; 204 | } 205 | 206 | /* Function: matrix_sum 207 | Calculate a function that depends on the values of elements in the matrix. 208 | 209 | For each element, accumulate into a temporary variable. 210 | 211 | As long as this value is under the parameter clipval, 212 | add 1 to the result if the element is bigger then the previous. 213 | 214 | Otherwise, reset the accumulator and add 10 to the result. 215 | */ 216 | ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) { 217 | MATRES tmp=0,prev=0,cur=0; 218 | ee_s16 ret=0; 219 | ee_u32 i,j; 220 | for (i=0; iclipval) { 225 | ret+=10; 226 | tmp=0; 227 | } else { 228 | ret += (cur>prev) ? 1 : 0; 229 | } 230 | prev=cur; 231 | } 232 | } 233 | return ret; 234 | } 235 | 236 | /* Function: matrix_mul_const 237 | Multiply a matrix by a constant. 238 | This could be used as a scaler for instance. 239 | */ 240 | void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) { 241 | ee_u32 i,j; 242 | for (i=0; i 20 | #include 21 | #include 22 | #include "coremark.h" 23 | 24 | #if VALIDATION_RUN 25 | volatile ee_s32 seed1_volatile=0x3415; 26 | volatile ee_s32 seed2_volatile=0x3415; 27 | volatile ee_s32 seed3_volatile=0x66; 28 | #endif 29 | #if PERFORMANCE_RUN 30 | volatile ee_s32 seed1_volatile=0x0; 31 | volatile ee_s32 seed2_volatile=0x0; 32 | volatile ee_s32 seed3_volatile=0x66; 33 | #endif 34 | #if PROFILE_RUN 35 | volatile ee_s32 seed1_volatile=0x8; 36 | volatile ee_s32 seed2_volatile=0x8; 37 | volatile ee_s32 seed3_volatile=0x8; 38 | #endif 39 | volatile ee_s32 seed4_volatile=ITERATIONS; 40 | volatile ee_s32 seed5_volatile=0; 41 | /* Porting : Timing functions 42 | How to capture time and convert to seconds must be ported to whatever is supported by the platform. 43 | e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. 44 | Sample implementation for standard time.h and windows.h definitions included. 45 | */ 46 | /* Define : TIMER_RES_DIVIDER 47 | Divider to trade off timer resolution and total time that can be measured. 48 | 49 | Use lower values to increase resolution, but make sure that overflow does not occur. 50 | If there are issues with the return value overflowing, increase this value. 51 | */ 52 | #define NSECS_PER_SEC RT_TICK_PER_SECOND 53 | #define CORETIMETYPE rt_tick_t 54 | #define GETMYTIME(_t) (*_t=rt_tick_get()) 55 | #define MYTIMEDIFF(fin,ini) ((fin)-(ini)) 56 | #define TIMER_RES_DIVIDER 1 57 | #define SAMPLE_TIME_IMPLEMENTATION 1 58 | #define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER) 59 | 60 | /** Define Host specific (POSIX), or target specific global time variables. */ 61 | static CORETIMETYPE start_time_val, stop_time_val; 62 | 63 | /* Function : start_time 64 | This function will be called right before starting the timed portion of the benchmark. 65 | 66 | Implementation may be capturing a system timer (as implemented in the example code) 67 | or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. 68 | */ 69 | void start_time(void) { 70 | GETMYTIME(&start_time_val ); 71 | } 72 | /* Function : stop_time 73 | This function will be called right after ending the timed portion of the benchmark. 74 | 75 | Implementation may be capturing a system timer (as implemented in the example code) 76 | or other system parameters - e.g. reading the current value of cpu cycles counter. 77 | */ 78 | void stop_time(void) { 79 | GETMYTIME(&stop_time_val ); 80 | } 81 | /* Function : get_time 82 | Return an abstract "ticks" number that signifies time on the system. 83 | 84 | Actual value returned may be cpu cycles, milliseconds or any other value, 85 | as long as it can be converted to seconds by . 86 | This methodology is taken to accomodate any hardware or simulated platform. 87 | The sample implementation returns millisecs by default, 88 | and the resolution is controlled by 89 | */ 90 | CORE_TICKS get_time(void) { 91 | CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); 92 | return elapsed; 93 | } 94 | /* Function : time_in_secs 95 | Convert the value returned by get_time to seconds. 96 | 97 | The type is used to accomodate systems with no support for floating point. 98 | Default implementation implemented by the EE_TICKS_PER_SEC macro above. 99 | */ 100 | secs_ret time_in_secs(CORE_TICKS ticks) { 101 | secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; 102 | return retval; 103 | } 104 | 105 | ee_u32 default_num_contexts=MULTITHREAD; 106 | 107 | /* Function : portable_init 108 | Target specific initialization code 109 | Test for some common mistakes. 110 | */ 111 | void portable_init(core_portable *p, int *argc, char *argv[]) 112 | { 113 | ee_printf("Benchmark started, please make sure it runs for at least 10s.\n\n"); 114 | if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { 115 | ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); 116 | } 117 | if (sizeof(ee_u32) != 4) { 118 | ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); 119 | } 120 | p->portable_id=1; 121 | } 122 | /* Function : portable_fini 123 | Target specific final code 124 | */ 125 | void portable_fini(core_portable *p) 126 | { 127 | p->portable_id=0; 128 | } 129 | 130 | #if USE_PTHREAD 131 | ee_u8 132 | core_start_parallel(core_results *res) 133 | { 134 | return (ee_u8)pthread_create( 135 | &(res->port.thread), NULL, iterate, (void *)res); 136 | } 137 | ee_u8 138 | core_stop_parallel(core_results *res) 139 | { 140 | void *retval; 141 | return (ee_u8)pthread_join(res->port.thread, &retval); 142 | } 143 | #endif 144 | -------------------------------------------------------------------------------- /coremark/core_portme.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* Topic : Description 20 | This file contains configuration constants required to execute on different platforms 21 | */ 22 | #ifndef CORE_PORTME_H 23 | #define CORE_PORTME_H 24 | 25 | #include 26 | 27 | #define COREMARK_ITERATIONS 36000 28 | #define ITERATIONS COREMARK_ITERATIONS 29 | 30 | /************************/ 31 | /* Data types and settings */ 32 | /************************/ 33 | /* Configuration : HAS_FLOAT 34 | Define to 1 if the platform supports floating point. 35 | */ 36 | #ifndef HAS_FLOAT 37 | #define HAS_FLOAT CORE_MARK_HAS_FLOAT 38 | #endif 39 | /* Configuration : HAS_TIME_H 40 | Define to 1 if platform has the time.h header file, 41 | and implementation of functions thereof. 42 | */ 43 | #ifndef HAS_TIME_H 44 | #define HAS_TIME_H 1 45 | #endif 46 | /* Configuration : USE_CLOCK 47 | Define to 1 if platform has the time.h header file, 48 | and implementation of functions thereof. 49 | */ 50 | #ifndef USE_CLOCK 51 | #define USE_CLOCK 1 52 | #endif 53 | /* Configuration : HAS_STDIO 54 | Define to 1 if the platform has stdio.h. 55 | */ 56 | #ifndef HAS_STDIO 57 | #define HAS_STDIO 1 58 | #endif 59 | /* Configuration : HAS_PRINTF 60 | Define to 1 if the platform has stdio.h and implements the printf function. 61 | */ 62 | #ifndef HAS_PRINTF 63 | #define HAS_PRINTF 1 64 | #endif 65 | 66 | /* Configuration : CORE_TICKS 67 | Define type of return from the timing functions. 68 | */ 69 | #include 70 | typedef clock_t CORE_TICKS; 71 | 72 | /* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION 73 | Initialize these strings per platform 74 | */ 75 | #ifndef COMPILER_VERSION 76 | #ifdef __GNUC__ 77 | #define COMPILER_VERSION "GCC"__VERSION__ 78 | #else 79 | #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" 80 | #endif 81 | #endif 82 | #ifndef COMPILER_FLAGS 83 | #define COMPILER_FLAGS "" /* "Please put compiler flags here (e.g. -o3)" */ 84 | #endif 85 | #ifndef MEM_LOCATION 86 | #define MEM_LOCATION "STACK" 87 | #endif 88 | 89 | /* Data Types : 90 | To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . 91 | 92 | *Imprtant* : 93 | ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! 94 | */ 95 | typedef signed short ee_s16; 96 | typedef unsigned short ee_u16; 97 | typedef signed int ee_s32; 98 | typedef double ee_f32; 99 | typedef unsigned char ee_u8; 100 | typedef unsigned int ee_u32; 101 | typedef ee_u32 ee_ptr_int; 102 | typedef size_t ee_size_t; 103 | /* align_mem : 104 | This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. 105 | */ 106 | #define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) 107 | 108 | /* Configuration : SEED_METHOD 109 | Defines method to get seed values that cannot be computed at compile time. 110 | 111 | Valid values : 112 | SEED_ARG - from command line. 113 | SEED_FUNC - from a system function. 114 | SEED_VOLATILE - from volatile variables. 115 | */ 116 | #ifndef SEED_METHOD 117 | #define SEED_METHOD SEED_VOLATILE 118 | #endif 119 | 120 | /* Configuration : MEM_METHOD 121 | Defines method to get a block of memry. 122 | 123 | Valid values : 124 | MEM_MALLOC - for platforms that implement malloc and have malloc.h. 125 | MEM_STATIC - to use a static memory array. 126 | MEM_STACK - to allocate the data block on the stack (NYI). 127 | */ 128 | #ifndef MEM_METHOD 129 | #define MEM_METHOD MEM_STACK 130 | #endif 131 | 132 | /* Configuration : MULTITHREAD 133 | Define for parallel execution 134 | 135 | Valid values : 136 | 1 - only one context (default). 137 | N>1 - will execute N copies in parallel. 138 | 139 | Note : 140 | If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. 141 | 142 | Two sample implementations are provided. Use or to enable them. 143 | 144 | It is valid to have a different implementation of and in , 145 | to fit a particular architecture. 146 | */ 147 | #ifndef MULTITHREAD 148 | #define MULTITHREAD 1 149 | #define USE_PTHREAD 0 150 | #define USE_FORK 0 151 | #define USE_SOCKET 0 152 | #endif 153 | 154 | /* Configuration : MAIN_HAS_NOARGC 155 | Needed if platform does not support getting arguments to main. 156 | 157 | Valid values : 158 | 0 - argc/argv to main is supported 159 | 1 - argc/argv to main is not supported 160 | 161 | Note : 162 | This flag only matters if MULTITHREAD has been defined to a value greater then 1. 163 | */ 164 | #ifndef MAIN_HAS_NOARGC 165 | #define MAIN_HAS_NOARGC 1 166 | #endif 167 | 168 | /* Configuration : MAIN_HAS_NORETURN 169 | Needed if platform does not support returning a value from main. 170 | 171 | Valid values : 172 | 0 - main returns an int, and return value will be 0. 173 | 1 - platform does not support returning a value from main 174 | */ 175 | #ifndef MAIN_HAS_NORETURN 176 | #define MAIN_HAS_NORETURN 0 177 | #endif 178 | 179 | /* Variable : default_num_contexts 180 | Not used for this simple port, must cintain the value 1. 181 | */ 182 | extern ee_u32 default_num_contexts; 183 | 184 | #if (MULTITHREAD > 1) 185 | #if USE_PTHREAD 186 | #include 187 | #define PARALLEL_METHOD "PThreads" 188 | #endif /* USE_PTHREAD */ 189 | #endif /* MULTITHREAD > 1 */ 190 | 191 | typedef struct CORE_PORTABLE_S { 192 | #if (MULTITHREAD > 1) 193 | #if USE_PTHREAD 194 | pthread_t thread; 195 | #endif /* Method for multithreading */ 196 | #endif /* MULTITHREAD>1 */ 197 | ee_u8 portable_id; 198 | } core_portable; 199 | 200 | /* target specific init/fini */ 201 | void portable_init(core_portable *p, int *argc, char *argv[]); 202 | void portable_fini(core_portable *p); 203 | 204 | #if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) 205 | #if (TOTAL_DATA_SIZE==1200) 206 | #define PROFILE_RUN 1 207 | #elif (TOTAL_DATA_SIZE==2000) 208 | #define PERFORMANCE_RUN 1 209 | #else 210 | #define VALIDATION_RUN 1 211 | #endif 212 | #endif 213 | 214 | #if (MULTITHREAD > 1) 215 | #if USE_PTHREAD 216 | #include 217 | #define PARALLEL_METHOD "PThreads" 218 | #endif /* Method for multithreading */ 219 | #endif /* MULTITHREAD > 1 */ 220 | 221 | #endif /* CORE_PORTME_H */ 222 | -------------------------------------------------------------------------------- /coremark/core_state.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* local functions */ 21 | enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count); 22 | 23 | /* 24 | Topic: Description 25 | Simple state machines like this one are used in many embedded products. 26 | 27 | For more complex state machines, sometimes a state transition table implementation is used instead, 28 | trading speed of direct coding for ease of maintenance. 29 | 30 | Since the main goal of using a state machine in CoreMark is to excercise the switch/if behaviour, 31 | we are using a small moore machine. 32 | 33 | In particular, this machine tests type of string input, 34 | trying to determine whether the input is a number or something else. 35 | (see core_state.png). 36 | */ 37 | 38 | /* Function: core_bench_state 39 | Benchmark function 40 | 41 | Go over the input twice, once direct, and once after introducing some corruption. 42 | */ 43 | ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, 44 | ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc) 45 | { 46 | ee_u32 final_counts[NUM_CORE_STATES]; 47 | ee_u32 track_counts[NUM_CORE_STATES]; 48 | ee_u8 *p=memblock; 49 | ee_u32 i; 50 | 51 | 52 | #if CORE_DEBUG 53 | ee_printf("State Bench: %d,%d,%d,%04x\n",seed1,seed2,step,crc); 54 | #endif 55 | for (i=0; i0) { 127 | for(i=0;i>3) & 0x3]; 138 | next=4; 139 | break; 140 | case 3: /* float */ 141 | case 4: /* float */ 142 | buf=floatpat[(seed>>3) & 0x3]; 143 | next=8; 144 | break; 145 | case 5: /* scientific */ 146 | case 6: /* scientific */ 147 | buf=scipat[(seed>>3) & 0x3]; 148 | next=8; 149 | break; 150 | case 7: /* invalid */ 151 | buf=errpat[(seed>>3) & 0x3]; 152 | next=8; 153 | break; 154 | default: /* Never happen, just to make some compilers happy */ 155 | break; 156 | } 157 | } 158 | size++; 159 | while (total='0') & (c<='9')) ? 1 : 0; 171 | return retval; 172 | } 173 | 174 | /* Function: core_state_transition 175 | Actual state machine. 176 | 177 | The state machine will continue scanning until either: 178 | 1 - an invalid input is detcted. 179 | 2 - a valid number has been detected. 180 | 181 | The input pointer is updated to point to the end of the token, and the end state is returned (either specific format determined or invalid). 182 | */ 183 | 184 | enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count) { 185 | ee_u8 *str=*instr; 186 | ee_u8 NEXT_SYMBOL; 187 | enum CORE_STATE state=CORE_START; 188 | for( ; *str && state != CORE_INVALID; str++ ) { 189 | NEXT_SYMBOL = *str; 190 | if (NEXT_SYMBOL==',') /* end of this input */ { 191 | str++; 192 | break; 193 | } 194 | switch(state) { 195 | case CORE_START: 196 | if(ee_isdigit(NEXT_SYMBOL)) { 197 | state = CORE_INT; 198 | } 199 | else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { 200 | state = CORE_S1; 201 | } 202 | else if( NEXT_SYMBOL == '.' ) { 203 | state = CORE_FLOAT; 204 | } 205 | else { 206 | state = CORE_INVALID; 207 | transition_count[CORE_INVALID]++; 208 | } 209 | transition_count[CORE_START]++; 210 | break; 211 | case CORE_S1: 212 | if(ee_isdigit(NEXT_SYMBOL)) { 213 | state = CORE_INT; 214 | transition_count[CORE_S1]++; 215 | } 216 | else if( NEXT_SYMBOL == '.' ) { 217 | state = CORE_FLOAT; 218 | transition_count[CORE_S1]++; 219 | } 220 | else { 221 | state = CORE_INVALID; 222 | transition_count[CORE_S1]++; 223 | } 224 | break; 225 | case CORE_INT: 226 | if( NEXT_SYMBOL == '.' ) { 227 | state = CORE_FLOAT; 228 | transition_count[CORE_INT]++; 229 | } 230 | else if(!ee_isdigit(NEXT_SYMBOL)) { 231 | state = CORE_INVALID; 232 | transition_count[CORE_INT]++; 233 | } 234 | break; 235 | case CORE_FLOAT: 236 | if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) { 237 | state = CORE_S2; 238 | transition_count[CORE_FLOAT]++; 239 | } 240 | else if(!ee_isdigit(NEXT_SYMBOL)) { 241 | state = CORE_INVALID; 242 | transition_count[CORE_FLOAT]++; 243 | } 244 | break; 245 | case CORE_S2: 246 | if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { 247 | state = CORE_EXPONENT; 248 | transition_count[CORE_S2]++; 249 | } 250 | else { 251 | state = CORE_INVALID; 252 | transition_count[CORE_S2]++; 253 | } 254 | break; 255 | case CORE_EXPONENT: 256 | if(ee_isdigit(NEXT_SYMBOL)) { 257 | state = CORE_SCIENTIFIC; 258 | transition_count[CORE_EXPONENT]++; 259 | } 260 | else { 261 | state = CORE_INVALID; 262 | transition_count[CORE_EXPONENT]++; 263 | } 264 | break; 265 | case CORE_SCIENTIFIC: 266 | if(!ee_isdigit(NEXT_SYMBOL)) { 267 | state = CORE_INVALID; 268 | transition_count[CORE_INVALID]++; 269 | } 270 | break; 271 | default: 272 | break; 273 | } 274 | } 275 | *instr=str; 276 | return state; 277 | } 278 | -------------------------------------------------------------------------------- /coremark/core_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | #include "coremark.h" 20 | /* Function: get_seed 21 | Get a values that cannot be determined at compile time. 22 | 23 | Since different embedded systems and compilers are used, 3 different methods are provided: 24 | 1 - Using a volatile variable. This method is only valid if the compiler is forced to generate code that 25 | reads the value of a volatile variable from memory at run time. 26 | Please note, if using this method, you would need to modify core_portme.c to generate training profile. 27 | 2 - Command line arguments. This is the preferred method if command line arguments are supported. 28 | 3 - System function. If none of the first 2 methods is available on the platform, 29 | a system function which is not a stub can be used. 30 | 31 | e.g. read the value on GPIO pins connected to switches, or invoke special simulator functions. 32 | */ 33 | #if (SEED_METHOD==SEED_VOLATILE) 34 | extern volatile ee_s32 seed1_volatile; 35 | extern volatile ee_s32 seed2_volatile; 36 | extern volatile ee_s32 seed3_volatile; 37 | extern volatile ee_s32 seed4_volatile; 38 | extern volatile ee_s32 seed5_volatile; 39 | ee_s32 get_seed_32(int i) { 40 | ee_s32 retval; 41 | switch (i) { 42 | case 1: 43 | retval=seed1_volatile; 44 | break; 45 | case 2: 46 | retval=seed2_volatile; 47 | break; 48 | case 3: 49 | retval=seed3_volatile; 50 | break; 51 | case 4: 52 | retval=seed4_volatile; 53 | break; 54 | case 5: 55 | retval=seed5_volatile; 56 | break; 57 | default: 58 | retval=0; 59 | break; 60 | } 61 | return retval; 62 | } 63 | #elif (SEED_METHOD==SEED_ARG) 64 | ee_s32 parseval(char *valstring) { 65 | ee_s32 retval=0; 66 | ee_s32 neg=1; 67 | int hexmode=0; 68 | if (*valstring == '-') { 69 | neg=-1; 70 | valstring++; 71 | } 72 | if ((valstring[0] == '0') && (valstring[1] == 'x')) { 73 | hexmode=1; 74 | valstring+=2; 75 | } 76 | /* first look for digits */ 77 | if (hexmode) { 78 | while (((*valstring >= '0') && (*valstring <= '9')) || ((*valstring >= 'a') && (*valstring <= 'f'))) { 79 | ee_s32 digit=*valstring-'0'; 80 | if (digit>9) 81 | digit=10+*valstring-'a'; 82 | retval*=16; 83 | retval+=digit; 84 | valstring++; 85 | } 86 | } else { 87 | while ((*valstring >= '0') && (*valstring <= '9')) { 88 | ee_s32 digit=*valstring-'0'; 89 | retval*=10; 90 | retval+=digit; 91 | valstring++; 92 | } 93 | } 94 | /* now add qualifiers */ 95 | if (*valstring=='K') 96 | retval*=1024; 97 | if (*valstring=='M') 98 | retval*=1024*1024; 99 | 100 | retval*=neg; 101 | return retval; 102 | } 103 | 104 | ee_s32 get_seed_args(int i, int argc, char *argv[]) { 105 | if (argc>i) 106 | return parseval(argv[i]); 107 | return 0; 108 | } 109 | 110 | #elif (SEED_METHOD==SEED_FUNC) 111 | /* If using OS based function, you must define and implement the functions below in core_portme.h and core_portme.c ! */ 112 | ee_s32 get_seed_32(int i) { 113 | ee_s32 retval; 114 | switch (i) { 115 | case 1: 116 | retval=portme_sys1(); 117 | break; 118 | case 2: 119 | retval=portme_sys2(); 120 | break; 121 | case 3: 122 | retval=portme_sys3(); 123 | break; 124 | case 4: 125 | retval=portme_sys4(); 126 | break; 127 | case 5: 128 | retval=portme_sys5(); 129 | break; 130 | default: 131 | retval=0; 132 | break; 133 | } 134 | return retval; 135 | } 136 | #endif 137 | 138 | /* Function: crc* 139 | Service functions to calculate 16b CRC code. 140 | 141 | */ 142 | ee_u16 crcu8(ee_u8 data, ee_u16 crc ) 143 | { 144 | ee_u8 i=0,x16=0,carry=0; 145 | 146 | for (i = 0; i < 8; i++) 147 | { 148 | x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); 149 | data >>= 1; 150 | 151 | if (x16 == 1) 152 | { 153 | crc ^= 0x4002; 154 | carry = 1; 155 | } 156 | else 157 | carry = 0; 158 | crc >>= 1; 159 | if (carry) 160 | crc |= 0x8000; 161 | else 162 | crc &= 0x7fff; 163 | } 164 | return crc; 165 | } 166 | ee_u16 crcu16(ee_u16 newval, ee_u16 crc) { 167 | crc=crcu8( (ee_u8) (newval) ,crc); 168 | crc=crcu8( (ee_u8) ((newval)>>8) ,crc); 169 | return crc; 170 | } 171 | ee_u16 crcu32(ee_u32 newval, ee_u16 crc) { 172 | crc=crc16((ee_s16) newval ,crc); 173 | crc=crc16((ee_s16) (newval>>16) ,crc); 174 | return crc; 175 | } 176 | ee_u16 crc16(ee_s16 newval, ee_u16 crc) { 177 | return crcu16((ee_u16)newval, crc); 178 | } 179 | 180 | ee_u8 check_data_types() { 181 | ee_u8 retval=0; 182 | if (sizeof(ee_u8) != 1) { 183 | ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); 184 | retval++; 185 | } 186 | if (sizeof(ee_u16) != 2) { 187 | ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); 188 | retval++; 189 | } 190 | if (sizeof(ee_s16) != 2) { 191 | ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); 192 | retval++; 193 | } 194 | if (sizeof(ee_s32) != 4) { 195 | ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); 196 | retval++; 197 | } 198 | if (sizeof(ee_u32) != 4) { 199 | ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); 200 | retval++; 201 | } 202 | if (sizeof(ee_ptr_int) != sizeof(int *)) { 203 | ee_printf("ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); 204 | retval++; 205 | } 206 | if (retval>0) { 207 | ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); 208 | } 209 | return retval; 210 | } 211 | -------------------------------------------------------------------------------- /coremark/coremark.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Original Author: Shay Gal-on 17 | */ 18 | 19 | /* Topic: Description 20 | This file contains declarations of the various benchmark functions. 21 | */ 22 | 23 | /* Configuration: TOTAL_DATA_SIZE 24 | Define total size for data algorithms will operate on 25 | */ 26 | #ifndef TOTAL_DATA_SIZE 27 | #define TOTAL_DATA_SIZE 2*1000 28 | #endif 29 | 30 | #define SEED_ARG 0 31 | #define SEED_FUNC 1 32 | #define SEED_VOLATILE 2 33 | 34 | #define MEM_STATIC 0 35 | #define MEM_MALLOC 1 36 | #define MEM_STACK 2 37 | 38 | #include "core_portme.h" 39 | 40 | #if HAS_STDIO 41 | #include 42 | #endif 43 | #if HAS_PRINTF 44 | #if(HAS_FLOAT) 45 | #define ee_printf printf 46 | #else 47 | #define ee_printf rt_kprintf 48 | #endif 49 | #endif 50 | 51 | /* Actual benchmark execution in iterate */ 52 | void *iterate(void *pres); 53 | 54 | /* Typedef: secs_ret 55 | For machines that have floating point support, get number of seconds as a double. 56 | Otherwise an unsigned int. 57 | */ 58 | #if HAS_FLOAT 59 | typedef double secs_ret; 60 | #else 61 | typedef ee_u32 secs_ret; 62 | #endif 63 | 64 | #if MAIN_HAS_NORETURN 65 | #define MAIN_RETURN_VAL 66 | #define MAIN_RETURN_TYPE void 67 | #else 68 | #define MAIN_RETURN_VAL 0 69 | #define MAIN_RETURN_TYPE int 70 | #endif 71 | 72 | void start_time(void); 73 | void stop_time(void); 74 | CORE_TICKS get_time(void); 75 | secs_ret time_in_secs(CORE_TICKS ticks); 76 | 77 | /* Misc useful functions */ 78 | ee_u16 crcu8(ee_u8 data, ee_u16 crc); 79 | ee_u16 crc16(ee_s16 newval, ee_u16 crc); 80 | ee_u16 crcu16(ee_u16 newval, ee_u16 crc); 81 | ee_u16 crcu32(ee_u32 newval, ee_u16 crc); 82 | ee_u8 check_data_types(void); 83 | void *portable_malloc(ee_size_t size); 84 | void portable_free(void *p); 85 | ee_s32 parseval(char *valstring); 86 | 87 | /* Algorithm IDS */ 88 | #define ID_LIST (1<<0) 89 | #define ID_MATRIX (1<<1) 90 | #define ID_STATE (1<<2) 91 | #define ALL_ALGORITHMS_MASK (ID_LIST|ID_MATRIX|ID_STATE) 92 | #define NUM_ALGORITHMS 3 93 | 94 | /* list data structures */ 95 | typedef struct list_data_s { 96 | ee_s16 data16; 97 | ee_s16 idx; 98 | } list_data; 99 | 100 | typedef struct list_head_s { 101 | struct list_head_s *next; 102 | struct list_data_s *info; 103 | } list_head; 104 | 105 | 106 | /*matrix benchmark related stuff */ 107 | #define MATDAT_INT 1 108 | #if MATDAT_INT 109 | typedef ee_s16 MATDAT; 110 | typedef ee_s32 MATRES; 111 | #else 112 | typedef ee_f16 MATDAT; 113 | typedef ee_f32 MATRES; 114 | #endif 115 | 116 | typedef struct MAT_PARAMS_S { 117 | int N; 118 | MATDAT *A; 119 | MATDAT *B; 120 | MATRES *C; 121 | } mat_params; 122 | 123 | /* state machine related stuff */ 124 | /* List of all the possible states for the FSM */ 125 | typedef enum CORE_STATE { 126 | CORE_START=0, 127 | CORE_INVALID, 128 | CORE_S1, 129 | CORE_S2, 130 | CORE_INT, 131 | CORE_FLOAT, 132 | CORE_EXPONENT, 133 | CORE_SCIENTIFIC, 134 | NUM_CORE_STATES 135 | } core_state_e ; 136 | 137 | 138 | /* Helper structure to hold results */ 139 | typedef struct RESULTS_S { 140 | /* inputs */ 141 | ee_s16 seed1; /* Initializing seed */ 142 | ee_s16 seed2; /* Initializing seed */ 143 | ee_s16 seed3; /* Initializing seed */ 144 | void *memblock[4]; /* Pointer to safe memory location */ 145 | ee_u32 size; /* Size of the data */ 146 | ee_u32 iterations; /* Number of iterations to execute */ 147 | ee_u32 execs; /* Bitmask of operations to execute */ 148 | struct list_head_s *list; 149 | mat_params mat; 150 | /* outputs */ 151 | ee_u16 crc; 152 | ee_u16 crclist; 153 | ee_u16 crcmatrix; 154 | ee_u16 crcstate; 155 | ee_s16 err; 156 | /* ultithread specific */ 157 | core_portable port; 158 | } core_results; 159 | 160 | /* Multicore execution handling */ 161 | #if (MULTITHREAD>1) 162 | ee_u8 core_start_parallel(core_results *res); 163 | ee_u8 core_stop_parallel(core_results *res); 164 | #endif 165 | 166 | /* list benchmark functions */ 167 | list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); 168 | ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); 169 | 170 | /* state benchmark functions */ 171 | void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); 172 | ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, 173 | ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc); 174 | 175 | /* matrix benchmark functions */ 176 | ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p); 177 | ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); 178 | 179 | -------------------------------------------------------------------------------- /coremark/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | rt_kprintf("Hello, world\n"); 6 | 7 | extern int core_mark(void); 8 | core_mark(); 9 | 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /cxx/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | # add C++ runtime wrapper 10 | group = group + SConscript('runtime/SConscript') 11 | 12 | Return('group') 13 | -------------------------------------------------------------------------------- /cxx/crt/SConscript: -------------------------------------------------------------------------------- 1 | import rtconfig 2 | from building import * 3 | 4 | src = Glob('*.c') + Glob('*.cpp') 5 | cwd = GetCurrentDir() 6 | CPPPATH = [cwd] 7 | 8 | if rtconfig.CPU == 'win32': 9 | group = [] 10 | else: 11 | group = DefineGroup('C++ Run time', src, depend = [''], CPPPATH=CPPPATH) 12 | 13 | Return('group') 14 | -------------------------------------------------------------------------------- /cxx/crt/crt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "crt.h" 3 | 4 | void *operator new(size_t size) 5 | { 6 | return rt_malloc(size); 7 | } 8 | 9 | void *operator new[](size_t size) 10 | { 11 | return rt_malloc(size); 12 | } 13 | 14 | void operator delete(void *ptr) 15 | { 16 | rt_free(ptr); 17 | } 18 | 19 | void operator delete[] (void *ptr) 20 | { 21 | return rt_free(ptr); 22 | } 23 | 24 | void __cxa_pure_virtual(void) 25 | { 26 | RT_ASSERT(!"Illegal to call a pure virtual function."); 27 | } 28 | 29 | #ifdef __GNUC__ 30 | namespace std { 31 | 32 | void __throw_bad_cast() 33 | { 34 | RT_ASSERT(!"Bad cast."); 35 | } 36 | 37 | void __throw_bad_alloc() 38 | { 39 | RT_ASSERT(!"Bad alloc."); 40 | } 41 | 42 | void __throw_bad_typeid() 43 | { 44 | RT_ASSERT(!"Bad typeid."); 45 | } 46 | 47 | void __throw_ios_failure(char const* p) 48 | { 49 | RT_ASSERT(!"iOS failure."); 50 | } 51 | 52 | void __throw_logic_error(char const* p) 53 | { 54 | RT_ASSERT(!"Logic error."); 55 | } 56 | 57 | void __throw_range_error(char const* p) 58 | { 59 | RT_ASSERT(!"Range error."); 60 | } 61 | 62 | void __throw_domain_error(char const* p) 63 | { 64 | RT_ASSERT(!"Domain error."); 65 | } 66 | 67 | void __throw_future_error(int p) 68 | { 69 | RT_ASSERT(!"Future error."); 70 | } 71 | 72 | void __throw_length_error(char const* p) 73 | { 74 | RT_ASSERT(!"Length error."); 75 | } 76 | 77 | void __throw_out_of_range(char const* p) 78 | { 79 | RT_ASSERT(!"Out of range error."); 80 | } 81 | 82 | void __throw_system_error(int p) 83 | { 84 | RT_ASSERT(!"System error."); 85 | } 86 | 87 | void __throw_bad_exception() 88 | { 89 | RT_ASSERT(!"Bad exception."); 90 | } 91 | 92 | void __throw_runtime_error(char const* p) 93 | { 94 | RT_ASSERT(!"Runtime error."); 95 | } 96 | 97 | void __throw_overflow_error(char const* p) 98 | { 99 | RT_ASSERT(!"Overflow error."); 100 | } 101 | 102 | void __throw_underflow_error(char const* p) 103 | { 104 | RT_ASSERT(!"Underflow error."); 105 | } 106 | 107 | void __throw_invalid_argument(char const* p) 108 | { 109 | RT_ASSERT(!"Invalid argument."); 110 | } 111 | 112 | void __throw_out_of_range_fmt(char const* p, ...) 113 | { 114 | RT_ASSERT(!"Out of range fmt."); 115 | } 116 | 117 | } 118 | #endif 119 | -------------------------------------------------------------------------------- /cxx/crt/crt.h: -------------------------------------------------------------------------------- 1 | #ifndef CRT_H_ 2 | #define CRT_H_ 3 | 4 | #include 5 | #include 6 | 7 | void *operator new(size_t size); 8 | void *operator new[](size_t size); 9 | 10 | void operator delete(void * ptr); 11 | void operator delete[] (void *ptr); 12 | 13 | extern "C" void __cxa_pure_virtual(void); 14 | extern "C" int cplusplus_system_init(void); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /cxx/cxx.cpp: -------------------------------------------------------------------------------- 1 | #include "cxx.h" 2 | 3 | #include 4 | 5 | A::A() 6 | : a(0) 7 | { 8 | } 9 | 10 | void A::setA(int value) 11 | { 12 | a = value; 13 | } 14 | 15 | int A::getA(void) 16 | { 17 | return a; 18 | } 19 | 20 | void A::toString() 21 | { 22 | rt_kprintf("A::a = %d\n", a); 23 | } 24 | 25 | extern "C" { 26 | 27 | int Atest(void) 28 | { 29 | A a; 30 | 31 | a.setA(100); 32 | a.toString(); 33 | 34 | return 0; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /cxx/cxx.h: -------------------------------------------------------------------------------- 1 | #ifndef CXX_H__ 2 | #define CXX_H__ 3 | 4 | class A 5 | { 6 | public: 7 | A(); 8 | 9 | void setA(int value); 10 | int getA(void); 11 | 12 | void toString(); 13 | 14 | private: 15 | int a; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /cxx/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int Atest(void); 4 | 5 | int main(int argc, char** argv) 6 | { 7 | Atest(); 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /devicetest/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /devicetest/device_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File : device_test.c 3 | * This file is part of RT-Thread RTOS 4 | * COPYRIGHT (C) 2011, RT-Thread Development Team 5 | * 6 | * The license and distribution terms for this file may be 7 | * found in the file LICENSE in this distribution or at 8 | * http://openlab.rt-thread.com/license/LICENSE. 9 | * 10 | * Change Logs: 11 | * Date Author Notes 12 | * 2011-01-01 aozima the first version. 13 | * 2012-02-11 aozima add multiple sector speed test. 14 | * 2012-05-27 aozima use rt_deice API. 15 | */ 16 | 17 | #include 18 | 19 | /* calculate speed */ 20 | static void calculate_speed_print(rt_uint32_t speed) 21 | { 22 | rt_uint32_t k,m; 23 | 24 | k = speed/1024UL; 25 | if( k ) 26 | { 27 | m = k/1024UL; 28 | if( m ) 29 | { 30 | rt_kprintf("%d.%dMbyte/s",m,k%1024UL*100/1024UL); 31 | } 32 | else 33 | { 34 | rt_kprintf("%d.%dKbyte/s",k,speed%1024UL*100/1024UL); 35 | } 36 | } 37 | else 38 | { 39 | rt_kprintf("%dbyte/s",speed); 40 | } 41 | } 42 | 43 | static rt_err_t _block_device_test(rt_device_t device) 44 | { 45 | rt_err_t result; 46 | struct rt_device_blk_geometry geometry; 47 | rt_uint8_t * read_buffer = RT_NULL; 48 | rt_uint8_t * write_buffer = RT_NULL; 49 | 50 | rt_kprintf("\r\n"); 51 | 52 | while (1) 53 | { 54 | if(rt_device_find("sd0") != RT_NULL) 55 | { 56 | if (dfs_unmount("/") == RT_EOK) 57 | { 58 | rt_kprintf("emmc dfs_unmount to '/' successful."); 59 | break; 60 | } 61 | else 62 | { 63 | rt_kprintf("emmc dfs_unmount to '/' failed!"); 64 | } 65 | } 66 | rt_thread_mdelay(5000); 67 | } 68 | 69 | if( (device->flag & RT_DEVICE_FLAG_RDWR) == RT_DEVICE_FLAG_RDWR ) 70 | { 71 | // device can read and write. 72 | // step 1: open device 73 | result = rt_device_open(device,RT_DEVICE_FLAG_RDWR); 74 | if( result != RT_EOK ) 75 | { 76 | return result; 77 | } 78 | 79 | // step 2: get device info 80 | rt_memset(&geometry, 0, sizeof(geometry)); 81 | result = rt_device_control(device, 82 | RT_DEVICE_CTRL_BLK_GETGEOME, 83 | &geometry); 84 | if( result != RT_EOK ) 85 | { 86 | rt_kprintf("device : %s cmd RT_DEVICE_CTRL_BLK_GETGEOME failed.\r\n"); 87 | return result; 88 | } 89 | rt_kprintf("device info:\r\n"); 90 | rt_kprintf("sector size : %d byte\r\n", geometry.bytes_per_sector); 91 | rt_kprintf("sector count : %d \r\n", geometry.sector_count); 92 | rt_kprintf("block size : %d byte\r\n", geometry.block_size); 93 | 94 | rt_kprintf("\r\n"); 95 | read_buffer = rt_malloc(geometry.bytes_per_sector); 96 | if( read_buffer == RT_NULL ) 97 | { 98 | rt_kprintf("no memory for read_buffer!\r\n"); 99 | goto __return; 100 | } 101 | write_buffer = rt_malloc(geometry.bytes_per_sector); 102 | if( write_buffer == RT_NULL ) 103 | { 104 | rt_kprintf("no memory for write_buffer!\r\n"); 105 | goto __return; 106 | } 107 | 108 | /* step 3: R/W test */ 109 | { 110 | rt_uint32_t i, err_count, sector_no; 111 | rt_uint8_t * data_point; 112 | 113 | i = rt_device_read(device, 0, read_buffer, 1); 114 | if(i != 1) 115 | { 116 | rt_kprintf("read device :%s ", device->parent.name); 117 | rt_kprintf("the first sector failed.\r\n"); 118 | goto __return; 119 | } 120 | 121 | data_point = write_buffer; 122 | for(i=0; iparent.name); 136 | rt_kprintf("the first sector failed.\r\n"); 137 | rt_kprintf("maybe readonly!\r\n"); 138 | goto __return; 139 | } 140 | 141 | /* write the second sector */ 142 | sector_no = 1; 143 | data_point = write_buffer; 144 | *data_point++ = (rt_uint8_t)sector_no; 145 | i = rt_device_write(device,sector_no,write_buffer,1); 146 | if( i != 1 ) 147 | { 148 | rt_kprintf("write device :%s ",device->parent.name); 149 | rt_kprintf("the second sector failed.\r\n"); 150 | goto __return; 151 | } 152 | 153 | /* write the end sector */ 154 | sector_no = geometry.sector_count-1; 155 | data_point = write_buffer; 156 | *data_point++ = (rt_uint8_t)sector_no; 157 | i = rt_device_write(device,sector_no,write_buffer,1); 158 | if( i != 1 ) 159 | { 160 | rt_kprintf("write device :%s ",device->parent.name); 161 | rt_kprintf("the end sector failed.\r\n"); 162 | goto __return; 163 | } 164 | 165 | /* verify first sector */ 166 | sector_no = 0; 167 | i = rt_device_read(device,sector_no,read_buffer,1); 168 | if( i != 1 ) 169 | { 170 | rt_kprintf("read device :%s ",device->parent.name); 171 | rt_kprintf("the first sector failed.\r\n"); 172 | goto __return; 173 | } 174 | err_count = 0; 175 | data_point = read_buffer; 176 | if( (*data_point++) != (rt_uint8_t)sector_no) 177 | { 178 | err_count++; 179 | } 180 | for(i=1; i 0 ) 188 | { 189 | rt_kprintf("verify device :%s ",device->parent.name); 190 | rt_kprintf("the first sector failed.\r\n"); 191 | goto __return; 192 | } 193 | 194 | /* verify sector sector */ 195 | sector_no = 1; 196 | i = rt_device_read(device,sector_no,read_buffer,1); 197 | if( i != 1 ) 198 | { 199 | rt_kprintf("read device :%s ",device->parent.name); 200 | rt_kprintf("the second sector failed.\r\n"); 201 | goto __return; 202 | } 203 | err_count = 0; 204 | data_point = read_buffer; 205 | if( (*data_point++) != (rt_uint8_t)sector_no) 206 | { 207 | err_count++; 208 | } 209 | for(i=1; i 0 ) 217 | { 218 | rt_kprintf("verify device :%s ",device->parent.name); 219 | rt_kprintf("the second sector failed.\r\n"); 220 | goto __return; 221 | } 222 | 223 | /* verify the end sector */ 224 | sector_no = geometry.sector_count-1; 225 | i = rt_device_read(device,sector_no,read_buffer,1); 226 | if( i != 1 ) 227 | { 228 | rt_kprintf("read device :%s ",device->parent.name); 229 | rt_kprintf("the end sector failed.\r\n"); 230 | goto __return; 231 | } 232 | err_count = 0; 233 | data_point = read_buffer; 234 | if( (*data_point++) != (rt_uint8_t)sector_no) 235 | { 236 | err_count++; 237 | } 238 | for(i=1; i 0 ) 246 | { 247 | rt_kprintf("verify device :%s ",device->parent.name); 248 | rt_kprintf("the end sector failed.\r\n"); 249 | goto __return; 250 | } 251 | rt_kprintf("device R/W test pass!\r\n"); 252 | 253 | } /* step 3: I/O R/W test */ 254 | 255 | rt_kprintf("\r\nRT_TICK_PER_SECOND:%d\r\n", RT_TICK_PER_SECOND); 256 | 257 | // step 4: continuous single sector speed test 258 | { 259 | rt_uint32_t tick_start,tick_end; 260 | rt_uint32_t i; 261 | 262 | rt_kprintf("\r\ncontinuous single sector speed test:\r\n"); 263 | 264 | if( geometry.sector_count < 10 ) 265 | { 266 | rt_kprintf("device sector_count < 10, speed test abort!\r\n"); 267 | } 268 | else 269 | { 270 | unsigned int sector; 271 | 272 | // sign sector write 273 | rt_kprintf("write: "); 274 | sector = 0; 275 | tick_start = rt_tick_get(); 276 | for(i=0; i<200; i++) 277 | { 278 | sector += rt_device_write(device, i, read_buffer, 1); 279 | if((i != 0) && ((i%4) == 0) ) 280 | { 281 | if(sector < 4) 282 | { 283 | rt_kprintf("#"); 284 | } 285 | else 286 | { 287 | rt_kprintf("<"); 288 | } 289 | sector = 0; 290 | } 291 | } 292 | tick_end = rt_tick_get(); 293 | rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end); 294 | calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) ); 295 | rt_kprintf("\r\n"); 296 | 297 | // sign sector read 298 | rt_kprintf("read : "); 299 | sector = 0; 300 | tick_start = rt_tick_get(); 301 | for(i=0; i<200; i++) 302 | { 303 | sector += rt_device_read(device, i, read_buffer, 1); 304 | if((i != 0) && ((i%4) == 0) ) 305 | { 306 | if(sector < 4) 307 | { 308 | rt_kprintf("#"); 309 | } 310 | else 311 | { 312 | rt_kprintf(">"); 313 | } 314 | sector = 0; 315 | } 316 | } 317 | tick_end = rt_tick_get(); 318 | rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end); 319 | calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) ); 320 | rt_kprintf("\r\n"); 321 | } 322 | }// step 4: speed test 323 | 324 | // step 5: random single sector speed test 325 | { 326 | rt_uint32_t tick_start,tick_end; 327 | rt_uint32_t i; 328 | 329 | rt_kprintf("\r\nrandom single sector speed test:\r\n"); 330 | 331 | if( geometry.sector_count < 10 ) 332 | { 333 | rt_kprintf("device sector_count < 10, speed test abort!\r\n"); 334 | } 335 | else 336 | { 337 | unsigned int sector; 338 | 339 | // sign sector write 340 | rt_kprintf("write: "); 341 | sector = 0; 342 | tick_start = rt_tick_get(); 343 | for(i=0; i<200; i++) 344 | { 345 | sector += rt_device_write(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1); 346 | if((i != 0) && ((i%4) == 0) ) 347 | { 348 | if(sector < 4) 349 | { 350 | rt_kprintf("#"); 351 | } 352 | else 353 | { 354 | rt_kprintf("<"); 355 | } 356 | sector = 0; 357 | } 358 | } 359 | tick_end = rt_tick_get(); 360 | rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end); 361 | calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) ); 362 | rt_kprintf("\r\n"); 363 | 364 | // sign sector read 365 | rt_kprintf("read : "); 366 | sector = 0; 367 | tick_start = rt_tick_get(); 368 | for(i=0; i<200; i++) 369 | { 370 | sector += rt_device_read(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1); 371 | if((i != 0) && ((i%4) == 0) ) 372 | { 373 | if(sector < 4) 374 | { 375 | rt_kprintf("#"); 376 | } 377 | else 378 | { 379 | rt_kprintf(">"); 380 | } 381 | sector = 0; 382 | } 383 | } 384 | tick_end = rt_tick_get(); 385 | rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end); 386 | calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) ); 387 | rt_kprintf("\r\n"); 388 | } 389 | }// step 4: speed test 390 | 391 | /* step 6: multiple sector speed test */ 392 | { 393 | rt_uint8_t * multiple_buffer; 394 | rt_uint8_t * ptr; 395 | rt_uint32_t tick_start,tick_end; 396 | rt_uint32_t sector,i; 397 | 398 | rt_kprintf("\r\nmultiple sector speed test\r\n"); 399 | 400 | for(sector=2; sector<256; sector=sector*2) 401 | { 402 | multiple_buffer = rt_malloc(geometry.bytes_per_sector * sector); 403 | 404 | if(multiple_buffer == RT_NULL) 405 | { 406 | rt_kprintf("no memory for %d sector! multiple sector speed test abort!\r\n", sector); 407 | break; 408 | } 409 | 410 | rt_memset(multiple_buffer, sector, geometry.bytes_per_sector * sector); 411 | rt_kprintf("write: "); 412 | tick_start = rt_tick_get(); 413 | for(i=0; i<10; i++) 414 | { 415 | rt_size_t n; 416 | n = rt_device_write(device, 50, multiple_buffer, sector); 417 | if(n == sector) 418 | { 419 | rt_kprintf("<"); 420 | } 421 | else 422 | { 423 | rt_kprintf("#"); 424 | } 425 | } 426 | tick_end = rt_tick_get(); 427 | rt_kprintf("\r\n"); 428 | rt_kprintf("multiple write %d sector speed : ", sector); 429 | calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) ); 430 | rt_kprintf("\r\n"); 431 | 432 | rt_memset(multiple_buffer, ~sector, geometry.bytes_per_sector * sector); 433 | rt_kprintf("read : "); 434 | tick_start = rt_tick_get(); 435 | for(i=0; i<10; i++) 436 | { 437 | rt_size_t n; 438 | n = rt_device_read(device, 50, multiple_buffer, sector); 439 | if(n == sector) 440 | { 441 | rt_kprintf(">"); 442 | } 443 | else 444 | { 445 | rt_kprintf("#"); 446 | } 447 | } 448 | tick_end = rt_tick_get(); 449 | rt_kprintf("\r\n"); 450 | rt_kprintf("multiple read %d sector speed : ", sector); 451 | calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) ); 452 | 453 | ptr = multiple_buffer; 454 | for(i=0; iflag & RT_DEVICE_FLAG_ACTIVATED)) 510 | { 511 | rt_err_t result; 512 | result = rt_device_init(device); 513 | if (result != RT_EOK) 514 | { 515 | rt_kprintf("To initialize device:%s failed. The error code is %d\r\n", 516 | device->parent.name, result); 517 | return result; 518 | } 519 | else 520 | { 521 | device->flag |= RT_DEVICE_FLAG_ACTIVATED; 522 | } 523 | } 524 | 525 | // step 3: device test 526 | switch( device->type ) 527 | { 528 | case RT_Device_Class_Block : 529 | rt_kprintf("block device!\r\n"); 530 | return _block_device_test(device); 531 | default: 532 | rt_kprintf("unkown device type : %02X",device->type); 533 | return RT_ERROR; 534 | } 535 | } 536 | MSH_CMD_EXPORT(device_test, run device_test sd0); 537 | -------------------------------------------------------------------------------- /devicetest/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | rt_kprintf("device testing\n"); 6 | 7 | extern int device_test(void); 8 | device_test(); 9 | 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /hello/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /hello/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | printf("Hello, world\n"); 6 | 7 | return 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /lib/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /lib/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int lib_func(void) 4 | { 5 | printf("hello world from RTT::dynamic library!\n"); 6 | 7 | return 0; 8 | } 9 | 10 | int add_func(int a, int b) 11 | { 12 | return (a + b); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /md5/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /md5/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "md5.h" 6 | 7 | #define BUF_SZ 2048 8 | 9 | void usage(void) 10 | { 11 | printf("The md5 value generation/comparision tool.\n"); 12 | printf("md5 -g filename : to generate md5 file.\n"); 13 | printf("md5 -c filename : to compare md5 value.\n"); 14 | 15 | return; 16 | } 17 | 18 | static MD5_CTX md5_ctx; 19 | static unsigned char md5[16]; 20 | 21 | int main(int argc, char** argv) 22 | { 23 | FILE* fp; 24 | char* fn; 25 | int generate = -1; 26 | 27 | MD5Init(&md5_ctx); 28 | 29 | if (argc != 3) 30 | { 31 | usage(); 32 | return -1; 33 | } 34 | 35 | /* parse argument */ 36 | if (strcmp(argv[1], "-g") == 0) generate = 1; 37 | if (strcmp(argv[1], "-c") == 0) generate = 0; 38 | 39 | if (generate == -1) 40 | { 41 | usage(); 42 | return -1; 43 | } 44 | 45 | fp = fopen(argv[2], "rb"); 46 | if (fp) 47 | { 48 | uint8_t *buf_ptr; 49 | 50 | buf_ptr = (uint8_t*)malloc(BUF_SZ); 51 | if (buf_ptr) 52 | { 53 | int length; 54 | 55 | while (!feof(fp)) 56 | { 57 | length = fread(buf_ptr, 1, BUF_SZ, fp); 58 | MD5Update(&md5_ctx, buf_ptr, length); 59 | } 60 | 61 | MD5Final(md5, &md5_ctx); 62 | free(buf_ptr); 63 | } 64 | 65 | fclose(fp); 66 | 67 | /* get the md5 file name */ 68 | fn = (char*) malloc(strlen(argv[2] + 16)); 69 | if (!fn) 70 | { 71 | printf("no memory!\n"); 72 | return -1; 73 | } 74 | 75 | { 76 | char *ptr; 77 | 78 | strcpy(fn, argv[2]); 79 | ptr = strchr(fn, '.'); 80 | if (ptr) 81 | { 82 | ptr ++; 83 | } 84 | else 85 | { 86 | /* no ext name */ 87 | ptr = &fn[strlen(fn)]; 88 | *ptr++ = '.'; 89 | } 90 | 91 | /* with .md5 ext name */ 92 | *ptr++ = 'm'; 93 | *ptr++ = 'd'; 94 | *ptr++ = '5'; 95 | *ptr = '\0'; 96 | } 97 | 98 | if (generate == 1) 99 | { 100 | /* generate md5 file */ 101 | fp = fopen(fn, "wb+"); 102 | free(fn); /* release filename memory */ 103 | 104 | if (fp) 105 | { 106 | fwrite(md5, 1, sizeof(md5), fp); 107 | fclose(fp); 108 | 109 | return 0; 110 | } 111 | } 112 | else if (generate == 0) 113 | { 114 | unsigned char md5_temp[16]; 115 | 116 | /* compare md5 file */ 117 | fp = fopen(fn, "rb"); 118 | free(fn); /* release filename memory */ 119 | 120 | if (fp) 121 | { 122 | fread(md5_temp, 1, sizeof(md5_temp), fp); 123 | fclose(fp); 124 | } 125 | 126 | if (memcmp(md5, md5_temp, sizeof(md5)) == 0) 127 | { 128 | printf("md5 value is the same!\n"); 129 | return 0; 130 | } 131 | else 132 | { 133 | printf("md5 value is different!\n"); 134 | return -1; 135 | } 136 | } 137 | } 138 | else 139 | { 140 | printf("%s open failed!\n", argv[2]); 141 | } 142 | 143 | return -1; 144 | } 145 | -------------------------------------------------------------------------------- /md5/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | *********************************************************************** 3 | ** md5.c -- the source code for MD5 routines ** 4 | ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** 5 | ** Created: 2/17/90 RLR ** 6 | ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** 7 | *********************************************************************** 8 | */ 9 | 10 | /* 11 | *********************************************************************** 12 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 13 | ** ** 14 | ** License to copy and use this software is granted provided that ** 15 | ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** 16 | ** Digest Algorithm" in all material mentioning or referencing this ** 17 | ** software or this function. ** 18 | ** ** 19 | ** License is also granted to make and use derivative works ** 20 | ** provided that such works are identified as "derived from the RSA ** 21 | ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** 22 | ** material mentioning or referencing the derived work. ** 23 | ** ** 24 | ** RSA Data Security, Inc. makes no representations concerning ** 25 | ** either the merchantability of this software or the suitability ** 26 | ** of this software for any particular purpose. It is provided "as ** 27 | ** is" without express or implied warranty of any kind. ** 28 | ** ** 29 | ** These notices must be retained in any copies of any part of this ** 30 | ** documentation and/or software. ** 31 | *********************************************************************** 32 | */ 33 | 34 | #include "md5.h" 35 | #include 36 | 37 | /* 38 | *********************************************************************** 39 | ** Message-digest routines: ** 40 | ** To form the message digest for a message M ** 41 | ** (1) Initialize a context buffer mdContext using MD5Init ** 42 | ** (2) Call MD5Update on mdContext and M ** 43 | ** (3) Call MD5Final on mdContext ** 44 | ** The message digest is now in mdContext->digest[0...15] ** 45 | *********************************************************************** 46 | */ 47 | 48 | /* forward declaration */ 49 | static void Transform (uint32_t *buf, uint32_t *in); 50 | 51 | static unsigned char PADDING[64] = { 52 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 60 | }; 61 | 62 | /* F, G, H and I are basic MD5 functions */ 63 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 64 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 65 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 66 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 67 | 68 | /* ROTATE_LEFT rotates x left n bits */ 69 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 70 | 71 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ 72 | /* Rotation is separate from addition to prevent recomputation */ 73 | #define FF(a, b, c, d, x, s, ac) \ 74 | {(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ 75 | (a) = ROTATE_LEFT ((a), (s)); \ 76 | (a) += (b); \ 77 | } 78 | #define GG(a, b, c, d, x, s, ac) \ 79 | {(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ 80 | (a) = ROTATE_LEFT ((a), (s)); \ 81 | (a) += (b); \ 82 | } 83 | #define HH(a, b, c, d, x, s, ac) \ 84 | {(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ 85 | (a) = ROTATE_LEFT ((a), (s)); \ 86 | (a) += (b); \ 87 | } 88 | #define II(a, b, c, d, x, s, ac) \ 89 | {(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ 90 | (a) = ROTATE_LEFT ((a), (s)); \ 91 | (a) += (b); \ 92 | } 93 | 94 | #ifdef __STDC__ 95 | #define UL(x) x##UL 96 | #else 97 | #ifdef WIN32 98 | #define UL(x) x##UL 99 | #else 100 | #define UL(x) x 101 | #endif 102 | #endif 103 | 104 | /* The routine MD5Init initializes the message-digest context 105 | mdContext. All fields are set to zero. 106 | */ 107 | void 108 | MD5Init (MD5_CTX *mdContext) 109 | { 110 | mdContext->i[0] = mdContext->i[1] = (uint32_t)0; 111 | 112 | /* Load magic initialization constants. */ 113 | mdContext->buf[0] = (uint32_t)0x67452301UL; 114 | mdContext->buf[1] = (uint32_t)0xefcdab89UL; 115 | mdContext->buf[2] = (uint32_t)0x98badcfeUL; 116 | mdContext->buf[3] = (uint32_t)0x10325476UL; 117 | } 118 | 119 | /* The routine MD5Update updates the message-digest context to 120 | account for the presence of each of the characters inBuf[0..inLen-1] 121 | in the message whose digest is being computed. 122 | */ 123 | void 124 | MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) 125 | { 126 | uint32_t in[16]; 127 | int mdi; 128 | unsigned int i, ii; 129 | 130 | /* compute number of bytes mod 64 */ 131 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 132 | 133 | /* update number of bits */ 134 | if ((mdContext->i[0] + ((uint32_t)inLen << 3)) < mdContext->i[0]) { 135 | mdContext->i[1]++; 136 | } 137 | mdContext->i[0] += ((uint32_t)inLen << 3); 138 | mdContext->i[1] += ((uint32_t)inLen >> 29); 139 | 140 | while (inLen--) { 141 | /* add new character to buffer, increment mdi */ 142 | mdContext->in[mdi++] = *inBuf++; 143 | 144 | /* transform if necessary */ 145 | if (mdi == 0x40) { 146 | for (i = 0, ii = 0; i < 16; i++, ii += 4) { 147 | in[i] = (((uint32_t)mdContext->in[ii+3]) << 24) | 148 | (((uint32_t)mdContext->in[ii+2]) << 16) | 149 | (((uint32_t)mdContext->in[ii+1]) << 8) | 150 | ((uint32_t)mdContext->in[ii]); 151 | } 152 | Transform (mdContext->buf, in); 153 | mdi = 0; 154 | } 155 | } 156 | } 157 | 158 | /* The routine MD5Final terminates the message-digest computation and 159 | ends with the desired message digest in mdContext->digest[0...15]. 160 | */ 161 | void 162 | MD5Final (unsigned char hash[], MD5_CTX *mdContext) 163 | { 164 | uint32_t in[16]; 165 | int mdi; 166 | unsigned int i, ii; 167 | unsigned int padLen; 168 | 169 | /* save number of bits */ 170 | in[14] = mdContext->i[0]; 171 | in[15] = mdContext->i[1]; 172 | 173 | /* compute number of bytes mod 64 */ 174 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 175 | 176 | /* pad out to 56 mod 64 */ 177 | padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); 178 | MD5Update (mdContext, PADDING, padLen); 179 | 180 | /* append length in bits and transform */ 181 | for (i = 0, ii = 0; i < 14; i++, ii += 4) { 182 | in[i] = (((uint32_t)mdContext->in[ii+3]) << 24) | 183 | (((uint32_t)mdContext->in[ii+2]) << 16) | 184 | (((uint32_t)mdContext->in[ii+1]) << 8) | 185 | ((uint32_t)mdContext->in[ii]); 186 | } 187 | Transform (mdContext->buf, in); 188 | 189 | /* store buffer in digest */ 190 | for (i = 0, ii = 0; i < 4; i++, ii += 4) { 191 | mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); 192 | mdContext->digest[ii+1] = 193 | (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); 194 | mdContext->digest[ii+2] = 195 | (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); 196 | mdContext->digest[ii+3] = 197 | (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); 198 | } 199 | memcpy(hash, mdContext->digest, 16); 200 | } 201 | 202 | /* Basic MD5 step. Transforms buf based on in. 203 | */ 204 | static void 205 | Transform (uint32_t *buf, uint32_t *in) 206 | { 207 | uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; 208 | 209 | /* Round 1 */ 210 | #define S11 7 211 | #define S12 12 212 | #define S13 17 213 | #define S14 22 214 | FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ 215 | FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ 216 | FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ 217 | FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ 218 | FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ 219 | FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ 220 | FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ 221 | FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ 222 | FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ 223 | FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ 224 | FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ 225 | FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ 226 | FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ 227 | FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ 228 | FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ 229 | FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ 230 | 231 | /* Round 2 */ 232 | #define S21 5 233 | #define S22 9 234 | #define S23 14 235 | #define S24 20 236 | GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ 237 | GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ 238 | GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ 239 | GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ 240 | GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ 241 | GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ 242 | GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ 243 | GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ 244 | GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ 245 | GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ 246 | GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ 247 | GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ 248 | GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ 249 | GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ 250 | GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ 251 | GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ 252 | 253 | /* Round 3 */ 254 | #define S31 4 255 | #define S32 11 256 | #define S33 16 257 | #define S34 23 258 | HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ 259 | HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ 260 | HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ 261 | HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ 262 | HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ 263 | HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ 264 | HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ 265 | HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ 266 | HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ 267 | HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ 268 | HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ 269 | HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ 270 | HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ 271 | HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ 272 | HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ 273 | HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ 274 | 275 | /* Round 4 */ 276 | #define S41 6 277 | #define S42 10 278 | #define S43 15 279 | #define S44 21 280 | II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ 281 | II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ 282 | II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ 283 | II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ 284 | II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ 285 | II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ 286 | II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ 287 | II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ 288 | II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ 289 | II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ 290 | II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ 291 | II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ 292 | II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ 293 | II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ 294 | II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ 295 | II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ 296 | 297 | buf[0] += a; 298 | buf[1] += b; 299 | buf[2] += c; 300 | buf[3] += d; 301 | } 302 | -------------------------------------------------------------------------------- /md5/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | *********************************************************************** 3 | ** md5.h -- header file for implementation of MD5 ** 4 | ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** 5 | ** Created: 2/17/90 RLR ** 6 | ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** 7 | ** Revised (for MD5): RLR 4/27/91 ** 8 | ** -- G modified to have y&~z instead of y&z ** 9 | ** -- FF, GG, HH modified to add in last register done ** 10 | ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** 11 | ** -- distinct additive constant for each step ** 12 | ** -- round 4 added, working mod 7 ** 13 | *********************************************************************** 14 | */ 15 | 16 | /* 17 | *********************************************************************** 18 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 19 | ** ** 20 | ** License to copy and use this software is granted provided that ** 21 | ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** 22 | ** Digest Algorithm" in all material mentioning or referencing this ** 23 | ** software or this function. ** 24 | ** ** 25 | ** License is also granted to make and use derivative works ** 26 | ** provided that such works are identified as "derived from the RSA ** 27 | ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** 28 | ** material mentioning or referencing the derived work. ** 29 | ** ** 30 | ** RSA Data Security, Inc. makes no representations concerning ** 31 | ** either the merchantability of this software or the suitability ** 32 | ** of this software for any particular purpose. It is provided "as ** 33 | ** is" without express or implied warranty of any kind. ** 34 | ** ** 35 | ** These notices must be retained in any copies of any part of this ** 36 | ** documentation and/or software. ** 37 | *********************************************************************** 38 | */ 39 | 40 | #ifndef MD5_H 41 | #define MD5_H 42 | 43 | #include 44 | 45 | /* Data structure for MD5 (Message-Digest) computation */ 46 | typedef struct { 47 | uint32_t i[2]; /* number of _bits_ handled mod 2^64 */ 48 | uint32_t buf[4]; /* scratch buffer */ 49 | unsigned char in[64]; /* input buffer */ 50 | unsigned char digest[16]; /* actual digest after MD5Final call */ 51 | } MD5_CTX; 52 | 53 | void MD5Init ( MD5_CTX *mdContext); 54 | void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen); 55 | void MD5Final ( unsigned char hash[], MD5_CTX *mdContext); 56 | 57 | #endif /* MD5_H */ 58 | -------------------------------------------------------------------------------- /memperf/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 SummerGift (summergift2019@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /memperf/README.md: -------------------------------------------------------------------------------- 1 | # Memory Performance Testing 2 | 3 | ## 1. 介绍 4 | 5 | 这是一个运行在 RT-Thread 上的内存性能测试软件包,用于对 ARM CPU 的 内存性能评估,可适用于如下场景: 6 | 7 | - 评估不同类型内存的读写性能 8 | - 对于带有 cache 的 CPU,可用于评估 cache 性能 9 | 10 | 非常欢迎小伙伴们在运行完测试程序后,将相关测试结果 PR 到 [测试示例](#测试示例) 中以供他人参考。 11 | 12 | ### 1.1 目录结构 13 | 14 | | 名称 | 说明 | 15 | | ---- | ---- | 16 | | inc | 头文件目录 | 17 | | src | 源代码目录 | 18 | 19 | ### 1.2 许可证 20 | 21 | `MemoryPerf` 软件包遵循 MIT 许可,详见 `LICENSE` 文件。 22 | 23 | ### 1.3 依赖 24 | 25 | 具有良好的移植性,无操作系统依赖。 26 | 27 | ## 2. 下载方式 28 | 29 | 使用 `MemoryPerf package` 需要在 RT-Thread 的包管理器中选择它,具体路径如下: 30 | 31 | ``` 32 | RT-Thread online packages 33 | tools packages ---> 34 | [*] MemoryPerf: Memory Performance Testing for ARM CPU. 35 | ``` 36 | 37 | 然后让 RT-Thread 的包管理器自动更新,或者使用 `pkgs --update` 命令更新包到 BSP 中。 38 | 39 | ## 3. 使用方法 40 | 41 | - 在 `msh` 中运行 `` 命令 42 | 43 | ## 4. 注意事项 44 | 45 | - 检查内存测试地址与长度是否设置正确 46 | - 测试内存性能时推荐对比打开 cache 与 关闭 cache 的测试结果 47 | 48 | ## 5. 联系方式 49 | 50 | * 维护:我夏了夏天 (SummerGift) 51 | * 主页:https://github.com/SummerLife 52 | 53 | ## 测试示例 54 | 55 | ### 6.1 示例一 56 | 57 | 测试环境 `zynq7045 Cortex-A9 800M SDRAM uncached GCC -O3` : 58 | 59 | ```shell 60 | msh />memory_perf 0x10100000 0x100000 61 | Memory performance testing start... 62 | address: 0x10100000, length: 0x100000 63 | Data length : 209 MB. 64 | -------------------------------------- 65 | 8-bit write speed test begin. 66 | Spend time : 7.480000 s. 67 | 8-bit write speed: 28.036793 M/s. 68 | 8-bit read speed test begin. 69 | Spend time : 5.380000 s. 70 | 8-bit Read speed: 38.980518 M/s. 71 | -------------------------------------- 72 | 16-bit write speed test begin. 73 | Spend time : 3.740000 s. 74 | 16-bit write speed: 56.073586 M/s. 75 | 16-bit read speed test begin. 76 | Spend time : 2.690000 s. 77 | 16-bit Read speed: 77.961037 M/s. 78 | -------------------------------------- 79 | 32-bit write speed test begin. 80 | Spend time : 1.870000 s. 81 | 32-bit Write speed: 112.147171 M/s. 82 | 32-bit read speed test begin. 83 | Spend time : 1.350000 s. 84 | 32-bit Read speed: 155.344589 M/s. 85 | Memory performance completed. 86 | ``` 87 | 88 | ### 6.2 示例二 89 | 90 | 测试环境 `zynq7045 Cortex-A9 800M SDRAM cached GCC -O3` : 91 | 92 | ```shell 93 | msh />memory_perf 0x10100000 0x100000 # Testing with cache 94 | Memory performance testing start... 95 | address: 0x10100000, length: 0x100000 96 | Data length : 209 MB. 97 | -------------------------------------- 98 | 8-bit write speed test begin. 99 | Spend time : 0.290000 s. 100 | 8-bit write speed: 723.155884 M/s. # Achieve the best write performance 101 | 8-bit read speed test begin. 102 | Spend time : 0.490000 s. 103 | 8-bit Read speed: 427.990204 M/s. 104 | -------------------------------------- 105 | 16-bit write speed test begin. 106 | Spend time : 0.290000 s. 107 | 16-bit write speed: 723.155884 M/s. # Achieve the best write performance 108 | 16-bit read speed test begin. 109 | Spend time : 0.410000 s. 110 | 16-bit Read speed: 511.500488 M/s. 111 | -------------------------------------- 112 | 32-bit write speed test begin. 113 | Spend time : 0.290000 s. 114 | 32-bit Write speed: 723.155884 M/s. # Achieve the best write performance 115 | 32-bit read speed test begin. 116 | Spend time : 0.370000 s. 117 | 32-bit Read speed: 566.797852 M/s. 118 | Memory performance completed. 119 | ``` 120 | 121 | ### 6.3 示例三 122 | 123 | 测试环境 `stm32f407-atk-explorer Cortex-M4 168M SRAM uncached GCC -O3` : 124 | 125 | ```shell 126 | msh >memory_perf 0x20010000 0x10000 127 | Memory performance testing start... 128 | address: 0x20010000, length: 0x10000, iterations: 200 129 | Data length : 13 MB. 130 | -------------------------------------- 131 | 8-bit write speed test begin. 132 | Spend time : 0.139000 s. 133 | 8-bit write speed: 94.296402 M/s. 134 | 8-bit read speed test begin. 135 | Spend time : 0.361000 s. 136 | 8-bit Read speed: 36.308033 M/s. 137 | -------------------------------------- 138 | 16-bit write speed test begin. 139 | Spend time : 0.070000 s. 140 | 16-bit write speed: 187.245712 M/s. 141 | 16-bit read speed test begin. 142 | Spend time : 0.180000 s. 143 | 16-bit Read speed: 72.817780 M/s. 144 | -------------------------------------- 145 | 32-bit write speed test begin. 146 | Spend time : 0.035000 s. 147 | 32-bit Write speed: 374.491425 M/s. 148 | 32-bit read speed test begin. 149 | Spend time : 0.090000 s. 150 | 32-bit Read speed: 145.635559 M/s. 151 | Memory performance completed. 152 | ``` 153 | 154 | ### 6.4 示例四 155 | 156 | 测试环境 `stm32f407-atk-explorer Cortex-M4 168M SRAM uncached ARM(AC6) -O3` : 157 | 158 | ```shell 159 | msh >memory_perf 0x20010000 0x10000 160 | Memory performance testing start... 161 | address: 20010000, length: 0x10000, iterations: 200 162 | Data length : 13 MB. 163 | -------------------------------------- 164 | 8-bit write speed test begin. 165 | Spend time : 0.094000 s. 166 | 8-bit write speed: 139.438309 M/s. 167 | 8-bit read speed test begin. 168 | Spend time : 0.268000 s. 169 | 8-bit Read speed: 48.907459 M/s. 170 | -------------------------------------- 171 | 16-bit write speed test begin. 172 | Spend time : 0.047000 s. 173 | 16-bit write speed: 278.876617 M/s. 174 | 16-bit read speed test begin. 175 | Spend time : 0.134000 s. 176 | 16-bit Read speed: 97.814919 M/s. 177 | -------------------------------------- 178 | 32-bit write speed test begin. 179 | Spend time : 0.023000 s. 180 | 32-bit Write speed: 569.878296 M/s. 181 | 32-bit read speed test begin. 182 | Spend time : 0.068000 s. 183 | 32-bit Read speed: 192.752930 M/s. 184 | Memory performance completed. 185 | ``` 186 | 187 | ### 6.5 示例五 188 | 189 | 测试环境 `stm32l475-atk-Pandora Cortex-M4 80M SRAM uncached GCC -O3` : 190 | 191 | ```shell 192 | msh >memory_perf 0x20008000 0xa000 193 | Memory performance testing start... 194 | address: 0x20008000, length: 0xa000, iterations: 200 195 | Data length : 8 MB. 196 | -------------------------------------- 197 | 8-bit write speed test begin. 198 | Spend time : 0.180000 s. 199 | 8-bit write speed: 45.511108 M/s. 200 | 8-bit read speed test begin. 201 | Spend time : 0.449000 s. 202 | 8-bit Read speed: 18.244987 M/s. 203 | -------------------------------------- 204 | 16-bit write speed test begin. 205 | Spend time : 0.090000 s. 206 | 16-bit write speed: 91.022217 M/s. 207 | 16-bit read speed test begin. 208 | Spend time : 0.225000 s. 209 | 16-bit Read speed: 36.408890 M/s. 210 | -------------------------------------- 211 | 32-bit write speed test begin. 212 | Spend time : 0.045000 s. 213 | 32-bit Write speed: 182.044434 M/s. 214 | 32-bit read speed test begin. 215 | Spend time : 0.113000 s. 216 | 32-bit Read speed: 72.495575 M/s. 217 | Memory performance completed. 218 | ``` 219 | 220 | -------------------------------------------------------------------------------- /memperf/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /memperf/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | extern int memory_perf(void); 6 | memory_perf(); 7 | 8 | return 0; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /memperf/mem_perf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 SummerGift (summergift2019@gmail.com) 3 | * 4 | * MIT License 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2020-11-27 SummerGift first version 9 | * 2020-11-28 SummerGift optimize cmd 10 | */ 11 | 12 | #include 13 | #include "portme.h" 14 | 15 | #define __version__ "1.0.0" 16 | 17 | #define ITERATIONS 200 18 | 19 | static mp_u32 data_len; 20 | 21 | static void memory_perf_8bit(void *addr, mp_u32 len) 22 | { 23 | volatile mp_u8 *read_addr; 24 | mp_f32 seconds, speed; 25 | 26 | 27 | printf("--------------------------------------\n"); 28 | printf("8-bit write speed test begin.\n"); 29 | 30 | start_time_mp(); 31 | for(int i = 0; i < ITERATIONS; i++) 32 | { 33 | for(int i = 0; i < len; i+=8) 34 | { 35 | read_addr = (mp_u8 *) (addr + i); 36 | *read_addr++ = 0x55; 37 | *read_addr++ = 0x55; 38 | *read_addr++ = 0x55; 39 | *read_addr++ = 0x55; 40 | *read_addr++ = 0x55; 41 | *read_addr++ = 0x55; 42 | *read_addr++ = 0x55; 43 | *read_addr++ = 0x55; 44 | } 45 | } 46 | stop_time_mp(); 47 | 48 | seconds = (unsigned int) get_time_mp() / (NSECS_PER_SEC * 1.0); 49 | speed = data_len / seconds; 50 | 51 | printf("Spend time : %f s.\n", seconds); 52 | printf("8-bit write speed: %f M/s.\n", speed / 1000000); 53 | 54 | printf("8-bit read speed test begin.\n"); 55 | 56 | start_time_mp(); 57 | for(int i = 0; i < ITERATIONS; i++) 58 | { 59 | for(int i = 0; i < len; i+=8) 60 | { 61 | read_addr = (mp_u8 *) (addr + i); 62 | __asm volatile ("ldrb r0, [%0]\n" 63 | ::"r"(read_addr++): "r0"); 64 | __asm volatile ("ldrb r0, [%0]\n" 65 | ::"r"(read_addr++): "r0"); 66 | __asm volatile ("ldrb r0, [%0]\n" 67 | ::"r"(read_addr++): "r0"); 68 | __asm volatile ("ldrb r0, [%0]\n" 69 | ::"r"(read_addr++): "r0"); 70 | __asm volatile ("ldrb r0, [%0]\n" 71 | ::"r"(read_addr++): "r0"); 72 | __asm volatile ("ldrb r0, [%0]\n" 73 | ::"r"(read_addr++): "r0"); 74 | __asm volatile ("ldrb r0, [%0]\n" 75 | ::"r"(read_addr++): "r0"); 76 | __asm volatile ("ldrb r0, [%0]\n" 77 | ::"r"(read_addr): "r0"); 78 | } 79 | } 80 | stop_time_mp(); 81 | 82 | seconds = (unsigned int) get_time_mp() / (NSECS_PER_SEC * 1.0); 83 | speed = data_len / seconds; 84 | 85 | printf("Spend time : %f s.\n", seconds); 86 | printf("8-bit Read speed: %f M/s.\n", speed / 1000000); 87 | } 88 | 89 | static void memory_perf_16bit(void *addr, mp_u32 len) 90 | { 91 | volatile mp_u16 *read_addr; 92 | mp_f32 seconds, speed; 93 | 94 | printf("--------------------------------------\n"); 95 | printf("16-bit write speed test begin.\n"); 96 | 97 | start_time_mp(); 98 | for(int i = 0; i < ITERATIONS; i++) 99 | { 100 | for(int i = 0; i < len; i += 16) 101 | { 102 | read_addr = (mp_u16 *) (addr + i); 103 | *read_addr++ = 0x55; 104 | *read_addr++ = 0x55; 105 | *read_addr++ = 0x55; 106 | *read_addr++ = 0x55; 107 | *read_addr++ = 0x55; 108 | *read_addr++ = 0x55; 109 | *read_addr++ = 0x55; 110 | *read_addr++ = 0x55; 111 | } 112 | } 113 | stop_time_mp(); 114 | 115 | seconds = (unsigned int) get_time_mp() / (NSECS_PER_SEC * 1.0); 116 | speed = data_len / seconds; 117 | 118 | printf("Spend time : %f s.\n", seconds); 119 | printf("16-bit write speed: %f M/s.\n", speed / 1000000); 120 | 121 | printf("16-bit read speed test begin.\n"); 122 | 123 | start_time_mp(); 124 | for(int i = 0; i < ITERATIONS; i++) 125 | { 126 | for(int i = 0; i < len; i += 16) 127 | { 128 | read_addr = (mp_u16 *) (addr + i); 129 | __asm volatile ("ldrh r0, [%0]\n" 130 | ::"r"(read_addr++): "r0"); 131 | __asm volatile ("ldrh r0, [%0]\n" 132 | ::"r"(read_addr++): "r0"); 133 | __asm volatile ("ldrh r0, [%0]\n" 134 | ::"r"(read_addr++): "r0"); 135 | __asm volatile ("ldrh r0, [%0]\n" 136 | ::"r"(read_addr++): "r0"); 137 | __asm volatile ("ldrh r0, [%0]\n" 138 | ::"r"(read_addr++): "r0"); 139 | __asm volatile ("ldrh r0, [%0]\n" 140 | ::"r"(read_addr++): "r0"); 141 | __asm volatile ("ldrh r0, [%0]\n" 142 | ::"r"(read_addr++): "r0"); 143 | __asm volatile ("ldrh r0, [%0]\n" 144 | ::"r"(read_addr): "r0"); 145 | } 146 | } 147 | stop_time_mp(); 148 | 149 | seconds = (unsigned int) get_time_mp() / (NSECS_PER_SEC * 1.0); 150 | speed = data_len / seconds; 151 | 152 | printf("Spend time : %f s.\n", seconds); 153 | printf("16-bit Read speed: %f M/s.\n", speed / 1000000); 154 | } 155 | 156 | static void memory_perf_32bit(void *addr, mp_u32 len) 157 | { 158 | volatile mp_u32 *read_addr; 159 | mp_f32 seconds, speed; 160 | 161 | printf("--------------------------------------\n"); 162 | printf("32-bit write speed test begin.\n"); 163 | 164 | start_time_mp(); 165 | for(int i = 0; i < ITERATIONS; i++) 166 | { 167 | for(int i = 0; i < len; i += 32) 168 | { 169 | read_addr = (mp_u32 *) (addr + i); 170 | *read_addr++ = 0x55; 171 | *read_addr++ = 0x55; 172 | *read_addr++ = 0x55; 173 | *read_addr++ = 0x55; 174 | *read_addr++ = 0x55; 175 | *read_addr++ = 0x55; 176 | *read_addr++ = 0x55; 177 | *read_addr++ = 0x55; 178 | } 179 | } 180 | stop_time_mp(); 181 | 182 | seconds = (unsigned int) get_time_mp() / (NSECS_PER_SEC * 1.0); 183 | speed = data_len / seconds; 184 | 185 | printf("Spend time : %f s.\n", seconds); 186 | printf("32-bit Write speed: %f M/s.\n", speed / 1000000); 187 | 188 | printf("32-bit read speed test begin.\n"); 189 | 190 | start_time_mp(); 191 | for(int i = 0; i < ITERATIONS; i++) 192 | { 193 | for(int i = 0; i < len; i += 32) 194 | { 195 | read_addr = (mp_u32 *) (addr + i); 196 | __asm volatile ("ldr r0, [%0]\n" 197 | ::"r"(read_addr++): "r0"); 198 | __asm volatile ("ldr r0, [%0]\n" 199 | ::"r"(read_addr++): "r0"); 200 | __asm volatile ("ldr r0, [%0]\n" 201 | ::"r"(read_addr++): "r0"); 202 | __asm volatile ("ldr r0, [%0]\n" 203 | ::"r"(read_addr++): "r0"); 204 | __asm volatile ("ldr r0, [%0]\n" 205 | ::"r"(read_addr++): "r0"); 206 | __asm volatile ("ldr r0, [%0]\n" 207 | ::"r"(read_addr++): "r0"); 208 | __asm volatile ("ldr r0, [%0]\n" 209 | ::"r"(read_addr++): "r0"); 210 | __asm volatile ("ldr r0, [%0]\n" 211 | ::"r"(read_addr): "r0"); 212 | } 213 | } 214 | stop_time_mp(); 215 | 216 | seconds = (mp_u32) get_time_mp() / (NSECS_PER_SEC * 1.0); 217 | speed = data_len / seconds; 218 | 219 | printf("Spend time : %f s.\n", seconds); 220 | printf("32-bit Read speed: %f M/s.\n", speed / 1000000); 221 | } 222 | 223 | static void memory_perf(int argc, char** argv) 224 | { 225 | printf("\nMemoryPerf version " __version__ " \n"); 226 | printf("Copyright (c) 2020 SummerGift (summergift2019@gmail.com)\n"); 227 | printf("Licensed under the MIT License version.\n\n"); 228 | 229 | if (argc != 3) 230 | { 231 | printf("Please set test address and length correctly.\n"); 232 | printf("Example: \n"); 233 | return; 234 | } 235 | 236 | void *address = (void *)strtol(argv[1] + 2, NULL, 16); 237 | mp_u32 len = (mp_u32)strtol(argv[2] + 2, NULL, 16); 238 | data_len = ITERATIONS * len; 239 | 240 | printf("Memory performance testing start...\n"); 241 | printf("address: %p, length: 0x%x, iterations: %d\n", address, len, ITERATIONS); 242 | printf("Data length : %u MB.\n", data_len / 1000000); 243 | 244 | memory_perf_8bit(address, len); 245 | memory_perf_16bit(address, len); 246 | memory_perf_32bit(address, len); 247 | 248 | printf("Memory performance completed.\n"); 249 | } 250 | MSH_CMD_EXPORT(memory_perf, run memory performance test); 251 | -------------------------------------------------------------------------------- /memperf/portme.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 SummerGift (summergift2019@gmail.com) 3 | * 4 | * MIT License 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2020-11-27 SummerGift first version 9 | */ 10 | 11 | #include "portme.h" 12 | 13 | static CORETIMETYPE start_time_val, stop_time_val; 14 | 15 | void start_time_mp(void) 16 | { 17 | GETMYTIME(&start_time_val); 18 | } 19 | 20 | void stop_time_mp(void) 21 | { 22 | GETMYTIME(&stop_time_val); 23 | } 24 | 25 | CORETIMETYPE get_time_mp(void) 26 | { 27 | CORETIMETYPE elapsed = (CORETIMETYPE) (MYTIMEDIFF(stop_time_val, start_time_val)); 28 | return elapsed; 29 | } 30 | -------------------------------------------------------------------------------- /memperf/portme.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 SummerGift (summergift2019@gmail.com) 3 | * 4 | * MIT License 5 | * 6 | * Change Logs: 7 | * Date Author Notes 8 | * 2020-11-27 SummerGift first version 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef unsigned char mp_u8; 16 | typedef unsigned short mp_u16; 17 | typedef unsigned int mp_u32; 18 | typedef float mp_f32; 19 | 20 | #define NSECS_PER_SEC RT_TICK_PER_SECOND 21 | #define CORETIMETYPE rt_tick_t 22 | #define MYTIMEDIFF(fin,ini) ((fin)-(ini)) 23 | #define GETMYTIME(_t) (*_t=rt_tick_get()) 24 | 25 | void start_time_mp(void); 26 | void stop_time_mp(void); 27 | CORETIMETYPE get_time_mp(void); 28 | -------------------------------------------------------------------------------- /tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RT-Thread/rtthread-apps/55e31c7262e65f22cccecb83369682d1553a6230/tools/__init__.py -------------------------------------------------------------------------------- /tools/host/building.py: -------------------------------------------------------------------------------- 1 | # 2 | # File : building.py 3 | # This file is part of RT-Thread RTOS 4 | # COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License along 17 | # with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | # 20 | # Change Logs: 21 | # Date Author Notes 22 | # 2015-01-20 Bernard Add copyright information 23 | # 24 | 25 | import os 26 | import sys 27 | import string 28 | 29 | from SCons.Script import * 30 | 31 | BuildOptions = {} 32 | Projects = [] 33 | Env = None 34 | 35 | def GetCurrentDir(): 36 | conscript = File('SConscript') 37 | fn = conscript.rfile() 38 | name = fn.name 39 | path = os.path.dirname(fn.abspath) 40 | return path 41 | 42 | def PrepareHostModuleBuilding(env): 43 | global Env 44 | Env = env; 45 | 46 | def GetDepend(depend): 47 | # always true 48 | return True 49 | 50 | def MergeGroup(src_group, group): 51 | src_group['src'] = src_group['src'] + group['src'] 52 | if group.has_key('CCFLAGS'): 53 | if src_group.has_key('CCFLAGS'): 54 | src_group['CCFLAGS'] = src_group['CCFLAGS'] + group['CCFLAGS'] 55 | else: 56 | src_group['CCFLAGS'] = group['CCFLAGS'] 57 | if group.has_key('CPPPATH'): 58 | if src_group.has_key('CPPPATH'): 59 | src_group['CPPPATH'] = src_group['CPPPATH'] + group['CPPPATH'] 60 | else: 61 | src_group['CPPPATH'] = group['CPPPATH'] 62 | if group.has_key('CPPDEFINES'): 63 | if src_group.has_key('CPPDEFINES'): 64 | src_group['CPPDEFINES'] = src_group['CPPDEFINES'] + group['CPPDEFINES'] 65 | else: 66 | src_group['CPPDEFINES'] = group['CPPDEFINES'] 67 | 68 | # for local CCFLAGS/CPPPATH/CPPDEFINES 69 | if group.has_key('LOCAL_CCFLAGS'): 70 | if src_group.has_key('LOCAL_CCFLAGS'): 71 | src_group['LOCAL_CCFLAGS'] = src_group['LOCAL_CCFLAGS'] + group['LOCAL_CCFLAGS'] 72 | else: 73 | src_group['LOCAL_CCFLAGS'] = group['LOCAL_CCFLAGS'] 74 | if group.has_key('LOCAL_CPPPATH'): 75 | if src_group.has_key('LOCAL_CPPPATH'): 76 | src_group['LOCAL_CPPPATH'] = src_group['LOCAL_CPPPATH'] + group['LOCAL_CPPPATH'] 77 | else: 78 | src_group['LOCAL_CPPPATH'] = group['LOCAL_CPPPATH'] 79 | if group.has_key('LOCAL_CPPDEFINES'): 80 | if src_group.has_key('LOCAL_CPPDEFINES'): 81 | src_group['LOCAL_CPPDEFINES'] = src_group['LOCAL_CPPDEFINES'] + group['LOCAL_CPPDEFINES'] 82 | else: 83 | src_group['LOCAL_CPPDEFINES'] = group['LOCAL_CPPDEFINES'] 84 | 85 | if group.has_key('LINKFLAGS'): 86 | if src_group.has_key('LINKFLAGS'): 87 | src_group['LINKFLAGS'] = src_group['LINKFLAGS'] + group['LINKFLAGS'] 88 | else: 89 | src_group['LINKFLAGS'] = group['LINKFLAGS'] 90 | if group.has_key('LIBS'): 91 | if src_group.has_key('LIBS'): 92 | src_group['LIBS'] = src_group['LIBS'] + group['LIBS'] 93 | else: 94 | src_group['LIBS'] = group['LIBS'] 95 | if group.has_key('LIBPATH'): 96 | if src_group.has_key('LIBPATH'): 97 | src_group['LIBPATH'] = src_group['LIBPATH'] + group['LIBPATH'] 98 | else: 99 | src_group['LIBPATH'] = group['LIBPATH'] 100 | 101 | def DefineGroup(name, src, depend, **parameters): 102 | global Env 103 | if not GetDepend(depend): 104 | return [] 105 | 106 | # find exist group and get path of group 107 | group_path = '' 108 | for g in Projects: 109 | if g['name'] == name: 110 | group_path = g['path'] 111 | if group_path == '': 112 | group_path = GetCurrentDir() 113 | 114 | group = parameters 115 | group['name'] = name 116 | group['path'] = group_path 117 | if type(src) == type(['src1']): 118 | group['src'] = File(src) 119 | else: 120 | group['src'] = src 121 | 122 | if group.has_key('CCFLAGS'): 123 | Env.Append(CCFLAGS = group['CCFLAGS']) 124 | if group.has_key('CPPPATH'): 125 | Env.Append(CPPPATH = group['CPPPATH']) 126 | if group.has_key('CPPDEFINES'): 127 | Env.Append(CPPDEFINES = group['CPPDEFINES']) 128 | if group.has_key('LINKFLAGS'): 129 | Env.Append(LINKFLAGS = group['LINKFLAGS']) 130 | 131 | if group.has_key('LIBS'): 132 | Env.Append(LIBS = group['LIBS']) 133 | if group.has_key('LIBPATH'): 134 | Env.Append(LIBPATH = group['LIBPATH']) 135 | 136 | if group.has_key('LIBRARY'): 137 | objs = Env.Library(name, group['src']) 138 | else: 139 | objs = group['src'] 140 | 141 | # merge group 142 | for g in Projects: 143 | if g['name'] == name: 144 | # merge to this group 145 | MergeGroup(g, group) 146 | return objs 147 | 148 | # add a new group 149 | Projects.append(group) 150 | 151 | return objs 152 | -------------------------------------------------------------------------------- /tools/host/rtthread/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | CPPDEFINES = ['HOST_BUILD'] 8 | 9 | group = DefineGroup('RT-Thread', src, depend = [''], CPPPATH=CPPPATH, CPPDEFINES = CPPDEFINES) 10 | 11 | Return('group') 12 | -------------------------------------------------------------------------------- /tools/host/rtthread/finsh.h: -------------------------------------------------------------------------------- 1 | #ifndef FINSH_H__ 2 | #define FINSH_H__ 3 | 4 | #define MSH_CMD_EXPORT(command, desc) 5 | #define MSH_CMD_EXPORT_ALIAS(command, alias, desc) 6 | 7 | #define FINSH_FUNCTION_EXPORT(name, desc) 8 | #define FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc) 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /tools/host/rtthread/rthw.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RT-Thread/rtthread-apps/55e31c7262e65f22cccecb83369682d1553a6230/tools/host/rtthread/rthw.h -------------------------------------------------------------------------------- /tools/host/rtthread/rtthread.c: -------------------------------------------------------------------------------- 1 | #include "rtthread.h" 2 | 3 | #include 4 | 5 | void rt_kprintf(const char *fmt, ...) 6 | { 7 | va_list argptr; 8 | 9 | va_start(argptr,fmt); 10 | vprintf(fmt,argptr); 11 | va_end(argptr); 12 | 13 | return ; 14 | } 15 | 16 | rt_tick_t rt_tick_get(void) 17 | { 18 | return 0; 19 | } 20 | 21 | void *rt_malloc(rt_size_t nbytes) 22 | { 23 | void* ret = malloc(nbytes); 24 | 25 | return ret; 26 | } 27 | 28 | void rt_free(void *ptr) 29 | { 30 | free(ptr); 31 | } 32 | 33 | int rt_hw_interrupt_disable(void) 34 | { 35 | return 0; 36 | } 37 | 38 | void rt_hw_interrupt_enable(int level) 39 | { 40 | return ; 41 | } 42 | -------------------------------------------------------------------------------- /tools/host/rtthread/rtthread.h: -------------------------------------------------------------------------------- 1 | #ifndef RTTHREAD_H__ 2 | #define RTTHREAD_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #define RT_USING_DFS 15 | #define RT_USING_DEVICE 16 | #define RT_TICK_PER_SECOND 100 17 | #define RT_CONSOLEBUF_SIZE 256 18 | 19 | #define RT_NULL NULL 20 | #define RT_ASSERT(EX) \ 21 | if (!(EX)) \ 22 | { \ 23 | printf(#EX); \ 24 | exit(-1); \ 25 | } 26 | 27 | #define rt_vsnprintf vsnprintf 28 | 29 | typedef size_t rt_size_t; 30 | typedef uint32_t rt_tick_t; 31 | 32 | void rt_kprintf(const char *fmt, ...); 33 | rt_tick_t rt_tick_get(void); 34 | 35 | void *rt_malloc(rt_size_t nbytes); 36 | void rt_free(void *ptr); 37 | 38 | int rt_hw_interrupt_disable(void); 39 | void rt_hw_interrupt_enable(int level); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /tools/ua.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | main 3 | -------------------------------------------------------------------------------- /tools/ua.py: -------------------------------------------------------------------------------- 1 | # File : ua.py 2 | # Tool Script for building User Applications 3 | # This file is part of RT-Thread RTOS 4 | # COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License along 17 | # with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | # 20 | # Change Logs: 21 | # Date Author Notes 22 | # 2015-02-07 Bernard The firstly version 23 | # 24 | 25 | import os 26 | import sys 27 | from SCons.Script import * 28 | 29 | Rtt_Root = '' 30 | BSP_Root = '' 31 | Env = None 32 | 33 | def BuildEnv(BSP_ROOT, RTT_ROOT): 34 | if BSP_ROOT == None: 35 | if os.getenv('BSP_ROOT'): 36 | BSP_ROOT = os.getenv('BSP_ROOT') 37 | else: 38 | print 'Please set BSP(board support package) directory!' 39 | exit(-1) 40 | 41 | if not os.path.exists(BSP_ROOT): 42 | print 'No BSP(board support package) directory found!' 43 | exit(-1) 44 | 45 | if RTT_ROOT == None: 46 | # get RTT_ROOT from BSP_ROOT 47 | sys.path = sys.path + [BSP_ROOT] 48 | try: 49 | import rtconfig 50 | RTT_ROOT = rtconfig.RTT_ROOT 51 | except Exception as e: 52 | print 'Import rtconfig.py in BSP(board support package) failed.' 53 | print e 54 | exit(-1) 55 | 56 | global Rtt_Root 57 | global BSP_Root 58 | 59 | Rtt_Root = RTT_ROOT 60 | BSP_Root = BSP_ROOT 61 | 62 | def BuildHostApplication(TARGET, SConscriptFile): 63 | import platform 64 | 65 | platform_type = platform.system() 66 | if platform_type == 'Windows' or platform_type.find('MINGW') != -1: 67 | TARGET = TARGET.replace('.mo', '.exe') 68 | 69 | sys.path = sys.path + [os.path.join(os.getcwd(), 'tools', 'host')] 70 | 71 | from building import PrepareHostModuleBuilding 72 | 73 | HostRtt = os.path.join(os.getcwd(), 'tools', 'host', 'rtthread') 74 | Env = Environment() 75 | 76 | if not GetOption('verbose'): 77 | # override the default verbose command string 78 | Env.Replace( 79 | ARCOMSTR = 'AR $TARGET', 80 | ASCOMSTR = 'AS $TARGET', 81 | ASPPCOMSTR = 'AS $TARGET', 82 | CCCOMSTR = 'CC $TARGET', 83 | CXXCOMSTR = 'CXX $TARGET', 84 | LINKCOMSTR = 'LINK $TARGET' 85 | ) 86 | 87 | PrepareHostModuleBuilding(Env) 88 | 89 | objs = SConscript(SConscriptFile) 90 | objs += SConscript(HostRtt + '/SConscript') 91 | 92 | target = Env.Program(TARGET, objs) 93 | return 94 | 95 | def BuildHostLibrary(TARGET, SConscriptFile): 96 | import platform 97 | 98 | platform_type = platform.system() 99 | if platform_type == 'Windows' or platform_type.find('MINGW') != -1: 100 | TARGET = TARGET.replace('.mo', '.exe') 101 | 102 | sys.path = sys.path + [os.path.join(os.getcwd(), 'tools', 'host')] 103 | 104 | from building import PrepareHostModuleBuilding 105 | 106 | HostRtt = os.path.join(os.getcwd(), 'tools', 'host', 'rtthread') 107 | Env = Environment() 108 | 109 | if not GetOption('verbose'): 110 | # override the default verbose command string 111 | Env.Replace( 112 | ARCOMSTR = 'AR $TARGET', 113 | ASCOMSTR = 'AS $TARGET', 114 | ASPPCOMSTR = 'AS $TARGET', 115 | CCCOMSTR = 'CC $TARGET', 116 | CXXCOMSTR = 'CXX $TARGET', 117 | LINKCOMSTR = 'LINK $TARGET' 118 | ) 119 | 120 | PrepareHostModuleBuilding(Env) 121 | 122 | objs = SConscript(SConscriptFile) 123 | objs += SConscript(HostRtt + '/SConscript') 124 | 125 | target = Env.Program(TARGET, objs) 126 | return 127 | 128 | 129 | def BuildApplication(TARGET, SConscriptFile, BSP_ROOT = None, RTT_ROOT = None): 130 | global Env 131 | global Rtt_Root 132 | global BSP_Root 133 | 134 | # add comstr option 135 | AddOption('--verbose', 136 | dest='verbose', 137 | action='store_true', 138 | default=False, 139 | help='print verbose information during build') 140 | 141 | # build application in host 142 | if BSP_ROOT == None and RTT_ROOT == None and not os.getenv('BSP_ROOT'): 143 | BuildHostApplication(TARGET, SConscriptFile) 144 | return 145 | 146 | if RTT_ROOT == None and os.getenv('RTT_ROOT'): 147 | RTT_ROOT = os.getenv('RTT_ROOT') 148 | 149 | # handle BSP_ROOT and RTT_ROOT 150 | BuildEnv(BSP_ROOT, RTT_ROOT) 151 | 152 | sys.path = sys.path + [os.path.join(Rtt_Root, 'tools'), BSP_Root] 153 | 154 | # get configuration from BSP 155 | import rtconfig 156 | from rtua import GetCPPPATH 157 | from rtua import GetCPPDEFINES 158 | from building import PrepareModuleBuilding 159 | 160 | linkflags = rtconfig.M_LFLAGS + ' -e main' 161 | CPPPATH = GetCPPPATH(BSP_Root, Rtt_Root) 162 | 163 | if rtconfig.PLATFORM == 'cl': 164 | Env = Environment(TARGET_ARCH='x86') 165 | Env.Append(CCFLAGS=rtconfig.M_CFLAGS) 166 | Env.Append(LINKFLAGS=rtconfig.M_LFLAGS) 167 | Env.Append(CPPPATH=CPPPATH) 168 | Env.Append(LIBS='rtthread', LIBPATH=BSP_Root) 169 | Env.Append(CPPDEFINES=GetCPPDEFINES() + ['RTT_IN_MODULE']) 170 | Env.PrependENVPath('PATH', rtconfig.EXEC_PATH) 171 | else: 172 | Env = Environment(tools = ['mingw'], 173 | AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, 174 | CC = rtconfig.CC, CCFLAGS = rtconfig.M_CFLAGS, 175 | CPPDEFINES = GetCPPDEFINES(), 176 | CXX = rtconfig.CXX, AR = rtconfig.AR, ARFLAGS = '-rc', 177 | LINK = rtconfig.LINK, LINKFLAGS = linkflags, 178 | CPPPATH = CPPPATH) 179 | 180 | if not GetOption('verbose'): 181 | # override the default verbose command string 182 | Env.Replace( 183 | ARCOMSTR = 'AR $TARGET', 184 | ASCOMSTR = 'AS $TARGET', 185 | ASPPCOMSTR = 'AS $TARGET', 186 | CCCOMSTR = 'CC $TARGET', 187 | CXXCOMSTR = 'CXX $TARGET', 188 | LINKCOMSTR = 'LINK $TARGET' 189 | ) 190 | 191 | PrepareModuleBuilding(Env, Rtt_Root, BSP_Root) 192 | 193 | objs = SConscript(SConscriptFile) 194 | 195 | # build program 196 | if rtconfig.PLATFORM == 'cl': 197 | dll_target = TARGET.replace('.mo', '.dll') 198 | target = Env.SharedLibrary(dll_target, objs) 199 | 200 | target = Command("$TARGET", dll_target, [Move(TARGET, dll_target)]) 201 | # target = dll_target 202 | else: 203 | target = Env.Program(TARGET, objs) 204 | 205 | if hasattr(rtconfig, 'M_POST_ACTION'): 206 | Env.AddPostAction(target, rtconfig.M_POST_ACTION) 207 | 208 | if hasattr(rtconfig, 'M_BIN_PATH'): 209 | Env.AddPostAction(target, [Copy(rtconfig.M_BIN_PATH, TARGET)]) 210 | 211 | def BuildLibrary(TARGET, SConscriptFile, BSP_ROOT = None, RTT_ROOT = None): 212 | global Env 213 | global Rtt_Root 214 | global BSP_Root 215 | 216 | # add comstr option 217 | AddOption('--verbose', 218 | dest='verbose', 219 | action='store_true', 220 | default=False, 221 | help='print verbose information during build') 222 | 223 | # build application in host 224 | if BSP_ROOT == None and RTT_ROOT == None and not os.getenv('BSP_ROOT'): 225 | BuildHostLibrary(TARGET, SConscriptFile) 226 | return 227 | 228 | if RTT_ROOT == None and os.getenv('RTT_ROOT'): 229 | RTT_ROOT = os.getenv('RTT_ROOT') 230 | 231 | # handle BSP_ROOT and RTT_ROOT 232 | BuildEnv(BSP_ROOT, RTT_ROOT) 233 | 234 | sys.path = sys.path + [os.path.join(Rtt_Root, 'tools'), BSP_Root] 235 | 236 | # get configuration from BSP 237 | import rtconfig 238 | from rtua import GetCPPPATH 239 | from rtua import GetCPPDEFINES 240 | from building import PrepareModuleBuilding 241 | 242 | linkflags = rtconfig.M_LFLAGS + ' -e 0' 243 | CPPPATH = GetCPPPATH(BSP_Root, Rtt_Root) 244 | 245 | if rtconfig.PLATFORM == 'cl': 246 | Env = Environment(TARGET_ARCH='x86') 247 | Env.Append(CCFLAGS=rtconfig.M_CFLAGS) 248 | Env.Append(LINKFLAGS=rtconfig.M_LFLAGS) 249 | Env.Append(CPPPATH=CPPPATH) 250 | Env.Append(LIBS='rtthread', LIBPATH=BSP_Root) 251 | Env.Append(CPPDEFINES=GetCPPDEFINES() + ['RTT_IN_MODULE']) 252 | Env.PrependENVPath('PATH', rtconfig.EXEC_PATH) 253 | else: 254 | Env = Environment(tools = ['mingw'], 255 | AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, 256 | CC = rtconfig.CC, CCFLAGS = rtconfig.M_CFLAGS, 257 | CPPDEFINES = GetCPPDEFINES(), 258 | CXX = rtconfig.CXX, AR = rtconfig.AR, ARFLAGS = '-rc', 259 | LINK = rtconfig.LINK, LINKFLAGS = linkflags, 260 | CPPPATH = CPPPATH) 261 | 262 | if not GetOption('verbose'): 263 | # override the default verbose command string 264 | Env.Replace( 265 | ARCOMSTR = 'AR $TARGET', 266 | ASCOMSTR = 'AS $TARGET', 267 | ASPPCOMSTR = 'AS $TARGET', 268 | CCCOMSTR = 'CC $TARGET', 269 | CXXCOMSTR = 'CXX $TARGET', 270 | LINKCOMSTR = 'LINK $TARGET' 271 | ) 272 | 273 | PrepareModuleBuilding(Env, Rtt_Root, BSP_Root) 274 | 275 | objs = SConscript(SConscriptFile) 276 | 277 | # build program 278 | if rtconfig.PLATFORM == 'cl': 279 | dll_target = TARGET.replace('.so', '.dll') 280 | target = Env.SharedLibrary(dll_target, objs) 281 | 282 | target = Command("$TARGET", dll_target, [Move(TARGET, dll_target)]) 283 | # target = dll_target 284 | else: 285 | target = Env.Program(TARGET, objs) 286 | 287 | if hasattr(rtconfig, 'M_POST_ACTION'): 288 | Env.AddPostAction(target, rtconfig.M_POST_ACTION) 289 | -------------------------------------------------------------------------------- /ymodem/SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | src = Glob('*.c') + Glob('*.cpp') 4 | cwd = GetCurrentDir() 5 | 6 | CPPPATH = [cwd] 7 | group = DefineGroup('', src, depend = [''], CPPPATH=CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /ymodem/tofile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ymodem.h" 6 | 7 | struct custom_ctx 8 | { 9 | struct rym_ctx parent; 10 | int fd; 11 | int flen; 12 | char fpath[256]; 13 | }; 14 | 15 | static enum rym_code _rym_bg( 16 | struct rym_ctx *ctx, 17 | rt_uint8_t *pbuf, 18 | rt_size_t len) 19 | { 20 | char *buf = (char*)pbuf; 21 | struct custom_ctx *cctx = (struct custom_ctx *)ctx; 22 | cctx->fpath[0] = '\0'; 23 | 24 | /* use current working directory */ 25 | getcwd(cctx->fpath, sizeof(cctx->fpath)); 26 | strcat(cctx->fpath, "/"); 27 | strcat(cctx->fpath, (char*)buf); 28 | 29 | cctx->fd = open(cctx->fpath, O_CREAT | O_WRONLY | O_TRUNC, 0); 30 | if (cctx->fd < 0) 31 | { 32 | rt_err_t err = rt_get_errno(); 33 | rt_kprintf("error creating file: %d\n", err); 34 | rt_kprintf("abort transmission\n"); 35 | return RYM_CODE_CAN; 36 | } 37 | 38 | cctx->flen = atoi(buf + strlen(buf) + 1); 39 | if (cctx->flen == 0) 40 | cctx->flen = -1; 41 | return RYM_CODE_ACK; 42 | } 43 | 44 | static enum rym_code _rym_tof( 45 | struct rym_ctx *ctx, 46 | rt_uint8_t *buf, 47 | rt_size_t len) 48 | { 49 | struct custom_ctx *cctx = (struct custom_ctx *)ctx; 50 | RT_ASSERT(cctx->fd >= 0); 51 | if (cctx->flen == -1) 52 | { 53 | write(cctx->fd, buf, len); 54 | } 55 | else 56 | { 57 | int wlen = len > cctx->flen ? cctx->flen : len; 58 | write(cctx->fd, buf, wlen); 59 | cctx->flen -= wlen; 60 | } 61 | return RYM_CODE_ACK; 62 | } 63 | 64 | static enum rym_code _rym_end( 65 | struct rym_ctx *ctx, 66 | rt_uint8_t *buf, 67 | rt_size_t len) 68 | { 69 | struct custom_ctx *cctx = (struct custom_ctx *)ctx; 70 | 71 | RT_ASSERT(cctx->fd >= 0); 72 | close(cctx->fd); 73 | cctx->fd = -1; 74 | 75 | return RYM_CODE_ACK; 76 | } 77 | 78 | rt_err_t rym_write_to_file(rt_device_t idev) 79 | { 80 | rt_err_t res; 81 | struct custom_ctx *ctx = rt_malloc(sizeof(*ctx)); 82 | 83 | RT_ASSERT(idev); 84 | 85 | rt_kprintf("entering RYM mode\n"); 86 | 87 | res = rym_recv_on_device(&ctx->parent, idev, 88 | _rym_bg, _rym_tof, _rym_end, 1000); 89 | 90 | /* there is no Ymodem traffic on the line so print out info. */ 91 | rt_kprintf("leaving RYM mode with code %d\n", res); 92 | rt_kprintf("file %s has been created.\n", ctx->fpath); 93 | 94 | rt_free(ctx); 95 | 96 | return res; 97 | } 98 | 99 | int main(int argc, char **argv) 100 | { 101 | rt_err_t res; 102 | 103 | if (argc != 2) 104 | { 105 | rt_kprintf("Usage: ymodem device\n"); 106 | return 0; 107 | } 108 | 109 | rt_device_t dev = rt_device_find(argv[1]); 110 | if (!dev) 111 | { 112 | rt_kprintf("could not find device:%s\n", argv[1]); 113 | return -RT_ERROR; 114 | } 115 | 116 | res = rym_write_to_file(dev); 117 | 118 | return res; 119 | } 120 | -------------------------------------------------------------------------------- /ymodem/ymodem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File : ymodem.c 3 | * COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd 4 | * 5 | * Change Logs: 6 | * Date Author Notes 7 | * 2013-04-14 Grissiom initial implementation 8 | */ 9 | 10 | #include 11 | #include "ymodem.h" 12 | 13 | static const rt_uint16_t ccitt_table[256] = 14 | { 15 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 16 | 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 17 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 18 | 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 19 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 20 | 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 21 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 22 | 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 23 | 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 24 | 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 25 | 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 26 | 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 27 | 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 28 | 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 29 | 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 30 | 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 31 | 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 32 | 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 33 | 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 34 | 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 35 | 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 36 | 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 37 | 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 38 | 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 39 | 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 40 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 41 | 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 42 | 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 43 | 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 44 | 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 45 | 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 46 | 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 47 | }; 48 | rt_uint16_t CRC16(unsigned char *q, int len) 49 | { 50 | rt_uint16_t crc = 0; 51 | 52 | while (len-- > 0) 53 | crc = (crc << 8) ^ ccitt_table[((crc >> 8) ^ *q++) & 0xff]; 54 | return crc; 55 | } 56 | 57 | // we could only use global varible because we could not use 58 | // rt_device_t->user_data(it is used by the serial driver)... 59 | static struct rym_ctx *_rym_the_ctx; 60 | 61 | static rt_err_t _rym_rx_ind(rt_device_t dev, rt_size_t size) 62 | { 63 | return rt_sem_release(&_rym_the_ctx->sem); 64 | } 65 | 66 | /* SOH/STX + seq + payload + crc */ 67 | #define _RYM_SOH_PKG_SZ (1+2+128+2) 68 | #define _RYM_STX_PKG_SZ (1+2+1024+2) 69 | 70 | static enum rym_code _rym_read_code( 71 | struct rym_ctx *ctx, 72 | rt_tick_t timeout) 73 | { 74 | /* consume the available sem and read the data in buffer if possible */ 75 | while (rt_sem_trytake(&ctx->sem) == RT_EOK) 76 | ; 77 | if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1) 78 | return *ctx->buf; 79 | /* no data yet, wait for one */ 80 | if (rt_sem_take(&ctx->sem, timeout) != RT_EOK) 81 | return RYM_CODE_NONE; 82 | /* read one */ 83 | if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1) 84 | return *ctx->buf; 85 | return RYM_CODE_NONE; 86 | } 87 | 88 | /* the caller should at least alloc _RYM_STX_PKG_SZ buffer */ 89 | static rt_size_t _rym_read_data( 90 | struct rym_ctx *ctx, 91 | rt_size_t len) 92 | { 93 | /* we should already have had the code */ 94 | rt_uint8_t *buf = ctx->buf + 1; 95 | rt_size_t readlen = 0; 96 | 97 | do 98 | { 99 | readlen += rt_device_read(ctx->dev, 100 | 0, buf + readlen, len - readlen); 101 | if (readlen >= len) 102 | return readlen; 103 | } 104 | while (rt_sem_take(&ctx->sem, RYM_WAIT_CHR_TICK) == RT_EOK); 105 | 106 | return readlen; 107 | } 108 | 109 | static rt_size_t _rym_putchar(struct rym_ctx *ctx, rt_uint8_t code) 110 | { 111 | rt_device_write(ctx->dev, 0, &code, sizeof(code)); 112 | return 1; 113 | } 114 | 115 | static rt_err_t _rym_do_handshake( 116 | struct rym_ctx *ctx, 117 | int tm_sec) 118 | { 119 | enum rym_code code; 120 | rt_size_t i; 121 | rt_uint16_t recv_crc, cal_crc; 122 | 123 | ctx->stage = RYM_STAGE_ESTABLISHING; 124 | /* send C every second, so the sender could know we are waiting for it. */ 125 | for (i = 0; i < tm_sec; i++) 126 | { 127 | _rym_putchar(ctx, RYM_CODE_C); 128 | code = _rym_read_code(ctx, 129 | RYM_CHD_INTV_TICK); 130 | if (code == RYM_CODE_SOH) 131 | break; 132 | } 133 | if (i == tm_sec) 134 | return -RYM_ERR_TMO; 135 | 136 | i = _rym_read_data(ctx, _RYM_SOH_PKG_SZ - 1); 137 | if (i != (_RYM_SOH_PKG_SZ - 1)) 138 | return -RYM_ERR_DSZ; 139 | 140 | /* sanity check */ 141 | if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF) 142 | return -RYM_ERR_SEQ; 143 | 144 | recv_crc = (rt_uint16_t)(*(ctx->buf + _RYM_SOH_PKG_SZ - 2) << 8) | *(ctx->buf + _RYM_SOH_PKG_SZ - 1); 145 | cal_crc = CRC16(ctx->buf + 3, _RYM_SOH_PKG_SZ - 5); 146 | if (recv_crc != cal_crc) 147 | return -RYM_ERR_CRC; 148 | 149 | /* congratulations, check passed. */ 150 | if (ctx->on_begin && ctx->on_begin(ctx, ctx->buf + 3, 128) != RYM_CODE_ACK) 151 | return -RYM_ERR_CAN; 152 | 153 | return RT_EOK; 154 | } 155 | 156 | static rt_err_t _rym_trans_data( 157 | struct rym_ctx *ctx, 158 | rt_size_t data_sz, 159 | enum rym_code *code) 160 | { 161 | const rt_size_t tsz = 2 + data_sz + 2; 162 | rt_uint16_t recv_crc; 163 | 164 | /* seq + data + crc */ 165 | rt_size_t i = _rym_read_data(ctx, tsz); 166 | if (i != tsz) 167 | return -RYM_ERR_DSZ; 168 | 169 | if ((ctx->buf[1] + ctx->buf[2]) != 0xFF) 170 | { 171 | return -RYM_ERR_SEQ; 172 | } 173 | 174 | /* sanity check */ 175 | recv_crc = (rt_uint16_t)(*(ctx->buf + tsz - 1) << 8) | *(ctx->buf + tsz); 176 | if (recv_crc != CRC16(ctx->buf + 3, data_sz)) 177 | return -RYM_ERR_CRC; 178 | 179 | /* congratulations, check passed. */ 180 | if (ctx->on_data) 181 | *code = ctx->on_data(ctx, ctx->buf + 3, data_sz); 182 | else 183 | *code = RYM_CODE_ACK; 184 | return RT_EOK; 185 | } 186 | 187 | static rt_err_t _rym_do_trans(struct rym_ctx *ctx) 188 | { 189 | _rym_putchar(ctx, RYM_CODE_ACK); 190 | _rym_putchar(ctx, RYM_CODE_C); 191 | ctx->stage = RYM_STAGE_ESTABLISHED; 192 | 193 | while (1) 194 | { 195 | rt_err_t err; 196 | enum rym_code code; 197 | rt_size_t data_sz; 198 | 199 | code = _rym_read_code(ctx, 200 | RYM_WAIT_PKG_TICK); 201 | switch (code) 202 | { 203 | case RYM_CODE_SOH: 204 | data_sz = 128; 205 | break; 206 | case RYM_CODE_STX: 207 | data_sz = 1024; 208 | break; 209 | case RYM_CODE_EOT: 210 | return RT_EOK; 211 | default: 212 | return -RYM_ERR_CODE; 213 | }; 214 | ctx->stage = RYM_STAGE_TRANSMITTING; 215 | 216 | err = _rym_trans_data(ctx, data_sz, &code); 217 | if (err != RT_EOK) 218 | return err; 219 | switch (code) 220 | { 221 | case RYM_CODE_CAN: 222 | /* the spec require multiple CAN */ 223 | _rym_putchar(ctx, RYM_CODE_CAN); 224 | _rym_putchar(ctx, RYM_CODE_CAN); 225 | _rym_putchar(ctx, RYM_CODE_CAN); 226 | _rym_putchar(ctx, RYM_CODE_CAN); 227 | _rym_putchar(ctx, RYM_CODE_CAN); 228 | _rym_putchar(ctx, RYM_CODE_CAN); 229 | _rym_putchar(ctx, RYM_CODE_CAN); 230 | _rym_putchar(ctx, RYM_CODE_CAN); 231 | _rym_putchar(ctx, RYM_CODE_CAN); 232 | return -RYM_ERR_CAN; 233 | case RYM_CODE_ACK: 234 | _rym_putchar(ctx, RYM_CODE_ACK); 235 | break; 236 | default: 237 | // wrong code 238 | break; 239 | }; 240 | } 241 | } 242 | 243 | static rt_err_t _rym_do_fin(struct rym_ctx *ctx) 244 | { 245 | enum rym_code code; 246 | rt_uint16_t recv_crc; 247 | rt_size_t i; 248 | 249 | ctx->stage = RYM_STAGE_FINISHING; 250 | /* we already got one EOT in the caller. invoke the callback if there is 251 | * one. */ 252 | if (ctx->on_end) 253 | ctx->on_end(ctx, ctx->buf + 3, 128); 254 | 255 | _rym_putchar(ctx, RYM_CODE_NAK); 256 | code = _rym_read_code(ctx, RYM_WAIT_PKG_TICK); 257 | if (code != RYM_CODE_EOT) 258 | return -RYM_ERR_CODE; 259 | 260 | _rym_putchar(ctx, RYM_CODE_ACK); 261 | _rym_putchar(ctx, RYM_CODE_C); 262 | 263 | code = _rym_read_code(ctx, RYM_WAIT_PKG_TICK); 264 | if (code != RYM_CODE_SOH) 265 | return -RYM_ERR_CODE; 266 | 267 | i = _rym_read_data(ctx, _RYM_SOH_PKG_SZ - 1); 268 | if (i != (_RYM_SOH_PKG_SZ - 1)) 269 | return -RYM_ERR_DSZ; 270 | 271 | /* sanity check 272 | * 273 | * TODO: multiple files transmission 274 | */ 275 | if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF) 276 | return -RYM_ERR_SEQ; 277 | 278 | recv_crc = (rt_uint16_t)(*(ctx->buf + _RYM_SOH_PKG_SZ - 2) << 8) | *(ctx->buf + _RYM_SOH_PKG_SZ - 1); 279 | if (recv_crc != CRC16(ctx->buf + 3, _RYM_SOH_PKG_SZ - 5)) 280 | return -RYM_ERR_CRC; 281 | 282 | /* congratulations, check passed. */ 283 | ctx->stage = RYM_STAGE_FINISHED; 284 | 285 | /* put the last ACK */ 286 | _rym_putchar(ctx, RYM_CODE_ACK); 287 | 288 | return RT_EOK; 289 | } 290 | 291 | static rt_err_t _rym_do_recv( 292 | struct rym_ctx *ctx, 293 | int handshake_timeout) 294 | { 295 | rt_err_t err; 296 | 297 | ctx->stage = RYM_STAGE_NONE; 298 | 299 | ctx->buf = rt_malloc(_RYM_STX_PKG_SZ); 300 | if (ctx->buf == RT_NULL) 301 | return -RT_ENOMEM; 302 | 303 | err = _rym_do_handshake(ctx, handshake_timeout); 304 | if (err != RT_EOK) 305 | return err; 306 | 307 | err = _rym_do_trans(ctx); 308 | if (err != RT_EOK) 309 | { 310 | if (ctx->on_end) 311 | ctx->on_end(ctx, RT_NULL, 0); 312 | return err; 313 | } 314 | 315 | return _rym_do_fin(ctx); 316 | } 317 | 318 | rt_err_t rym_recv_on_device( 319 | struct rym_ctx *ctx, 320 | rt_device_t dev, 321 | rym_callback on_begin, 322 | rym_callback on_data, 323 | rym_callback on_end, 324 | int handshake_timeout) 325 | { 326 | rt_err_t res; 327 | rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size); 328 | rt_uint16_t odev_flag; 329 | int int_lvl; 330 | 331 | RT_ASSERT(_rym_the_ctx == 0); 332 | _rym_the_ctx = ctx; 333 | 334 | ctx->on_begin = on_begin; 335 | ctx->on_data = on_data; 336 | ctx->on_end = on_end; 337 | ctx->dev = dev; 338 | rt_sem_init(&ctx->sem, "rymsem", 0, RT_IPC_FLAG_FIFO); 339 | 340 | odev_rx_ind = dev->rx_indicate; 341 | /* no data should be received before the device has been fully setted up. 342 | */ 343 | int_lvl = rt_hw_interrupt_disable(); 344 | rt_device_set_rx_indicate(dev, _rym_rx_ind); 345 | 346 | odev_flag = dev->flag; 347 | /* make sure the device don't change the content. */ 348 | dev->flag &= ~RT_DEVICE_FLAG_STREAM; 349 | rt_hw_interrupt_enable(int_lvl); 350 | 351 | res = rt_device_open(dev, 0); 352 | if (res != RT_EOK) 353 | goto __exit; 354 | 355 | res = _rym_do_recv(ctx, handshake_timeout); 356 | 357 | rt_device_close(dev); 358 | 359 | __exit: 360 | /* no rx_ind should be called before the callback has been fully detached. 361 | */ 362 | int_lvl = rt_hw_interrupt_disable(); 363 | rt_sem_detach(&ctx->sem); 364 | 365 | dev->flag = odev_flag; 366 | rt_device_set_rx_indicate(dev, odev_rx_ind); 367 | rt_hw_interrupt_enable(int_lvl); 368 | 369 | rt_free(ctx->buf); 370 | _rym_the_ctx = RT_NULL; 371 | 372 | return res; 373 | } 374 | 375 | -------------------------------------------------------------------------------- /ymodem/ymodem.h: -------------------------------------------------------------------------------- 1 | #ifndef __YMODEM_H__ 2 | #define __YMODEM_H__ 3 | /* 4 | * File : ymodem.h 5 | * COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd 6 | * 7 | * Change Logs: 8 | * Date Author Notes 9 | * 2013-04-14 Grissiom initial implementation 10 | */ 11 | 12 | #include "rtthread.h" 13 | 14 | /* The word "RYM" is stand for "Real-YModem". */ 15 | 16 | enum rym_code 17 | { 18 | RYM_CODE_NONE = 0x00, 19 | RYM_CODE_SOH = 0x01, 20 | RYM_CODE_STX = 0x02, 21 | RYM_CODE_EOT = 0x04, 22 | RYM_CODE_ACK = 0x06, 23 | RYM_CODE_NAK = 0x15, 24 | RYM_CODE_CAN = 0x18, 25 | RYM_CODE_C = 0x43, 26 | }; 27 | 28 | /* RYM error code 29 | * 30 | * We use the rt_err_t to return error values. We take use of current error 31 | * codes available in RTT and append ourselves. 32 | */ 33 | /* timeout on handshake */ 34 | #define RYM_ERR_TMO 0x70 35 | /* wrong code, wrong SOH, STX etc. */ 36 | #define RYM_ERR_CODE 0x71 37 | /* wrong sequence number */ 38 | #define RYM_ERR_SEQ 0x72 39 | /* wrong CRC checksum */ 40 | #define RYM_ERR_CRC 0x73 41 | /* not enough data received */ 42 | #define RYM_ERR_DSZ 0x74 43 | /* the transmission is aborted by user */ 44 | #define RYM_ERR_CAN 0x75 45 | 46 | /* how many ticks wait for chars between packet. */ 47 | #ifndef RYM_WAIT_CHR_TICK 48 | #define RYM_WAIT_CHR_TICK (RT_TICK_PER_SECOND * 3) 49 | #endif 50 | /* how many ticks wait for between packet. */ 51 | #ifndef RYM_WAIT_PKG_TICK 52 | #define RYM_WAIT_PKG_TICK (RT_TICK_PER_SECOND * 3) 53 | #endif 54 | /* how many ticks between two handshake code. */ 55 | #ifndef RYM_CHD_INTV_TICK 56 | #define RYM_CHD_INTV_TICK (RT_TICK_PER_SECOND / 4) 57 | #endif 58 | 59 | enum rym_stage 60 | { 61 | RYM_STAGE_NONE, 62 | /* set when C is send */ 63 | RYM_STAGE_ESTABLISHING, 64 | /* set when we've got the packet 0 and sent ACK and second C */ 65 | RYM_STAGE_ESTABLISHED, 66 | /* set when the sender respond to our second C */ 67 | RYM_STAGE_TRANSMITTING, 68 | /* set when the sender send a EOT */ 69 | RYM_STAGE_FINISHING, 70 | /* set when transmission is really finished, i.e., after the NAK, C, final 71 | * NULL packet stuff. */ 72 | RYM_STAGE_FINISHED, 73 | }; 74 | 75 | struct rym_ctx; 76 | /* when receiving files, the buf will be the data received from ymodem protocol 77 | * and the len is the data size. 78 | * 79 | * TODO: 80 | * When sending files, the len is the buf size in RYM. The callback need to 81 | * fill the buf with data to send. Returning RYM_CODE_EOT will terminate the 82 | * transfer and the buf will be discarded. Any other return values will cause 83 | * the transfer continue. 84 | */ 85 | typedef enum rym_code(*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len); 86 | 87 | /* Currently RYM only support one transfer session(ctx) for simplicity. 88 | * 89 | * In case we could support multiple sessions in The future, the first argument 90 | * of APIs are (struct rym_ctx*). 91 | */ 92 | struct rym_ctx 93 | { 94 | rym_callback on_data; 95 | rym_callback on_begin; 96 | rym_callback on_end; 97 | /* When error happened, user need to check this to get when the error has 98 | * happened. */ 99 | enum rym_stage stage; 100 | /* user could get the error content through this */ 101 | rt_uint8_t *buf; 102 | 103 | struct rt_semaphore sem; 104 | 105 | rt_device_t dev; 106 | }; 107 | 108 | /** recv a file on device dev with ymodem session ctx. 109 | * 110 | * If an error happens, you can get where it is failed from ctx->stage. 111 | * 112 | * @param on_begin The callback will be invoked when the first packet arrived. 113 | * This packet often contain file names and the size of the file, if the sender 114 | * support it. So if you want to save the data to a file, you may need to 115 | * create the file on need. It is the on_begin's responsibility to parse the 116 | * data content. The on_begin can be NULL, in which case the transmission will 117 | * continue without any side-effects. 118 | * 119 | * @param on_data The callback will be invoked on the packets received. The 120 | * callback should save the data to the destination. The return value will be 121 | * sent to the sender and in turn, only RYM_{ACK,CAN} is valid. When on_data is 122 | * NULL, RYM will barely send ACK on every packet and have no side-effects. 123 | * 124 | * @param on_end The callback will be invoked when one transmission is 125 | * finished. The data should be 128 bytes of NULL. You can do some cleaning job 126 | * in this callback such as closing the file. The return value of this callback 127 | * is ignored. As above, this parameter can be NULL if you don't need such 128 | * function. 129 | * 130 | * @param handshake_timeout the timeout when hand shaking. The unit is in 131 | * second. 132 | */ 133 | rt_err_t rym_recv_on_device(struct rym_ctx *ctx, rt_device_t dev, 134 | rym_callback on_begin, rym_callback on_data, rym_callback on_end, 135 | int handshake_timeout); 136 | 137 | #endif 138 | --------------------------------------------------------------------------------