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/Data_Path</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="05_Opcode_Fetch.html">Previous Lesson</a></th><th class="ttop"><a href="toc.html">Table of Content</a></th><th class="tnxt"><a href="07_Opcode_Decoder.html">Next Lesson</a></th></table>
|
11 |
|
|
<hr>
|
12 |
|
|
|
13 |
|
|
<H1><A NAME="section_1">6 DATA PATH</A></H1>
|
14 |
|
|
|
15 |
|
|
<P>In this lesson we will describe the data path of the CPU. We discuss
|
16 |
|
|
the basic elements of the data path, but without reference to particular
|
17 |
|
|
instructions. The implementation of instructions will be discussed in the
|
18 |
|
|
next lesson. In this lesson we are more interested in the capabilities
|
19 |
|
|
of the data path.
|
20 |
|
|
|
21 |
|
|
<P>The data path consists of 3 major components: a register file,
|
22 |
|
|
an ALU (arithmetic/logic unit), and the data memory:
|
23 |
|
|
|
24 |
|
|
<P><br>
|
25 |
|
|
|
26 |
|
|
<P><img src="data_path_1.png">
|
27 |
|
|
|
28 |
|
|
<P><br>
|
29 |
|
|
|
30 |
|
|
<H2><A NAME="section_1_1">6.1 Register File</A></H2>
|
31 |
|
|
|
32 |
|
|
<P>The AVR CPU has 32 general purpose 8-bit registers. Most opcodes use
|
33 |
|
|
individual 8-bit registers, but some that use a pair of registers. The
|
34 |
|
|
first register of a register pair is always an even register, while the
|
35 |
|
|
other register of a pair is the next higher odd register. Instead of using
|
36 |
|
|
32 8-bit registers, we use 16 16-bit register pairs. Each register pair
|
37 |
|
|
consists of two 8-bit registers.
|
38 |
|
|
|
39 |
|
|
<H3><A NAME="section_1_1_1">6.1.1 Register Pair</A></H3>
|
40 |
|
|
|
41 |
|
|
<P>A single register pair is defined as:
|
42 |
|
|
|
43 |
|
|
<P><br>
|
44 |
|
|
|
45 |
|
|
<pre class="vhdl">
|
46 |
|
|
|
47 |
|
|
32 entity reg_16 is
|
48 |
|
|
33 port ( I_CLK : in std_logic;
|
49 |
|
|
34
|
50 |
|
|
35 I_D : in std_logic_vector (15 downto 0);
|
51 |
|
|
36 I_WE : in std_logic_vector ( 1 downto 0);
|
52 |
|
|
37
|
53 |
|
|
38 Q : out std_logic_vector (15 downto 0));
|
54 |
|
|
39 end reg_16;
|
55 |
|
|
<pre class="filename">
|
56 |
|
|
reg_16.vhd
|
57 |
|
|
</pre></pre>
|
58 |
|
|
<P>
|
59 |
|
|
|
60 |
|
|
<P><br>
|
61 |
|
|
|
62 |
|
|
<P>The <STRONG>Q</STRONG> output provides the current value of the register pair. There is
|
63 |
|
|
no need for a read strobe, because (unlike I/O devices) reading the current
|
64 |
|
|
value of a register pair has no side effects.
|
65 |
|
|
|
66 |
|
|
<P>The register pair can be written by setting one or both bits of the <STRONG>WE</STRONG>
|
67 |
|
|
input. If both bits are set then the all 16 bits of <STRONG>D</STRONG> are written; the
|
68 |
|
|
low byte to the even register and the higher byte to the odd register of the
|
69 |
|
|
pair. If only one bit is set then the register corresponding then the bit set
|
70 |
|
|
in <STRONG>WE</STRONG> defines the register to be written (even bit = even register,
|
71 |
|
|
odd bit = odd register) and the value to be written is in the lower byte
|
72 |
|
|
of <STRONG>DIN</STRONG>:
|
73 |
|
|
|
74 |
|
|
<P><br>
|
75 |
|
|
|
76 |
|
|
<pre class="vhdl">
|
77 |
|
|
|
78 |
|
|
46 process(I_CLK)
|
79 |
|
|
47 begin
|
80 |
|
|
48 if (rising_edge(I_CLK)) then
|
81 |
|
|
49 if (I_WE(1) = '1') then
|
82 |
|
|
50 L(15 downto 8) <= I_D(15 downto 8);
|
83 |
|
|
51 end if;
|
84 |
|
|
52 if (I_WE(0) = '1') then
|
85 |
|
|
53 L( 7 downto 0) <= I_D( 7 downto 0);
|
86 |
|
|
54 end if;
|
87 |
|
|
55 end if;
|
88 |
|
|
56 end process;
|
89 |
|
|
<pre class="filename">
|
90 |
|
|
src/reg_16.vhd
|
91 |
|
|
</pre></pre>
|
92 |
|
|
<P>
|
93 |
|
|
|
94 |
|
|
<P><br>
|
95 |
|
|
|
96 |
|
|
<H3><A NAME="section_1_1_2">6.1.2 The Status Register</A></H3>
|
97 |
|
|
|
98 |
|
|
<P>The status register is an 8-bit register. This register can be updated by
|
99 |
|
|
writing to address 0x5F. Primarily it is updated, however, as a side
|
100 |
|
|
effect of the execution of ALU operations. If, for example, an
|
101 |
|
|
arithmetic/logic instruction produces a result of 0, then the zero flag
|
102 |
|
|
(the second bit in the status register) is set. An arithmetic overflow
|
103 |
|
|
in an ADD instruction causes the carry bit to be set, and so on.
|
104 |
|
|
The status register is declared as:
|
105 |
|
|
|
106 |
|
|
<P><br>
|
107 |
|
|
|
108 |
|
|
<pre class="vhdl">
|
109 |
|
|
|
110 |
|
|
32 entity status_reg is
|
111 |
|
|
33 port ( I_CLK : in std_logic;
|
112 |
|
|
34
|
113 |
|
|
35 I_COND : in std_logic_vector ( 3 downto 0);
|
114 |
|
|
36 I_DIN : in std_logic_vector ( 7 downto 0);
|
115 |
|
|
37 I_FLAGS : in std_logic_vector ( 7 downto 0);
|
116 |
|
|
38 I_WE_F : in std_logic;
|
117 |
|
|
39 I_WE_SR : in std_logic;
|
118 |
|
|
40
|
119 |
|
|
41 Q : out std_logic_vector ( 7 downto 0);
|
120 |
|
|
42 Q_CC : out std_logic);
|
121 |
|
|
43 end status_reg;
|
122 |
|
|
<pre class="filename">
|
123 |
|
|
src/status_reg.vhd
|
124 |
|
|
</pre></pre>
|
125 |
|
|
<P>
|
126 |
|
|
|
127 |
|
|
<P><br>
|
128 |
|
|
|
129 |
|
|
<P>If <STRONG>WE_FLAGS</STRONG> is '1' then the status register is updated as a result
|
130 |
|
|
of an ALU operation; the new value of the status register is provided on the
|
131 |
|
|
<STRONG>FLAGS</STRONG> input which comes from the ALU.
|
132 |
|
|
|
133 |
|
|
<P>If <STRONG>WE_SR</STRONG> is '1' then the status register is updated as a result
|
134 |
|
|
of an I/O write operation (like <STRONG>OUT</STRONG> or <STRONG>STS</STRONG>); the new value of the
|
135 |
|
|
status register is provided on the <STRONG>DIN</STRONG> input.
|
136 |
|
|
|
137 |
|
|
<P>The output <STRONG>Q</STRONG> of the status register holds the current value of the register.
|
138 |
|
|
In addition there is a <STRONG>CC</STRONG> output that is '1' when the condition
|
139 |
|
|
indicated by the <STRONG>COND</STRONG> input is fulfilled. This is used for conditional
|
140 |
|
|
branch instructions. <STRONG>COND</STRONG> comes directly from the opcode for a branch
|
141 |
|
|
instruction (bit 10 of the opcode for the "polarity" and bits 2-0 of the
|
142 |
|
|
opcode for the bit of the status register that is being tested).
|
143 |
|
|
|
144 |
|
|
<H3><A NAME="section_1_1_3">6.1.3 Register File Components</A></H3>
|
145 |
|
|
|
146 |
|
|
<P>The register file consists of 16 general purpose register pairs <STRONG>r00</STRONG> to
|
147 |
|
|
<STRONG>r30</STRONG>, a stack pointer <STRONG>sp</STRONG>, and an 8-bit status register <STRONG>sr</STRONG>:
|
148 |
|
|
|
149 |
|
|
<P><br>
|
150 |
|
|
|
151 |
|
|
<pre class="vhdl">
|
152 |
|
|
|
153 |
|
|
131 r00: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE( 1 downto 0), I_D => I_DIN, Q => R_R00);
|
154 |
|
|
132 r02: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE( 3 downto 2), I_D => I_DIN, Q => R_R02);
|
155 |
|
|
133 r04: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE( 5 downto 4), I_D => I_DIN, Q => R_R04);
|
156 |
|
|
134 r06: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE( 7 downto 6), I_D => I_DIN, Q => R_R06);
|
157 |
|
|
135 r08: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE( 9 downto 8), I_D => I_DIN, Q => R_R08);
|
158 |
|
|
136 r10: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(11 downto 10), I_D => I_DIN, Q => R_R10);
|
159 |
|
|
137 r12: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(13 downto 12), I_D => I_DIN, Q => R_R12);
|
160 |
|
|
138 r14: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(15 downto 14), I_D => I_DIN, Q => R_R14);
|
161 |
|
|
139 r16: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(17 downto 16), I_D => I_DIN, Q => R_R16);
|
162 |
|
|
140 r18: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(19 downto 18), I_D => I_DIN, Q => R_R18);
|
163 |
|
|
141 r20: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(21 downto 20), I_D => I_DIN, Q => R_R20);
|
164 |
|
|
142 r22: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(23 downto 22), I_D => I_DIN, Q => R_R22);
|
165 |
|
|
143 r24: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(25 downto 24), I_D => I_DIN, Q => R_R24);
|
166 |
|
|
144 r26: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(27 downto 26), I_D => L_DX, Q => R_R26);
|
167 |
|
|
145 r28: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(29 downto 28), I_D => L_DY, Q => R_R28);
|
168 |
|
|
146 r30: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE(31 downto 30), I_D => L_DZ, Q => R_R30);
|
169 |
|
|
<pre class="filename">
|
170 |
|
|
src/register_file.vhd
|
171 |
|
|
</pre></pre>
|
172 |
|
|
<P>
|
173 |
|
|
|
174 |
|
|
<pre class="vhdl">
|
175 |
|
|
|
176 |
|
|
147 sp: reg_16 port map(I_CLK => I_CLK, I_WE => L_WE_SP, I_D => L_DSP, Q => R_SP);
|
177 |
|
|
<pre class="filename">
|
178 |
|
|
src/register_file.vhd
|
179 |
|
|
</pre></pre>
|
180 |
|
|
<P>
|
181 |
|
|
|
182 |
|
|
<pre class="vhdl">
|
183 |
|
|
|
184 |
|
|
149 sr: status_reg
|
185 |
|
|
150 port map( I_CLK => I_CLK,
|
186 |
|
|
151 I_COND => I_COND,
|
187 |
|
|
152 I_DIN => I_DIN(7 downto 0),
|
188 |
|
|
153 I_FLAGS => I_FLAGS,
|
189 |
|
|
154 I_WE_F => I_WE_F,
|
190 |
|
|
155 I_WE_SR => L_WE_SR,
|
191 |
|
|
156 Q => S_FLAGS,
|
192 |
|
|
157 Q_CC => Q_CC);
|
193 |
|
|
<pre class="filename">
|
194 |
|
|
src/register_file.vhd
|
195 |
|
|
</pre></pre>
|
196 |
|
|
<P>
|
197 |
|
|
|
198 |
|
|
<P><br>
|
199 |
|
|
|
200 |
|
|
<P>Each register pair drives a 16-bit signal according to the (even) number
|
201 |
|
|
of the register pair in the register file:
|
202 |
|
|
|
203 |
|
|
<P><br>
|
204 |
|
|
|
205 |
|
|
<pre class="vhdl">
|
206 |
|
|
|
207 |
|
|
71 signal R_R00 : std_logic_vector(15 downto 0);
|
208 |
|
|
72 signal R_R02 : std_logic_vector(15 downto 0);
|
209 |
|
|
73 signal R_R04 : std_logic_vector(15 downto 0);
|
210 |
|
|
74 signal R_R06 : std_logic_vector(15 downto 0);
|
211 |
|
|
75 signal R_R08 : std_logic_vector(15 downto 0);
|
212 |
|
|
76 signal R_R10 : std_logic_vector(15 downto 0);
|
213 |
|
|
77 signal R_R12 : std_logic_vector(15 downto 0);
|
214 |
|
|
78 signal R_R14 : std_logic_vector(15 downto 0);
|
215 |
|
|
79 signal R_R16 : std_logic_vector(15 downto 0);
|
216 |
|
|
80 signal R_R18 : std_logic_vector(15 downto 0);
|
217 |
|
|
81 signal R_R20 : std_logic_vector(15 downto 0);
|
218 |
|
|
82 signal R_R22 : std_logic_vector(15 downto 0);
|
219 |
|
|
83 signal R_R24 : std_logic_vector(15 downto 0);
|
220 |
|
|
84 signal R_R26 : std_logic_vector(15 downto 0);
|
221 |
|
|
85 signal R_R28 : std_logic_vector(15 downto 0);
|
222 |
|
|
86 signal R_R30 : std_logic_vector(15 downto 0);
|
223 |
|
|
87 signal R_SP : std_logic_vector(15 downto 0); -- stack pointer
|
224 |
|
|
<pre class="filename">
|
225 |
|
|
src/register_file.vhd
|
226 |
|
|
</pre></pre>
|
227 |
|
|
<P>
|
228 |
|
|
|
229 |
|
|
<P><br>
|
230 |
|
|
|
231 |
|
|
<H3><A NAME="section_1_1_4">6.1.4 Addressing of General Purpose Registers</A></H3>
|
232 |
|
|
|
233 |
|
|
<P>We address individual general purpose registers by a 5-bit value.
|
234 |
|
|
Normally an opcode using an individual general purpose 8-bit register
|
235 |
|
|
has a 5 bit field which is the address of the register. The opcode decoder
|
236 |
|
|
transfers this field to its <STRONG>DDDDD</STRONG> or <STRONG>RRRRR</STRONG> output. For some opcodes
|
237 |
|
|
not all 32 registers can be used, but only 16 (e.g. <STRONG>ANDI</STRONG>) or 8 (e.g. <STRONG>MUL</STRONG>).
|
238 |
|
|
In these cases the register field in the opcode is smaller and the opcode
|
239 |
|
|
decoder fills in the missing bits. Some opcodes imply particular registers
|
240 |
|
|
(e.g. some <STRONG>LPM</STRONG> variant), and again the opcode decoder fills in the implied
|
241 |
|
|
register number.
|
242 |
|
|
|
243 |
|
|
<P>An opcode may address no, one, two, or three registers or pairs.
|
244 |
|
|
If one register is addressed, then the number of that register is
|
245 |
|
|
encoded in the <STRONG>DDDDD</STRONG> signal.<BR>
|
246 |
|
|
If two (or more) registers are used, then one (normally the destination
|
247 |
|
|
register) is encoded in the <STRONG>DDDDD</STRONG> signal and the other (source) is encoded
|
248 |
|
|
in the <STRONG>RRRRR</STRONG> signal. Opcodes with 3 registers (e.g. MUL) use an implied
|
249 |
|
|
destination register pair (register pair 0) and two source registers encoded
|
250 |
|
|
in the <STRONG>DDDDD</STRONG> and <STRONG>RRRRR</STRONG> signals.
|
251 |
|
|
|
252 |
|
|
<H3><A NAME="section_1_1_5">6.1.5 Addressing of General Purpose Register Pairs</A></H3>
|
253 |
|
|
|
254 |
|
|
<P>We address register pairs by addressing the even register of the pair.
|
255 |
|
|
The address of a register pair is therefore a 5-bit value with the lowest
|
256 |
|
|
bit cleared. The opcode normally only has a 4-bit field for a register pair
|
257 |
|
|
and the lowest (cleared) bit is filled in by the opcode decoder. Like
|
258 |
|
|
for individual registers it can happen that not all 16 register pairs can
|
259 |
|
|
be addresses (e.g. <STRONG>ADIW</STRONG>). This is handles in the same way as for individual
|
260 |
|
|
registers.
|
261 |
|
|
|
262 |
|
|
<P>In the AVR context, the register pairs <STRONG>R26</STRONG>, <STRONG>R28</STRONG>, and <STRONG>R30</STRONG> are also called
|
263 |
|
|
(pointer registers) <STRONG>X</STRONG>, <STRONG>Y</STRONG>, and <STRONG>Z</STRONG> respectively.
|
264 |
|
|
|
265 |
|
|
<H3><A NAME="section_1_1_6">6.1.6 Requirements on the Register File</A></H3>
|
266 |
|
|
|
267 |
|
|
<P>If we go through the opcodes of the AVR CPU, then we see the
|
268 |
|
|
capabilities that the register file must provide for general purpose
|
269 |
|
|
registers (or register pairs):
|
270 |
|
|
|
271 |
|
|
<TABLE border="1">
|
272 |
|
|
<THEAD><TR><TH>Capability</TH><TH>Opcode (example)</TH></TR></THEAD>
|
273 |
|
|
<TBODY>
|
274 |
|
|
<TR><TD>Read one register, read/write another register</TD><TD>ADD Rd, Rr</TD></TR>
|
275 |
|
|
<TR><TD>Write one register, read/write another register</TD><TD>LD Rd, (X+)</TD></TR>
|
276 |
|
|
<TR><TD>Write one register, read another register</TD><TD>LD Rd, (X)</TD></TR>
|
277 |
|
|
<TR><TD>Read/write one register</TD><TD>ASR Rd</TD></TR>
|
278 |
|
|
<TR><TD>Read one register, read another register</TD><TD>CMP Rd, Rr</TD></TR>
|
279 |
|
|
<TR><TD>Read one register, read another register</TD><TD>LD Rd, Rr</TD></TR>
|
280 |
|
|
<TR><TD>Read one register</TD><TD>IN Rd, A</TD></TR>
|
281 |
|
|
<TR><TD>Write one register</TD><TD>OUT A, Rr</TD></TR>
|
282 |
|
|
</TBODY>
|
283 |
|
|
</TABLE>
|
284 |
|
|
|
285 |
|
|
<H3><A NAME="section_1_1_7">6.1.7 Reading Registers or Register Pairs</A></H3>
|
286 |
|
|
|
287 |
|
|
<P>There are 4 cases:
|
288 |
|
|
|
289 |
|
|
<UL>
|
290 |
|
|
<LI>Read register or register pair addresses by <STRONG>DDDDD</STRONG>.
|
291 |
|
|
<LI>Read register or register pair addresses by <STRONG>RRRRR</STRONG>.
|
292 |
|
|
<LI>Read register addressed by the current I/O address.
|
293 |
|
|
<LI>Read <STRONG>X</STRONG>, <STRONG>Y</STRONG>, or <STRONG>Z</STRONG> pointer implied by the addressing mode <STRONG>AMOD</STRONG>.
|
294 |
|
|
<LI>Read the <STRONG>Z</STRONG> pointer implied by the instruction (<STRONG>IJMP</STRONG> or <STRONG>ICALL</STRONG>).
|
295 |
|
|
</UL>
|
296 |
|
|
<P>Some of these cases can happen simultaneously. For example the <STRONG>ICALL</STRONG>
|
297 |
|
|
instruction reads the <STRONG>Z</STRONG> register (the target address of the call) while
|
298 |
|
|
it pushed the current PC onto the stack. Likewise, <STRONG>ST</STRONG> may need the
|
299 |
|
|
<STRONG>X</STRONG>, <STRONG>Y</STRONG>, or <STRONG>Z</STRONG> for address calculations and a general purpose register that
|
300 |
|
|
is to be stored in memory. For this reason we provide 5 different outputs
|
301 |
|
|
in the register file. These outputs are addressing the general purpose
|
302 |
|
|
registers differently (and they can be used in parallel):
|
303 |
|
|
|
304 |
|
|
<UL>
|
305 |
|
|
<LI><STRONG>Q_D</STRONG> is the content of the register addressed by <STRONG>DDDDD</STRONG>.
|
306 |
|
|
<LI><STRONG>Q_R</STRONG> is the content of the register pair addressed by <STRONG>RRRR</STRONG>.
|
307 |
|
|
<LI><STRONG>Q_S</STRONG> is the content of the register addressed by <STRONG>ADR</STRONG>.
|
308 |
|
|
<LI><STRONG>Q_ADR</STRONG> is an address defined by <STRONG>AMOD</STRONG> (and may use <STRONG>X</STRONG>, <STRONG>Y</STRONG>, or <STRONG>Z</STRONG>).
|
309 |
|
|
<LI><STRONG>Q_X</STRONG> is the content of the Z register.
|
310 |
|
|
</UL>
|
311 |
|
|
<P><STRONG>Q_D</STRONG> is one of the register pair signals as defined by <STRONG>DDDDD</STRONG>. We read the
|
312 |
|
|
entire pair; the selection of the even/odd register within the pair is done
|
313 |
|
|
later in the ALU based on <STRONG>DDDDD(0)</STRONG>:
|
314 |
|
|
|
315 |
|
|
<P><br>
|
316 |
|
|
|
317 |
|
|
<pre class="vhdl">
|
318 |
|
|
|
319 |
|
|
189 process(R_R00, R_R02, R_R04, R_R06, R_R08, R_R10, R_R12, R_R14,
|
320 |
|
|
190 R_R16, R_R18, R_R20, R_R22, R_R24, R_R26, R_R28, R_R30,
|
321 |
|
|
191 I_DDDDD(4 downto 1))
|
322 |
|
|
192 begin
|
323 |
|
|
193 case I_DDDDD(4 downto 1) is
|
324 |
|
|
194 when "0000" => Q_D <= R_R00;
|
325 |
|
|
195 when "0001" => Q_D <= R_R02;
|
326 |
|
|
196 when "0010" => Q_D <= R_R04;
|
327 |
|
|
197 when "0011" => Q_D <= R_R06;
|
328 |
|
|
198 when "0100" => Q_D <= R_R08;
|
329 |
|
|
199 when "0101" => Q_D <= R_R10;
|
330 |
|
|
200 when "0110" => Q_D <= R_R12;
|
331 |
|
|
201 when "0111" => Q_D <= R_R14;
|
332 |
|
|
202 when "1000" => Q_D <= R_R16;
|
333 |
|
|
203 when "1001" => Q_D <= R_R18;
|
334 |
|
|
204 when "1010" => Q_D <= R_R20;
|
335 |
|
|
205 when "1011" => Q_D <= R_R22;
|
336 |
|
|
206 when "1100" => Q_D <= R_R24;
|
337 |
|
|
207 when "1101" => Q_D <= R_R26;
|
338 |
|
|
208 when "1110" => Q_D <= R_R28;
|
339 |
|
|
209 when others => Q_D <= R_R30;
|
340 |
|
|
210 end case;
|
341 |
|
|
211 end process;
|
342 |
|
|
<pre class="filename">
|
343 |
|
|
src/register_file.vhd
|
344 |
|
|
</pre></pre>
|
345 |
|
|
<P>
|
346 |
|
|
|
347 |
|
|
<P><br>
|
348 |
|
|
|
349 |
|
|
<P><STRONG>Q_R</STRONG> is one of the register pair signals as defined by <STRONG>RRRR</STRONG>:
|
350 |
|
|
|
351 |
|
|
<P><br>
|
352 |
|
|
|
353 |
|
|
<pre class="vhdl">
|
354 |
|
|
|
355 |
|
|
215 process(R_R00, R_R02, R_R04, R_R06, R_R08, R_R10, R_R12, R_R14,
|
356 |
|
|
216 R_R16, R_R18, R_R20, R_R22, R_R24, R_R26, R_R28, R_R30, I_RRRR)
|
357 |
|
|
217 begin
|
358 |
|
|
218 case I_RRRR is
|
359 |
|
|
219 when "0000" => Q_R <= R_R00;
|
360 |
|
|
220 when "0001" => Q_R <= R_R02;
|
361 |
|
|
221 when "0010" => Q_R <= R_R04;
|
362 |
|
|
222 when "0011" => Q_R <= R_R06;
|
363 |
|
|
223 when "0100" => Q_R <= R_R08;
|
364 |
|
|
224 when "0101" => Q_R <= R_R10;
|
365 |
|
|
225 when "0110" => Q_R <= R_R12;
|
366 |
|
|
226 when "0111" => Q_R <= R_R14;
|
367 |
|
|
227 when "1000" => Q_R <= R_R16;
|
368 |
|
|
228 when "1001" => Q_R <= R_R18;
|
369 |
|
|
229 when "1010" => Q_R <= R_R20;
|
370 |
|
|
230 when "1011" => Q_R <= R_R22;
|
371 |
|
|
231 when "1100" => Q_R <= R_R24;
|
372 |
|
|
232 when "1101" => Q_R <= R_R26;
|
373 |
|
|
233 when "1110" => Q_R <= R_R28;
|
374 |
|
|
234 when others => Q_R <= R_R30;
|
375 |
|
|
235 end case;
|
376 |
|
|
236 end process;
|
377 |
|
|
<pre class="filename">
|
378 |
|
|
src/register_file.vhd
|
379 |
|
|
</pre></pre>
|
380 |
|
|
<P>
|
381 |
|
|
|
382 |
|
|
<P><br>
|
383 |
|
|
|
384 |
|
|
<P>The general purpose registers, but also the stack pointer and the status
|
385 |
|
|
register, are mapped into the data memory space:
|
386 |
|
|
|
387 |
|
|
<TABLE border="1">
|
388 |
|
|
<THEAD><TR><TH>Address</TH><TH>Purpose</TH></TR></THEAD>
|
389 |
|
|
<TBODY>
|
390 |
|
|
<TR><TD>0x00 - 0x1F</TD><TD>general purpose CPU registers.</TD></TR>
|
391 |
|
|
<TR><TD>0x20 - 0x5C</TD><TD>miscellaneous I/O registers.</TD></TR>
|
392 |
|
|
<TR><TD>0x5D</TD><TD>stack pointer low</TD></TR>
|
393 |
|
|
<TR><TD>0x5E</TD><TD>stack pointer high</TD></TR>
|
394 |
|
|
<TR><TD>0x5F</TD><TD>status register</TD></TR>
|
395 |
|
|
<TR><TD>0x60 - 0xFFFF</TD><TD>data memory</TD></TR>
|
396 |
|
|
</TBODY>
|
397 |
|
|
</TABLE>
|
398 |
|
|
|
399 |
|
|
<P>If an address corresponding to a register in the register file (i.e. a
|
400 |
|
|
general purpose register, the stack pointer, or the status register is read,
|
401 |
|
|
then the register shall be returned.<BR>
|
402 |
|
|
For example, LD Rd, R22 shall give the same result as LDS Rd, 22.
|
403 |
|
|
|
404 |
|
|
<P>The 8-bit <STRONG>Q_S</STRONG> output contains the register addresses by <STRONG>ADR</STRONG>:
|
405 |
|
|
|
406 |
|
|
<P><br>
|
407 |
|
|
|
408 |
|
|
<pre class="vhdl">
|
409 |
|
|
|
410 |
|
|
161 process(R_R00, R_R02, R_R04, R_R06, R_R08, R_R10, R_R12, R_R14,
|
411 |
|
|
162 R_R16, R_R18, R_R20, R_R22, R_R24, R_R26, R_R28, R_R30,
|
412 |
|
|
163 R_SP, S_FLAGS, L_ADR(6 downto 1))
|
413 |
|
|
164 begin
|
414 |
|
|
165 case L_ADR(6 downto 1) is
|
415 |
|
|
166 when "000000" => L_S <= R_R00;
|
416 |
|
|
167 when "000001" => L_S <= R_R02;
|
417 |
|
|
168 when "000010" => L_S <= R_R04;
|
418 |
|
|
169 when "000011" => L_S <= R_R06;
|
419 |
|
|
170 when "000100" => L_S <= R_R08;
|
420 |
|
|
171 when "000101" => L_S <= R_R10;
|
421 |
|
|
172 when "000110" => L_S <= R_R12;
|
422 |
|
|
173 when "000111" => L_S <= R_R14;
|
423 |
|
|
174 when "001000" => L_S <= R_R16;
|
424 |
|
|
175 when "001001" => L_S <= R_R18;
|
425 |
|
|
176 when "001010" => L_S <= R_R20;
|
426 |
|
|
177 when "001011" => L_S <= R_R22;
|
427 |
|
|
178 when "001100" => L_S <= R_R24;
|
428 |
|
|
179 when "001101" => L_S <= R_R26;
|
429 |
|
|
180 when "001110" => L_S <= R_R28;
|
430 |
|
|
181 when "001111" => L_S <= R_R30;
|
431 |
|
|
182 when "101111" => L_S <= R_SP ( 7 downto 0) & X"00"; -- SPL
|
432 |
|
|
183 when others => L_S <= S_FLAGS & R_SP (15 downto 8); -- SR/SPH
|
433 |
|
|
184 end case;
|
434 |
|
|
185 end process;
|
435 |
|
|
186
|
436 |
|
|
<pre class="filename">
|
437 |
|
|
src/register_file.vhd
|
438 |
|
|
</pre></pre>
|
439 |
|
|
<P>
|
440 |
|
|
|
441 |
|
|
<P><br>
|
442 |
|
|
|
443 |
|
|
<H3><A NAME="section_1_1_8">6.1.8 Writing Registers or Register Pairs</A></H3>
|
444 |
|
|
|
445 |
|
|
<P>In order to write a register, we need to select the proper input (data
|
446 |
|
|
source) and the proper <STRONG>WE</STRONG> signal. For most registers, the only possible
|
447 |
|
|
data source is <STRONG>DIN</STRONG> which comes straight from the ALU. The pointer
|
448 |
|
|
register pairs <STRONG>X</STRONG>, <STRONG>Y</STRONG>, and <STRONG>Z</STRONG>, however, can also be changed as a side effect
|
449 |
|
|
of the post-increment (<STRONG>X+</STRONG>, <STRONG>Y+</STRONG>, <STRONG>Z+</STRONG>) and pre-decrement (<STRONG>-X</STRONG>, <STRONG>-Y</STRONG>, <STRONG>-Z</STRONG>)
|
450 |
|
|
addressing modes of the <STRONG>LDS</STRONG> and <STRONG>STS</STRONG> instructions. The addressing modes are
|
451 |
|
|
discussed in more detail in the next chapter; here it suffices to note that
|
452 |
|
|
the <STRONG>X</STRONG>, <STRONG>Y</STRONG>, and #Z #registers get there data from <STRONG>DX</STRONG>, <STRONG>DY</STRONG>, and <STRONG>DZ</STRONG>,
|
453 |
|
|
respectively rather than from <STRONG>DIN</STRONG>.
|
454 |
|
|
|
455 |
|
|
<P>There is a total of 4 cases where general purpose registers are written.
|
456 |
|
|
Three of these cases that are applicable to all general purpose registers
|
457 |
|
|
and one case collects special cases for particular registers (the register
|
458 |
|
|
numbers are then implied).
|
459 |
|
|
|
460 |
|
|
<P>We compute a 32 bit write enable signal for each of the four cases and <STRONG>OR</STRONG>
|
461 |
|
|
them together.
|
462 |
|
|
|
463 |
|
|
<P>The first case is a write to an 8-bit register addressed by <STRONG>DDDDD</STRONG>.
|
464 |
|
|
For this case we create the signal <STRONG>WE_D</STRONG>:
|
465 |
|
|
|
466 |
|
|
<P><br>
|
467 |
|
|
|
468 |
|
|
<pre class="vhdl">
|
469 |
|
|
|
470 |
|
|
288 L_WE_D( 0) <= I_WE_D(0) when (I_DDDDD = "00000") else '0';
|
471 |
|
|
289 L_WE_D( 1) <= I_WE_D(0) when (I_DDDDD = "00001") else '0';
|
472 |
|
|
290 L_WE_D( 2) <= I_WE_D(0) when (I_DDDDD = "00010") else '0';
|
473 |
|
|
291 L_WE_D( 3) <= I_WE_D(0) when (I_DDDDD = "00011") else '0';
|
474 |
|
|
292 L_WE_D( 4) <= I_WE_D(0) when (I_DDDDD = "00100") else '0';
|
475 |
|
|
293 L_WE_D( 5) <= I_WE_D(0) when (I_DDDDD = "00101") else '0';
|
476 |
|
|
294 L_WE_D( 6) <= I_WE_D(0) when (I_DDDDD = "00110") else '0';
|
477 |
|
|
295 L_WE_D( 7) <= I_WE_D(0) when (I_DDDDD = "00111") else '0';
|
478 |
|
|
296 L_WE_D( 8) <= I_WE_D(0) when (I_DDDDD = "01000") else '0';
|
479 |
|
|
297 L_WE_D( 9) <= I_WE_D(0) when (I_DDDDD = "01001") else '0';
|
480 |
|
|
298 L_WE_D(10) <= I_WE_D(0) when (I_DDDDD = "01010") else '0';
|
481 |
|
|
299 L_WE_D(11) <= I_WE_D(0) when (I_DDDDD = "01011") else '0';
|
482 |
|
|
300 L_WE_D(12) <= I_WE_D(0) when (I_DDDDD = "01100") else '0';
|
483 |
|
|
301 L_WE_D(13) <= I_WE_D(0) when (I_DDDDD = "01101") else '0';
|
484 |
|
|
302 L_WE_D(14) <= I_WE_D(0) when (I_DDDDD = "01110") else '0';
|
485 |
|
|
303 L_WE_D(15) <= I_WE_D(0) when (I_DDDDD = "01111") else '0';
|
486 |
|
|
304 L_WE_D(16) <= I_WE_D(0) when (I_DDDDD = "10000") else '0';
|
487 |
|
|
305 L_WE_D(17) <= I_WE_D(0) when (I_DDDDD = "10001") else '0';
|
488 |
|
|
306 L_WE_D(18) <= I_WE_D(0) when (I_DDDDD = "10010") else '0';
|
489 |
|
|
307 L_WE_D(19) <= I_WE_D(0) when (I_DDDDD = "10011") else '0';
|
490 |
|
|
308 L_WE_D(20) <= I_WE_D(0) when (I_DDDDD = "10100") else '0';
|
491 |
|
|
309 L_WE_D(21) <= I_WE_D(0) when (I_DDDDD = "10101") else '0';
|
492 |
|
|
310 L_WE_D(22) <= I_WE_D(0) when (I_DDDDD = "10110") else '0';
|
493 |
|
|
311 L_WE_D(23) <= I_WE_D(0) when (I_DDDDD = "10111") else '0';
|
494 |
|
|
312 L_WE_D(24) <= I_WE_D(0) when (I_DDDDD = "11000") else '0';
|
495 |
|
|
313 L_WE_D(25) <= I_WE_D(0) when (I_DDDDD = "11001") else '0';
|
496 |
|
|
314 L_WE_D(26) <= I_WE_D(0) when (I_DDDDD = "11010") else '0';
|
497 |
|
|
315 L_WE_D(27) <= I_WE_D(0) when (I_DDDDD = "11011") else '0';
|
498 |
|
|
316 L_WE_D(28) <= I_WE_D(0) when (I_DDDDD = "11100") else '0';
|
499 |
|
|
317 L_WE_D(29) <= I_WE_D(0) when (I_DDDDD = "11101") else '0';
|
500 |
|
|
318 L_WE_D(30) <= I_WE_D(0) when (I_DDDDD = "11110") else '0';
|
501 |
|
|
319 L_WE_D(31) <= I_WE_D(0) when (I_DDDDD = "11111") else '0';
|
502 |
|
|
<pre class="filename">
|
503 |
|
|
src/register_file.vhd
|
504 |
|
|
</pre></pre>
|
505 |
|
|
<P>
|
506 |
|
|
|
507 |
|
|
<P><br>
|
508 |
|
|
|
509 |
|
|
<P>The second case is a write to a 16-bit register pair addressed by <STRONG>DDDD</STRONG>
|
510 |
|
|
(<STRONG>DDDD</STRONG> is the four upper bits of <STRONG>DDDDD</STRONG>). For this case we create
|
511 |
|
|
signal <STRONG>WE_DD</STRONG>:
|
512 |
|
|
|
513 |
|
|
<P><br>
|
514 |
|
|
|
515 |
|
|
<pre class="vhdl">
|
516 |
|
|
|
517 |
|
|
326 L_DDDD <= I_DDDDD(4 downto 1);
|
518 |
|
|
327 L_WE_D2 <= I_WE_D(1) & I_WE_D(1);
|
519 |
|
|
328 L_WE_DD( 1 downto 0) <= L_WE_D2 when (L_DDDD = "0000") else "00";
|
520 |
|
|
329 L_WE_DD( 3 downto 2) <= L_WE_D2 when (L_DDDD = "0001") else "00";
|
521 |
|
|
330 L_WE_DD( 5 downto 4) <= L_WE_D2 when (L_DDDD = "0010") else "00";
|
522 |
|
|
331 L_WE_DD( 7 downto 6) <= L_WE_D2 when (L_DDDD = "0011") else "00";
|
523 |
|
|
332 L_WE_DD( 9 downto 8) <= L_WE_D2 when (L_DDDD = "0100") else "00";
|
524 |
|
|
333 L_WE_DD(11 downto 10) <= L_WE_D2 when (L_DDDD = "0101") else "00";
|
525 |
|
|
334 L_WE_DD(13 downto 12) <= L_WE_D2 when (L_DDDD = "0110") else "00";
|
526 |
|
|
335 L_WE_DD(15 downto 14) <= L_WE_D2 when (L_DDDD = "0111") else "00";
|
527 |
|
|
336 L_WE_DD(17 downto 16) <= L_WE_D2 when (L_DDDD = "1000") else "00";
|
528 |
|
|
337 L_WE_DD(19 downto 18) <= L_WE_D2 when (L_DDDD = "1001") else "00";
|
529 |
|
|
338 L_WE_DD(21 downto 20) <= L_WE_D2 when (L_DDDD = "1010") else "00";
|
530 |
|
|
339 L_WE_DD(23 downto 22) <= L_WE_D2 when (L_DDDD = "1011") else "00";
|
531 |
|
|
340 L_WE_DD(25 downto 24) <= L_WE_D2 when (L_DDDD = "1100") else "00";
|
532 |
|
|
341 L_WE_DD(27 downto 26) <= L_WE_D2 when (L_DDDD = "1101") else "00";
|
533 |
|
|
342 L_WE_DD(29 downto 28) <= L_WE_D2 when (L_DDDD = "1110") else "00";
|
534 |
|
|
343 L_WE_DD(31 downto 30) <= L_WE_D2 when (L_DDDD = "1111") else "00";
|
535 |
|
|
<pre class="filename">
|
536 |
|
|
src/register_file.vhd
|
537 |
|
|
</pre></pre>
|
538 |
|
|
<P>
|
539 |
|
|
|
540 |
|
|
<P><br>
|
541 |
|
|
|
542 |
|
|
<P>The third case is writing to the memory mapped I/O space of the general
|
543 |
|
|
purpose registers. It is similar to the first case, but now we select
|
544 |
|
|
the register by <STRONG>ADR</STRONG> instead of <STRONG>DDDDD</STRONG>. When reading from the I/O mapped
|
545 |
|
|
register above we did not check if <STRONG>ADR</STRONG> was completely correct (and different
|
546 |
|
|
addresses could read the same register. This was OK, since some multiplexer
|
547 |
|
|
somewhere else would discard the value read for addresses outside the range
|
548 |
|
|
from 0x00 to 0x1F. When writing we have to be more careful and check the
|
549 |
|
|
range by means of <STRONG>WE_A</STRONG>. For the third case we use signal <STRONG>WE_IO</STRONG>:
|
550 |
|
|
|
551 |
|
|
<P><br>
|
552 |
|
|
|
553 |
|
|
<pre class="vhdl">
|
554 |
|
|
|
555 |
|
|
350 L_WE_IO( 0) <= L_WE_A when (L_ADR(4 downto 0) = "00000") else '0';
|
556 |
|
|
351 L_WE_IO( 1) <= L_WE_A when (L_ADR(4 downto 0) = "00001") else '0';
|
557 |
|
|
352 L_WE_IO( 2) <= L_WE_A when (L_ADR(4 downto 0) = "00010") else '0';
|
558 |
|
|
353 L_WE_IO( 3) <= L_WE_A when (L_ADR(4 downto 0) = "00011") else '0';
|
559 |
|
|
354 L_WE_IO( 4) <= L_WE_A when (L_ADR(4 downto 0) = "00100") else '0';
|
560 |
|
|
355 L_WE_IO( 5) <= L_WE_A when (L_ADR(4 downto 0) = "00101") else '0';
|
561 |
|
|
356 L_WE_IO( 6) <= L_WE_A when (L_ADR(4 downto 0) = "00110") else '0';
|
562 |
|
|
357 L_WE_IO( 7) <= L_WE_A when (L_ADR(4 downto 0) = "00111") else '0';
|
563 |
|
|
358 L_WE_IO( 8) <= L_WE_A when (L_ADR(4 downto 0) = "01000") else '0';
|
564 |
|
|
359 L_WE_IO( 9) <= L_WE_A when (L_ADR(4 downto 0) = "01001") else '0';
|
565 |
|
|
360 L_WE_IO(10) <= L_WE_A when (L_ADR(4 downto 0) = "01010") else '0';
|
566 |
|
|
361 L_WE_IO(11) <= L_WE_A when (L_ADR(4 downto 0) = "01011") else '0';
|
567 |
|
|
362 L_WE_IO(12) <= L_WE_A when (L_ADR(4 downto 0) = "01100") else '0';
|
568 |
|
|
363 L_WE_IO(13) <= L_WE_A when (L_ADR(4 downto 0) = "01101") else '0';
|
569 |
|
|
364 L_WE_IO(14) <= L_WE_A when (L_ADR(4 downto 0) = "01110") else '0';
|
570 |
|
|
365 L_WE_IO(15) <= L_WE_A when (L_ADR(4 downto 0) = "01111") else '0';
|
571 |
|
|
366 L_WE_IO(16) <= L_WE_A when (L_ADR(4 downto 0) = "10000") else '0';
|
572 |
|
|
367 L_WE_IO(17) <= L_WE_A when (L_ADR(4 downto 0) = "10001") else '0';
|
573 |
|
|
368 L_WE_IO(18) <= L_WE_A when (L_ADR(4 downto 0) = "10010") else '0';
|
574 |
|
|
369 L_WE_IO(19) <= L_WE_A when (L_ADR(4 downto 0) = "10011") else '0';
|
575 |
|
|
370 L_WE_IO(20) <= L_WE_A when (L_ADR(4 downto 0) = "10100") else '0';
|
576 |
|
|
371 L_WE_IO(21) <= L_WE_A when (L_ADR(4 downto 0) = "10101") else '0';
|
577 |
|
|
372 L_WE_IO(22) <= L_WE_A when (L_ADR(4 downto 0) = "10110") else '0';
|
578 |
|
|
373 L_WE_IO(23) <= L_WE_A when (L_ADR(4 downto 0) = "10111") else '0';
|
579 |
|
|
374 L_WE_IO(24) <= L_WE_A when (L_ADR(4 downto 0) = "11000") else '0';
|
580 |
|
|
375 L_WE_IO(25) <= L_WE_A when (L_ADR(4 downto 0) = "11001") else '0';
|
581 |
|
|
376 L_WE_IO(26) <= L_WE_A when (L_ADR(4 downto 0) = "11010") else '0';
|
582 |
|
|
377 L_WE_IO(27) <= L_WE_A when (L_ADR(4 downto 0) = "11011") else '0';
|
583 |
|
|
378 L_WE_IO(28) <= L_WE_A when (L_ADR(4 downto 0) = "11100") else '0';
|
584 |
|
|
379 L_WE_IO(29) <= L_WE_A when (L_ADR(4 downto 0) = "11101") else '0';
|
585 |
|
|
380 L_WE_IO(30) <= L_WE_A when (L_ADR(4 downto 0) = "11110") else '0';
|
586 |
|
|
381 L_WE_IO(31) <= L_WE_A when (L_ADR(4 downto 0) = "11111") else '0';
|
587 |
|
|
<pre class="filename">
|
588 |
|
|
src/register_file.vhd
|
589 |
|
|
</pre></pre>
|
590 |
|
|
<P>
|
591 |
|
|
|
592 |
|
|
<P><br>
|
593 |
|
|
|
594 |
|
|
<P>The last case for writing is handled by <STRONG>WE_MISC</STRONG>.
|
595 |
|
|
The various multiplication opcodes write their result to register pair 0;
|
596 |
|
|
this case is indicated the the <STRONG>WE_01</STRONG> input. Then we have the pre-decrement
|
597 |
|
|
and post-increment addressing modes that update the <STRONG>X</STRONG>, <STRONG>Y</STRONG>, or <STRONG>Z</STRONG> register:
|
598 |
|
|
|
599 |
|
|
<P><br>
|
600 |
|
|
|
601 |
|
|
<pre class="vhdl">
|
602 |
|
|
|
603 |
|
|
389 L_WE_X <= I_WE_XYZS when (I_AMOD(3 downto 0) = AM_WX) else '0';
|
604 |
|
|
390 L_WE_Y <= I_WE_XYZS when (I_AMOD(3 downto 0) = AM_WY) else '0';
|
605 |
|
|
391 L_WE_Z <= I_WE_XYZS when (I_AMOD(3 downto 0) = AM_WZ) else '0';
|
606 |
|
|
392 L_WE_MISC <= L_WE_Z & L_WE_Z & -- -Z and Z+ address modes r30
|
607 |
|
|
393 L_WE_Y & L_WE_Y & -- -Y and Y+ address modes r28
|
608 |
|
|
394 L_WE_X & L_WE_X & -- -X and X+ address modes r26
|
609 |
|
|
395 X"000000" & -- never r24 - r02
|
610 |
|
|
396 I_WE_01 & I_WE_01; -- multiplication result r00
|
611 |
|
|
<pre class="filename">
|
612 |
|
|
src/register_file.vhd
|
613 |
|
|
</pre></pre>
|
614 |
|
|
<P>
|
615 |
|
|
|
616 |
|
|
<P><br>
|
617 |
|
|
|
618 |
|
|
<P>The final <STRONG>WE</STRONG> signal is then computed by <STRONG>or</STRONG>'ing the four cases above:
|
619 |
|
|
|
620 |
|
|
<P><br>
|
621 |
|
|
|
622 |
|
|
<pre class="vhdl">
|
623 |
|
|
|
624 |
|
|
398 L_WE <= L_WE_D or L_WE_DD or L_WE_IO or L_WE_MISC;
|
625 |
|
|
<pre class="filename">
|
626 |
|
|
src/register_file.vhd
|
627 |
|
|
</pre></pre>
|
628 |
|
|
<P>
|
629 |
|
|
|
630 |
|
|
<P><br>
|
631 |
|
|
|
632 |
|
|
<P>The stack pointer can be updated from two sources: from <STRONG>DIN</STRONG> as a memory
|
633 |
|
|
mapped I/O or implicitly from <STRONG>XYZS</STRONG> by addressing modes (e.g. for
|
634 |
|
|
<STRONG>CALL</STRONG>, <STRONG>RET</STRONG>, <STRONG>PUSH</STRONG>, and <STRONG>POP</STRONG> instructions) that write to the <STRONG>SP</STRONG> (<STRONG>AM_WS</STRONG>).
|
635 |
|
|
|
636 |
|
|
<P><br>
|
637 |
|
|
|
638 |
|
|
<pre class="vhdl">
|
639 |
|
|
|
640 |
|
|
280 L_DSP <= L_XYZS when (I_AMOD(3 downto 0) = AM_WS) else I_DIN;
|
641 |
|
|
<pre class="filename">
|
642 |
|
|
src/register_file.vhd
|
643 |
|
|
</pre></pre>
|
644 |
|
|
<P>
|
645 |
|
|
|
646 |
|
|
<P><br>
|
647 |
|
|
|
648 |
|
|
<P>The status register can be written as memory mapped I/O from the <STRONG>DIN</STRONG> input
|
649 |
|
|
or from the <STRONG>FLAGS</STRONG> input (from the ALU). The <STRONG>WE_SR</STRONG> input (for memory
|
650 |
|
|
mapped I/O) and the <STRONG>WE_FLAGS</STRONG> input (for flags set as side effect of
|
651 |
|
|
ALU operations) control from where the new value comes:
|
652 |
|
|
|
653 |
|
|
<P><br>
|
654 |
|
|
|
655 |
|
|
<pre class="vhdl">
|
656 |
|
|
|
657 |
|
|
272 L_WE_SR <= I_WE_M when (L_ADR = X"005F") else '0';
|
658 |
|
|
<pre class="filename">
|
659 |
|
|
src/register_file.vhd
|
660 |
|
|
</pre></pre>
|
661 |
|
|
<P>
|
662 |
|
|
|
663 |
|
|
<P><br>
|
664 |
|
|
|
665 |
|
|
<pre class="vhdl">
|
666 |
|
|
|
667 |
|
|
152 I_DIN => I_DIN(7 downto 0),
|
668 |
|
|
153 I_FLAGS => I_FLAGS,
|
669 |
|
|
154 I_WE_F => I_WE_F,
|
670 |
|
|
<pre class="filename">
|
671 |
|
|
src/register_file.vhd
|
672 |
|
|
</pre></pre>
|
673 |
|
|
<P>
|
674 |
|
|
|
675 |
|
|
<P><br>
|
676 |
|
|
|
677 |
|
|
<H3><A NAME="section_1_1_9">6.1.9 Addressing Modes</A></H3>
|
678 |
|
|
|
679 |
|
|
<P>The CPU provides a number of addressing modes. An addressing mode is a way
|
680 |
|
|
to compute an address. The address specifies a location in the program memory,
|
681 |
|
|
the data memory, the I/O memory, or some general purpose register. Computing
|
682 |
|
|
an address can have side effects such as incrementing or decrementing a
|
683 |
|
|
pointer register.
|
684 |
|
|
|
685 |
|
|
<P>The addressing mode to be used (if any) is encoded in the <STRONG>AMOD</STRONG> signal.
|
686 |
|
|
The <STRONG>AMOD</STRONG> signal consists of two sub-fields: the address source and the
|
687 |
|
|
address offset.
|
688 |
|
|
|
689 |
|
|
<P>There are 5 possible address sources:
|
690 |
|
|
|
691 |
|
|
<P><br>
|
692 |
|
|
|
693 |
|
|
<pre class="vhdl">
|
694 |
|
|
|
695 |
|
|
84 constant AS_SP : std_logic_vector(2 downto 0) := "000"; -- SP
|
696 |
|
|
85 constant AS_Z : std_logic_vector(2 downto 0) := "001"; -- Z
|
697 |
|
|
86 constant AS_Y : std_logic_vector(2 downto 0) := "010"; -- Y
|
698 |
|
|
87 constant AS_X : std_logic_vector(2 downto 0) := "011"; -- X
|
699 |
|
|
88 constant AS_IMM : std_logic_vector(2 downto 0) := "100"; -- IMM
|
700 |
|
|
<pre class="filename">
|
701 |
|
|
src/common.vhd
|
702 |
|
|
</pre></pre>
|
703 |
|
|
<P>
|
704 |
|
|
|
705 |
|
|
<P><br>
|
706 |
|
|
|
707 |
|
|
<P>The address sources <STRONG>AS_SP</STRONG>, <STRONG>AS_X</STRONG>, <STRONG>AS_Y</STRONG>, and <STRONG>AS_Z</STRONG> are the stack pointer,
|
708 |
|
|
the <STRONG>X</STRONG> register pair, the <STRONG>Y</STRONG> register pair, or the <STRONG>Z</STRONG> register pair.
|
709 |
|
|
The <STRONG>AS_IMM</STRONG> source is the <STRONG>IMM</STRONG> input (which was computed from the opcode
|
710 |
|
|
in the opcode decoder).
|
711 |
|
|
|
712 |
|
|
<P>There are 6 different address offsets. An address offset can imply a side
|
713 |
|
|
effect like incrementing or decrementing the address source. The lowest
|
714 |
|
|
bit of the address offset indicates whether a side effect is intended or not:
|
715 |
|
|
|
716 |
|
|
<P><br>
|
717 |
|
|
|
718 |
|
|
<pre class="vhdl">
|
719 |
|
|
|
720 |
|
|
91 constant AO_0 : std_logic_vector(5 downto 3) := "000"; -- as is
|
721 |
|
|
92 constant AO_Q : std_logic_vector(5 downto 3) := "010"; -- +q
|
722 |
|
|
93 constant AO_i : std_logic_vector(5 downto 3) := "001"; -- +1
|
723 |
|
|
94 constant AO_ii : std_logic_vector(5 downto 3) := "011"; -- +2
|
724 |
|
|
95 constant AO_d : std_logic_vector(5 downto 3) := "101"; -- -1
|
725 |
|
|
96 constant AO_dd : std_logic_vector(5 downto 3) := "111"; -- -2
|
726 |
|
|
<pre class="filename">
|
727 |
|
|
src/common.vhd
|
728 |
|
|
</pre></pre>
|
729 |
|
|
<P>
|
730 |
|
|
|
731 |
|
|
<P><br>
|
732 |
|
|
|
733 |
|
|
<P>The address offset <STRONG>AO_0</STRONG> does nothing; the address source is not modified.
|
734 |
|
|
Address offset <STRONG>AO_Q</STRONG> adds some constant <STRONG>q</STRONG> to the address source; the constant
|
735 |
|
|
<STRONG>q</STRONG> is provided on the <STRONG>IMM</STRONG> input (thus derived from the opcode).
|
736 |
|
|
Address offsets <STRONG>AO_i</STRONG> resp. <STRONG>AO_ii</STRONG> increment the address source after the
|
737 |
|
|
operation by 1 resp. 2 bytes. The address computed is the address source.
|
738 |
|
|
Address offsets <STRONG>AO_d</STRONG> resp. <STRONG>AO_dd</STRONG> decrement the address source before the
|
739 |
|
|
operation by 1 resp. 2 bytes. The address computed is the address source
|
740 |
|
|
minus 1 or 2.
|
741 |
|
|
|
742 |
|
|
<P>The constants <STRONG>AM_WX</STRONG>, <STRONG>AM_WY</STRONG>, <STRONG>AM_WZ</STRONG>, and <STRONG>AM_WS</STRONG> respectively indicate if
|
743 |
|
|
the <STRONG>X</STRONG>, <STRONG>Y</STRONG>, <STRONG>Z</STRONG>, or <STRONG>SP</STRONG> registers will be updated and are used to decode
|
744 |
|
|
the <STRONG>WE_XYZS</STRONG> signal to the register concerned and to select the proper
|
745 |
|
|
inputs:
|
746 |
|
|
|
747 |
|
|
<P><br>
|
748 |
|
|
|
749 |
|
|
<pre class="vhdl">
|
750 |
|
|
|
751 |
|
|
389 L_WE_X <= I_WE_XYZS when (I_AMOD(3 downto 0) = AM_WX) else '0';
|
752 |
|
|
390 L_WE_Y <= I_WE_XYZS when (I_AMOD(3 downto 0) = AM_WY) else '0';
|
753 |
|
|
391 L_WE_Z <= I_WE_XYZS when (I_AMOD(3 downto 0) = AM_WZ) else '0';
|
754 |
|
|
392 L_WE_MISC <= L_WE_Z & L_WE_Z & -- -Z and Z+ address modes r30
|
755 |
|
|
393 L_WE_Y & L_WE_Y & -- -Y and Y+ address modes r28
|
756 |
|
|
394 L_WE_X & L_WE_X & -- -X and X+ address modes r26
|
757 |
|
|
<pre class="filename">
|
758 |
|
|
src/register_file.vhd
|
759 |
|
|
</pre></pre>
|
760 |
|
|
<P>
|
761 |
|
|
|
762 |
|
|
<P><br>
|
763 |
|
|
|
764 |
|
|
<pre class="vhdl">
|
765 |
|
|
|
766 |
|
|
277 L_DX <= L_XYZS when (L_WE_MISC(26) = '1') else I_DIN;
|
767 |
|
|
278 L_DY <= L_XYZS when (L_WE_MISC(28) = '1') else I_DIN;
|
768 |
|
|
279 L_DZ <= L_XYZS when (L_WE_MISC(30) = '1') else I_DIN;
|
769 |
|
|
280 L_DSP <= L_XYZS when (I_AMOD(3 downto 0) = AM_WS) else I_DIN;
|
770 |
|
|
<pre class="filename">
|
771 |
|
|
src/register_file.vhd
|
772 |
|
|
</pre></pre>
|
773 |
|
|
<P>
|
774 |
|
|
|
775 |
|
|
<P><br>
|
776 |
|
|
|
777 |
|
|
<P>Not all combinations of address source and address offset occur; only
|
778 |
|
|
the following combinations are needed:
|
779 |
|
|
|
780 |
|
|
<P><br>
|
781 |
|
|
|
782 |
|
|
<pre class="vhdl">
|
783 |
|
|
|
784 |
|
|
108 constant AMOD_ABS : std_logic_vector(5 downto 0) := AO_0 & AS_IMM; -- IMM
|
785 |
|
|
109 constant AMOD_X : std_logic_vector(5 downto 0) := AO_0 & AS_X; -- (X)
|
786 |
|
|
110 constant AMOD_Xq : std_logic_vector(5 downto 0) := AO_Q & AS_X; -- (X+q)
|
787 |
|
|
111 constant AMOD_Xi : std_logic_vector(5 downto 0) := AO_i & AS_X; -- (X++)
|
788 |
|
|
112 constant AMOD_dX : std_logic_vector(5 downto 0) := AO_d & AS_X; -- (--X)
|
789 |
|
|
113 constant AMOD_Y : std_logic_vector(5 downto 0) := AO_0 & AS_Y; -- (Y)
|
790 |
|
|
114 constant AMOD_Yq : std_logic_vector(5 downto 0) := AO_Q & AS_Y; -- (Y+q)
|
791 |
|
|
115 constant AMOD_Yi : std_logic_vector(5 downto 0) := AO_i & AS_Y; -- (Y++)
|
792 |
|
|
116 constant AMOD_dY : std_logic_vector(5 downto 0) := AO_d & AS_Y; -- (--Y)
|
793 |
|
|
117 constant AMOD_Z : std_logic_vector(5 downto 0) := AO_0 & AS_Z; -- (Z)
|
794 |
|
|
118 constant AMOD_Zq : std_logic_vector(5 downto 0) := AO_Q & AS_Z; -- (Z+q)
|
795 |
|
|
119 constant AMOD_Zi : std_logic_vector(5 downto 0) := AO_i & AS_Z; -- (Z++)
|
796 |
|
|
120 constant AMOD_dZ : std_logic_vector(5 downto 0) := AO_d & AS_Z; -- (--Z)
|
797 |
|
|
121 constant AMOD_SPi : std_logic_vector(5 downto 0) := AO_i & AS_SP; -- (SP++)
|
798 |
|
|
122 constant AMOD_SPii: std_logic_vector(5 downto 0) := AO_ii & AS_SP; -- (SP++)
|
799 |
|
|
123 constant AMOD_dSP : std_logic_vector(5 downto 0) := AO_d & AS_SP; -- (--SP)
|
800 |
|
|
124 constant AMOD_ddSP: std_logic_vector(5 downto 0) := AO_dd & AS_SP; -- (--SP)
|
801 |
|
|
<pre class="filename">
|
802 |
|
|
src/common.vhd
|
803 |
|
|
</pre></pre>
|
804 |
|
|
<P>
|
805 |
|
|
|
806 |
|
|
<P><br>
|
807 |
|
|
|
808 |
|
|
<P>The following figure shows the computation of addresses:
|
809 |
|
|
|
810 |
|
|
<P><br>
|
811 |
|
|
|
812 |
|
|
<P><img src="data_path_2.png">
|
813 |
|
|
|
814 |
|
|
<P><br>
|
815 |
|
|
|
816 |
|
|
<H2><A NAME="section_1_2">6.2 Data memory</A></H2>
|
817 |
|
|
|
818 |
|
|
<P>The data memory is conceptually an 8-bit memory. However, some instructions
|
819 |
|
|
(e.g. CALL, RET) write two bytes to consecutive memory locations. We do the
|
820 |
|
|
same trick as for the program memory and divide the data memory into an
|
821 |
|
|
even half and an odd half. The only new thing is a multiplexer at the input:
|
822 |
|
|
|
823 |
|
|
<P><br>
|
824 |
|
|
|
825 |
|
|
<pre class="vhdl">
|
826 |
|
|
|
827 |
|
|
179 L_DIN_E <= I_DIN( 7 downto 0) when (I_ADR(0) = '0') else I_DIN(15 downto 8);
|
828 |
|
|
180 L_DIN_O <= I_DIN( 7 downto 0) when (I_ADR(0) = '1') else I_DIN(15 downto 8);
|
829 |
|
|
<pre class="filename">
|
830 |
|
|
src/data_mem.vhd
|
831 |
|
|
</pre></pre>
|
832 |
|
|
<P>
|
833 |
|
|
|
834 |
|
|
<P><br>
|
835 |
|
|
|
836 |
|
|
<P>The multiplexer is needed because the data memory is a read/write memory
|
837 |
|
|
while the program memory was read-only. The multiplexer swaps the upper
|
838 |
|
|
and lower bytes of <STRONG>DIN</STRONG> when writing to odd addresses.
|
839 |
|
|
|
840 |
|
|
<H2><A NAME="section_1_3">6.3 Arithmetic/Logic Unit (ALU)</A></H2>
|
841 |
|
|
|
842 |
|
|
<P>The most obvious component of a CPU is the ALU where all arithmetic and
|
843 |
|
|
logic operations are computed. We do a little trick here and implement
|
844 |
|
|
the data move instructions (<STRONG>MOV</STRONG>, <STRONG>LD</STRONG>, <STRONG>ST</STRONG>, etc.) as ALU operations
|
845 |
|
|
that simply moves the data source to the output of the ALU.
|
846 |
|
|
The data move instructions can use the same data paths as the arithmetic
|
847 |
|
|
and logic instructions.
|
848 |
|
|
|
849 |
|
|
<P>If we look at the instructions set of the CPU then we see that a number
|
850 |
|
|
of instructions are quite similar. We use these similarities to reduce
|
851 |
|
|
the number of different instructions that need to be implemented in the ALU.
|
852 |
|
|
|
853 |
|
|
<UL>
|
854 |
|
|
<LI>Some instructions have 8-bit and 16-bit variants (e.g. <STRONG>ADD</STRONG> and <STRONG>ADIW</STRONG>).
|
855 |
|
|
<LI>Some instructions have immediate variants (e.g. <STRONG>CMP</STRONG> and <STRONG>CMPI</STRONG>).
|
856 |
|
|
<LI>Some instructions differ only in whether they update the destination
|
857 |
|
|
register or not (e.g. <STRONG>CMP</STRONG> and <STRONG>SUB</STRONG>).
|
858 |
|
|
</UL>
|
859 |
|
|
<P>The ALU is a completely combinational circuit and therefore it has
|
860 |
|
|
no clock input. We can divide the ALU into a number of blocks that
|
861 |
|
|
are explained in the following.
|
862 |
|
|
|
863 |
|
|
<P>6.3.1 <STRONG>D</STRONG> Input Multiplexing.
|
864 |
|
|
|
865 |
|
|
<P>We have seen earlier that the <STRONG>D</STRONG> input of the ALU is the output of the
|
866 |
|
|
register pair addressed by <STRONG>DDDDD[4:1]</STRONG> and that the <STRONG>D0</STRONG> input of the ALU
|
867 |
|
|
is <STRONG>DDDDD[0]</STRONG>:
|
868 |
|
|
|
869 |
|
|
<P><br>
|
870 |
|
|
|
871 |
|
|
<pre class="vhdl">
|
872 |
|
|
|
873 |
|
|
178 Q_D => F_D,
|
874 |
|
|
<pre class="filename">
|
875 |
|
|
src/data_path.vhd
|
876 |
|
|
</pre></pre>
|
877 |
|
|
<P>
|
878 |
|
|
|
879 |
|
|
<P><br>
|
880 |
|
|
|
881 |
|
|
<pre class="vhdl">
|
882 |
|
|
|
883 |
|
|
146 I_D => F_D,
|
884 |
|
|
147 I_D0 => I_DDDDD(0),
|
885 |
|
|
<pre class="filename">
|
886 |
|
|
src/data_path.vhd
|
887 |
|
|
</pre></pre>
|
888 |
|
|
<P>
|
889 |
|
|
|
890 |
|
|
<P><br>
|
891 |
|
|
|
892 |
|
|
<P>If <STRONG>D0</STRONG> is zero, then the lower byte of the ALU operation comes from
|
893 |
|
|
the even register regardless of the size (8-bit or 16-bit) of the operation.
|
894 |
|
|
If <STRONG>D0</STRONG> is odd, then the lower byte of the ALU operation comes from the
|
895 |
|
|
odd register of the pair (and must be an 8-bit operation since register pairs
|
896 |
|
|
always have the lowest bit of <STRONG>DDDDD</STRONG> cleared.
|
897 |
|
|
|
898 |
|
|
<P>The upper byte of the operation (if any) is always the odd register of the pair.
|
899 |
|
|
|
900 |
|
|
<P>We can therefore compute the lower byte, called <STRONG>D8</STRONG>, from <STRONG>D</STRONG> and <STRONG>D0</STRONG>:
|
901 |
|
|
|
902 |
|
|
<P><br>
|
903 |
|
|
|
904 |
|
|
<pre class="vhdl">
|
905 |
|
|
|
906 |
|
|
356 L_D8 <= I_D(15 downto 8) when (I_D0 = '1') else I_D(7 downto 0);
|
907 |
|
|
<pre class="filename">
|
908 |
|
|
src/alu.vhd
|
909 |
|
|
</pre></pre>
|
910 |
|
|
<P>
|
911 |
|
|
|
912 |
|
|
<P><br>
|
913 |
|
|
|
914 |
|
|
<P>6.3.2 <STRONG>R</STRONG> and <STRONG>IMM</STRONG> Input Multiplexing.
|
915 |
|
|
|
916 |
|
|
<P>Multiplexing of the <STRONG>R</STRONG> input works like multiplexing of the <STRONG>D</STRONG> input.
|
917 |
|
|
Some opcodes can have immediate operand instead of a register addressed
|
918 |
|
|
by <STRONG>RRRRR</STRONG>. We compute the signal <STRONG>R8</STRONG> for opcodes that cannot have
|
919 |
|
|
an immediate operand, and <STRONG>RI8</STRONG> for opcodes that can have an immediate
|
920 |
|
|
operand.
|
921 |
|
|
|
922 |
|
|
<P>This is some fine tuning of the design: the <STRONG>MULT</STRONG> opcodes can take
|
923 |
|
|
a while to compute but cannot have an immediate operand. It makes
|
924 |
|
|
therefore sense to have a path from the register addressed by <STRONG>RRRRR</STRONG>
|
925 |
|
|
to the multiplier and to put the register/immediate multiplexer
|
926 |
|
|
outside that critical path through the ALU.
|
927 |
|
|
|
928 |
|
|
<P><br>
|
929 |
|
|
|
930 |
|
|
<pre class="vhdl">
|
931 |
|
|
|
932 |
|
|
357 L_R8 <= I_R(15 downto 8) when (I_R0 = '1') else I_R(7 downto 0);
|
933 |
|
|
358 L_RI8 <= I_IMM when (I_RSEL = RS_IMM) else L_R8;
|
934 |
|
|
<pre class="filename">
|
935 |
|
|
src/alu.vhd
|
936 |
|
|
</pre></pre>
|
937 |
|
|
<P>
|
938 |
|
|
|
939 |
|
|
<P><br>
|
940 |
|
|
|
941 |
|
|
<H3><A NAME="section_1_3_1">6.3.3 Arithmetic and Logic Functions</A></H3>
|
942 |
|
|
|
943 |
|
|
<P>The first step in the computation of the arithmetic and logic functions
|
944 |
|
|
is to compute a number of helper values. The reason for computing them
|
945 |
|
|
beforehand is that we need these values several times,
|
946 |
|
|
either for different but similar opcodes (e.g. <STRONG>CMP</STRONG> and <STRONG>SUB</STRONG>) but also
|
947 |
|
|
for the result and for the flags of the same opcode.
|
948 |
|
|
|
949 |
|
|
<P><br>
|
950 |
|
|
|
951 |
|
|
<pre class="vhdl">
|
952 |
|
|
|
953 |
|
|
360 L_ADIW_D <= I_D + ("0000000000" & I_IMM(5 downto 0));
|
954 |
|
|
361 L_SBIW_D <= I_D - ("0000000000" & I_IMM(5 downto 0));
|
955 |
|
|
362 L_ADD_DR <= L_D8 + L_RI8;
|
956 |
|
|
363 L_ADC_DR <= L_ADD_DR + ("0000000" & I_FLAGS(0));
|
957 |
|
|
364 L_ASR_D <= L_D8(7) & L_D8(7 downto 1);
|
958 |
|
|
365 L_AND_DR <= L_D8 and L_RI8;
|
959 |
|
|
366 L_DEC_D <= L_D8 - X"01";
|
960 |
|
|
367 L_INC_D <= L_D8 + X"01";
|
961 |
|
|
368 L_LSR_D <= '0' & L_D8(7 downto 1);
|
962 |
|
|
369 L_NEG_D <= X"00" - L_D8;
|
963 |
|
|
370 L_NOT_D <= not L_D8;
|
964 |
|
|
371 L_OR_DR <= L_D8 or L_RI8;
|
965 |
|
|
372 L_PROD <= (L_SIGN_D & L_D8) * (L_SIGN_R & L_R8);
|
966 |
|
|
373 L_ROR_D <= I_FLAGS(0) & L_D8(7 downto 1);
|
967 |
|
|
374 L_SUB_DR <= L_D8 - L_RI8;
|
968 |
|
|
375 L_SBC_DR <= L_SUB_DR - ("0000000" & I_FLAGS(0));
|
969 |
|
|
376 L_SIGN_D <= L_D8(7) and I_IMM(6);
|
970 |
|
|
377 L_SIGN_R <= L_R8(7) and I_IMM(5);
|
971 |
|
|
378 L_SWAP_D <= L_D8(3 downto 0) & L_D8(7 downto 4);
|
972 |
|
|
379 L_XOR_DR <= L_D8 xor L_R8;
|
973 |
|
|
<pre class="filename">
|
974 |
|
|
src/alu.vhd
|
975 |
|
|
</pre></pre>
|
976 |
|
|
<P>
|
977 |
|
|
|
978 |
|
|
<P><br>
|
979 |
|
|
|
980 |
|
|
<P>Most values should be obvious, but a few deserve an explanation:
|
981 |
|
|
There is a considerable number of multiplication functions that only differ
|
982 |
|
|
in the signedness of their operands. Instead of implementing a different
|
983 |
|
|
8-bit multiplier for each opcode, we use a common signed 9-bit multiplier
|
984 |
|
|
for all opcodes. The opcode decoder sets bits 6 and/or 5 of the <STRONG>IMM</STRONG> input
|
985 |
|
|
if the <STRONG>D</STRONG> operand and/or the <STRONG>R</STRONG> operand is signed. The signs of the
|
986 |
|
|
operands are then <STRONG>SIGN_D</STRONG> and <STRONG>SIGN_R</STRONG>; they are 0 for unsigned operations.
|
987 |
|
|
Next the signs are prepended to the operands so that each operand is 9-bit
|
988 |
|
|
signed. If the operand was unsigned (and the sign was 0) then the new signed
|
989 |
|
|
9-bit operand is positive. If the operand was signed and positive (and the
|
990 |
|
|
sign was 0 again) then the new operand is positive again. If the operand was
|
991 |
|
|
signed and negative, then the sign was 1 and the new operand is also negative.
|
992 |
|
|
|
993 |
|
|
<H3><A NAME="section_1_3_2">6.3.4 Output and Flag Multiplexing</A></H3>
|
994 |
|
|
|
995 |
|
|
<P>The necessary computations in the ALU have already been made in the previous
|
996 |
|
|
section. What remains is to select the proper result and setting the flags.
|
997 |
|
|
The output <STRONG>DOUT</STRONG> and the flags are selected by <STRONG>ALU_OP</STRONG>. We take the
|
998 |
|
|
first two values of <STRONG>ALU_OP</STRONG> as an example and leave the remaining ones
|
999 |
|
|
as an exercise for the reader.
|
1000 |
|
|
|
1001 |
|
|
<P><br>
|
1002 |
|
|
|
1003 |
|
|
<pre class="vhdl">
|
1004 |
|
|
|
1005 |
|
|
118 process(L_ADC_DR, L_ADD_DR, L_ADIW_D, I_ALU_OP, L_AND_DR, L_ASR_D,
|
1006 |
|
|
119 I_BIT, I_D, L_D8, L_DEC_D, I_DIN, I_FLAGS, I_IMM, L_MASK_I,
|
1007 |
|
|
120 L_INC_D, L_LSR_D, L_NEG_D, L_NOT_D, L_OR_DR, I_PC, L_PROD,
|
1008 |
|
|
121 I_R, L_RI8, L_RBIT, L_ROR_D, L_SBIW_D, L_SUB_DR, L_SBC_DR,
|
1009 |
|
|
122 L_SIGN_D, L_SIGN_R, L_SWAP_D, L_XOR_DR)
|
1010 |
|
|
123 begin
|
1011 |
|
|
124 Q_FLAGS(9) <= L_RBIT xor not I_BIT(3); -- DIN[BIT] = BIT[3]
|
1012 |
|
|
125 Q_FLAGS(8) <= ze(L_SUB_DR); -- D == R for CPSE
|
1013 |
|
|
126 Q_FLAGS(7 downto 0) <= I_FLAGS;
|
1014 |
|
|
127 L_DOUT <= X"0000";
|
1015 |
|
|
128
|
1016 |
|
|
129 case I_ALU_OP is
|
1017 |
|
|
130 when ALU_ADC =>
|
1018 |
|
|
131 L_DOUT <= L_ADC_DR & L_ADC_DR;
|
1019 |
|
|
132 Q_FLAGS(0) <= cy(L_D8(7), L_RI8(7), L_ADC_DR(7)); -- Carry
|
1020 |
|
|
133 Q_FLAGS(1) <= ze(L_ADC_DR); -- Zero
|
1021 |
|
|
134 Q_FLAGS(2) <= L_ADC_DR(7); -- Negative
|
1022 |
|
|
135 Q_FLAGS(3) <= ov(L_D8(7), L_RI8(7), L_ADC_DR(7)); -- Overflow
|
1023 |
|
|
136 Q_FLAGS(4) <= si(L_D8(7), L_RI8(7), L_ADC_DR(7)); -- Signed
|
1024 |
|
|
137 Q_FLAGS(5) <= cy(L_D8(3), L_RI8(3), L_ADC_DR(3)); -- Halfcarry
|
1025 |
|
|
138
|
1026 |
|
|
139 when ALU_ADD =>
|
1027 |
|
|
140 L_DOUT <= L_ADD_DR & L_ADD_DR;
|
1028 |
|
|
141 Q_FLAGS(0) <= cy(L_D8(7), L_RI8(7), L_ADD_DR(7)); -- Carry
|
1029 |
|
|
142 Q_FLAGS(1) <= ze(L_ADD_DR); -- Zero
|
1030 |
|
|
143 Q_FLAGS(2) <= L_ADD_DR(7); -- Negative
|
1031 |
|
|
144 Q_FLAGS(3) <= ov(L_D8(7), L_RI8(7), L_ADD_DR(7)); -- Overflow
|
1032 |
|
|
145 Q_FLAGS(4) <= si(L_D8(7), L_RI8(7), L_ADD_DR(7)); -- Signed
|
1033 |
|
|
146 Q_FLAGS(5) <= cy(L_D8(3), L_RI8(3), L_ADD_DR(3)); -- Halfcarry
|
1034 |
|
|
<pre class="filename">
|
1035 |
|
|
src/alu.vhd
|
1036 |
|
|
</pre></pre>
|
1037 |
|
|
<P>
|
1038 |
|
|
|
1039 |
|
|
<P><br>
|
1040 |
|
|
|
1041 |
|
|
<P>First of all, the default values for the flags and the ALU output are chosen.
|
1042 |
|
|
The default of <STRONG>L_OUT</STRONG> is 0, while the default for <STRONG>O_FLAGS</STRONG> is <STRONG>I_FLAGS</STRONG>. This
|
1043 |
|
|
means that all flags that are not explicitly changed remain the same.
|
1044 |
|
|
The upper two flag bits are set according to specific needs of certain
|
1045 |
|
|
skip instructions (CPSE, SBIC, SBIS, SBRC, and SBRS).
|
1046 |
|
|
|
1047 |
|
|
<P>Then comes a big case statement for which we explain only the first two cases,
|
1048 |
|
|
<STRONG>ALU_ADC</STRONG> and <STRONG>ALU_ADD</STRONG>.
|
1049 |
|
|
|
1050 |
|
|
<P>The expected value of <STRONG>DOUT</STRONG> was already computed as <STRONG>L_ADC_DR</STRONG>
|
1051 |
|
|
in the previous section and this value is assigned to <STRONG>DOUT</STRONG>.
|
1052 |
|
|
|
1053 |
|
|
<P>After that the flags that can change in the execution of the <STRONG>ADC</STRONG> opcode
|
1054 |
|
|
are computed. The computation of flags is very similar for a number of
|
1055 |
|
|
different opcodes. We have therefore defined functions <STRONG>cy()</STRONG>, <STRONG>ze()</STRONG>,
|
1056 |
|
|
<STRONG>ov()</STRONG>, and <STRONG>si()</STRONG> for the usual way of computing these flags:
|
1057 |
|
|
|
1058 |
|
|
<P>The half-carry flags is computed like the carry flag but on bits 3 rather
|
1059 |
|
|
than bits 7 of the operands and result.
|
1060 |
|
|
|
1061 |
|
|
<P>The next example is <STRONG>ADD</STRONG>. It is similar to <STRONG>ADC</STRONG>, but now <STRONG>L_ADD_DR</STRONG>
|
1062 |
|
|
is used instead of <STRONG>L_ADC_DR</STRONG>.
|
1063 |
|
|
|
1064 |
|
|
<H3><A NAME="section_1_3_3">6.3.5 Individual ALU Operations</A></H3>
|
1065 |
|
|
|
1066 |
|
|
<P>The following table briefly describes how the <STRONG>DOUT</STRONG> output of the ALU
|
1067 |
|
|
is computed for the different <STRONG>ALU_OP</STRONG> values.
|
1068 |
|
|
|
1069 |
|
|
<TABLE>
|
1070 |
|
|
<TR><TD><STRONG>ALU_OP</STRONG></TD><TD><STRONG>DOUT</STRONG></TD><TD ALIGN="RIGHT"><STRONG>Size</STRONG>
|
1071 |
|
|
</TD></TR><TR><TD>ALU_ADC</TD><TD>D + R + Carry</TD><TD ALIGN="RIGHT">8-bit
|
1072 |
|
|
</TD></TR><TR><TD>ALU_ADD</TD><TD>D + R</TD><TD ALIGN="RIGHT">8-bit
|
1073 |
|
|
</TD></TR><TR><TD>ALU_ADIW</TD><TD>D + IMM</TD><TD ALIGN="RIGHT">16-bit
|
1074 |
|
|
</TD></TR><TR><TD>ALU_AND</TD><TD>D and R</TD><TD ALIGN="RIGHT">8-bit
|
1075 |
|
|
</TD></TR><TR><TD>ALU_ASR</TD><TD>D >> 1</TD><TD ALIGN="RIGHT">8-bit
|
1076 |
|
|
</TD></TR><TR><TD>ALU_BLD</TD><TD>T-flag << IMM</TD><TD ALIGN="RIGHT">8-bit
|
1077 |
|
|
</TD></TR><TR><TD>ALU_BST</TD><TD>(set T-flag)</TD><TD ALIGN="RIGHT">8-bit
|
1078 |
|
|
</TD></TR><TR><TD>ALU_COM</TD><TD>not D</TD><TD ALIGN="RIGHT">8-bit
|
1079 |
|
|
</TD></TR><TR><TD>ALU_DEC</TD><TD>D - 1</TD><TD ALIGN="RIGHT">8-bit
|
1080 |
|
|
</TD></TR><TR><TD>ALU_EOR</TD><TD>D xor R</TD><TD ALIGN="RIGHT">8-bit
|
1081 |
|
|
</TD></TR><TR><TD>ALU_IN</TD><TD>DIN</TD><TD ALIGN="RIGHT">8-bit
|
1082 |
|
|
</TD></TR><TR><TD>ALU_INC</TD><TD>D + 1</TD><TD ALIGN="RIGHT">8-bit
|
1083 |
|
|
</TD></TR><TR><TD>ALU_LSR</TD><TD>D >> 1</TD><TD ALIGN="RIGHT">8-bit
|
1084 |
|
|
</TD></TR><TR><TD>ALU_D_MOV_Q</TD><TD>D</TD><TD ALIGN="RIGHT">16-bit
|
1085 |
|
|
</TD></TR><TR><TD>ALU_R_MOV_Q</TD><TD>R</TD><TD ALIGN="RIGHT">16-bit
|
1086 |
|
|
</TD></TR><TR><TD>ALU_MULT</TD><TD>D * R</TD><TD ALIGN="RIGHT">16-bit
|
1087 |
|
|
</TD></TR><TR><TD>ALU_NEG</TD><TD>0 - D</TD><TD ALIGN="RIGHT">8-bit
|
1088 |
|
|
</TD></TR><TR><TD>ALU_OR</TD><TD>A or R</TD><TD ALIGN="RIGHT">8-bit
|
1089 |
|
|
</TD></TR><TR><TD>ALU_PC</TD><TD>PC</TD><TD ALIGN="RIGHT">16-bit
|
1090 |
|
|
</TD></TR><TR><TD>ALU_PC_1</TD><TD>PC + 1</TD><TD ALIGN="RIGHT">16-bit
|
1091 |
|
|
</TD></TR><TR><TD>ALU_PC_2</TD><TD>PC + 2</TD><TD ALIGN="RIGHT">16-bit
|
1092 |
|
|
</TD></TR><TR><TD>ALU_ROR</TD><TD>D rotated right</TD><TD ALIGN="RIGHT">8-bit
|
1093 |
|
|
</TD></TR><TR><TD>ALU_SBC</TD><TD>D - R - Carry</TD><TD ALIGN="RIGHT">8-bit
|
1094 |
|
|
</TD></TR><TR><TD>ALU_SBIW</TD><TD>D - IMM</TD><TD ALIGN="RIGHT">16-bit
|
1095 |
|
|
</TD></TR><TR><TD>ALU_SREG</TD><TD>(set a flag)</TD><TD ALIGN="RIGHT">8-bit
|
1096 |
|
|
</TD></TR><TR><TD>ALU_SUB</TD><TD>D - R</TD><TD ALIGN="RIGHT">8-bit
|
1097 |
|
|
</TD></TR><TR><TD>ALU_SWAP</TD><TD>D[3:0] & D[7:4]</TD><TD ALIGN="RIGHT">8-bit
|
1098 |
|
|
</TD></TR>
|
1099 |
|
|
</TABLE>
|
1100 |
|
|
<P>For all 8-bit computations, the result is placed onto the upper and
|
1101 |
|
|
onto the lower byte of <STRONG>L_DOUT</STRONG>. This saves a multiplexer at the
|
1102 |
|
|
inputs of the registers.
|
1103 |
|
|
|
1104 |
|
|
<P>The final result of the ALU is obtained by multiplexing the local result
|
1105 |
|
|
<STRONG>L_DOUT</STRONG> and <STRONG>DIN</STRONG> based on <STRONG>I_RSEL</STRONG>.
|
1106 |
|
|
|
1107 |
|
|
<P><br>
|
1108 |
|
|
|
1109 |
|
|
<pre class="vhdl">
|
1110 |
|
|
|
1111 |
|
|
381 Q_DOUT <= (I_DIN & I_DIN) when (I_RSEL = RS_DIN) else L_DOUT;
|
1112 |
|
|
<pre class="filename">
|
1113 |
|
|
src/alu.vhd
|
1114 |
|
|
</pre></pre>
|
1115 |
|
|
<P>
|
1116 |
|
|
|
1117 |
|
|
<P><br>
|
1118 |
|
|
|
1119 |
|
|
<P>We could have placed this multiplexer at the <STRONG>R</STRONG> input (combined with the
|
1120 |
|
|
multiplexer for the <STRONG>DIN</STRONG> input) or at the <STRONG>DOUT</STRONG> output. Placing it at
|
1121 |
|
|
the output gives a better timing, since the opcodes using the DIN input
|
1122 |
|
|
do not perform ALU operations.
|
1123 |
|
|
|
1124 |
|
|
<H3><A NAME="section_1_3_4">6.3.5 Temporary Z and T Flags</A></H3>
|
1125 |
|
|
|
1126 |
|
|
<P>There are two opcodes that use the value of the <STRONG>Z</STRONG> flag (<STRONG>CPSE</STRONG>) or
|
1127 |
|
|
the #T flag (SBIC, SBIS) without setting them. For timing
|
1128 |
|
|
reasons, they are executed in two cycles - one cycle for performing a
|
1129 |
|
|
comparison or a bit access and a second cycle for actually making the
|
1130 |
|
|
decision to skip the next instruction or not.
|
1131 |
|
|
|
1132 |
|
|
<P>For this reason we have introduced copies of the <STRONG>Z</STRONG> and <STRONG>T</STRONG> flags and called
|
1133 |
|
|
them <STRONG>FLAGS_98</STRONG>. They store the values of these flags within an instruction,
|
1134 |
|
|
but without updating the status register. The two flags are computed in
|
1135 |
|
|
the ALU:
|
1136 |
|
|
|
1137 |
|
|
<P><br>
|
1138 |
|
|
|
1139 |
|
|
<pre class="vhdl">
|
1140 |
|
|
|
1141 |
|
|
124 Q_FLAGS(9) <= L_RBIT xor not I_BIT(3); -- DIN[BIT] = BIT[3]
|
1142 |
|
|
125 Q_FLAGS(8) <= ze(L_SUB_DR); -- D == R for CPSE
|
1143 |
|
|
<pre class="filename">
|
1144 |
|
|
src/alu.vhd
|
1145 |
|
|
</pre></pre>
|
1146 |
|
|
<P>
|
1147 |
|
|
|
1148 |
|
|
<P><br>
|
1149 |
|
|
|
1150 |
|
|
<P><br>
|
1151 |
|
|
|
1152 |
|
|
<P>The result is stored in the data path:
|
1153 |
|
|
|
1154 |
|
|
<pre class="vhdl">
|
1155 |
|
|
|
1156 |
|
|
195 flg98: process(I_CLK)
|
1157 |
|
|
196 begin
|
1158 |
|
|
197 if (rising_edge(I_CLK)) then
|
1159 |
|
|
198 L_FLAGS_98 <= A_FLAGS(9 downto 8);
|
1160 |
|
|
199 end if;
|
1161 |
|
|
200 end process;
|
1162 |
|
|
<pre class="filename">
|
1163 |
|
|
src/data_path.vhd
|
1164 |
|
|
</pre></pre>
|
1165 |
|
|
<P>
|
1166 |
|
|
|
1167 |
|
|
<P><br>
|
1168 |
|
|
|
1169 |
|
|
<H2><A NAME="section_1_4">6.4 Other Functions</A></H2>
|
1170 |
|
|
|
1171 |
|
|
<P>Most of the data path is contained in its components <STRONG>alu</STRONG>, <STRONG>register_file</STRONG>,
|
1172 |
|
|
and <STRONG>data_mem</STRONG>. A few things are written directly in VHDL and shall be
|
1173 |
|
|
explained here.
|
1174 |
|
|
|
1175 |
|
|
<P>Some output signals are driven directly from inputs or from instantiated
|
1176 |
|
|
components:
|
1177 |
|
|
|
1178 |
|
|
<P><br>
|
1179 |
|
|
|
1180 |
|
|
<pre class="vhdl">
|
1181 |
|
|
|
1182 |
|
|
231 Q_ADR <= F_ADR;
|
1183 |
|
|
232 Q_DOUT <= A_DOUT(7 downto 0);
|
1184 |
|
|
233 Q_INT_ENA <= A_FLAGS(7);
|
1185 |
|
|
234 Q_OPC <= I_OPC;
|
1186 |
|
|
235 Q_PC <= I_PC;
|
1187 |
|
|
<pre class="filename">
|
1188 |
|
|
src/data_path.vhd
|
1189 |
|
|
</pre></pre>
|
1190 |
|
|
<P>
|
1191 |
|
|
|
1192 |
|
|
<P><br>
|
1193 |
|
|
|
1194 |
|
|
<P>The address space of the data memory is spread over the register file (general
|
1195 |
|
|
purpose registers, stack pointer, and status register), the data RAM, and the
|
1196 |
|
|
external I/O registers outside of the data path. The external I/O registers
|
1197 |
|
|
reach from 0x20 to 0x5C (including) and the data RAM starts at 0x60. We
|
1198 |
|
|
generate write enable signals for these address ranges, and a read strobe for
|
1199 |
|
|
external I/O registers. We also control the multiplexer at the input of the
|
1200 |
|
|
ALU by the address output of the register file:
|
1201 |
|
|
|
1202 |
|
|
<P><br>
|
1203 |
|
|
|
1204 |
|
|
<pre class="vhdl">
|
1205 |
|
|
|
1206 |
|
|
237 Q_RD_IO <= '0' when (F_ADR < X"20")
|
1207 |
|
|
238 else (I_RD_M and not I_PMS) when (F_ADR < X"5D")
|
1208 |
|
|
239 else '0';
|
1209 |
|
|
240 Q_WE_IO <= '0' when (F_ADR < X"20")
|
1210 |
|
|
241 else I_WE_M(0) when (F_ADR < X"5D")
|
1211 |
|
|
242 else '0';
|
1212 |
|
|
243 L_WE_SRAM <= "00" when (F_ADR < X"0060") else I_WE_M;
|
1213 |
|
|
244 L_DIN <= I_DIN when (I_PMS = '1')
|
1214 |
|
|
245 else F_S when (F_ADR < X"0020")
|
1215 |
|
|
246 else I_DIN when (F_ADR < X"005D")
|
1216 |
|
|
247 else F_S when (F_ADR < X"0060")
|
1217 |
|
|
248 else M_DOUT(7 downto 0);
|
1218 |
|
|
<pre class="filename">
|
1219 |
|
|
src/data_path.vhd
|
1220 |
|
|
</pre></pre>
|
1221 |
|
|
<P>
|
1222 |
|
|
|
1223 |
|
|
<P><br>
|
1224 |
|
|
|
1225 |
|
|
<P>Most instructions that modify the program counter (other than incrementing
|
1226 |
|
|
it) use addresses that are being provided on the <STRONG>IMM</STRONG> input (from the
|
1227 |
|
|
opcode decoder).<BR>
|
1228 |
|
|
The two exceptions are the <STRONG>IJMP</STRONG> instruction where the new <STRONG>PC</STRONG> value is the
|
1229 |
|
|
value of the <STRONG>Z</STRONG> register pair, and the <STRONG>RET</STRONG> and <STRONG>RETI</STRONG> instructions where the
|
1230 |
|
|
new <STRONG>PC</STRONG> value is popped from the stack. The new value of the <STRONG>PC</STRONG> (if any) is
|
1231 |
|
|
therefore:
|
1232 |
|
|
|
1233 |
|
|
<P><br>
|
1234 |
|
|
|
1235 |
|
|
<pre class="vhdl">
|
1236 |
|
|
|
1237 |
|
|
252 Q_NEW_PC <= F_Z when I_PC_OP = PC_LD_Z -- IJMP, ICALL
|
1238 |
|
|
253 else M_DOUT when I_PC_OP = PC_LD_S -- RET, RETI
|
1239 |
|
|
254 else I_JADR; -- JMP adr
|
1240 |
|
|
<pre class="filename">
|
1241 |
|
|
src/data_path.vhd
|
1242 |
|
|
</pre></pre>
|
1243 |
|
|
<P>
|
1244 |
|
|
|
1245 |
|
|
<P><br>
|
1246 |
|
|
|
1247 |
|
|
<P>Conditional branches use the <STRONG>CC</STRONG> output of the register file in order to
|
1248 |
|
|
decide whether the branch shall be taken or not. The opcode decoder
|
1249 |
|
|
drives the <STRONG>COND</STRONG> input according to the relevant bit in the status register
|
1250 |
|
|
(<STRONG>I_COND[2:0]</STRONG>) and according to the expected value (<STRONG>COND[3]</STRONG>) of that bit.
|
1251 |
|
|
|
1252 |
|
|
<P>The <STRONG>LOAD_PC</STRONG> output is therefore '1' for unconditional branches and <STRONG>CC</STRONG>
|
1253 |
|
|
for conditional branches:
|
1254 |
|
|
|
1255 |
|
|
<P><br>
|
1256 |
|
|
|
1257 |
|
|
<pre class="vhdl">
|
1258 |
|
|
|
1259 |
|
|
205 process(I_PC_OP, F_CC)
|
1260 |
|
|
206 begin
|
1261 |
|
|
207 case I_PC_OP is
|
1262 |
|
|
208 when PC_BCC => Q_LOAD_PC <= F_CC; -- maybe (PC on I_JADR)
|
1263 |
|
|
209 when PC_LD_I => Q_LOAD_PC <= '1'; -- yes: new PC on I_JADR
|
1264 |
|
|
210 when PC_LD_Z => Q_LOAD_PC <= '1'; -- yes: new PC in Z
|
1265 |
|
|
211 when PC_LD_S => Q_LOAD_PC <= '1'; -- yes: new PC on stack
|
1266 |
|
|
212 when others => Q_LOAD_PC <= '0'; -- no.
|
1267 |
|
|
213 end case;
|
1268 |
|
|
214 end process;
|
1269 |
|
|
<pre class="filename">
|
1270 |
|
|
src/data_path.vhd
|
1271 |
|
|
</pre></pre>
|
1272 |
|
|
<P>
|
1273 |
|
|
|
1274 |
|
|
<P><br>
|
1275 |
|
|
|
1276 |
|
|
<P>When a branch is taken (in the execution stage of the pipeline), then the next
|
1277 |
|
|
instruction after the branch is about to be decoded in the opcode decoder
|
1278 |
|
|
stage. This instruction must not be executed, however, and we therefore
|
1279 |
|
|
invalidate it by asserting the <STRONG>SKIP</STRONG> output.
|
1280 |
|
|
Another case where instructions need to be invalidated are skip instructions
|
1281 |
|
|
(<STRONG>CPSE</STRONG>, <STRONG>SBIC</STRONG>, <STRONG>SBIS</STRONG>, <STRONG>SBRC</STRONG>, and <STRONG>SBRS</STRONG>). These instructions do not
|
1282 |
|
|
modify the <STRONG>PC</STRONG>, but they nevertheless cause the next instruction to be
|
1283 |
|
|
invalidated:
|
1284 |
|
|
|
1285 |
|
|
<P><br>
|
1286 |
|
|
|
1287 |
|
|
<pre class="vhdl">
|
1288 |
|
|
|
1289 |
|
|
218 process(I_PC_OP, L_FLAGS_98, F_CC)
|
1290 |
|
|
219 begin
|
1291 |
|
|
220 case I_PC_OP is
|
1292 |
|
|
221 when PC_BCC => Q_SKIP <= F_CC; -- if cond met
|
1293 |
|
|
222 when PC_LD_I => Q_SKIP <= '1'; -- yes
|
1294 |
|
|
223 when PC_LD_Z => Q_SKIP <= '1'; -- yes
|
1295 |
|
|
224 when PC_LD_S => Q_SKIP <= '1'; -- yes
|
1296 |
|
|
225 when PC_SKIP_Z => Q_SKIP <= L_FLAGS_98(8); -- if Z set
|
1297 |
|
|
226 when PC_SKIP_T => Q_SKIP <= L_FLAGS_98(9); -- if T set
|
1298 |
|
|
227 when others => Q_SKIP <= '0'; -- no.
|
1299 |
|
|
228 end case;
|
1300 |
|
|
229 end process;
|
1301 |
|
|
<pre class="filename">
|
1302 |
|
|
src/data_path.vhd
|
1303 |
|
|
</pre></pre>
|
1304 |
|
|
<P>
|
1305 |
|
|
|
1306 |
|
|
<P><br>
|
1307 |
|
|
|
1308 |
|
|
<P>This concludes the discussion of the data path. We have now installed
|
1309 |
|
|
the environment that is needed to execute opcodes.
|
1310 |
|
|
|
1311 |
|
|
<P><hr><BR>
|
1312 |
|
|
<table class="ttop"><th class="tpre"><a href="05_Opcode_Fetch.html">Previous Lesson</a></th><th class="ttop"><a href="toc.html">Table of Content</a></th><th class="tnxt"><a href="07_Opcode_Decoder.html">Next Lesson</a></th></table>
|
1313 |
|
|
</BODY>
|
1314 |
|
|
</HTML>
|