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

Subversion Repositories cpu_lecture

[/] [cpu_lecture/] [trunk/] [html/] [09_Toolchain_Setup.html] - Blame information for rev 2

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

Line No. Rev Author Line
1 2 jsauermann
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2
"http://www.w3.org/TR/html4/strict.dtd">
3
<HTML>
4
<HEAD>
5
<TITLE>html/Toolchain_Setup</TITLE>
6
<META NAME="generator" CONTENT="HTML::TextToHTML v2.46">
7
<LINK REL="stylesheet" TYPE="text/css" HREF="lecture.css">
8
</HEAD>
9
<BODY>
10
<P><table class="ttop"><th class="tpre"><a href="08_IO.html">Previous Lesson</a></th><th class="ttop"><a href="toc.html">Table of Content</a></th><th class="tnxt"><a href="10_Listing_of_alu_vhd.html">Next Lesson</a></th></table>
11
<hr>
12
 
13
<H1><A NAME="section_1">9 TOOLCHAIN SETUP</A></H1>
14
 
15
<P>In this lesson we will learn how to set up a toolchain on a Linux box.
16
We will not describe, however, how the tools are downloaded and installed.
17
The installation of a tools is normally described in the documentation
18
that comes with the tool.
19
 
20
<P>Places from where tools can be downloaded were already presented in the
21
first lecture.
22
 
23
<P>The following figure gives an overview of the entire flow. We show source files
24
in yellow, temporary files in white and tools in green.
25
 
26
<P><br>
27
 
28
<P><img src="toolchain_1.png">
29
 
30
<P><br>
31
 
32
<P>We start with a C source file <STRONG>hello.c</STRONG>. This file is compiled with <STRONG>avr-gcc</STRONG>,
33
a <STRONG>gcc</STRONG> variant that generates opcodes for the AVR CPU. The compilation
34
produces 2 output files: <STRONG>hello.lss</STRONG> and <STRONG>hello.hex</STRONG>.
35
 
36
<P><STRONG>hello.lss</STRONG> is a listing file and may optionally be post-processed by the
37
tool <STRONG>end_conv</STRONG> which converts the little-endian format of <STRONG>hello.lss</STRONG> into
38
a slightly different format that is more in line with the way gtkwave shows
39
the hex values of signals.
40
 
41
<P>The main purpose of the compilation is to produce <STRONG>hello.hex</STRONG>. <STRONG>hello.hex</STRONG>
42
contains the opcodes produced from <STRONG>hello.c</STRONG> in Intel-Hex format.
43
 
44
<P><STRONG>hello.hex</STRONG> is then fed into <STRONG>make_mem</STRONG>. <STRONG>make_mem</STRONG> is a tool that converts
45
the Intel-Hex format into VHDL constants. These constants are used to
46
initialize the block RAM modules of the program memory. The output of
47
<STRONG>make_mem</STRONG> is <STRONG>memory_content.vhd</STRONG> (which, as you certainly remember,
48
was included by <STRONG>prog_mem.vhd</STRONG>).
49
 
50
<P>At this point, there are two possible ways to proceed. You could do a
51
functional simulation or a timing simulation.
52
 
53
<H2><A NAME="section_1_1">8.1 Functional Simulation</A></H2>
54
 
55
<P>Initially you will be concerned mostly with the functional simulation.
56
On this branch you debug the VHDL code until it looks functionally OK.
57
In order to perform the functional simulation, you need 3 sorts of VHDL files:
58
 
59
<OL>
60
  <LI>The VHLD source files that were discussed in the previous lessons,
61
  <LI>the <STRONG>memory_content.vhd</STRONG> just described, and
62
  <LI>a testbench that mimics the board containing the FPGA to be (<STRONG>test_tb.vhd</STRONG>,
63
   and a VHDL implementation of device specific components used (in our case
64
   this is only <STRONG>RAMB4_S4_S4.vhd</STRONG>). Both files are provided in the directory
65
   called <STRONG>test</STRONG>.
66
</OL>
67
<P>All these VHDL files are then processed by <STRONG>ghdl</STRONG>. <STRONG>ghdl</STRONG> produces a single
68
output file <STRONG>testbench</STRONG> in directory <STRONG>simu</STRONG>. <STRONG>testbench</STRONG> is an executable
69
file. <STRONG>testbench</STRONG> is then run in order to produces a gzip'ed <STRONG>vcd</STRONG> (value change
70
dump) file called <STRONG>testbench.vcdgz</STRONG>.
71
 
72
<P>The last step is visualize <STRONG>testbench.vcdgz</STRONG> by means of the tool <STRONG>gtkwave</STRONG>.
73
<STRONG>gtkwave</STRONG> is similar to the <STRONG>ModelSim</STRONG> provided by Xilinx, but it has
74
two advantages: it does not bother the user with licence installations
75
(even in the "free" versions provided by Xilinx) and it runs under Linux.
76
There are actually more advantages of the <STRONG>ghdl</STRONG>/<STRONG>gtkwave</STRONG> combination;
77
after having used both tools in the past the author definitely prefers
78
<STRONG>ghdl</STRONG>/<STRONG>gtkwave</STRONG>.
79
 
80
<P>An example output of the functional simulation that shows the  operation
81
our CPU:
82
 
83
<P><br>
84
 
85
<P><img src="GTKWave.png">
86
 
87
<P><br>
88
 
89
<P>We can compare the CPU signals shown with the assembler code being executed.
90
The CPU is executing inside the C function <STRONG>uart_puts()</STRONG>:
91
 
92
<P><br>
93
 
94
<pre class="vhdl">
95
 
96
156     00000095: (uart_puts):
97
157       95:   01AC            movw    r20, r24
98
158       96:   C003            rjmp     0x9A           ; 0x134 <uart_puts+0xa>
99
159       97:   9B5D            sbis    0x0b, 5 ; 11
100
160       98:   CFFE            rjmp     0x97           ; 0x12e <uart_puts+0x4>
101
161       99:   B92C            out     0x0c, r18       ; 12
102
162       9A:   01FC            movw    r30, r24
103
163       9B:   9601            adiw    r24, 0x01       ; 1
104
164       9C:   9124            lpm     r18, Z
105
165       9D:   2322            and     r18, r18
106
166       9E:   F7C1            brne     0x97           ; 0x12e <uart_puts+0x4>
107
167       9F:   1B84            sub     r24, r20
108
168       A0:   0B95            sbc     r25, r21
109
169       A1:   9701            sbiw    r24, 0x01       ; 1
110
170       A2:   9508            ret
111
<pre class="filename">
112
app/hello.lss1
113
</pre></pre>
114
<P>
115
 
