OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

[/] [openarty/] [trunk/] [sw/] [zlib/] [crt0.c] - Blame information for rev 54

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 54 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    crt0.c
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     To start a program from flash, loading its various components
8
//              into on-chip block RAM, or off-chip DDR3 SDRAM, as indicated
9
//      by the symbols/pointers within the program itself.  As you will notice
10
//      by the names of the symbols, it is assumed that a kernel will be placed
11
//      into block RAM.
12
//
13
//      This particular implementation depends upon the following symbols
14
//      being defined:
15
//
16
//      int main(int argc, char **argv)
17
//              The location where your program will start from, once fully
18
//              loaded.  argc will always be set to zero, and ARGV to a pointer
19
//              to zero.
20
//
21
//      _top_of_stack:
22
//              A pointer to a location in memory which we can use for a stack.
23
//              The bootloader doesn't use much of this memory, although it does
24
//              use it.  It then resets the stack to this location and calls
25
//              your program.
26
//
27
//      _top_of_heap:
28
//              While not used by this program, this is assumed to be defined
29
//              by the linker as the lowest memory address in a space that can
30
//              be used by a malloc/free restore capability.
31
//
32
//      _flash:
33
//              The address of the beginning of physical FLASH device.  This is
34
//              not the first usable address on that device, as that is often
35
//              reserved for the first two FPGA configurations.
36
//
37
//      _blkram:
38
//              The first address of the block RAM memory within the FPGA.
39
//
40
//      _sdram:
41
//              The address of the beginning of physical SDRAM.
42
//
43
//      _kernel_image_start:
44
//              The address of that location within FLASH where the sections
45
//              needing to be moved begin at.
46
//
47
//      _kernel_image_end:
48
//              The last address within block RAM that needs to be filled in.
49
//
50
//      _sdram_image_start:
51
//              This address is more confusing.  This is equal to one past the
52
//              last used block RAM address, or the last used flash address if
53
//              no block RAM is used.  It is used for determining whether or not
54
//              block RAM was used at all.
55
//
56
//      _sdram_image_end:
57
//              This is one past the last address in SDRAM that needs to be
58
//              set with valid data.
59
//
60
//              This pointer is made even more confusing by the fact that,
61
//              if there is nothing allocated in SDRAM, this pointer will
62
//              still point to block RAM.  To make matters worse, the MAP
63
//              file won't match the pointer in memory.  (I spent three days
64
//              trying to chase this down, and came up empty.  Basically,
65
//              the BFD structures may set this to point to block RAM, whereas
66
//              the MAP--which uses different data and different methods of
67
//              computation--may leave this pointing to SDRAM.  Go figure.)
68
//
69
//      _bss_image_end:
70
//              This is the last address of memory that must be cleared upon
71
//              startup, for which the program is assuming that it is zero.
72
//              While it may not be necessary to clear the BSS memory, since
73
//              BSS memory is always zero on power up, this bootloader does so
74
//              anyway--since we might be starting from a reset instead of power
75
//              up.
76
//
77
//
78
//
79
// Creator:     Dan Gisselquist, Ph.D.
80
//              Gisselquist Technology, LLC
81
//
82
////////////////////////////////////////////////////////////////////////////////
83
//
84
// Copyright (C) 2017, Gisselquist Technology, LLC
85
//
86
// This program is free software (firmware): you can redistribute it and/or
87
// modify it under the terms of  the GNU General Public License as published
88
// by the Free Software Foundation, either version 3 of the License, or (at
89
// your option) any later version.
90
//
91
// This program is distributed in the hope that it will be useful, but WITHOUT
92
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
93
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
94
// for more details.
95
//
96
// License:     GPL, v3, as defined and found on www.gnu.org,
97
//              http://www.gnu.org/licenses/gpl.html
98
//
99
//
100
////////////////////////////////////////////////////////////////////////////////
101
//
102
//
103
#include "zipcpu.h"
104
#include "artyboard.h"          // Our current board support file
105
#include "bootloader.h"
106
 
