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

Subversion Repositories openarty

[/] [openarty/] [trunk/] [sw/] [host/] [zipload.cpp] - Blame information for rev 31

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 31 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    zipload.cpp
4
//
5
// Project:     OpenArty, an entirely open SoC based upon the Arty platform
6
//
7
// Purpose:     To load a program for the ZipCPU into memory, whether flash
8
//              or SDRAM.  This requires a working/running configuration
9
//      in order to successfully load.
10
//
11
//
12
// Creator:     Dan Gisselquist, Ph.D.
13
//              Gisselquist Technology, LLC
14
//
15
////////////////////////////////////////////////////////////////////////////////
16
//
17
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
18
//
19
// This program is free software (firmware): you can redistribute it and/or
20
// modify it under the terms of  the GNU General Public License as published
21
// by the Free Software Foundation, either version 3 of the License, or (at
22
// your option) any later version.
23
//
24
// This program is distributed in the hope that it will be useful, but WITHOUT
25
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
26
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27
// for more details.
28
//
29
// You should have received a copy of the GNU General Public License along
30
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
31
// target there if the PDF file isn't present.)  If not, see
32
// <http://www.gnu.org/licenses/> for a copy.
33
//
34
// License:     GPL, v3, as defined and found on www.gnu.org,
35
//              http://www.gnu.org/licenses/gpl.html
36
//
37
//
38
////////////////////////////////////////////////////////////////////////////////
39
//
40
//
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <sys/types.h>
44
#include <sys/stat.h>
45
#include <fcntl.h>
46
#include <unistd.h>
47
#include <strings.h>
48
#include <ctype.h>
49
#include <string.h>
50
#include <signal.h>
51
#include <assert.h>
52
 
53
#include "port.h"
54
#include "llcomms.h"
55
#include "regdefs.h"
56
#include "flashdrvr.h"
57
 
58
bool    iself(const char *fname) {
59
        FILE    *fp;
60
        bool    ret = true;
61
 
62
        if ((!fname)||(!fname[0]))
63
                return false;
64
 
65
        fp = fopen(fname, "rb");
66
 
67
        if (!fp)        return false;
68
        if (0x7f != fgetc(fp))  ret = false;
69
        if ('E'  != fgetc(fp))  ret = false;
70
        if ('L'  != fgetc(fp))  ret = false;
71
        if ('F'  != fgetc(fp))  ret = false;
72
        fclose(fp);
73
        return  ret;
74
}
75
 
76
long    fgetwords(FILE *fp) {
77
        // Return the number of words in the current file, and return the 
78
        // file as though it had never been adjusted
79
        long    fpos, flen;
80
        fpos = ftell(fp);
81
        if (0 != fseek(fp, 0l, SEEK_END)) {
82
                fprintf(stderr, "ERR: Could not determine file size\n");
83
                perror("O/S Err:");
84
                exit(-2);
85
        } flen = ftell(fp);
86
        if (0 != fseek(fp, fpos, SEEK_SET)) {
87
                fprintf(stderr, "ERR: Could not seek on file\n");
88
                perror("O/S Err:");
89
                exit(-2);
90
        } flen /= sizeof(FPGA::BUSW);
91
        return flen;
92
}
93
 
94
FPGA    *m_fpga;
95
class   SECTION {
96
public:
97
        unsigned        m_start, m_len;
98
        FPGA::BUSW      m_data[1];
99
};
100
 
101
SECTION **singlesection(int nwords) {
102
        fprintf(stderr, "NWORDS = %d\n", nwords);
103
        size_t  sz = (2*(sizeof(SECTION)+sizeof(SECTION *))
104
                +(nwords-1)*(sizeof(FPGA::BUSW)));
105
        char    *d = (char *)malloc(sz);
106
        SECTION **r = (SECTION **)d;
107
        memset(r, 0, sz);
108
        r[0] = (SECTION *)(&d[2*sizeof(SECTION *)]);
109
        r[0]->m_len   = nwords;
110
        r[1] = (SECTION *)(&r[0]->m_data[r[0]->m_len]);
111
        r[0]->m_start = 0;
112
        r[1]->m_start = 0;
113
        r[1]->m_len   = 0;
114
 
115
        return r;
116
}
117
 