116
<P><br>
117
 
118
<H2><A NAME="section_1_2">8.2 Timing Simulation and FPGA Configuration</A></H2>
119
 
120
<P>After the CPU functions correctly, the design can be fed into the Xilinx
121
toolchain. This toolchain is better described in the documentation that
122
comes with it, so we don't go to too much detail here.
123
 
124
<P>We used Webpack 10.1, which can be downloaded from Xilinx.
125
 
126
<P>The first step is to set up a project in the ISE project navigator with
127
the proper target device. Then the VHDL files in the <STRONG>src</STRONG> directory are
128
added to the project. Next the <STRONG>Synthesize</STRONG> and <STRONG>Implementation</STRONG> steps
129
of the design flow are run.
130
 
131
<P>If this is successful, then we can generate a programming file. There are
132
a number of ways to configure Xilinx FPGAs, and the type of programming file
133
needed depends on the particular way of configuring the device. The board
134
we used for testing the CPU had a serial PROM and therefore we generated
135
a programming file for the serial PROM on the board. The FPGA would then
136
load from the PROM on start-up. Other ways of configuring the device are
137
via JTAG, which is also quite handy during debugging.
138
 
139
<P>The entire build process is a little lengthy (and the devil is known to
140
hide in the details). We therefore go through the entire design flow in
141
a step-by-step fashion.
142
 
143
<H2><A NAME="section_1_3">8.3 Downloading and Building the Tools </A></H2>
144
 
145
<UL>
146
  <LI>Download and install <STRONG>ghdl</STRONG>.
147
  <LI>Download and install <STRONG>gtkwave</STRONG>.
148
  <LI>Download and install the Xilinx toolchain.
149
  <LI>Build the <STRONG>make_mem</STRONG> tool. The source is this:
150
</UL>
151
<P><br>
152
 
153
<pre class="vhdl">
154
 
155
  1     #include "assert.h"
156
  2     #include "stdio.h"
157
  3     #include "stdint.h"
158
  4     #include "string.h"
159
  5
160
  6     const char * hex_file = 0;
161
  7     const char * vhdl_file = 0;
162
  8
163
  9     uint8_t buffer[0x10000];
164
 10
165
 11     //-----------------------------------------------------------------------------
166
 12     uint32_t
167
 13     get_byte(const char *  cp)
168
 14     {
169
 15     uint32_t value;
170
 16     const char cc[3] = { cp[0], cp[1], 0 };
171
 17     const int cnt = sscanf(cc, "%X", &value);
172
 18        assert(cnt == 1);
173
 19        return value;
174
 20     }
175
 21     //-----------------------------------------------------------------------------
176
 22     void
177
 23     read_file(FILE * in)
178
 24     {
179
 25        memset(buffer, 0xFF, sizeof(buffer));
180
 26     char line[200];
181
 27        for (;;)
182
 28            {
183
 29              const char * s = fgets(line, sizeof(line) - 2, in);
184
 30              if (s == 0)   return;
185
 31              assert(*s++ == ':');
186
 32              const uint32_t len     = get_byte(s);
187
 33              const uint32_t ah      = get_byte(s + 2);
188
 34              const uint32_t al      = get_byte(s + 4);
189
 35              const uint32_t rectype = get_byte(s + 6);
190
 36              const char * d = s + 8;
191
 37              const uint32_t addr = ah << 8 | al;
192
 38
193
 39              uint32_t csum = len + ah + al + rectype;
194
 40              assert((addr + len) <= 0x10000);
195
 41              for (uint32_t l = 0; l < len; ++l)
196
 42                  {
197
 43                    const uint32_t byte = get_byte(d);
198
 44                    d += 2;
199
 45                    buffer[addr + l] = byte;
200
 46                    csum += byte;
201
 47                  }
202
 48
203
 49              csum = 0xFF & -csum;
204
 50              const uint32_t sum = get_byte(d);
205
 51              assert(sum == csum);
206
 52            }
207
 53     }
208
 54     //-----------------------------------------------------------------------------
209
 55     void
210
 56     write_vector(FILE * out, bool odd, uint32_t mem, uint32_t v)
211
 57     {
212
 58     const uint8_t * base = buffer;
213
 59
214
 60        // total memory is 2 even bytes, 2 odd bytes, 2 even bytes, ...
215
 61        //
216
 62        if (odd)   base += 2;
217
 63
218
 64        // total memory is 4 kByte organized into 8 memories.
219
 65        // thus each of the 16 vectors covers 256 bytes.
220
 66        //
221
 67        base += v*256;
222
 68
223
 69        // memories 0 and 1 are the low byte of the opcode while
224
 70        // memories 2 and 3 are the high byte.
225
 71        //
226
 72        if (mem >= 2)   ++base;
227
 73
228
 74     const char * px = odd ? "po" : "pe";
229
 75        fprintf(out, "constant %s_%u_%2.2X : BIT_VECTOR := X\"", px, mem, v);
230
 76        for (int32_t d = 63; d >= 0; --d)
231
 77            {
232
 78              uint32_t q = base[4*d];
233
 79              if (mem & 1)   q >>= 4;     // high nibble
234
 80              else           q &= 0x0F;   // low nibble
235
 81              fprintf(out, "%X", q);
236
 82            }
237
 83
238
 84        fprintf(out, "\";\r\n");
239
 85     }
240
 86     //-----------------------------------------------------------------------------
241
 87     void
242
 88     write_mem(FILE * out, bool odd, uint32_t mem)
243
 89     {
244
 90     const char * px = odd ? "po" : "pe";
245
 91
246
 92        fprintf(out, "-- content of %s_%u --------------------------------------"
247
 93                     "--------------------------------------------\r\n", px, mem);
248
 94
249
 95        for (uint32_t v = 0; v < 16; ++v)
250
 96            write_vector(out, odd, mem, v);
251
 97
252
 98        fprintf(out, "\r\n");
253
 99     }