107
// A bootloader is about nothing more than copying memory from a couple
108
// particular locations (Flash/ROM) to other locations in memory (BLKRAM
109
// and SDRAM).  Our DMA is a hardware accelerator that does nothing but
110
// copy memory from one location to another.  Why not use the DMA for this
111
// purpose then?
112
//
113
// Here, we have a USE_DMA #define.  When this is defined, the memory copy
114
// will be done using the DMA hardware accelerator.  This is a good thing,
115
// and this should be defined.  There are two problems with defining this
116
// however: 1) It obscures for any readers of this code what is actually
117
// happening, and 2) it makes the code dependent upon yet another piece of the
118
// hardware design working.  For these reasons, we allow you to turn it off.
119
#ifdef _HAS_ZIPSYS_DMA
120
#define USE_DMA
121
#endif
122
 
123
//
124
// _start:
125
//
126
// Every computer needs to start processing from somewhere on reboot, and every
127
// program needs some entry point.  For the ZipCPU, that starting place is the
128
// routine with the _start symbol.  It is important that this start symbol be
129
// placed at the boot address for the CPU.  This is the very first address of
130
// program memory, and (currently) on the Arty board it is placed in Flash at
131
// _start = 0x4e0000.  To make certain this routine goes into the very first
132
// address in flash, we place it into it's own special section, the .start
133
// section, and then tell the linker that the .start section is the first
134
// section where it needs to start placing code.
135
//
136
// If you read through this short assembly routine below, you'll find that it
137
// does only a small number of tasks.  It sets the stack pointer to point to
138
// the top of the stack (a symbol defined in the linker file), calls the 
139
// bootloader, resets the stack pointer, clears any data cache, and then calls
140
// the kernel entry function.  It also sets up a return address for the kernel
141
// entry function so that, should the kernel ever exit, it wouldn't exit on 
142
// any error but rather it would exit by halting the CPU.
143
//
144
asm("\t.section\t.start,\"ax\",@progbits\n"
145
        "\t.global\t_start\n"
146
"_start:"       "\t; Here's the global ZipCPU entry point upon reset/reboot\n"
147
        "\tLDI\t_top_of_stack,SP"       "\t; Set up our supervisor stack ptr\n"
148
        "\tMOV\t_kernel_is_dead(PC),uPC" "\t; Set user PC pointer to somewhere valid\n"
149
#ifndef SKIP_BOOTLOADER
150
        "\tMOV\t_after_bootloader(PC),R0" " ; JSR to the bootloader routine\n"
151
        "\tBRA\t_bootloader\n"
152
"_after_bootloader:\n"
153
        "\tLDI\t_top_of_stack,SP"       "\t; Set up our supervisor stack ptr\n"
154
        "\tOR\t0x4000,CC"               "\t; Clear the data cache\n"
155
#endif
156
#ifdef  __USE_INIT_FINIT
157
        "\tJSR\tinit"           "\t; Initialize any constructor code\n"
158
        //
159
        "\tLDI\tfini,R1"        "\t; \n"
160
        "\tJSR\t_atexit"        "\t; Initialize any constructor code\n"
161
#endif
162
        //
163
        "\tCLR\tR1"                     "\t; argc = 0\n"
164
        "\tMOV\t_argv(PC),R2"           "\t; argv = &0\n"
165
        "\tLDI\t__env,R3"               "\t; env = NULL\n"
166
        "\tJSR\tmain"           "\t; Call the user main() function\n"
167
        //
168
"_graceful_kernel_exit:"        "\t; Halt on any return from main--gracefully\n"
169
        "\tJSR\texit\n" "\t; Call the _exit as part of exiting\n"
170
"\t.global\t_exit\n"
171
"_exit:\n"
172
#ifdef  _HAS_WBUART
173
        "\tLW 0x45c,R2\n"
174
        "\tTEST 0xffc,R2\n"
175
        "\tBNZ _exit\n"
176
        "\tLSR  16,R2\n"
177
        "\tTEST 0xffc,R2\n"
178
        "\tBNZ _exit\n"
179
#endif
180
        "\tNEXIT\tR1\n"         "\t; If in simulation, call an exit function\n"
181
"_kernel_is_dead:"              "\t; Halt the CPU\n"
182
        "\tHALT\n"              "\t; We should *never* continue following a\n"
183
        "\tBRA\t_kernel_is_dead" "\t; halt, do something useful if so ??\n"
184
"_argv:\n"
185
        "\t.WORD\t0,0\n"
186
        "\t.section\t.text");
187
 