118
SECTION **rawsection(const char *fname) {
119
        SECTION         **secpp, *secp;
120
        unsigned        num_words;
121
        FILE            *fp;
122
        int             nr;
123
 
124
        fp = fopen(fname, "r");
125
        if (fp == NULL) {
126
                fprintf(stderr, "Could not open: %s\n", fname);
127
                exit(-1);
128
        }
129
 
130
        if ((num_words=fgetwords(fp)) > FLASHWORDS-(RESET_ADDRESS-EQSPIFLASH)) {
131
                fprintf(stderr, "File overruns flash memory\n");
132
                exit(-1);
133
        }
134
        secpp = singlesection(num_words);
135
        secp = secpp[0];
136
        secp->m_start = RAMBASE;
137
        secp->m_len = num_words;
138
        nr= fread(secp->m_data, sizeof(FPGA::BUSW), num_words, fp);
139
        if (nr != (int)num_words) {
140
                fprintf(stderr, "Could not read entire file\n");
141
                perror("O/S Err:");
142
                exit(-2);
143
        } assert(secpp[1]->m_len == 0);
144
 
145
        return secpp;
146
}
147
 
148
unsigned        byteswap(unsigned n) {
149
        unsigned        r;
150
 
151
        r = (n&0x0ff); n>>= 8;
152
        r = (r<<8) | (n&0x0ff); n>>= 8;
153
        r = (r<<8) | (n&0x0ff); n>>= 8;
154
        r = (r<<8) | (n&0x0ff); n>>= 8;
155
 
156
        return r;
157
}
158
 
159
// #define      CHEAP_AND_EASY
160
#ifdef  CHEAP_AND_EASY
161
#else
162
#include <libelf.h>
163
#include <gelf.h>
164
 
165
void    elfread(const char *fname, unsigned &entry, SECTION **&sections) {
166
        Elf     *e;
167
        int     fd, i;
168
        size_t  n;
169
        char    *id;
170
        Elf_Kind        ek;
171
        GElf_Ehdr       ehdr;
172
        GElf_Phdr       phdr;
173
        const   bool    dbg = false;
174
 
175
        if (elf_version(EV_CURRENT) == EV_NONE) {
176
                fprintf(stderr, "ELF library initialization err, %s\n", elf_errmsg(-1));
177
                perror("O/S Err:");
178
                exit(EXIT_FAILURE);
179
        } if ((fd = open(fname, O_RDONLY, 0)) < 0) {
180
                fprintf(stderr, "Could not open %s\n", fname);
181
                perror("O/S Err:");
182
                exit(EXIT_FAILURE);
183
        } if ((e = elf_begin(fd, ELF_C_READ, NULL))==NULL) {
184
                fprintf(stderr, "Could not run elf_begin, %s\n", elf_errmsg(-1));
185
                exit(EXIT_FAILURE);
186
        }
187
 
188
        ek = elf_kind(e);
189
        if (ek == ELF_K_ELF) {
190
                ; // This is the kind of file we should expect
191
        } else if (ek == ELF_K_AR) {
192
                fprintf(stderr, "Cannot run an archive!\n");
193
                exit(EXIT_FAILURE);
194
        } else if (ek == ELF_K_NONE) {
195
                ;
196
        } else {
197
                fprintf(stderr, "Unexpected ELF file kind!\n");
198
                exit(EXIT_FAILURE);
199
        }
200
 
201
        if (gelf_getehdr(e, &ehdr) == NULL) {
202
                fprintf(stderr, "getehdr() failed: %s\n", elf_errmsg(-1));
203
                exit(EXIT_FAILURE);
204
        } if ((i=gelf_getclass(e)) == ELFCLASSNONE) {
205
                fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1));