254
100     //-----------------------------------------------------------------------------
255
101     void
256
102     write_file(FILE * out)
257
103     {
258
104        fprintf(out,
259
105     "\r\n"
260
106     "library IEEE;\r\n"
261
107     "use IEEE.STD_LOGIC_1164.all;\r\n"
262
108     "\r\n"
263
109     "package prog_mem_content is\r\n"
264
110     "\r\n");
265
111
266
112        for (uint32_t m = 0; m < 4; ++m)
267
113            write_mem(out, false, m);
268
114
269
115        for (uint32_t m = 0; m < 4; ++m)
270
116            write_mem(out, true,  m);
271
117
272
118        fprintf(out,
273
119     "end prog_mem_content;\r\n"
274
120     "\r\n");
275
121     }
276
122     //-----------------------------------------------------------------------------
277
123     int
278
124     main(int argc, char * argv[])
279
125     {
280
126        if (argc > 1)   hex_file = argv[1];
281
127        if (argc > 2)   vhdl_file = argv[2];
282
128
283
129     FILE * in = stdin;
284
130        if (hex_file)   in = fopen(hex_file, "r");
285
131        assert(in);
286
132        read_file(in);
287
133        fclose(in);
288
134
289
135     FILE * out = stdout;
290
136        if (vhdl_file)   out = fopen(vhdl_file, "w");
291
137        write_file(out);
292
138        assert(out);
293
139     }
294
140     //-----------------------------------------------------------------------------
295
<pre class="filename">
296
tools/make_mem.cc
297
</pre></pre>
298
<P>
299
 
300
<P><br>
301
 
302
<P>The command to build the tool is:
303
 
304
<P><br>
305
 
306
<pre class="cmd">
307
 
308
# Build makemem.
309
g++ -o make_mem make_mem.cc
310
 
311
</pre>
312
<P>
313
 
314
<P><br>
315
 
316
<UL>
317
  <LI>Build the <STRONG>end_conv</STRONG> tool. The source is this:
318
</UL>
319
<P><br>
320
 
321
<pre class="vhdl">
322
 
323
  1     #include "assert.h"
324
  2     #include "ctype.h"
325
  3     #include "stdio.h"
326
  4     #include "string.h"
327
  5
328
  6     //-----------------------------------------------------------------------------
329
  7     int
330
  8     main(int argc, const char * argv)
331
  9     {
332
 10     char buffer[2000];
333
 11     int pc, val, val2;
334
 12
335
 13        for (;;)
336
 14            {
337
 15              char * s = fgets(buffer, sizeof(buffer) - 2, stdin);
338
 16              if (s == 0)   return 0;
339
 17
340
 18              // map lines '  xx:' and 'xxxxxxxx; to 2* the hex value.
341
 19              //
342
 20              if (
343
 21                  (isxdigit(s[0]) || s[0] == ' ') &&
344
 22                  (isxdigit(s[1]) || s[1] == ' ') &&
345
 23                  (isxdigit(s[2]) || s[2] == ' ') &&
346
 24                   isxdigit(s[3]) && s[4] == ':')   // '  xx:'
347
 25                 {
348
 26                   assert(1 == sscanf(s, " %x:", &pc));
349
 27                   if (pc & 1)       printf("%4X+:", pc/2);
350
 28                   else              printf("%4X:", pc/2);
351
 29                   s += 5;
352
 30                 }
353
 31              else if (isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) &&
354
 32                       isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) &&
355
 33                       isxdigit(s[6]) && isxdigit(s[7]))             // 'xxxxxxxx'
356
 34                 {
357
 35                   assert(1 == sscanf(s, "%x", &pc));
358
 36                   if (pc & 1)   printf("%8.8X+:", pc/2);
359
 37                   else          printf("%8.8X:", pc/2);
360
 38                   s += 8;
361
 39                 }
362
 40              else                             // other: copy verbatim
363
 41                 {
364
 42                   printf("%s", s);
365
 43                   continue;
366
 44                 }
367
 45
368
 46               while (isblank(*s))   printf("%c", *s++);
369
 47
370
 48               // endian swap.
371
 49               //
372
 50               while (isxdigit(s[0]) &&
373
 51                      isxdigit(s[1]) &&
374
 52                               s[2] == ' ' &&
375
 53                      isxdigit(s[3]) &&
376
 54                      isxdigit(s[4]) &&
377
 55                               s[5] == ' ')
378
 56                  {
379
 57                   assert(2 == sscanf(s, "%x %x ", &val, &val2));
380
 58                   printf("%2.2X%2.2X  ", val2, val);
381
 59                   s += 6;
382
 60                  }
383
 61
384
 62              char * s1 = strstr(s, ".+");
385
 63              char * s2 = strstr(s, ".-");
386
 64              if (s1)
387
 65                 {
388
 66                   assert(1 == sscanf(s1 + 2, "%d", &val));
389
 67                   assert((val & 1) == 0);
390
 68                   sprintf(s1, " 0x%X", (pc + val)/2 + 1);
391
 69                   printf(s);
392
 70                   s = s1 + strlen(s1) + 1;
393
 71                 }
394
 72              else if (s2)
395
 73                 {
396
 74                   assert(1 == sscanf(s2 + 2, "%d", &val));
397
 75                   assert((val & 1) == 0);
398
 76                   sprintf(s2, " 0x%X", (pc - val)/2 + 1);
399
 77                   printf(s);
400
 78                   s = s2 + strlen(s2) + 1;
401
 79                 }
402
 80
403
 81              printf("%s", s);
404
 82            }
405
 83     }
406
 84     //-----------------------------------------------------------------------------
407
<pre class="filename">
408
tools/end_conv.cc
409
</pre></pre>
410
<P>
411
 
412
<P><br>
413
 
414
<P>The command to build the tool is:
415
 
416
<P><br>
417
 
418
<pre class="cmd">
419
 
420
# Build end_conv.
421
g++ -o end_conv end_conv.cc
422
 
423
</pre>
424
<P>
425
 
426
<P><br>
427
 
428
<H2><A NAME="section_1_4">8.4 Preparing the Memory Content</A></H2>
429
 
430
<P>We write a program <STRONG>hello.c</STRONG> that prints "Hello World" to the serial line.
431
 
432
<P>The source is this:
433
 
434
<P><br>
435
 
436
<pre class="vhdl">
437
 
438
  1     #include "stdint.h"
439
  2     #include "avr/io.h"
440
  3     #include "avr/pgmspace.h"
441
  4
442
  5     #undef F_CPU
443
  6     #define F_CPU 25000000UL
444
  7     #include "util/delay.h"
445
  8
446
  9
