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

Subversion Repositories tcp_socket

[/] [tcp_socket/] [trunk/] [chips2/] [docs/] [source/] [tutorial/] [index.rst] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 jondawson
Tutorial
2
========
3
 
4
Create and Test a C component
5
-----------------------------
6
 
7
Why not start with a simple example. With your favourite text editor, create a
8
file count.c and add the following::
9
 
10
        void count(){
11
                for(i=1; i<=10; i++){
12
                        report(i);
13
                }
14
        }
15
 
16
You can convert C components into Verilog components using the C2Verilog
17
compiler. The *iverilog* option causes the generated Verilog component to be
18
compiled using Icarus Verilog. The *run* option causes simulation to be run::
19
 
20
        ~$ c2verilog iverilog run test.c
21
        1
22
        2
23
        3
24
        4
25
        5
26
        6
27
        7
28
        8
29
        9
30
        10
31
 
32
When a design is reset, execution starts with the last function defined in
33
the C file. This need not be called *main*. The name of the last function
34
will be used as the name for the generated Verilog component. The C program will
35
appear to execute in sequence, although the compiler may execute instructions
36
concurrently if it does not affect the outcome of the program. This will allow
37
your component to take advantage of the inherent parallelism present in a hardware
38
design.
39
 
40
The *report* function is a *built-in* function which is helpful for debug, it
41
will print the value of a variable on the console during simulations, when you
42
synthesise the design it will be ignored.
43
 
44
This component doesn't have any inputs or outputs, so it isn't going to be very
45
useful in a real design. You can add inputs and outputs to a components using
46
function calls with special names. Functions that start with the name *input_*
47
or *output_* are interpreted as inputs, or outputs respectively.
48
 
49
::
50
 
51
        int temp;
52
        temp = input_spam(); //reads from an input called spam
53
        temp = input_eggs(); //reads from an input called eggs
54
        output_fish(temp);   //writes to an output called fish
55
 
56
 
57
Reading or writing from inputs and outputs causes program execution to block
58
until data is available. This synchronises data transfers with other components
59
executing in the same device, this method of passing data between concurrent
60
processes is much simpler than the mutex/lock/semaphore mechanisms used in
61
multithreaded applications.
62
 
63
If you don't want to commit yourself to reading and input and blocking
64
execution, you can check if data is ready::
65
 
66
        int temp;
67
        if(ready_spam()){
68
                temp = input_spam();
69
        }
70
 
71
There is no equivalent function to check if an output is ready to receive data,
72
this could cause deadlocks if both the sending and receiving end were waiting
73
for one another.
74
 
75
We can now construct some basic hardware components quite simply. Here's a counter for instance::
76
 
77
        void counter(){
78
                while(1){
79
                        for(i=1; i<=10; i++){
80
                                output_out(i);
81
                        }
82
                }
83
        }
84
 
85
We can generate an adder like this::
86
 
87
        void added(){
88
                while(1){
89
                        output_z(input_a()+input_b());
90
                }
91
        }
92
 
93
Or a divider like this (yes, you can synthesise division)::
94
 
95
        void divider(){
96
                while(1){
97
                        output_z(input_a()/input_b());
98
                }
99
        }
100
 
101
We can split a stream of data into two identical data streams using a tee function::
102
 
103
        void tee(){
104
                int temp;
105
                while(1){
106
                        temp = input_a();
107
                        output_y(temp);
108
                        output_z(temp);
109
                }
110
        }
111
 
112
If we want to merge two streams of data, we could interlace them::
113
 
114
        void interlace(){
115
                int temp;
116
                while(1){
117
                        temp = input_a();
118
                        output_z(temp);
119
                        temp = input_b();
120
                        output_z(temp);
121
                }
122
        }
123
 
124
or we could prioritise one stream over the other::
125
 
126
        void arbiter(){
127
                int temp;
128
                while(1){
129
                        if( ready_a() ){
130
                                temp = input_a();
131
                                output_z(temp);
132
                        } else if( ready_b() ){
133
                                temp = input_b();
134
                                output_z(temp);
135
                        }
136
                }
137
        }
138
 

powered by: WebSVN 2.1.0

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