206
                exit(EXIT_FAILURE);
207
        } if ((id = elf_getident(e, NULL)) == NULL) {
208
                fprintf(stderr, "getident() failed: %s\n", elf_errmsg(-1));
209
                exit(EXIT_FAILURE);
210
        } if (i != ELFCLASS32) {
211
                fprintf(stderr, "This is a 64-bit ELF file, ZipCPU ELF files are all 32-bit\n");
212
                exit(EXIT_FAILURE);
213
        }
214
 
215
        if (dbg) {
216
        printf("    %-20s 0x%jx\n", "e_type", (uintmax_t)ehdr.e_type);
217
        printf("    %-20s 0x%jx\n", "e_machine", (uintmax_t)ehdr.e_machine);
218
        printf("    %-20s 0x%jx\n", "e_version", (uintmax_t)ehdr.e_version);
219
        printf("    %-20s 0x%jx\n", "e_entry", (uintmax_t)ehdr.e_entry);
220
        printf("    %-20s 0x%jx\n", "e_phoff", (uintmax_t)ehdr.e_phoff);
221
        printf("    %-20s 0x%jx\n", "e_shoff", (uintmax_t)ehdr.e_shoff);
222
        printf("    %-20s 0x%jx\n", "e_flags", (uintmax_t)ehdr.e_flags);
223
        printf("    %-20s 0x%jx\n", "e_ehsize", (uintmax_t)ehdr.e_ehsize);
224
        printf("    %-20s 0x%jx\n", "e_phentsize", (uintmax_t)ehdr.e_phentsize);
225
        printf("    %-20s 0x%jx\n", "e_shentsize", (uintmax_t)ehdr.e_shentsize);
226
        printf("\n");
227
        }
228
 
229
 
230
        // Check whether or not this is an ELF file for the ZipCPU ...
231
        if (ehdr.e_machine != 0x0dadd) {
232
                fprintf(stderr, "This is not a ZipCPU ELF file\n");
233
                exit(EXIT_FAILURE);
234
        }
235
 
236
        // Get our entry address
237
        entry = ehdr.e_entry;
238
 
239
 
240
        // Now, let's go look at the program header
241
        if (elf_getphdrnum(e, &n) != 0) {
242
                fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1));
243
                exit(EXIT_FAILURE);
244
        }
245
 
246
        unsigned total_octets = 0, current_offset=0, current_section=0;
247
        for(i=0; i<(int)n; i++) {
248
                total_octets += sizeof(SECTION *)+sizeof(SECTION);
249
 
250
                if (gelf_getphdr(e, i, &phdr) != &phdr) {
251
                        fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1));
252
                        exit(EXIT_FAILURE);
253
                }
254
 
255
                if (dbg) {
256
                printf("    %-20s 0x%x\n", "p_type",   phdr.p_type);
257
                printf("    %-20s 0x%jx\n", "p_offset", phdr.p_offset);
258
                printf("    %-20s 0x%jx\n", "p_vaddr",  phdr.p_vaddr);
259
                printf("    %-20s 0x%jx\n", "p_paddr",  phdr.p_paddr);
260
                printf("    %-20s 0x%jx\n", "p_filesz", phdr.p_filesz);
261
                printf("    %-20s 0x%jx\n", "p_memsz",  phdr.p_memsz);
262
                printf("    %-20s 0x%x [", "p_flags",  phdr.p_flags);
263
 
264
                if (phdr.p_flags & PF_X)        printf(" Execute");
265
                if (phdr.p_flags & PF_R)        printf(" Read");
266
                if (phdr.p_flags & PF_W)        printf(" Write");
267
                printf("]\n");
268
                printf("    %-20s 0x%jx\n", "p_align", phdr.p_align);
269
                }