447
 10          //----------------------------------------------------------------------//
448
 11         //                                                                      //
449
 12        //   print char cc on UART.                                             //
450
 13       //    return number of chars printed (i.e. 1).                          //
451
 14      //                                                                      //
452
 15     //----------------------------------------------------------------------//
453
 16     uint8_t
454
 17     uart_putc(uint8_t cc)
455
 18     {
456
 19         while ((UCSRA & (1 << UDRE)) == 0)      ;
457
 20         UDR = cc;
458
 21         return 1;
459
 22     }
460
 23
461
 24          //----------------------------------------------------------------------//
462
 25         //                                                                      //
463
 26        //   print char cc on 7 segment display.                                //
464
 27       //    return number of chars printed (i.e. 1).                          //
465
 28      //                                                                      //
466
 29     //----------------------------------------------------------------------//
467
 30     // The segments of the display are encoded like this:
468
 31     //
469
 32     //
470
 33     //      segment     PORT B
471
 34     //      name        Bit number
472
 35     //      ----A----   ----0----
473
 36     //      |       |   |       |
474
 37     //      F       B   5       1
475
 38     //      |       |   |       |
476
 39     //      ----G----   ----6----
477
 40     //      |       |   |       |
478
 41     //      E       C   4       2
479
 42     //      |       |   |       |
480
 43     //      ----D----   ----3----
481
 44     //
482
 45     //-----------------------------------------------------------------------------
483
 46
484
 47     #define SEG7(G, F, E, D, C, B, A)   (~(G<<6|F<<5|E<<4|D<<3|C<<2|B<<1|A))
485
 48
486
 49     uint8_t
487
 50     seg7_putc(uint8_t cc)
488
 51     {
489
 52     uint16_t t;
490
 53
491
 54         switch(cc)
492
 55         {                   //   G F E D C B A
493
 56         case ' ':   PORTB = SEG7(0,0,0,0,0,0,0);        break;
494
 57         case 'E':   PORTB = SEG7(1,1,1,1,0,0,1);        break;
495
 58         case 'H':   PORTB = SEG7(1,1,1,0,1,1,0);        break;
496
 59         case 'L':   PORTB = SEG7(0,1,1,1,0,0,0);        break;
497
 60         case 'O':   PORTB = SEG7(0,1,1,1,1,1,1);        break;
498
 61         default:    PORTB = SEG7(1,0,0,1,0,0,1);        break;
499
 62         }
500
 63
501
 64         // wait 800 + 200 ms. This can be quite boring in simulations,
502
 65         // so we wait only if DIP switch 6 is closed.
503
 66         //
504
 67         if (!(PINB & 0x20))     for (t = 0; t < 800; ++t)   _delay_ms(1);
505
 68         PORTB = SEG7(0,0,0,0,0,0,0);
506
 69         if (!(PINB & 0x20))     for (t = 0; t < 200; ++t)   _delay_ms(1);
507
 70
508
 71         return 1;
509
 72     }
510
 73
511
 74          //----------------------------------------------------------------------//
512
 75         //                                                                      //
513
 76        //   print string s on UART.                                            //
514
 77       //    return number of chars printed.                                   //
515
 78      //                                                                      //
516
 79     //----------------------------------------------------------------------//
517
 80     uint16_t
518
 81     uart_puts(const char * s)
519
 82     {
520
 83     const char * from = s;
521
 84     uint8_t cc;
522
 85         while ((cc = pgm_read_byte(s++)))   uart_putc(cc);
523
 86         return s - from - 1;
524
 87     }
525
 88
526
 89          //----------------------------------------------------------------------//
527
 90         //                                                                      //
528
 91        //   print string s on 7 segment display.                               //
529
 92       //    return number of chars printed.                                   //
530
 93      //                                                                      //
531
 94     //----------------------------------------------------------------------//
532
 95     uint16_t
533
 96     seg7_puts(const char * s)
534
 97     {
535
 98     const char * from = s;
536
 99     uint8_t cc;
537
100         while ((cc = pgm_read_byte(s++)))   seg7_putc(cc);
538
101         return s - from - 1;
539
102     }
540
103
541
104     //-----------------------------------------------------------------------------
542
105     int
543
106     main(int argc, char * argv[])
544
107     {
545
108         for (;;)
546
109         {
547
110             if (PINB & 0x40)    // DIP switch 7 open.
548
111                 {
549
112                     // print 'Hello world' on UART.
550
113                     uart_puts(PSTR("Hello, World!\r\n"));
551
114                 }
552
115             else                // DIP switch 7 closed.
553
116                 {
554
117                     // print 'HELLO' on 7-segment display
555
118                     seg7_puts(PSTR("HELLO "));
556
119                 }
557
120         }
558
121     }
559
122     //-----------------------------------------------------------------------------
560
<pre class="filename">
561
app/hello.c
562
</pre></pre>
563
<P>
564
 
565
<P><br>
566
 
567
<P>The commands to create <STRONG>hello.hex</STRONG> and <STRONG>hello.css</STRONG> are:
568
 
569
<P><br>
570
 
571
<pre class="cmd">
572
 
573
# Compile and link hello.c.
574
avr-gcc -Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=atmega8 \
575
    -DF_CPU=33333333UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "main.c"
576
avr-gcc -Wl,-Map,AVR_FPGA.map -mmcu=atmega8 -o"AVR_FPGA.elf"  ./main.o
577
 
578
# Create an opcode listing.
579
avr-objdump -h -S AVR_FPGA.elf  >"AVR_FPGA.lss"
580
 
581
# Create intel hex file.
582
avr-objcopy -R .eeprom -O ihex AVR_FPGA.elf  "AVR_FPGA.hex"
583
 
584
</pre>
585
<P>
586
 
587
<P><br>
588
 
589
<P>Create  <STRONG>hello.css1</STRONG>, a better readable from of  <STRONG>hello.css</STRONG>:
590
 
591
<P><br>
592
 
593
<pre class="cmd">
594
 
595
# Create hello.css1.
596
./end_conv < hello.css > hello.css1
597
 
598
</pre>
599
<P>
600
 
601
<P><br>
602
 
603
<P>Create <STRONG>prog_mem_content.vhd</STRONG>.
604
 
605
<P><br>
606
 
607
<pre class="cmd">
608
 
609
# Create prog_mem_content.vhd.
610
./make_mem < hello.hex > src/prog_mem_content.vhd
611
 
