├── .cproject
├── .github
├── build.sh
└── workflows
│ └── build.yaml
├── .gitignore
├── .project
├── .settings
├── language.settings.xml
└── org.eclipse.cdt.core.prefs
├── LICENSE
├── Makefile
├── Makefile.loader
├── Makefile.sdk
├── README.md
├── flash
├── flash.h
└── w25q256fv.c
├── img
├── nucleistudio_enter_project_config.png
├── nucleistudio_import_flashloader_1.png
├── nucleistudio_import_flashloader_2.png
├── nucleistudio_modify_build_command.png
├── nucleistudio_modify_flashloader_mode.png
├── nucleistudio_modify_nuclei-sdk_path.png
└── procedure.png
├── loader
├── loader.c
├── riscv.lds
└── startup.S
├── loader_debug_openocd.launch
├── npk.yml
├── spi
├── fespi.c
├── nuspi.c
└── spi.h
└── test
└── main.c
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
--------------------------------------------------------------------------------
/.github/build.sh:
--------------------------------------------------------------------------------
1 | #/bin/env bash
2 |
3 | # Reset
4 | COLOROFF='\033[0m' # Text Reset
5 |
6 | # Regular Colors
7 | BLACK='\033[0;30m' # Black
8 | RED='\033[0;31m' # Red
9 | GREEN='\033[0;32m' # Green
10 | YELLOW='\033[0;33m' # Yellow
11 |
12 | if [ ! -f $NUCLEI_SDK_ROOT/NMSIS_VERSION ] ; then
13 | echo -e "${RED}NUCLEI_SDK_ROOT environment variable is not set or path not valid, please set it to where your Nuclei SDK located!${COLOROFF}"
14 | echo "eg. export NUCLEI_SDK_ROOT=/path/to/nuclei-sdk"
15 | exit 1
16 | else
17 | echo -e "${YELLOW}Setup Nuclei SDK build environment${COLOROFF}"
18 | pushd ${NUCLEI_SDK_ROOT}
19 | echo -e "${GREEN}Nuclei SDK version is $(git describe --tags --always 2>/dev/null || echo "not a git repo, please check version in ${NUCLEI_SDK_ROOT}/npk.yml")${COLOROFF}"
20 | source setup.sh
21 | popd
22 | fi
23 |
24 | echo -e "${YELLOW}Here is your NUCLEI_SDK_ROOT=$NUCLEI_SDK_ROOT ${COLOROFF}"
25 |
26 | # Exit on error
27 | set -e
28 |
29 | echo -e "${YELLOW}Start to do flashloader build test in different build mode${COLOROFF}"
30 | for mode in "sdk" "loader"; do
31 | for arch in "rv32" "rv64"; do
32 | for spi in "nuspi" "fespi"; do
33 | makeflags="MODE=$mode ARCH=$arch SPI=$spi FLASH=w25q256fv"
34 | echo -e "${YELLOW}Clean and build freeloader for $makeflags ${COLOROFF}"
35 | make $makeflags clean all
36 | if [ "$spi" == "fespi" ] && [ "$mode" == "sdk" ]; then
37 | make $makeflags clean
38 | echo -e "${YELLOW}Test in qemu and check whether pass or fail${COLOROFF}"
39 | timeout --foreground -s SIGTERM 30s make $makeflags SIMU=qemu run_qemu
40 | if [ "x$?" == "x0" ] ; then
41 | echo -e "${GREEN}Test in qemu for $makeflags: PASS ${COLOROFF}"
42 | else
43 | echo -e "${RED}Test in qemu for $makeflags: FAIL ${COLOROFF}"
44 | fi
45 | fi
46 | make $makeflags clean
47 | done
48 | done
49 | done
50 |
51 | echo -e "${GREEN}Freeloader build testing passed!${COLOROFF}"
52 |
53 | exit 0
54 |
--------------------------------------------------------------------------------
/.github/workflows/build.yaml:
--------------------------------------------------------------------------------
1 | name: Build OpenOCD Flash Loader
2 |
3 | concurrency:
4 | group: ${{ github.workflow }}-${{ github.ref }}
5 | cancel-in-progress: true
6 |
7 | on:
8 | push:
9 | paths:
10 | - "**"
11 |
12 | pull_request:
13 | paths:
14 | - "*"
15 |
16 | schedule:
17 | - cron: '0 0 */3 * *'
18 |
19 | jobs:
20 | build:
21 | name: build flashloader
22 | runs-on: ${{ matrix.os }}
23 | strategy:
24 | matrix:
25 | os: [ubuntu-22.04]
26 | sdkbranch: [master, develop]
27 |
28 | steps:
29 | - uses: actions/checkout@v4
30 | with:
31 | submodules: recursive
32 | fetch-depth: 0
33 |
34 | - name: Caching tools
35 | uses: actions/cache@v4
36 | with:
37 | path: |
38 | prebuilt_tools/*.tar.bz2
39 | prebuilt_tools/*.zip
40 | prebuilt_tools/*.tar.gz
41 | key: build
42 |
43 | - name: Prepare Tools
44 | if: startsWith(matrix.os, 'ubuntu')
45 | run: |
46 | sudo apt-get -q update
47 | sudo apt install -yq python3 python3-pip unzip libz-dev libssl-dev libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev libncursesw5-dev libncursesw5 libgmp-dev libmpfr-dev libmpc-dev
48 | sudo python3 -m pip install -q --upgrade pip
49 | mkdir -p prebuilt_tools
50 | cd prebuilt_tools
51 | TOOLROOT=$(pwd)
52 | TOOLVER=2025.02
53 | echo "Prepare Nuclei Toolchain $TOOLVER ......"
54 | toolzip=nuclei_riscv_newlibc_prebuilt_linux64_${TOOLVER}.tar.bz2
55 | if [ ! -e $toolzip ] ; then
56 | echo "Download Nuclei toolchain now!"
57 | wget --progress=dot:giga --no-check-certificate https://download.nucleisys.com/upload/files/toolchain/gcc/$toolzip
58 | ls -lh $toolzip
59 | md5sum $toolzip
60 | fi
61 | tar -xjf $toolzip
62 | echo "Prepare Nuclei QEMU $TOOLVER ......."
63 | toolzip=nuclei-qemu-${TOOLVER}-linux-x64.tar.gz
64 | if [ ! -e $toolzip ] ; then
65 | echo "Download Nuclei qemu now!"
66 | wget --progress=dot:giga --no-check-certificate https://download.nucleisys.com/upload/files/toolchain/qemu/$toolzip
67 | ls -lh $toolzip
68 | md5sum $toolzip
69 | fi
70 | tar -xzf $toolzip
71 | if [ -d linux_qemu ] ; then
72 | mv linux_qemu qemu
73 | fi
74 | echo "Check gcc and qemu version"
75 | ldd ./qemu/bin/qemu-system-riscv32
76 | ./qemu/bin/qemu-system-riscv32 --version
77 | ./gcc/bin/riscv64-unknown-elf-gcc -v
78 | cd ..
79 | SDKBRANCH=${{ matrix.sdkbranch }}
80 | echo "Clone Nuclei SDK using branch $SDKBRANCH"
81 | git clone -b $SDKBRANCH --depth 1 https://github.com/Nuclei-Software/nuclei-sdk
82 | cd nuclei-sdk
83 | echo "NUCLEI_TOOL_ROOT=${TOOLROOT}" > setup_config.sh
84 | cd ..
85 |
86 | - name: Build and Test Flashloader
87 | run: |
88 | echo "Set NUCLEI_SDK_ROOT=$(pwd)/nuclei-sdk"
89 | export NUCLEI_SDK_ROOT=$(pwd)/nuclei-sdk
90 | echo "Start to do freeloader build testing"
91 | bash .github/build.sh
92 |
93 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o*
2 | *.dasm
3 | *.verilog
4 | *.bin
5 | *.elf
6 | *.map
7 | build
8 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | openocd-flashloader
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 |
14 |
15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
16 | full,incremental,
17 |
18 |
19 |
20 |
21 |
22 | org.eclipse.cdt.core.cnature
23 | org.eclipse.cdt.core.ccnature
24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.settings/language.settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.cdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999.33724627/NUCLEI_SDK_ROOT/delimiter=;
3 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999.33724627/NUCLEI_SDK_ROOT/operation=append
4 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999.33724627/NUCLEI_SDK_ROOT/value=../nuclei-sdk
5 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999.33724627/append=true
6 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999.33724627/appendContributed=true
7 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999/append=true
8 | environment/project/ilg.gnumcueclipse.managedbuild.cross.riscv.toolchain.base.427724999/appendContributed=true
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | MODE ?= loader
2 | SPI ?= nuspi
3 | FLASH ?= w25q256fv
4 | ARCH ?= rv32
5 |
6 | $(info Build Flash Loader in $(MODE) mode: MODE=$(MODE) SPI=$(SPI) FLASH=$(FLASH) ARCH=$(ARCH))
7 |
8 | ifeq ($(MODE),sdk)
9 | include Makefile.sdk
10 | else
11 | include Makefile.loader
12 | endif
13 |
--------------------------------------------------------------------------------
/Makefile.loader:
--------------------------------------------------------------------------------
1 | # When using Nuclei RISC-V Toolchain <= 2022.12
2 | #CROSS_COMPILE ?= riscv-nuclei-elf-
3 |
4 | # When using Nuclei RISC-V Toolchain >= 2023.10
5 | # see https://github.com/riscv-mcu/riscv-gnu-toolchain/releases
6 | CROSS_COMPILE ?= riscv64-unknown-elf-
7 |
8 |
9 | TARGET ?= loader
10 | ARCH ?= rv32
11 | O ?= build
12 | SPI ?= nuspi
13 | FLASH ?= w25q256fv
14 |
15 | CFLAGS := -nostdlib -nostartfiles -Wall -Os -fPIC -Wunused-result -g
16 |
17 | ifeq ($(ARCH),rv32)
18 | CFLAGS += -march=rv32e -mabi=ilp32e
19 | else
20 | CFLAGS += -march=rv64i -mabi=lp64
21 | endif
22 |
23 | ## source control
24 | C_SRCS := loader/loader.c
25 | C_SRCS += spi/$(SPI).c
26 | C_SRCS += flash/$(FLASH).c
27 | ASM_SRCS := loader/startup.S
28 |
29 | LINKER_SCRIPT := loader/riscv.lds
30 |
31 | INCDIRS := flash loader spi
32 |
33 | ## extra options
34 | CC = $(CROSS_COMPILE)gcc
35 | OBJCOPY = $(CROSS_COMPILE)objcopy
36 | OBJDUMP = $(CROSS_COMPILE)objdump
37 |
38 | CFLAGS += $(addprefix -I,$(sort $(INCDIRS)))
39 |
40 | ## output directory
41 | OUTDIR := $(O)/$(ARCH)
42 |
43 | ## targets
44 | LOADER_PREFIX := $(OUTDIR)/$(TARGET)
45 | LOADER_ELF := $(LOADER_PREFIX).elf
46 | LOADER_BIN := $(LOADER_PREFIX).bin
47 |
48 | ## objects
49 | ASM_OBJS := $(addprefix $(OUTDIR)/, $(ASM_SRCS:=.o))
50 | C_OBJS := $(addprefix $(OUTDIR)/, $(C_SRCS:=.o))
51 |
52 | ALL_SRCS := $(C_SRCS) $(ASM_SRCS)
53 | ALL_OBJS := $(ASM_OBJS) $(C_OBJS)
54 | ALL_DEPS := $(ALL_OBJS:=.d)
55 |
56 | MKDEP_OPT = -MMD -MT $@ -MF $@.d
57 |
58 | all: $(LOADER_BIN)
59 |
60 | ifneq ($(MAKECMDGOALS),clean)
61 | -include $(ALL_DEPS)
62 | endif
63 |
64 | .PHONY: clean all cleanall
65 |
66 | $(LOADER_BIN): $(LOADER_ELF)
67 | $(OBJCOPY) -Obinary $< $@
68 | $(OBJDUMP) -S $< > $(LOADER_PREFIX).dasm
69 |
70 | $(ALL_OBJS): $(OUTDIR)/%.o: %
71 | @mkdir -p $(@D)
72 | $(CC) -c $(CFLAGS) $(MKDEP_OPT) -o $@ $<
73 |
74 | $(LOADER_ELF): $(ALL_OBJS)
75 | $(CC) $(CFLAGS) -T $(LINKER_SCRIPT) $^ -o $@
76 |
77 | clean:
78 | rm -rf $(OUTDIR)
79 |
80 | cleanall:
81 | rm -rf $(O)
82 |
--------------------------------------------------------------------------------
/Makefile.sdk:
--------------------------------------------------------------------------------
1 | TARGET = test_loader
2 |
3 | # TODO: You can change this NUCLEI_SDK_ROOT to where your nuclei sdk located
4 | NUCLEI_SDK_ROOT ?= ../
5 |
6 | SPI ?= nuspi
7 | FLASH ?= w25q256fv
8 | ARCH ?= rv32
9 |
10 | ifeq ($(ARCH),rv32)
11 | CORE := n300fd
12 | RISCV_ARCH := rv32imac
13 | RISCV_ABI := ilp32
14 | RISCV_TUNE :=
15 | else
16 | CORE := nx900fd
17 | RISCV_ARCH := rv64imac
18 | RISCV_ABI := lp64
19 | RISCV_TUNE :=
20 | endif
21 |
22 | C_SRCS := loader/loader.c
23 | C_SRCS += spi/$(SPI).c
24 | C_SRCS += flash/$(FLASH).c
25 | C_SRCS += test/main.c
26 |
27 | # loader/startup.S is not used by this self test
28 | # It is only used by loader itself
29 | ASM_SRCS :=
30 |
31 | INCDIRS := flash loader spi
32 |
33 | include $(NUCLEI_SDK_ROOT)/Build/Makefile.base
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Openocd-Flashloader
2 |
3 | [](https://github.com/riscv-mcu/openflashloader/actions/workflows/build.yaml)
4 |
5 | ## Introduction
6 |
7 | With the increasing number of customers, the standard OpenOCD can no longer met the market demand.
8 |
9 | In order to enable customers to customize the flash driver and loader algorithm of OpenOCD without recompiling the OpenOCD tool,
10 | OpenOCD flashLoader perfectly solves this problem.
11 |
12 | Please refer to the following description for details.
13 |
14 | ## Directory Structure
15 |
16 | The directory structure of openocd-flashloader.
17 |
18 | ```console
19 | openocd-flashloader
20 | ├── flash // FLASH Drivers Directory
21 | │ ├── flash.h // FLASH Driver's API
22 | │ ├── w25q256fv.c // W25Q256FV Driver Source Code
23 | ├── img // Store README.md Needs image
24 | │ ├── procedure.png // Flash Loader Execute Procedure
25 | ├── loader // Flash Loader Directory
26 | │ ├── loader.c // Loader Source Code
27 | │ ├── riscv.lds // Loader Link Script
28 | │ ├── startup.S // Loader startup file
29 | ├── spi // SPI Driver Directory
30 | │ ├── spi.h // SPI Driver's API
31 | │ ├── nuspi.c // Nuclei SPI Driver
32 | │ ├── fespi.c // Sifive SPI Driver
33 | ├── test // Loader Tests Directory
34 | │ ├── main.c // Loader Self-test Code
35 | ├── .gitignore // Git Ignore File
36 | ├── Makefile // Main Makefile
37 | ├── Makefile.loader // Loader Makefile
38 | ├── Makefile.sdk // Tests Makefile
39 | ├── README.md // Readme
40 | ```
41 |
42 | ## Execute Procedure
43 |
44 | Nuclei OpenOCD will load the flash loader binary which specified in openocd configuration file using ``flash bank name custom`` feature, see https://doc.nucleisys.com/nuclei_tools/openocd/intro.html#nuclei-customized-features
45 |
46 | The flash loader(loader/loader.c) binary will ``loader_main`` with parameters passed in openocd custom flash driver, see https://github.com/riscv-mcu/riscv-openocd/blob/a383d1d034d87b6527e9e9ee8426973b7e0a12d0/src/flash/nor/custom.c#L111-L270
47 |
48 | > Nuclei OpenOCD source code can be found in https://github.com/riscv-mcu/riscv-openocd/
49 | >
50 | > Nuclei OpenOCD documentation can be found in https://doc.nucleisys.com/nuclei_tools/openocd/intro.html
51 |
52 | 
53 |
54 | ## Prerequisites
55 |
56 | **The following environment must be setuped**
57 |
58 | - **Nuclei Studio Version >= 2024.02**, which contains prebuilt gcc and openocd
59 |
60 | > [!IMPORTANT]
61 | >
62 | > **WARNING** Don't use any global variables in flashloader implementation source code.
63 |
64 | > [!IMPORTANT]
65 | >
66 | > **WARNING** These events cause a system reset and require the user to initialize the corresponding controllers themselves.
67 | >
68 | > 1、gdb-flash-erase-start "reset init
69 | >
70 | > 2、gdb-flash-write-end "reset halt"
71 |
72 | ## Flash Driver API
73 |
74 | This section mainly describe the flash driver API you must implemented for your own flash driver.
75 |
76 | If some argument is not suitable for you, you can ignore it or use it as your requirement.
77 |
78 | eg. ``spi_base`` in this flash driver API maybe not suitable for the case which flash are not interfaced via
79 | spi, but it is passed to this via openocd ``flash bank`` command, see https://doc.nucleisys.com/nuclei_tools/openocd/intro.html#nuclei-customized-features
80 |
81 | #### flash_init
82 |
83 | ****
84 |
85 | **Prototype**
86 |
87 | ```c
88 | int flash_init(uint32_t *spi_base);
89 | ```
90 |
91 | **Description**
92 |
93 | Initialize nuspi, read flash ID and return the flash ID.
94 |
95 | **Parameters**
96 |
97 | * spi_base: SPI base address.
98 |
99 | **Return values**
100 |
101 | Flash ID
102 |
103 | #### flash_erase
104 |
105 | ****
106 |
107 | **Prototype**
108 |
109 | ```c
110 | int flash_erase(uint32_t *spi_base, uint32_t start_addr, uint32_t end_addr);
111 | ```
112 |
113 | **Description**
114 |
115 | Erases Flash space between **start_addr** and **end_addr**.
116 |
117 | **Parameters**
118 |
119 | * spi_base: SPI base address.
120 | * start_addr: start addr of the flash to be erased.
121 | * end_addr: end addr of the flash to be erased.
122 |
123 | **Return values**
124 |
125 | * 0: OK
126 | * Other: ERROR
127 |
128 | #### flash_write
129 |
130 | ****
131 |
132 | **Prototype**
133 |
134 | ```c
135 | int flash_write(uint32_t *spi_base, uint8_t* buffer, uint32_t offset, uint32_t count);
136 | ```
137 |
138 | **Description**
139 |
140 | Write the **count** data from **buffer** to flash's **offset**.
141 |
142 | **Parameters**
143 |
144 | * spi_base: SPI base address.
145 | * buffer: source address.
146 | * offset: flash offset.
147 | * count: number of bytes to be write.
148 |
149 | **Return values**
150 |
151 | * 0: OK
152 | * Other: ERROR
153 |
154 | #### flash_read
155 |
156 | ****
157 |
158 | **Prototype**
159 |
160 | ```c
161 | int flash_read(uint32_t *spi_base, uint8_t* buffer, uint32_t offset, uint32_t count);
162 | ```
163 |
164 | **Description**
165 |
166 | Read the **count** data from flash's **offset** to **buffer**.
167 |
168 | **Parameters**
169 |
170 | * spi_base: SPI base address.
171 | * buffer: destination address.
172 | * offset: flash offset.
173 | * count: number of bytes to be read.
174 |
175 | **Return values**
176 |
177 | * 0: OK
178 | * Other: ERROR
179 |
180 | ## How To Compile In Command Line
181 |
182 | To compile this flashloader code, you need to install Nuclei RISC-V Toolchain or Nuclei Studio(preferred, which contains the toolchain in ``/toolchain/gcc``), see https://nucleisys.com/download.php#tools
183 |
184 | You can directly setup environment **PATH** via command line before you build flashloader.
185 |
186 | ```shell
187 | # Assume that you have downloaded Nuclei Studio latest version, currently 2024.02
188 | # Please change NUCLEI_TOOL_ROOT to the real path of where your toolchain folder located in windows or linux
189 |
190 | # Only execute commands below, if you are in windows cmd terminal
191 | set NUCLEI_TOOL_ROOT=C:\NucleiStudio\toolchain
192 | set PATH=%NUCLEI_TOOL_ROOT%\gcc\bin;%NUCLEI_TOOL_ROOT%\openocd\bin;%NUCLEI_TOOL_ROOT%\build-tools\bin;%NUCLEI_TOOL_ROOT%\qemu\bin;%PATH%
193 |
194 | # Only execute commands below, if you are in linux bash terminal
195 | NUCLEI_TOOL_ROOT=~/NucleiStudio/toolchain
196 | export PATH=$NUCLEI_TOOL_ROOT/gcc/bin:$NUCLEI_TOOL_ROOT/openocd/bin:$NUCLEI_TOOL_ROOT/qemu/bin:$PATH
197 | ```
198 |
199 | In this repo, we provide sample flash loader implementation code which can be directly used with our Nuclei Evaluation SoC(SPI=nuspi FLASH=w25q256fv),
200 | which means you can check and verify it directly without any modification to see how it will work.
201 |
202 | For Nuclei Evalation SoC doc, please contact with our support engineer to get it.
203 |
204 | ### Compile/Debug Self-Test
205 |
206 | This self test code in ``test/main.c`` is mainly used to validate whether the loader implementation
207 | is ok or not.
208 |
209 | > You need to check **TODO** in this ``test/main.c``
210 |
211 | Here we use [Nuclei SDK](https://github.com/Nuclei-Software/nuclei-sdk) as self-test code
212 | executing environment, **if your board is not yet supported by Nuclei SDK**, you will not be
213 | able to do this test, you will need to port this selftest code in `test/main.c` to your environment,
214 | the required other source files see ``Makefile.sdk``
215 |
216 | Here below are just some sample commands when you are using nuclei sdk to test and validate
217 | your flash loader implementation.
218 |
219 | ```shell
220 | ## set NUCLEI_SDK_ROOT variable required by this self test code, see Makefile.sdk
221 | set NUCLEI_SDK_ROOT=D:\Nuclei_Work\Git\nuclei-sdk
222 |
223 | ## SPI and FLASH make variable should be changed to match your real spi and flash driver name
224 | ## Here list some sample build command and debug command using gdb
225 |
226 | ## compile/debug self-test with rv32 spi:nuspi.c flash:w25q256fv.c
227 | make ARCH=rv32 MODE=sdk SPI=nuspi FLASH=w25q256fv clean all
228 | make ARCH=rv32 MODE=sdk SPI=nuspi FLASH=w25q256fv debug
229 |
230 | ## compile/debug self-test with rv64 spi:nuspi.c flash:w25q256fv.c
231 | make ARCH=rv64 MODE=sdk SPI=nuspi FLASH=w25q256fv clean all
232 | make ARCH=rv64 MODE=sdk SPI=nuspi FLASH=w25q256fv debug
233 |
234 | ## compile/debug self-test with rv32 spi:fespi.c flash:w25q256fv.c
235 | make ARCH=rv32 MODE=sdk SPI=fespi FLASH=w25q256fv clean all
236 | make ARCH=rv32 MODE=sdk SPI=fespi FLASH=w25q256fv debug
237 |
238 | ## compile/debug self-test with rv64 spi:fespi.c flash:w25q256fv.c
239 | make ARCH=rv64 MODE=sdk SPI=fespi FLASH=w25q256fv clean all
240 | make ARCH=rv64 MODE=sdk SPI=fespi FLASH=w25q256fv debug
241 | ```
242 |
243 | > [!NOTE]
244 | >
245 | > The loader can only be compiled if self-test has passed.
246 | >
247 | > The **SPI** compile option is used to specify the spi driver source file without the suffix.
248 | >
249 | > The **FLASH** compile option is used to specify the flash driver source file without the suffix.
250 |
251 | ### Compile Flashloader
252 |
253 | When your flash loader implementation is done and validated using your environment,
254 | you can build this flashloader binary and use it with openocd.
255 |
256 | ```shell
257 | # build loader spi:nuspi.c flash:w25q256fv.c
258 | make ARCH=rv32 MODE=loader SPI=nuspi FLASH=w25q256fv clean all
259 | make ARCH=rv64 MODE=loader SPI=nuspi FLASH=w25q256fv clean all
260 |
261 | # build loader spi:fespi.c flash:w25q256fv.c
262 | make ARCH=rv32 MODE=loader SPI=fespi FLASH=w25q256fv clean all
263 | make ARCH=rv64 MODE=loader SPI=fespi FLASH=w25q256fv clean all
264 | ```
265 |
266 | **Flashloader can be found** in ``build/rv32/loader.bin`` for ``ARCH=rv32``,
267 | and ``build/rv64/loader.bin`` for ``ARCH=rv64``.
268 |
269 | ## How To Compile In NucleiStudio
270 |
271 | 1. **Clone Repositories**
272 | Clone or download the source code from GitHub or Gitee websites. The repository links are as follows:
273 |
274 | - [GitHub - RISCV-MCU/openflashloader](https://github.com/riscv-mcu/openflashloader)
275 |
276 | - [Gitee - RISCV-MCU/openflashloader](https://gitee.com/riscv-mcu/openflashloader)
277 |
278 | - [GitHub - Nuclei-Software/nuclei-sdk](https://github.com/Nuclei-Software/nuclei-sdk)
279 |
280 | 2. **Import Project**
281 | Follow these steps in NucleiStudio:
282 | 
283 |
284 | To import the openflashloader project:
285 |
286 | 1. Download the ZIP archive from the openflashloader repository on GitHub or Gitee websites for import (left side of the figure)
287 |
288 | 2. Clone the source code repository via git for import (right side of the figure).
289 |
290 | Follow the steps shown in the figure below to complete the openflashloader project import process.
291 |
292 | 
293 |
294 | 3. **Configuration**
295 |
296 | After importing the openflashloader project into NucleiStudio, you can switch the build mode (Loader represents mode=loader in compilation options, SDK represents mode=sdk in compilation options) by following these steps shown in the figure below:
297 |
298 | > Right-click the project -> Build Configurations -> Set Active -> mode.
299 |
300 | 
301 |
302 | After switching the compilation mode, you can access the configuration options page for the selected mode by following the steps shown in the figure below.
303 |
304 | > Right-click the project -> Properties.
305 |
306 | 
307 |
308 | After entering the project's mode configuration options page, you can modify the compilation options by adjusting the Build and Clean settings.
309 |
310 | > under C/C++ Build->Behavior.
311 |
312 | 
313 |
314 | When switching to SDK mode, you need to set NUCLEI_SDK_ROOT to the path of nuclei-sdk (since SDK mode relies on nuclei-sdk).
315 |
316 | > under the C/C++ Build->Environment section.
317 |
318 | 
319 |
320 | ## How To Use
321 |
322 | Implement your own flash driver to match above `Flash driver API`, this flash loader is called via openocd **custom** loader developed in https://github.com/riscv-mcu/riscv-openocd/blob/a383d1d034d87b6527e9e9ee8426973b7e0a12d0/src/flash/nor/custom.c#L111-L270.
323 |
324 | - Flash driver reference: `flash/w25q256fv.c`
325 |
326 | - SPI driver reference maybe used by flash: `spi/nuspi.c`How To Use
327 |
328 | Implement your own flash driver to match above `Flash driver API`, this flash loader is called via openocd **custom** loader developed in https://github.com/riscv-mcu/riscv-openocd/blob/a383d1d034d87b6527e9e9ee8426973b7e0a12d0/src/flash/nor/custom.c#L111-L270.
329 |
330 | - Flash driver reference: `flash/w25q256fv.c`
331 | - SPI driver reference maybe used by flash: `spi/nuspi.c`
332 |
333 | ### Flash Bank Configuration
334 |
335 | If your flashloader binary is validated and compiled successfully with above steps, now you can
336 | use it with openocd now, you need to modify your openocd configuration file, sample configuration
337 | file for Nuclei HBird Debugger to access to Nuclei Evaluation SoC, please see
338 |
339 | - https://github.com/Nuclei-Software/nuclei-sdk/blob/develop/SoC/evalsoc/Board/nuclei_fpga_eval/openocd_evalsoc.cfg
340 | - https://github.com/Nuclei-Software/nuclei-sdk/blob/develop/SoC/gd32vf103/Board/gd32vf103v_rvstar/openocd_gd32vf103.cfg
341 |
342 | For Nuclei OpenOCD guide, see https://doc.nucleisys.com/nuclei_tools/openocd/intro.html
343 |
344 | ```shell
345 | # openocd flash bank configure command(only parameters in parentheses can be modified)
346 | # For detail flash bank explaination, see openocd/doc/pdf/openocd.pdf
347 | flash bank $FLASHNAME custom 0 0 0 $TARGETNAME [simulation]
348 |
349 | # openocd flash bank configure example
350 | # Please change 0x20000000 - the spiflash xip address to the real address of your spiflash xip address
351 | # please change 0x10014000 - the spi base to access the spiflash to the real spi base to access your spiflash or some other value required by you
352 | # please change /path/to/loader.bin to the real path of your flash loader binary
353 | flash bank $FLASHNAME custom 0x20000000 0 0 0 $TARGETNAME 0x10014000 /path/to/loader.bin
354 | # while [simulation] exist, the loader's timeout=0xFFFFFFFF
355 | flash bank $FLASHNAME custom 0x20000000 0 0 0 $TARGETNAME 0x10014000 /path/to/loader.bin simulation
356 | ```
357 |
358 | If the configuration is modified, eg. call it ``openocd.cfg``, then you can use run following command to test it:
359 |
360 | ```shell
361 | openocd -f /path/to/openocd.cfg
362 | ```
363 |
364 | > [!NOTE]
365 | >
366 | > **custom** is the keyword and should not be changed with others.
367 | >
368 | > In the current command **custom** option can't be modified.
369 | >
370 | > **** option advised to write the full path, because you maybe don't know where you are.
371 |
372 | ## Error Codes
373 |
374 | | Description | Value |
375 | | ------------------------ | --------- |
376 | | RETURN_OK | 0x0 |
377 | | RETURN_ERROR | 0x1 << 31 |
378 | | RETURN_FLASH_WIP_ERROR | 0x1 << 0 |
379 | | RETURN_FLASH_ERASE_ERROR | 0x1 << 1 |
380 | | RETURN_FLASH_WRITE_ERROR | 0x1 << 2 |
381 | | RETURN_FLASH_READ_ERROR | 0x1 << 3 |
382 | | RETURN_SPI_TX_ERROR | 0x1 << 4 |
383 | | RETURN_SPI_RX_ERROR | 0x1 << 5 |
--------------------------------------------------------------------------------
/flash/flash.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define RETURN_FLASH_WIP_ERROR (0x1 << 0)
4 | #define RETURN_FLASH_ERASE_ERROR (0x1 << 1)
5 | #define RETURN_FLASH_WRITE_ERROR (0x1 << 2)
6 | #define RETURN_FLASH_READ_ERROR (0x1 << 3)
7 |
8 | int flash_init(uint32_t *spi_base);
9 | int flash_erase(uint32_t *spi_base, uint32_t start_addr, uint32_t end_addr);
10 | int flash_write(uint32_t *spi_base, uint8_t* buffer, uint32_t offset, uint32_t count);
11 | int flash_read(uint32_t *spi_base, uint8_t* buffer, uint32_t offset, uint32_t count);
12 |
--------------------------------------------------------------------------------
/flash/w25q256fv.c:
--------------------------------------------------------------------------------
1 | #include "flash.h"
2 | #include "spi.h"
3 |
4 | /* WARNING: NEVER USE GLOBAL VARIABLE IN THIS FILE */
5 |
6 | /*==== FLASH ====*/
7 | #define SPIFLASH_BSY 0
8 | #define SPIFLASH_BSY_BIT (1 << SPIFLASH_BSY) /* WIP Bit of SPI SR */
9 | /* SPI Flash Commands */
10 | #define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */
11 | #define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */
12 | #define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */
13 | #define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */
14 | #define SPIFLASH_PAGE_SIZE 0x100
15 | #define SPIFLASH_READ 0x03 /* Normal Read */
16 | #define SPIFLASH_BLOCK_ERASE 0xD8 /* Block Erase */
17 | #define SPIFLASH_BLOCK_SIZE 0x10000
18 |
19 | static inline int flash_wip(uint32_t *spi_base)
20 | {
21 | int retval = 0;
22 | uint8_t value = 0;
23 | /* read status */
24 | spi_cs(spi_base, true);
25 | value = SPIFLASH_READ_STATUS;
26 | retval |= spi_tx(spi_base, &value, 1);
27 | while (1) {
28 | retval |= spi_rx(spi_base, &value, 1);
29 | if ((value & SPIFLASH_BSY_BIT) == 0) {
30 | break;
31 | }
32 | }
33 | spi_cs(spi_base, false);
34 | if (retval) {
35 | return retval | RETURN_FLASH_WIP_ERROR;
36 | }
37 | return retval;
38 | }
39 |
40 | int flash_init(uint32_t *spi_base)
41 | {
42 | int retval = 0;
43 | uint8_t value[3] = {0};
44 | spi_init(spi_base);
45 | /* read flash id */
46 | spi_hw(spi_base, false);
47 | spi_cs(spi_base, true);
48 | value[0] = SPIFLASH_READ_ID;
49 | retval |= spi_tx(spi_base, value, 1);
50 | retval |= spi_rx(spi_base, value, 3);
51 | spi_cs(spi_base, false);
52 | spi_hw(spi_base, true);
53 | retval = (value[2] << 16) | (value[1] << 8) | value[0];
54 | return retval;
55 | }
56 |
57 | int flash_erase(uint32_t *spi_base, uint32_t start_addr, uint32_t end_addr)
58 | {
59 | int retval = 0;
60 | uint8_t value[4] = {0};
61 | uint32_t curr_addr = start_addr;
62 | uint32_t sector_num = (end_addr - start_addr) / SPIFLASH_BLOCK_SIZE;
63 | /* erase flash */
64 | spi_hw(spi_base, false);
65 | for (int i = 0;i < sector_num;i++) {
66 | /* send write enable cmd */
67 | spi_cs(spi_base, true);
68 | value[0] = SPIFLASH_WRITE_ENABLE;
69 | retval |= spi_tx(spi_base, value, 1);
70 | spi_cs(spi_base, false);
71 | /* send erase cmd and addr*/
72 | spi_cs(spi_base, true);
73 | value[0] = SPIFLASH_BLOCK_ERASE;
74 | value[1] = curr_addr >> 16;
75 | value[2] = curr_addr >> 8;
76 | value[3] = curr_addr >> 0;
77 | retval |= spi_tx(spi_base, value, 4);
78 | spi_cs(spi_base, false);
79 | retval |= flash_wip(spi_base);
80 | curr_addr += SPIFLASH_BLOCK_SIZE;
81 | }
82 | spi_hw(spi_base, true);
83 | if (retval) {
84 | return retval | RETURN_FLASH_ERASE_ERROR;
85 | }
86 | return retval;
87 | }
88 |
89 | int flash_write(uint32_t *spi_base, uint8_t* buffer, uint32_t offset, uint32_t count)
90 | {
91 | int retval = 0;
92 | uint8_t value[4] = {0};
93 | uint32_t cur_offset = offset % SPIFLASH_PAGE_SIZE;
94 | uint32_t cur_count = 0;
95 | /* write flash */
96 | spi_hw(spi_base, false);
97 | while (count > 0) {
98 | if ((cur_offset + count) >= SPIFLASH_PAGE_SIZE) {
99 | cur_count = SPIFLASH_PAGE_SIZE - cur_offset;
100 | } else {
101 | cur_count = count;
102 | }
103 | cur_offset = 0;
104 | /* send write enable cmd */
105 | spi_cs(spi_base, true);
106 | value[0] = SPIFLASH_WRITE_ENABLE;
107 | retval |= spi_tx(spi_base, value, 1);
108 | spi_cs(spi_base, false);
109 | /* send write cmd and addr*/
110 | spi_cs(spi_base, true);
111 | value[0] = SPIFLASH_PAGE_PROGRAM;
112 | value[1] = offset >> 16;
113 | value[2] = offset >> 8;
114 | value[3] = offset >> 0;
115 | retval |= spi_tx(spi_base, value, 4);
116 | retval |= spi_tx(spi_base, buffer, cur_count);
117 | spi_cs(spi_base, false);
118 | retval |= flash_wip(spi_base);
119 | buffer += cur_count;
120 | offset += cur_count;
121 | count -= cur_count;
122 | }
123 | spi_hw(spi_base, true);
124 | if (retval) {
125 | return retval | RETURN_FLASH_WRITE_ERROR;
126 | }
127 | return retval;
128 | }
129 |
130 | int flash_read(uint32_t *spi_base, uint8_t* buffer, uint32_t offset, uint32_t count)
131 | {
132 | int retval = 0;
133 | uint8_t value[4] = {0};
134 | /* read flash */
135 | spi_hw(spi_base, false);
136 | /* send read cmd and addr*/
137 | spi_cs(spi_base, true);
138 | value[0] = SPIFLASH_READ;
139 | value[1] = offset >> 16;
140 | value[2] = offset >> 8;
141 | value[3] = offset >> 0;
142 | retval |= spi_tx(spi_base, value, 4);
143 | retval |= spi_rx(spi_base, buffer, count);
144 | spi_cs(spi_base, false);
145 | retval |= flash_wip(spi_base);
146 | spi_hw(spi_base, true);
147 | if (retval) {
148 | return retval | RETURN_FLASH_READ_ERROR;
149 | }
150 | return retval;
151 | }
152 |
--------------------------------------------------------------------------------
/img/nucleistudio_enter_project_config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/nucleistudio_enter_project_config.png
--------------------------------------------------------------------------------
/img/nucleistudio_import_flashloader_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/nucleistudio_import_flashloader_1.png
--------------------------------------------------------------------------------
/img/nucleistudio_import_flashloader_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/nucleistudio_import_flashloader_2.png
--------------------------------------------------------------------------------
/img/nucleistudio_modify_build_command.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/nucleistudio_modify_build_command.png
--------------------------------------------------------------------------------
/img/nucleistudio_modify_flashloader_mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/nucleistudio_modify_flashloader_mode.png
--------------------------------------------------------------------------------
/img/nucleistudio_modify_nuclei-sdk_path.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/nucleistudio_modify_nuclei-sdk_path.png
--------------------------------------------------------------------------------
/img/procedure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/riscv-mcu/openflashloader/a74964a2db08a7542eff9245210b4144c387d0a2/img/procedure.png
--------------------------------------------------------------------------------
/loader/loader.c:
--------------------------------------------------------------------------------
1 | #include "flash.h"
2 |
3 | /* WARNING: NEVER USE GLOBAL VARIABLE IN THIS FILE */
4 |
5 | /*==== Loader ====*/
6 | #define ERASE_CMD (1)
7 | #define WRITE_CMD (2)
8 | #define READ_CMD (3)
9 | #define PROBE_CMD (4)
10 |
11 | #define RETURN_OK (0)
12 | #define RETURN_ERROR (0x1 << 31)
13 |
14 | int loader_main(uint32_t cs, uint32_t *spi_base, uint32_t params1, uint32_t params2, uint32_t params3)
15 | {
16 | int retval = 0;
17 | unsigned long params1_temp = params1;
18 | switch (cs)
19 | {
20 | case ERASE_CMD:
21 | retval = flash_erase(spi_base, params1, params2);
22 | break;
23 | case WRITE_CMD:
24 | retval = flash_write(spi_base, (uint8_t*)params1_temp, params2, params3);
25 | break;
26 | case READ_CMD:
27 | retval = flash_read(spi_base, (uint8_t*)params1_temp, params2, params3);
28 | break;
29 | case PROBE_CMD:
30 | retval = flash_init(spi_base);
31 | break;
32 | default:
33 | retval = RETURN_ERROR;
34 | break;
35 | }
36 | return retval;
37 | }
38 |
--------------------------------------------------------------------------------
/loader/riscv.lds:
--------------------------------------------------------------------------------
1 | OUTPUT_ARCH( "riscv" )
2 |
3 | SECTIONS
4 | {
5 | . = 0x80000000;
6 |
7 | .text :
8 | {
9 | *(.text.entry)
10 | *(.text)
11 | }
12 |
13 | .data :
14 | {
15 | *(.data)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/loader/startup.S:
--------------------------------------------------------------------------------
1 | #if __riscv_xlen == 64
2 | # define LREG ld
3 | # define SREG sd
4 | # define REGBYTES 8
5 | #else
6 | # define LREG lw
7 | # define SREG sw
8 | # define REGBYTES 4
9 | #endif
10 |
11 | .section .text.entry
12 | .global _start
13 | _start:
14 | lla sp, stack_end
15 |
16 | lla t0, early_exc_entry
17 | csrw mtvec, t0
18 | csrw mcause, x0
19 | csrw mtval, x0
20 |
21 | /* no global variables or static variables are allowed in loader_main and its called sub functions */
22 | /* TODO: take care of the stack size usage, if your function and subfunction are complex and use many variable */
23 | jal loader_main
24 |
25 | ebreak
26 |
27 | /* Early boot exception entry before main */
28 | .align 6
29 | .global early_exc_entry
30 | .type early_exc_entry, @function
31 | early_exc_entry:
32 | wfi
33 | j early_exc_entry
34 |
35 | .section .data
36 | .balign REGBYTES
37 | stack:
38 | /* TODO: Change 128 to bigger size if your code is complex and workarea is big enough */
39 | /* Otherwise it may crupt normal text section code */
40 | .fill 128, REGBYTES, 0x8675309
41 | stack_end:
42 |
--------------------------------------------------------------------------------
/loader_debug_openocd.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/npk.yml:
--------------------------------------------------------------------------------
1 | ## Package Base Information
2 | name: app-nsdk_flashloader_test
3 | owner: nuclei
4 | version: 1.0.0
5 | description: Nuclei OpenOCD Flashloader Test
6 | type: app
7 | keywords:
8 | - baremetal
9 | - get started
10 | - flashloader
11 | category: baremetal application
12 | license: Apache-2.0
13 | homepage: https://github.com/riscv-mcu/openflashloader
14 |
15 | ## Package Dependency
16 | dependencies:
17 | - name: sdk-nuclei_sdk
18 | owner: nuclei
19 | version:
20 | - name: ssp-nsdk_evalsoc
21 | owner: nuclei
22 | version:
23 |
24 | ## Package Configurations
25 | configuration:
26 | app_commonflags:
27 | value: -O2
28 | type: text
29 | description: Application Compile Flags
30 |
31 | ## Set Configuration for other packages
32 | setconfig:
33 |
34 |
35 | ## Source Code Management
36 | codemanage:
37 | copyfiles:
38 | - path: ["flash/w25q256fv.c", "flash/flash.h"]
39 | - path: ["spi/nuspi.c", "spi/spi.h"]
40 | - path: ["loader/loader.c"]
41 | - path: ["test/main.c"]
42 | incdirs:
43 | - path: ["spi", "loader", "flash"]
44 | libdirs:
45 | ldlibs:
46 | - libs:
47 |
48 | ## Build Configuration
49 | buildconfig:
50 | - type: common
51 | common_flags: # flags need to be combined together across all packages
52 | - flags: ${app_commonflags}
53 |
--------------------------------------------------------------------------------
/spi/fespi.c:
--------------------------------------------------------------------------------
1 | #include "spi.h"
2 |
3 | /* WARNING: NEVER USE GLOBAL VARIABLE IN THIS FILE */
4 |
5 | /* Register offsets */
6 | #define FESPI_REG_SCKMODE (0x04)
7 | #define FESPI_REG_FORCE (0x0C)
8 | #define FESPI_REG_CSMODE (0x18)
9 | #define FESPI_REG_FMT (0x40)
10 | #define FESPI_REG_TXDATA (0x48)
11 | #define FESPI_REG_RXDATA (0x4C)
12 | #define FESPI_REG_FCTRL (0x60)
13 | #define FESPI_REG_FFMT (0x64)
14 | #define FESPI_REG_IP (0x74)
15 | #define FESPI_REG_STATUS (0x7C)
16 | #define FESPI_REG_RXEDGE (0x80)
17 | /* IP register */
18 | #define FESPI_IP_TXWM (0x1)
19 | /* FCTRL register */
20 | #define FESPI_FCTRL_EN (0x1)
21 | #define FESPI_INSN_CMD_EN (0x1)
22 | /* FMT register */
23 | #define FESPI_FMT_DIR(x) (((x) & 0x1) << 3)
24 | /* STATUS register */
25 | #define FESPI_STAT_BUSY (0x1 << 0)
26 | #define FESPI_STAT_TXFULL (0x1 << 4)
27 | #define FESPI_STAT_RXEMPTY (0x1 << 5)
28 | #define FESPI_CSMODE_AUTO (0)
29 | #define FESPI_CSMODE_HOLD (2)
30 | #define FESPI_DIR_RX (0)
31 | #define FESPI_DIR_TX (1)
32 |
33 | #define FESPI_TX_TIMES_OUT (500)
34 | #define FESPI_RX_TIMES_OUT (500)
35 |
36 | static inline void fespi_read_reg(uint32_t volatile *spi_base, uint32_t offset, uint32_t *value)
37 | {
38 | *value = spi_base[offset / 4];
39 | }
40 |
41 | static inline void fespi_write_reg(uint32_t volatile *spi_base, uint32_t offset, uint32_t value)
42 | {
43 | spi_base[offset / 4] = value;
44 | }
45 |
46 | static inline void fespi_set_dir(uint32_t *spi_base, uint32_t dir)
47 | {
48 | uint32_t fmt = 0;
49 | fespi_read_reg(spi_base, FESPI_REG_FMT, &fmt);
50 | fespi_write_reg(spi_base, FESPI_REG_FMT, (fmt & ~(FESPI_FMT_DIR(0xFFFFFFFF))) | FESPI_FMT_DIR(dir));
51 | }
52 |
53 | void spi_init(uint32_t *spi_base)
54 | {
55 | /* clear rxfifo */
56 | uint32_t value = 0;
57 | while (1) {
58 | fespi_read_reg(spi_base, FESPI_REG_RXDATA, &value);
59 | if (value >> 31) {
60 | break;
61 | }
62 | }
63 | /* init register */
64 | fespi_write_reg(spi_base, FESPI_REG_SCKMODE, 0x0);
65 | fespi_write_reg(spi_base, FESPI_REG_FORCE, 0x3);
66 | fespi_write_reg(spi_base, FESPI_REG_FCTRL, 0x0);
67 | fespi_write_reg(spi_base, FESPI_REG_FMT, 0x80008);
68 | fespi_write_reg(spi_base, FESPI_REG_FFMT, 0x30007);
69 | fespi_write_reg(spi_base, FESPI_REG_RXEDGE, 0x0);
70 | }
71 |
72 | void spi_hw(uint32_t *spi_base, bool sel)
73 | {
74 | uint32_t fctrl = 0;
75 | fespi_read_reg(spi_base, FESPI_REG_FCTRL, &fctrl);
76 | if (sel) {
77 | fespi_write_reg(spi_base, FESPI_REG_FCTRL, fctrl | FESPI_FCTRL_EN);
78 | } else {
79 | fespi_write_reg(spi_base, FESPI_REG_FCTRL, fctrl & ~FESPI_FCTRL_EN);
80 | }
81 | }
82 |
83 | void spi_cs(uint32_t *spi_base, bool sel)
84 | {
85 | if (sel) {
86 | fespi_write_reg(spi_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
87 | } else {
88 | fespi_write_reg(spi_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
89 | }
90 | }
91 |
92 | int spi_tx(uint32_t *spi_base, uint8_t *in, uint32_t len)
93 | {
94 | uint32_t times_out = 0;
95 | uint32_t value = 0;
96 | fespi_set_dir(spi_base, FESPI_DIR_TX);
97 | for (int i = 0;i < len;i++) {
98 | times_out = FESPI_TX_TIMES_OUT;
99 | while (times_out--) {
100 | fespi_read_reg(spi_base, FESPI_REG_TXDATA, &value);
101 | if (!(value >> 31)) {
102 | break;
103 | }
104 | }
105 | if (0 >= times_out) {
106 | return RETURN_SPI_TX_ERROR;
107 | }
108 | fespi_write_reg(spi_base, FESPI_REG_TXDATA, in[i]);
109 | }
110 | times_out = FESPI_TX_TIMES_OUT;
111 | while (times_out--) {
112 | fespi_read_reg(spi_base, FESPI_REG_IP, &value);
113 | if (value & FESPI_IP_TXWM) {
114 | break;
115 | }
116 | }
117 | if (0 >= times_out) {
118 | return RETURN_SPI_TX_ERROR;
119 | }
120 | return 0;
121 | }
122 |
123 | int spi_rx(uint32_t *spi_base, uint8_t *out, uint32_t len)
124 | {
125 | uint32_t times_out = 0;
126 | uint32_t value = 0;
127 | fespi_set_dir(spi_base, FESPI_DIR_RX);
128 | for (int i = 0;i < len;i++) {
129 | times_out = FESPI_RX_TIMES_OUT;
130 | fespi_write_reg(spi_base, FESPI_REG_TXDATA, 0x00);
131 | while (times_out--) {
132 | fespi_read_reg(spi_base, FESPI_REG_RXDATA, &value);
133 | if (!(value >> 31)) {
134 | break;
135 | }
136 | }
137 | if (0 >= times_out) {
138 | return RETURN_SPI_RX_ERROR;
139 | }
140 | out[i] = value & 0xff;
141 | }
142 | return 0;
143 | }
144 |
--------------------------------------------------------------------------------
/spi/nuspi.c:
--------------------------------------------------------------------------------
1 | #include "spi.h"
2 |
3 | /* WARNING: NEVER USE GLOBAL VARIABLE IN THIS FILE */
4 |
5 | /* Register offsets */
6 | #define NUSPI_REG_SCKMODE (0x04)
7 | #define NUSPI_REG_FORCE (0x0C)
8 | #define NUSPI_REG_CSMODE (0x18)
9 | #define NUSPI_REG_FMT (0x40)
10 | #define NUSPI_REG_TXDATA (0x48)
11 | #define NUSPI_REG_RXDATA (0x4C)
12 | #define NUSPI_REG_FCTRL (0x60)
13 | #define NUSPI_REG_FFMT (0x64)
14 | #define NUSPI_REG_STATUS (0x7C)
15 | #define NUSPI_REG_RXEDGE (0x80)
16 | /* FCTRL register */
17 | #define NUSPI_FCTRL_EN (0x1)
18 | #define NUSPI_INSN_CMD_EN (0x1)
19 | /* FMT register */
20 | #define NUSPI_FMT_DIR(x) (((x) & 0x1) << 3)
21 | /* STATUS register */
22 | #define NUSPI_STAT_BUSY (0x1 << 0)
23 | #define NUSPI_STAT_TXFULL (0x1 << 4)
24 | #define NUSPI_STAT_RXEMPTY (0x1 << 5)
25 | #define NUSPI_CSMODE_AUTO (0)
26 | #define NUSPI_CSMODE_HOLD (2)
27 | #define NUSPI_DIR_RX (0)
28 | #define NUSPI_DIR_TX (1)
29 |
30 | #define NUSPI_TX_TIMES_OUT (500)
31 | #define NUSPI_RX_TIMES_OUT (500)
32 |
33 | static inline void nuspi_read_reg(uint32_t volatile *spi_base, uint32_t offset, uint32_t *value)
34 | {
35 | *value = spi_base[offset / 4];
36 | }
37 |
38 | static inline void nuspi_write_reg(uint32_t volatile *spi_base, uint32_t offset, uint32_t value)
39 | {
40 | spi_base[offset / 4] = value;
41 | }
42 |
43 | static inline void nuspi_set_dir(uint32_t *spi_base, uint32_t dir)
44 | {
45 | uint32_t fmt = 0;
46 | nuspi_read_reg(spi_base, NUSPI_REG_FMT, &fmt);
47 | nuspi_write_reg(spi_base, NUSPI_REG_FMT, (fmt & ~(NUSPI_FMT_DIR(0xFFFFFFFF))) | NUSPI_FMT_DIR(dir));
48 | }
49 |
50 | void spi_init(uint32_t *spi_base)
51 | {
52 | /* clear rxfifo */
53 | uint32_t status = 0;
54 | while (1) {
55 | nuspi_read_reg(spi_base, NUSPI_REG_RXDATA, &status);
56 | nuspi_read_reg(spi_base, NUSPI_REG_STATUS, &status);
57 | if (status & NUSPI_STAT_RXEMPTY) {
58 | break;
59 | }
60 | }
61 | /* init register */
62 | nuspi_write_reg(spi_base, NUSPI_REG_SCKMODE, 0x0);
63 | nuspi_write_reg(spi_base, NUSPI_REG_FORCE, 0x3);
64 | nuspi_write_reg(spi_base, NUSPI_REG_FCTRL, 0x0);
65 | nuspi_write_reg(spi_base, NUSPI_REG_FMT, 0x80008);
66 | nuspi_write_reg(spi_base, NUSPI_REG_FFMT, 0x30007);
67 | nuspi_write_reg(spi_base, NUSPI_REG_RXEDGE, 0x0);
68 | }
69 |
70 | void spi_hw(uint32_t *spi_base, bool sel)
71 | {
72 | uint32_t fctrl = 0;
73 | nuspi_read_reg(spi_base, NUSPI_REG_FCTRL, &fctrl);
74 | if (sel) {
75 | nuspi_write_reg(spi_base, NUSPI_REG_FCTRL, fctrl | NUSPI_FCTRL_EN);
76 | } else {
77 | nuspi_write_reg(spi_base, NUSPI_REG_FCTRL, fctrl & ~NUSPI_FCTRL_EN);
78 | }
79 | }
80 |
81 | void spi_cs(uint32_t *spi_base, bool sel)
82 | {
83 | if (sel) {
84 | nuspi_write_reg(spi_base, NUSPI_REG_CSMODE, NUSPI_CSMODE_HOLD);
85 | } else {
86 | nuspi_write_reg(spi_base, NUSPI_REG_CSMODE, NUSPI_CSMODE_AUTO);
87 | }
88 | }
89 |
90 | int spi_tx(uint32_t *spi_base, uint8_t *in, uint32_t len)
91 | {
92 | uint32_t times_out = 0;
93 | uint32_t value = 0;
94 | nuspi_set_dir(spi_base, NUSPI_DIR_TX);
95 | for (int i = 0;i < len;i++) {
96 | times_out = NUSPI_TX_TIMES_OUT;
97 | while (times_out--) {
98 | nuspi_read_reg(spi_base, NUSPI_REG_STATUS, &value);
99 | if (!(value & NUSPI_STAT_TXFULL)) {
100 | break;
101 | }
102 | }
103 | if (0 >= times_out) {
104 | return RETURN_SPI_TX_ERROR;
105 | }
106 | nuspi_write_reg(spi_base, NUSPI_REG_TXDATA, in[i]);
107 | }
108 | times_out = NUSPI_TX_TIMES_OUT;
109 | while (times_out--) {
110 | nuspi_read_reg(spi_base, NUSPI_REG_STATUS, &value);
111 | if (0 == (value & NUSPI_STAT_BUSY)) {
112 | break;
113 | }
114 | }
115 | if (0 >= times_out) {
116 | return RETURN_SPI_TX_ERROR;
117 | }
118 | return 0;
119 | }
120 |
121 | int spi_rx(uint32_t *spi_base, uint8_t *out, uint32_t len)
122 | {
123 | uint32_t times_out = 0;
124 | uint32_t value = 0;
125 | nuspi_set_dir(spi_base, NUSPI_DIR_RX);
126 | for (int i = 0;i < len;i++) {
127 | times_out = NUSPI_RX_TIMES_OUT;
128 | nuspi_write_reg(spi_base, NUSPI_REG_TXDATA, 0x00);
129 | while (times_out--) {
130 | nuspi_read_reg(spi_base, NUSPI_REG_STATUS, &value);
131 | if (!(value & NUSPI_STAT_RXEMPTY)) {
132 | break;
133 | }
134 | }
135 | if (0 >= times_out) {
136 | return RETURN_SPI_RX_ERROR;
137 | }
138 | nuspi_read_reg(spi_base, NUSPI_REG_RXDATA, &value);
139 | out[i] = value & 0xff;
140 | }
141 | return 0;
142 | }
143 |
--------------------------------------------------------------------------------
/spi/spi.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #define RETURN_SPI_TX_ERROR (0x1 << 4)
6 | #define RETURN_SPI_RX_ERROR (0x1 << 5)
7 |
8 | void spi_init(uint32_t *spi_base);
9 | void spi_hw(uint32_t *spi_base, bool sel);
10 | void spi_cs(uint32_t *spi_base, bool sel);
11 | int spi_tx(uint32_t *spi_base, uint8_t *in, uint32_t len);
12 | int spi_rx(uint32_t *spi_base, uint8_t *out, uint32_t len);
13 |
--------------------------------------------------------------------------------
/test/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | /* NOTE: THIS TEST CODE IS USED WITH NUCLEI SDK */
5 |
6 | #define DEBUG_INFO (1)
7 |
8 | /*==== Loader ====*/
9 | #define ERASE_CMD (1)
10 | #define WRITE_CMD (2)
11 | #define READ_CMD (3)
12 | #define PROBE_CMD (4)
13 |
14 | // TODO Modify the following macro as your test requirements
15 | #define TEST_ERASE_SIZE (0x10000)
16 | #define TEST_OFFSET (0x00)
17 | #define TEST_COUNT (512)
18 |
19 | uint8_t write_buf[TEST_COUNT] = {0};
20 | uint8_t read_buf[TEST_COUNT] = {0};
21 |
22 | void data_init(uint8_t* buf, uint32_t len)
23 | {
24 | for (int i = 0;i < len;i++) {
25 | // TODO you can random it
26 | buf[i] = i + 2;
27 | }
28 | }
29 |
30 | int memory_compare(uint8_t* src, uint8_t* dst, uint32_t len)
31 | {
32 | while (len--) {
33 | if(*src++ != *dst++) {
34 | return -1;
35 | }
36 | }
37 | return 0;
38 | }
39 |
40 |
41 | // TODO Change SPI_BASE to your real base address
42 |
43 | #define SPI_BASE 0x10014000
44 |
45 | extern int loader_main(uint32_t cs, uint32_t *spi_base, uint32_t params1, uint32_t params2, uint32_t params3);
46 |
47 | int main(void)
48 | {
49 | int flash_id = 0;
50 | int retval = 0;
51 | int ret = 0;
52 |
53 | /* flash loader in/out params */
54 | uint32_t cs = 0x00;
55 | uint32_t *spi_base = (uint32_t*)SPI_BASE;
56 | uint32_t params1 = 0x00;
57 | uint32_t params2 = 0x00;
58 | uint32_t params3 = 0x00;
59 |
60 | #if DEBUG_INFO
61 | printf("Start to do flash loader test at SPI base address 0x%x\r\n", spi_base);
62 | #endif
63 |
64 | /* data init */
65 | data_init(write_buf, TEST_COUNT);
66 |
67 | /* flash init */
68 | cs = PROBE_CMD;
69 | flash_id = loader_main(cs, spi_base, params1, params2, params3);
70 | #if DEBUG_INFO
71 | printf("The current Flash ID is %#x\r\n", flash_id);
72 | #endif
73 |
74 | /* flash erase */
75 | cs = ERASE_CMD;
76 | params1 = TEST_OFFSET;//start_addr
77 | params2 = TEST_OFFSET + TEST_ERASE_SIZE;//end_addr
78 | retval = loader_main(cs, spi_base, params1, params2, params3);
79 | if (retval) {
80 | #if DEBUG_INFO
81 | printf("The erase error code\r\n");
82 | #endif
83 | ret |= 0x1;
84 | } else {
85 | #if DEBUG_INFO
86 | printf("Erase success\r\n");
87 | #endif
88 | }
89 |
90 | /* flash write */
91 | cs = WRITE_CMD;
92 | params1 = (uint32_t)write_buf;//buffer
93 | params2 = TEST_OFFSET;//offset
94 | params3 = TEST_COUNT;//count
95 | retval = loader_main(cs, spi_base, params1, params2, params3);
96 | if (retval) {
97 | #if DEBUG_INFO
98 | printf("The write error code\r\n");
99 | #endif
100 | ret |= 0x2;
101 | } else {
102 | #if DEBUG_INFO
103 | printf("Write success\r\n");
104 | #endif
105 | }
106 |
107 | /* flash read */
108 | cs = READ_CMD;
109 | params1 = (uint32_t)read_buf;//buffer
110 | params2 = TEST_OFFSET;//offset
111 | params3 = TEST_COUNT;//count
112 | retval = loader_main(cs, spi_base, params1, params2, params3);
113 | if (retval) {
114 | #if DEBUG_INFO
115 | printf("The read error code\r\n");
116 | #endif
117 | ret |= 0x4;
118 | } else {
119 | #if DEBUG_INFO
120 | printf("read success\r\n");
121 | #endif
122 | }
123 |
124 | /* verify */
125 | if (memory_compare(write_buf, read_buf, TEST_COUNT)) {
126 | #if DEBUG_INFO
127 | printf("Test fail\r\n");
128 | #endif
129 | ret |= 0x5;
130 | } else {
131 | #if DEBUG_INFO
132 | printf("Test pass\r\n");
133 | #endif
134 | }
135 |
136 | return ret;
137 | }
138 |
--------------------------------------------------------------------------------