270
 
271
                total_octets += phdr.p_memsz;
272
        }
273
 
274
        char    *d = (char *)malloc(total_octets + sizeof(SECTION)+sizeof(SECTION *));
275
        memset(d, 0, total_octets);
276
 
277
        SECTION **r = sections = (SECTION **)d;
278
        current_offset = (n+1)*sizeof(SECTION *);
279
        current_section = 0;
280
 
281
        for(i=0; i<(int)n; i++) {
282
                r[i] = (SECTION *)(&d[current_offset]);
283
 
284
                if (gelf_getphdr(e, i, &phdr) != &phdr) {
285
                        fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1));
286
                        exit(EXIT_FAILURE);
287
                }
288
 
289
                if (dbg) {
290
                printf("    %-20s 0x%jx\n", "p_offset", phdr.p_offset);
291
                printf("    %-20s 0x%jx\n", "p_vaddr",  phdr.p_vaddr);
292
                printf("    %-20s 0x%jx\n", "p_paddr",  phdr.p_paddr);
293
                printf("    %-20s 0x%jx\n", "p_filesz", phdr.p_filesz);
294
                printf("    %-20s 0x%jx\n", "p_memsz",  phdr.p_memsz);
295
                printf("    %-20s 0x%x [", "p_flags",  phdr.p_flags);
296
 
297
                if (phdr.p_flags & PF_X)        printf(" Execute");
298
                if (phdr.p_flags & PF_R)        printf(" Read");
299
                if (phdr.p_flags & PF_W)        printf(" Write");
300
                printf("]\n");
301
 
302
                printf("    %-20s 0x%jx\n", "p_align", phdr.p_align);
303
                }
304
 
305
                current_section++;
306
 
307
                r[i]->m_start = phdr.p_paddr;
308
                r[i]->m_len   = phdr.p_filesz/ sizeof(FPGA::BUSW);
309
 
310
                current_offset += phdr.p_memsz + sizeof(SECTION);
311
 
312
                // Now, let's read in our section ...
313
                if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) {
314
                        fprintf(stderr, "Could not seek to file position %08lx\n", phdr.p_offset);
315
                        perror("O/S Err:");
316
                        exit(EXIT_FAILURE);
317
                } if (phdr.p_filesz > phdr.p_memsz)
318
                        phdr.p_filesz = 0;
319
                if (read(fd, r[i]->m_data, phdr.p_filesz) != (int)phdr.p_filesz) {
320
                        fprintf(stderr, "Didnt read entire section\n");
321
                        perror("O/S Err:");
322
                        exit(EXIT_FAILURE);
323
                }
324
 
325
                // Next, we need to byte swap it from big to little endian
326
                for(unsigned j=0; j<r[i]->m_len; j++)
327
                        r[i]->m_data[j] = byteswap(r[i]->m_data[j]);
328
 
329
                if (dbg) for(unsigned j=0; j<r[i]->m_len; j++)
330
                        fprintf(stderr, "ADR[%04x] = %08x\n", r[i]->m_start+j,
331
                        r[i]->m_data[j]);
332
        }
333
 
334
        r[i] = (SECTION *)(&d[current_offset]);
335
        r[current_section]->m_start = 0;
336
        r[current_section]->m_len   = 0;
337
 
338
        elf_end(e);
339
        close(fd);
340
}
341
#endif
342
 
343
void    usage(void) {
344
        printf("USAGE: zipload [-hr] <zip-program-file>\n");
345
        printf("\n"
346
"\t-h\tDisplay this usage statement\n");
347
        printf(
348
"\t-r\tStart the ZipCPU running from the address in the program file\n");
349
}
350
 