612
</pre>
613
<P>
614
 
615
<P><br>
616
 
617
<H2><A NAME="section_1_5">8.5 Performing the Functional Simulation</A></H2>
618
 
619
<H3><A NAME="section_1_5_1">8.5.1 Preparing a Testbench</A></H3>
620
 
621
<P>We prepare a testbench in which we instantiate the top-level FPGA design
622
of the CPU. The test bench provides a clock signal and a reset signal
623
for the CPU:
624
 
625
<P><br>
626
 
627
<pre class="vhdl">
628
 
629
  1     -------------------------------------------------------------------------------
630
  2     --
631
  3     -- Copyright (C) 2009, 2010 Dr. Juergen Sauermann
632
  4     --
633
  5     --  This code is free software: you can redistribute it and/or modify
634
  6     --  it under the terms of the GNU General Public License as published by
635
  7     --  the Free Software Foundation, either version 3 of the License, or
636
  8     --  (at your option) any later version.
637
  9     --
638
 10     --  This code is distributed in the hope that it will be useful,
639
 11     --  but WITHOUT ANY WARRANTY; without even the implied warranty of
640
 12     --  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
641
 13     --  GNU General Public License for more details.
642
 14     --
643
 15     --  You should have received a copy of the GNU General Public License
644
 16     --  along with this code (see the file named COPYING).
645
 17     --  If not, see http://www.gnu.org/licenses/.
646
 18     --
647
 19     -------------------------------------------------------------------------------
648
 20     -------------------------------------------------------------------------------
649
 21     --
650
 22     -- Module Name:    alu - Behavioral
651
 23     -- Create Date:    16:47:24 12/29/2009
652
 24     -- Description:    arithmetic logic unit of a CPU
653
 25     --
654
 26     -------------------------------------------------------------------------------
655
 27     --
656
 28     library IEEE;
657
 29     use IEEE.STD_LOGIC_1164.ALL;
658
 30     use IEEE.STD_LOGIC_ARITH.ALL;
659
 31     use IEEE.STD_LOGIC_UNSIGNED.ALL;
660
 32
661
 33     entity testbench is
662
 34     end testbench;
663
 35
664
 36     architecture Behavioral of testbench is
665
 37
666
 38     component avr_fpga
667
 39         port (  I_CLK_100   : in  std_logic;
668
 40                 I_SWITCH    : in  std_logic_vector(9 downto 0);
669
 41                 I_RX        : in  std_logic;
670
 42
671
 43                 Q_7_SEGMENT : out std_logic_vector(6 downto 0);
672
 44                 Q_LEDS      : out std_logic_vector(3 downto 0);
673
 45                 Q_TX        : out std_logic);
674
 46     end component;
675
 47
676
 48     signal L_CLK_100            : std_logic;
677
 49     signal L_LEDS               : std_logic_vector(3 downto 0);
678
 50     signal L_7_SEGMENT          : std_logic_vector(6 downto 0);
679
 51     signal L_RX                 : std_logic;
680
 52     signal L_SWITCH             : std_logic_vector(9 downto 0);
681
 53     signal L_TX                 : std_logic;
682
 54
683
 55     signal  L_CLK_COUNT         : integer := 0;
684
 56
685
 57     begin
686
 58
687
 59         fpga: avr_fpga
688
 60         port map(   I_CLK_100   => L_CLK_100,
689
 61                     I_SWITCH    => L_SWITCH,
690
 62                     I_RX        => L_RX,
691
 63
692
 64                     Q_LEDS      => L_LEDS,
693
 65                     Q_7_SEGMENT => L_7_SEGMENT,
694
 66                     Q_TX        => L_TX);
695
 67
696
 68         process -- clock process for CLK_100,
697
 69         begin
698
 70             clock_loop : loop
699
 71                 L_CLK_100 <= transport '0';
700
 72                 wait for 5 ns;
701
 73
702
 74                 L_CLK_100 <= transport '1';
703
 75                 wait for 5 ns;
704
 76             end loop clock_loop;
705
 77         end process;
706
 78
707
 79         process(L_CLK_100)
708
 80         begin
709
 81             if (rising_edge(L_CLK_100)) then
710
 82                 case L_CLK_COUNT is
711
 83                     when 0 => L_SWITCH <= "0011100000";   L_RX <= '0';
712
 84                     when 2 => L_SWITCH(9 downto 8) <= "11";
713
 85                     when others =>
714
 86                 end case;
715
 87                 L_CLK_COUNT <= L_CLK_COUNT + 1;
716
 88             end if;
717
 89         end process;
718
 90     end Behavioral;
719
 91
720
<pre class="filename">
721
test/test_tb.vhd
722
</pre></pre>
723
<P>
724
 
725
<P><br>
726
 
727
<H3><A NAME="section_1_5_2">8.5.2 Defining Memory Modules</A></H3>
728
 
729
<P>We also need a VHDL file that implements the Xilinx primitives that
730
we use. This is only one: the memory module RAMB4_S4_S4:
731
 
732
<P><br>
733
 
734
<pre class="vhdl">
735
 
736
  1     -------------------------------------------------------------------------------
737
  2     --
738
  3     -- Copyright (C) 2009, 2010 Dr. Juergen Sauermann
739
  4     --
740
  5     --  This code is free software: you can redistribute it and/or modify
741
  6     --  it under the terms of the GNU General Public License as published by
742
  7     --  the Free Software Foundation, either version 3 of the License, or
743
  8     --  (at your option) any later version.
744
  9     --
745
 10     --  This code is distributed in the hope that it will be useful,
746
 11     --  but WITHOUT ANY WARRANTY; without even the implied warranty of
747
 12     --  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
748
 13     --  GNU General Public License for more details.
749
 14     --
750
 15     --  You should have received a copy of the GNU General Public License
751
 16     --  along with this code (see the file named COPYING).
752
 17     --  If not, see http://www.gnu.org/licenses/.
753
 18     --
754
 19     -------------------------------------------------------------------------------
755
 20     -------------------------------------------------------------------------------
756
 21     --
757
 22     -- Module Name:    prog_mem - Behavioral
758
 23     -- Create Date:    14:09:04 10/30/2009
759
 24     -- Description:    a block memory module
760
 25     --
761
 26     -------------------------------------------------------------------------------
762
 27
763
 28     library IEEE;
764
 29     use IEEE.STD_LOGIC_1164.ALL;