188
//
189
// We need to insist that the bootloader be kept in Flash, else it would depend
190
// upon running a routine from memory that ... wasn't in memory yet.  For this
191
// purpose, we place the bootloader in a special .boot section.  We'll also tell
192
// the linker, via the linker script, that this .boot section needs to be placed
193
// into flash.
194
//
195
extern  void    _bootloader(void) __attribute__ ((section (".boot")));
196
 
197
//
198
// bootloader()
199
//
200
// Here's the actual boot loader itself.  It copies three areas from flash:
201
//      1. An area from flash to block RAM
202
//      2. A second area from flash to SDRAM
203
//      3. The third area isn't copied from flash, but rather it is just set to
204
//              zero.  This is sometimes called the BSS segment.
205
//
206
#ifndef SKIP_BOOTLOADER
207
void    _bootloader(void) {
208
        int *sdend = _sdram_image_end, *bsend = _bss_image_end;
209
        if (sdend < _sdram)
210
                sdend = _sdram; // R7
211
        if (bsend < sdend)
212
                bsend = sdend;  // R6
213
 
214
#ifdef  USE_DMA
215
        zip->z_dma.d_ctrl= DMACLEAR;
216
        zip->z_dma.d_rd = _kernel_image_start;
217
        if (_kernel_image_end != _blkram) {
218
                zip->z_dma.d_len = _kernel_image_end - _blkram;
219
                zip->z_dma.d_wr  = _blkram;
220
                zip->z_dma.d_ctrl= DMACCOPY;
221
 
222
                zip->z_pic = SYSINT_DMAC;
223
                while((zip->z_pic & SYSINT_DMAC)==0)
224
                        ;
225
        }
226
 
227
        // zip->z_dma.d_rd // Keeps the same value
228
        zip->z_dma.d_wr  = _sdram;
229
        if (sdend != _sdram) {
230
                zip->z_dma.d_len = sdend - _sdram;
231
                zip->z_dma.d_ctrl= DMACCOPY;
232
 
233
                zip->z_pic = SYSINT_DMAC;
234
                while((zip->z_pic & SYSINT_DMAC)==0)
235
                        ;
236
        }
237
 
238
        if (bsend != sdend) {
239
                volatile int    zero = 0;
240
 
241
                zip->z_dma.d_len = bsend - sdend;
242
                zip->z_dma.d_rd  = (unsigned *)&zero;
243
                // zip->z_dma.wr // Keeps the same value
244
                zip->z_dma.d_ctrl = DMACCOPY|DMA_CONSTSRC;
245
 
246
                zip->z_pic = SYSINT_DMAC;
247
                while((zip->z_pic & SYSINT_DMAC)==0)
248
                        ;
249
        }
250
#else
251
        int     *rdp = _kernel_image_start, *wrp = _blkram;
252
 
253
        if ((((int)wrp) & -4)==0)
254
                wrp = _sdram;
255
 
256
        //
257
        // Load any part of the image into block RAM, but *only* if there's a
258
        // block RAM section in the image.  Based upon our LD script, the
259
        // block RAM should be filled from _blkram to _kernel_image_end.
260
        // It starts at _kernel_image_start --- our last valid address within
261
        // the flash address region.
262
        //
263
        if (_kernel_image_end != _kernel_image_start) {
264
                while(wrp < _kernel_image_end)
265
                        *wrp++ = *rdp++;
266
                if (_kernel_image_end < _sdram)
267
                        wrp = _sdram;
268
        }
269
 
270
        //
271
        // Now, we move on to the SDRAM image.  We'll here load into SDRAM
272
        // memory up to the end of the SDRAM image, _sdram_image_end.
273
        // As with the last pointer, this one is also created for us by the
274
        // linker.
275
        // 
276
        // while(wrp < sdend)   // Could also be done this way ...
277
        for(int i=0; i< sdend - _sdram; i++)
278
                *wrp++ = *rdp++;
279
 
280
        //
281
        // Finally, we load BSS.  This is the segment that only needs to be
282
        // cleared to zero.  It is available for global variables, but some
283
        // initialization is expected within it.  We start writing where
284
        // the valid SDRAM context, i.e. the non-zero contents, end.
285
        //
286
        for(int i=0; i<bsend - sdend; i++)
287
                *wrp++ = 0;
288
 
289
#endif
290
}
291
#endif
292
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.