351
int main(int argc, char **argv) {
352
        int             skp=0;
353
        bool            start_when_finished = false;
354
        unsigned        entry = 0;
355
        FLASHDRVR       *flash = NULL;
356
        const char      *bitfile = NULL, *altbitfile = NULL;
357
 
358
        if (argc < 2) {
359
                usage();
360
                exit(EXIT_SUCCESS);
361
        }
362
 
363
        skp=1;
364
        for(int argn=0; argn<argc-skp; argn++) {
365
                if (argv[argn+skp][0] == '-') {
366
                        switch(argv[argn+skp][1]) {
367
                        case 'h':
368
                                usage();
369
                                exit(EXIT_SUCCESS);
370
                                break;
371
                        case 'r':
372
                                start_when_finished = true;
373
                                break;
374
                        default:
375
                                fprintf(stderr, "Unknown option, -%c\n\n",
376
                                        argv[argn+skp][0]);
377
                                usage();
378
                                exit(EXIT_FAILURE);
379
                                break;
380
                        } skp++; argn--;
381
                } else {
382
                        // Anything here must be the program to load.
383
                        argv[argn] = argv[argn+skp];
384
                }
385
        } argc -= skp;
386
 
387
 
388
        if (argc == 0) {
389
                printf("No executable file given!\n\n");
390
                usage();
391
                exit(EXIT_FAILURE);
392
        } if (access(argv[0],R_OK)!=0) {
393
                // If there's no code file, or the code file cannot be opened
394
                fprintf(stderr, "Cannot open executable, %s\n", argv[0]);
395
                exit(EXIT_FAILURE);
396
        }
397
 
398
        const char *codef = (argc>0)?argv[0]:NULL;
399
        DEVBUS::BUSW    *fbuf = new DEVBUS::BUSW[FLASHWORDS];
400
 
401
        // Set the flash buffer to all ones
402
        memset(fbuf, -1, FLASHWORDS*sizeof(fbuf[0]));
403
 
404
        m_fpga = FPGAOPEN(m_fpga);
405
 
406
        // Make certain we can talk to the FPGA
407
        try {
408
                unsigned v  = m_fpga->readio(R_VERSION);
409
                if (v < 0x20161000) {
410
                        fprintf(stderr, "Could not communicate with board (invalid version)\n");
411
                        exit(EXIT_FAILURE);
412
                }
413
        } catch(BUSERR b) {
414
                fprintf(stderr, "Could not communicate with board (BUSERR when reading VERSION)\n");
415
                exit(EXIT_FAILURE);
416
        }
417
 
418
        // Halt the CPU
419
        try {
420
                unsigned v;
421
                printf("Halting the CPU\n");
422
                m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_RESET);
423
        } catch(BUSERR b) {
424
                fprintf(stderr, "Could not halt the CPU (BUSERR)\n");
425
                exit(EXIT_FAILURE);
426
        }
427
 
428
        flash = new FLASHDRVR(m_fpga);
429
 