765
 30     use IEEE.STD_LOGIC_ARITH.ALL;
766
 31     use IEEE.STD_LOGIC_UNSIGNED.ALL;
767
 32
768
 33     entity RAMB4_S4_S4 is
769
 34         generic(INIT_00 : bit_vector := X"00000000000000000000000000000000"
770
 35                                       &  "00000000000000000000000000000000";
771
 36                 INIT_01 : bit_vector := X"00000000000000000000000000000000"
772
 37                                       & X"00000000000000000000000000000000";
773
 38                 INIT_02 : bit_vector := X"00000000000000000000000000000000"
774
 39                                       & X"00000000000000000000000000000000";
775
 40                 INIT_03 : bit_vector := X"00000000000000000000000000000000"
776
 41                                       & X"00000000000000000000000000000000";
777
 42                 INIT_04 : bit_vector := X"00000000000000000000000000000000"
778
 43                                       & X"00000000000000000000000000000000";
779
 44                 INIT_05 : bit_vector := X"00000000000000000000000000000000"
780
 45                                       & X"00000000000000000000000000000000";
781
 46                 INIT_06 : bit_vector := X"00000000000000000000000000000000"
782
 47                                       & X"00000000000000000000000000000000";
783
 48                 INIT_07 : bit_vector := X"00000000000000000000000000000000"
784
 49                                       & X"00000000000000000000000000000000";
785
 50                 INIT_08 : bit_vector := X"00000000000000000000000000000000"
786
 51                                       & X"00000000000000000000000000000000";
787
 52                 INIT_09 : bit_vector := X"00000000000000000000000000000000"
788
 53                                       & X"00000000000000000000000000000000";
789
 54                 INIT_0A : bit_vector := X"00000000000000000000000000000000"
790
 55                                       & X"00000000000000000000000000000000";
791
 56                 INIT_0B : bit_vector := X"00000000000000000000000000000000"
792
 57                                       & X"00000000000000000000000000000000";
793
 58                 INIT_0C : bit_vector := X"00000000000000000000000000000000"
794
 59                                       & X"00000000000000000000000000000000";
795
 60                 INIT_0D : bit_vector := X"00000000000000000000000000000000"
796
 61                                       & X"00000000000000000000000000000000";
797
 62                 INIT_0E : bit_vector := X"00000000000000000000000000000000"
798
 63                                       & X"00000000000000000000000000000000";
799
 64                 INIT_0F : bit_vector := X"00000000000000000000000000000000"
800
 65                                       & X"00000000000000000000000000000000");
801
 66
802
 67         port(   ADDRA   : in  std_logic_vector(9 downto 0);
803
 68                 ADDRB   : in  std_logic_vector(9 downto 0);
804
 69                 CLKA    : in  std_ulogic;
805
 70                 CLKB    : in  std_ulogic;
806
 71                 DIA     : in  std_logic_vector(3 downto 0);
807
 72                 DIB     : in  std_logic_vector(3 downto 0);
808
 73                 ENA     : in  std_ulogic;
809
 74                 ENB     : in  std_ulogic;
810
 75                 RSTA    : in  std_ulogic;
811
 76                 RSTB    : in  std_ulogic;
812
 77                 WEA     : in  std_ulogic;
813
 78                 WEB     : in  std_ulogic;
814
 79
815
 80                 DOA     : out std_logic_vector(3 downto 0);
816
 81                 DOB     : out std_logic_vector(3 downto 0));
817
 82     end RAMB4_S4_S4;
818
 83
819
 84     architecture Behavioral of RAMB4_S4_S4 is
820
 85
821
 86     function cv(A : bit) return std_logic is
822
 87     begin
823
 88        if (A = '1') then return '1';
824
 89        else              return '0';
825
 90        end if;
826
 91     end;
827
 92
828
 93     function cv1(A : std_logic) return bit is
829
 94     begin
830
 95        if (A = '1') then return '1';
831
 96        else              return '0';
832
 97        end if;
833
 98     end;
834
 99
835
100     signal DATA : bit_vector(4095 downto 0) :=
836
101         INIT_0F & INIT_0E & INIT_0D & INIT_0C & INIT_0B & INIT_0A & INIT_09 & INIT_08 &
837
102         INIT_07 & INIT_06 & INIT_05 & INIT_04 & INIT_03 & INIT_02 & INIT_01 & INIT_00;
838
103
839
104     begin
840
105
841
106         process(CLKA, CLKB)
842
107         begin
843
108             if (rising_edge(CLKA)) then
844
109                 if (ENA = '1') then
845
110                     DOA(3) <= cv(DATA(conv_integer(ADDRA & "11")));
846
111                     DOA(2) <= cv(DATA(conv_integer(ADDRA & "10")));
847
112                     DOA(1) <= cv(DATA(conv_integer(ADDRA & "01")));
848
113                     DOA(0) <= cv(DATA(conv_integer(ADDRA & "00")));
849
114                     if (WEA = '1') then
850
115                         DATA(conv_integer(ADDRA & "11")) <= cv1(DIA(3));
851
116                         DATA(conv_integer(ADDRA & "10")) <= cv1(DIA(2));
852
117                         DATA(conv_integer(ADDRA & "01")) <= cv1(DIA(1));
853
118                         DATA(conv_integer(ADDRA & "00")) <= cv1(DIA(0));
854
119                     end if;
855
120                end if;
856
121             end if;
857
122
858
123             if (rising_edge(CLKB)) then
859
124                 if (ENB = '1') then
860
125                     DOB(3) <= cv(DATA(conv_integer(ADDRB & "11")));
861
126                     DOB(2) <= cv(DATA(conv_integer(ADDRB & "10")));
862
127                     DOB(1) <= cv(DATA(conv_integer(ADDRB & "01")));
863
128                     DOB(0) <= cv(DATA(conv_integer(ADDRB & "00")));
864
129                     if (WEB = '1') then
865
130                         DATA(conv_integer(ADDRB & "11")) <= cv1(DIB(3));
866
131                         DATA(conv_integer(ADDRB & "10")) <= cv1(DIB(2));
867
132                         DATA(conv_integer(ADDRB & "01")) <= cv1(DIB(1));
868
133                         DATA(conv_integer(ADDRB & "00")) <= cv1(DIB(0));
869
134                     end if;
870
135                 end if;
871
136             end if;
872
137         end process;
873
138
874
139     end Behavioral;
875
140
876
<pre class="filename">
877
test/RAMB4_S4_S4.vhd
878
</pre></pre>
879
<P>
880
 
881
<P><br>
882
 
883
<H3><A NAME="section_1_5_3">8.5.3 Creating the testbench executable</A></H3>
884
 
885
<P>We assume the following file structure:
886
 
887
<UL>
888
  <LI>a <STRONG>test</STRONG> directory that contains the testbench (<STRONG>test_tb.vhd</STRONG>) and the
889
  memory module (<STRONG>RAMB4_S4_S4.vhd</STRONG>).
890
  <LI>a <STRONG>src</STRONG> directory that contains all other VHDL files.
891
  <LI>a <STRONG>simu</STRONG> directory (empty).
892
  <LI>A <STRONG>Makefile</STRONG> like this:
893
</UL>
894
<P><br>
895
 
896
<pre class="vhdl">
897
 
898
  1     PROJECT=avr_core
899
  2
900
  3     # the vhdl source files (except testbench)
901
  4     #
902
  5     FILES           += src/*.vhd
903
  6
904
  7     # the testbench sources and binary.
905
  8     #
906
  9     SIMFILES        = test/test_tb.vhd test/RAMB4_S4_S4.vhd
907
 10     SIMTOP          = testbench
908
 11
909
 12     # When to stop the simulation
910
 13     #
911
 14     # GHDL_SIM_OPT  = --assert-level=error
912
 15     GHDL_SIM_OPT    = --stop-time=40us
913
 16
914
 17     SIMDIR          = simu
915
 18
916
 19     FLAGS           = --ieee=synopsys --warn-no-vital-generic -fexplicit --std=93c
917
 20
918
 21     all:
919
 22             make compile
920
 23             make run 2>& 1 | grep -v std_logic_arith
921
 24             make view
922
 25
923
 26     compile:
924
 27             @mkdir -p simu
925
 28             @echo -----------------------------------------------------------------
926
 29             ghdl -i $(FLAGS) --workdir=simu --work=work $(SIMFILES) $(FILES)
927
 30             @echo
928
 31             @echo -----------------------------------------------------------------
929
 32             ghdl -m $(FLAGS) --workdir=simu --work=work $(SIMTOP)
930
 33             @echo
931
 34             @mv $(SIMTOP) simu/$(SIMTOP)
932
 35
933
 36     run:
934
 37             @$(SIMDIR)/$(SIMTOP) $(GHDL_SIM_OPT) --vcdgz=$(SIMDIR)/$(SIMTOP).vcdgz
935
 38
936
 39     view:
937
 40             gunzip --stdout $(SIMDIR)/$(SIMTOP).vcdgz | gtkwave --vcd gtkwave.save
938
 41
939
 42     clean:
940
 43             ghdl --clean --workdir=simu
941
 44
942
<pre class="filename">
943
Makefile
944
</pre></pre>
945
<P>
946
 
947
<P><br>
948
 
949
<DL>
950
  <DT>Then</DT>
951
<DD>
952
</DL>
953
<P><br>
954
 
955
<pre class="cmd">
956
 
957
# Run the functional simulation.
958
make
959
 
960
</pre>
961
<P>
962
 
963
<P><br>
964
 
965
<P>It will take a moment, but then a <STRONG>gtkwave</STRONG> window like the one shown
966
earlier in this lesson will appear. It my look a little different due
967
due to different default settings (like background color). In that
968
window you can add new signals from the design that you would like
969
to investigate, remove signals you are not interested in, and so on.
970
At the first time, no signals will be shown; you can add some by selecting
971
a component instance at the right, selecting a signal in that component,
972
and then pushing the <STRONG>append</STRONG> button on the right.
973
 
974
<P>The <STRONG>make</STRONG> command has actually made 3 things:
975
 
976
<UL>
977
  <LI>make compile (compile the VHLD files)
978
  <LI>make run (run the simulation), and
979
  <LI>make view
980
</UL>
981
<P>The first two steps (which took most of the total time) need only be run
982
after changes to the VHDL files.
983
 
984
<H2><A NAME="section_1_6">8.6 Building the Design</A></H2>
985
 
986
<P>When the functional simulation looks OK, it is time to implement the design
987
and check the timing. We describe this only briefly, since the Xilinx
988
documentation of the Xilinx toolchain is a much better source of
989
information.
990
 
991
<H3><A NAME="section_1_6_1">8.6.1 Creating an UCF file</A></H3>
992
 
993
<P>Before implementing the design, we need an <STRONG>UCF</STRONG> file. That file
994
describes timing requirements, pin properties (like pull-ups for our
995
DIP switch), and pin-to-signal mappings:
996
 
997
<P><br>
998
 
999
<pre class="vhdl">
1000
 
1001
  1     NET     I_CLK_100       PERIOD = 10 ns;
1002
  2     NET     L_CLK           PERIOD = 35 ns;
1003
  3
1004
  4     NET     I_CLK_100       TNM_NET = I_CLK_100;
1005
  5     NET     L_CLK           TNM_NET = L_CLK;
1006
  6
1007
  7     NET     I_CLK_100       LOC = AA12;
1008
  8     NET     I_RX            LOC = M3;
1009
  9     NET     Q_TX            LOC = M4;
1010
 10
1011
 11     # 7 segment LED display
1012
 12     #
1013
 13     NET     Q_7_SEGMENT<0>  LOC = V3;
1014
 14     NET     Q_7_SEGMENT<1>  LOC = V4;
1015
 15     NET     Q_7_SEGMENT<2>  LOC = W3;
1016
 16     NET     Q_7_SEGMENT<3>  LOC = T4;
1017
 17     NET     Q_7_SEGMENT<4>  LOC = T3;
1018
 18     NET     Q_7_SEGMENT<5>  LOC = U3;
1019
 19     NET     Q_7_SEGMENT<6>  LOC = U4;
1020
 20
1021
 21     # single LEDs
1022
 22     #
1023
 23     NET     Q_LEDS<0>       LOC = N1;
1024
 24     NET     Q_LEDS<1>       LOC = N2;
1025
 25     NET     Q_LEDS<2>       LOC = P1;
1026
 26     NET     Q_LEDS<3>       LOC = P2;
1027
 27
1028
 28     # DIP switch(0 ... 7) and two pushbuttons (8, 9)
1029
 29     #
1030
 30     NET     I_SWITCH<0>     LOC = H2;
1031
 31     NET     I_SWITCH<1>     LOC = H1;
1032
 32     NET     I_SWITCH<2>     LOC = J2;
1033
 33     NET     I_SWITCH<3>     LOC = J1;
1034
 34     NET     I_SWITCH<4>     LOC = K2;
1035
 35     NET     I_SWITCH<5>     LOC = K1;
1036
 36     NET     I_SWITCH<6>     LOC = L2;
1037
 37     NET     I_SWITCH<7>     LOC = L1;
1038
 38     NET     I_SWITCH<8>     LOC = R1;
1039
 39     NET     I_SWITCH<9>     LOC = R2;
1040
 40
1041
 41     NET     I_SWITCH<*>     PULLUP;
1042
 42
1043
<pre class="filename">
1044
src/avr_fpga.ucf
1045
</pre></pre>
1046
<P>
1047
 
1048
<P><br>
1049
 
1050
<H3><A NAME="section_1_6_2">8.6.2 Synthesis and Implementation</A></H3>
1051
 
1052
<UL>
1053
  <LI>Start the ISE project manager and open a new project with the desired
1054
  FPGA device.
1055
  <LI>Add the VHDL files and the <STRONG>UCF</STRONG> file in the <STRONG>src</STRONG> directory to the
1056
  project (Project-&gt;Add Source).
1057
  <LI>Synthesize and implement the design (Process-&gt;Implement top Module).
1058
</UL>
1059
<P>This generates a number of reports, netlists, and other files.
1060
There should be no errors. There will be warnings though, including
1061
timing constraints that are not met.
1062
 
1063
<P>It is important to understand the reason for each warning. Warnings often
1064
point to faults in the design.
1065
 
1066
<P>The next thing to check is the timing reports. We were lucky:
1067
 
1068
<P><br>
1069
 
1070
<pre class="cmd">
1071
 
1072
#Timing report fragment:
1073
================================================================================
1074
Timing constraint: NET "L_CLK" PERIOD = 35 ns HIGH 50%;
1075
 
1076
 676756190 paths analyzed, 2342 endpoints analyzed, 0 failing endpoints
1077
 
1078
 Minimum period is  34.981ns.
1079
--------------------------------------------------------------------------------
1080
 
1081
================================================================================
1082
Timing constraint: NET "I_CLK_100_BUFGP/IBUFG" PERIOD = 10 ns HIGH 50%;
1083
 
1084
 19 paths analyzed, 11 endpoints analyzed, 0 failing endpoints
1085
 
1086
 Minimum period is   3.751ns.
1087
--------------------------------------------------------------------------------
1088
 
1089
 
1090
All constraints were met.
1091
 
1092
</pre>
1093
<P>
1094
 
1095
<P><br>
1096
 
1097
<P>This tells us that we have enough slack on the crystal CLK_100 signal
1098
(8.048ns would allow for up to 124 MHz). We had specified a period
1099
of 35 ns irequirement for the CPU clock:
1100
 
1101
<P><br>
1102
 
1103
<pre class="vhdl">
1104
 
1105
  2     NET     L_CLK           PERIOD = 35 ns;
1106
<pre class="filename">
1107
src/avr_fpga.ucf
1108
</pre></pre>
1109
<P>
1110
 
1111
<P><br>
1112
 
1113
<P>The CPU runs at 25 MHz, or 40 ns. The 35 ns come from the 40 ms minus
1114
a slack of 5 ns. With some tweaking of optimization options, we could
1115
have reached 33 MHz, but then the slack would have been pretty small.
1116
 
1117
<P>However, we rather stay on th safe side.
1118
 
1119
<H2><A NAME="section_1_7">8.7 Creating a Programming File</A></H2>
1120
 
1121
<P>Next we double-click "Generate Programming file" in the ISE project navigator.
1122
This generates a file <STRONG>avr_fpga.bit</STRONG> in the project directory. This can also
1123
be run from a Makefile or from the command line (the command is <STRONG>bitgen</STRONG>).
1124
 
1125
<H2><A NAME="section_1_8">8.8 Configuring the FPGA</A></H2>
1126
 
1127
<P>At this point, we have the choice between configuring the FPGA directly
1128
via JTAG, or flashing an EEPROM and then loading the FPGA from the EEPROM.
1129
 
1130
<H3><A NAME="section_1_8_1">8.8.1 Configuring the FPGA via JTAG Boundary Scan</A></H3>
1131
 
1132
<P>Configuring the FPGA can be done with the Xilinx tool called <STRONG>impact</STRONG>.
1133
The file needed by <STRONG>impact</STRONG> is <STRONG>avr_fpga.bit</STRONG> from above. The configuration
1134
loaded via JTAG will be lost when the FPGA looses power.
1135
 
1136
<P>Choose "Boundary Scan" in <STRONG>impact</STRONG>, select the FPGA and follow the instructions.
1137
 
1138
<H3><A NAME="section_1_8_2">8.8.2 Flashing PROMs</A></H3>
1139
 
1140
<P>In theory this can also be done from ISE. In practice it could (and actually
1141
did) happen that the programming cable (I use an old parallel 3 cable)
1142
is not detected by impact.
1143
 
1144
<P>Before flashing the PROM, the <STRONG>avr_fpga.bit</STRONG> from the previous step needs to
1145
translated into a format suitable for the PROM. My PROM is of the serial
1146
variety, so I start <STRONG>impact</STRONG>, choose "PROM File Formatter" and follow the
1147
instructions.
1148
 
1149
<P>After converting <STRONG>avr_fpga.bit</STRONG> into, for example, <STRONG>avr_fpga.mcs</STRONG>, the
1150
PROM can be flashed. Like before choose "Boundary Scan" in #impact. This
1151
time, however, you select the PROM and not the FPGA, and follow the
1152
instructions.
1153
 
1154
<P>This concludes the description of the design flow and also of the CPU.
1155
The remaining lessons contain the complete listings of all sources files
1156
discussed in this lectures.
1157
 
1158
<P>Thank you very much for your attention.
1159
 
1160
<P><hr><BR>
1161
<table class="ttop"><th class="tpre"><a href="08_IO.html">Previous Lesson</a></th><th class="ttop"><a href="toc.html">Table of Content</a></th><th class="tnxt"><a href="10_Listing_of_alu_vhd.html">Next Lesson</a></th></table>
1162
</BODY>
1163
</HTML>

powered by: WebSVN 2.1.0

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