430
        if (codef) try {
431
                SECTION **secpp = NULL, *secp;
432
 
433
                if(iself(codef)) {
434
                        // zip-readelf will help with both of these ...
435
                        elfread(codef, entry, secpp);
436
                } else {
437
                        fprintf(stderr, "ERR: %s is not in ELF format\n", codef);
438
                        exit(EXIT_FAILURE);
439
                }
440
 
441
                printf("Loading: %s\n", codef);
442
                // assert(secpp[1]->m_len = 0);
443
                for(int i=0; secpp[i]->m_len; i++) {
444
                        bool    valid = false;
445
                        secp=  secpp[i];
446
 
447
                        // Make sure our section is either within block RAM
448
                        if ((secp->m_start >= MEMBASE)
449
                                &&(secp->m_start+secp->m_len
450
                                                <= MEMBASE+MEMWORDS))
451
                                valid = true;
452
 
453
                        // Flash
454
                        if ((secp->m_start >= RESET_ADDRESS)
455
                                &&(secp->m_start+secp->m_len
456
                                                <= EQSPIFLASH+FLASHWORDS))
457
                                valid = true;
458
 
459
                        // Or SDRAM
460
                        if ((secp->m_start >= RAMBASE)
461
                                &&(secp->m_start+secp->m_len
462
                                                <= RAMBASE+RAMWORDS))
463
                                valid = true;
464
                        if (!valid) {
465
                                fprintf(stderr, "No such memory on board: 0x%08x - %08x\n",
466
                                        secp->m_start, secp->m_start+secp->m_len);
467
                                exit(EXIT_FAILURE);
468
                        }
469
                }
470
 
471
                unsigned        startaddr = RESET_ADDRESS, codelen = 0;
472
                for(int i=0; secpp[i]->m_len; i++) {
473
                        secp = secpp[i];
474
                        if ( ((secp->m_start >= RAMBASE)
475
                                &&(secp->m_start+secp->m_len
476
                                                <= RAMBASE+RAMWORDS))
477
                                ||((secp->m_start >= MEMBASE)
478
                                  &&(secp->m_start+secp->m_len
479
                                                <= MEMBASE+MEMWORDS)) ) {
480
                                for(int i=0; (unsigned)i<secp->m_len; i++) {
481
                                        m_fpga->writei(secp->m_start,
482
                                                secp->m_len,
483
                                                secp->m_data);
484
                                }
485
                        } else {
486
                                if (secp->m_start < startaddr) {
487
                                        codelen += (startaddr-secp->m_start);
488
                                        startaddr = secp->m_start;
489
                                } if (secp->m_start+secp->m_len > startaddr+codelen) {
490
                                        codelen = secp->m_start+secp->m_len-startaddr;
491
                                } memcpy(&fbuf[secp->m_start-EQSPIFLASH],
492
                                        secp->m_data,
493
                                        secp->m_len*sizeof(FPGA::BUSW));
494
                        }
495
                }
496
                if ((flash)&&(!flash->write(startaddr, codelen, &fbuf[startaddr-EQSPIFLASH], true))) {
497
                        fprintf(stderr, "ERR: Could not write program to flash\n");
498
                        exit(EXIT_FAILURE);
499
                } else if (!flash)
500
                        printf("flash->write(%08x, %d, ... );\n", startaddr,
501
                                codelen);
502
                if (m_fpga) m_fpga->readio(R_VERSION); // Check for bus errors
503
 
504
                // Now ... how shall we start this CPU?
505
                if (start_when_finished) {
506
                        printf("Clearing the CPUs registers\n");
507
                        for(int i=0; i<32; i++) {
508
                                m_fpga->writeio(R_ZIPCTRL, CPU_HALT|i);
509
                                if (i == CPU_sPC)
510
                                        m_fpga->writeio(R_ZIPDATA, entry);
511
                                else
512
                                        m_fpga->writeio(R_ZIPDATA, 0);
513
                        }
514
 
515
                        m_fpga->writeio(R_CPUSCOPE, 25);
516
                        printf("Starting the CPU\n");
517
                        m_fpga->writeio(R_ZIPCTRL, CPU_HALT|CPU_CLRCACHE|CPU_RESET);
518
                        m_fpga->writeio(R_ZIPCTRL, CPU_GO|CPU_sPC);
519
                } else {
520
                        printf("The CPU should be fully loaded, you may now\n");
521
                        printf("start it (from reset/reboot) with:\n");
522
                        printf("> wbregs cpu 0x40\n");
523
                        printf("\n");
524
                }
525
        } catch(BUSERR a) {
526
                fprintf(stderr, "ARTY-BUS error: %08x\n", a.addr);
527
                exit(-2);
528
        }
529
 
530
        printf("CPU Status is: %08x\n", m_fpga->readio(R_ZIPCTRL));
531
        if (m_fpga) delete      m_fpga;
532
 
533
        return EXIT_SUCCESS;
534
}
535
 

powered by: WebSVN 2.1.0

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