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

Subversion Repositories avr8

[/] [avr8/] [trunk/] [rtl/] [rAVR.v] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 marsohod
 
2
// http://marsohod.org 
3
// see full project description at http://www.marsohod.org/index.php/projects/66-makeavr
4
// Reduced AVRCore, Verilog HDL
5
// tested on MARSOHOD development board!
6
 
7
// Сильно упрощенная версия ядра AVR микропроцессора для Altera CPLD MAX2
8
 
9
module rAVR(
10
        input wire reset,
11
        input wire clk,
12
 
13
        //UFM (User Flash Memory) interface
14
        //Интерфейс к флеш памяти UFM, которая находится внутри чипа MAX2
15
        //Флеш память - последовательная, и адреса и данные передаются сдвиговыми регистрами
16
 
17
        //address
18
        //сигналы управления адресом UFM
19
        output wire arclkena,
20
        output wire arclkshift,
21
        output wire ardout,
22
 
23
        //data
24
        //сигналы для чтения последовательных данных из UFM
25
        input  wire drdin,
26
        output wire drshift,
27
 
28
        //interface to PIO ports
29
        //Устройства, которыми может управлять микроконтроллер - это три порта
30
        output reg  [7:0]port0, //typically connect to LEDs
31
                                                        //обычно, на плате Марсоход, подключаем сюда 8 светодиодов
32
        output reg  [7:0]port1, //typically attached to motors
33
                                                        //обычно, на плате Марсоход, подлючаем сюда шаговые двигатели
34
        input  wire [7:0]port2  //connect to Buttons and other inputs
35
                                                        //обычно, на плате Марсоход, подключаем сюда входы четырех кнопочек
36
);
37
 
38
//opcode read from UFM
39
//код инструкции процессора, считанной из флеш UFM
40
reg [15:0]opcode;
41
 
42
//instruction pointer
43
//указатель на текущую комманду процессора в флеш памяти
44
reg [8:0]ip;
45
 
46
//four common purpose registers
47
//четыре регистра общего назначения
48
reg [7:0]register[3:0];
49
 
50
//ALU operands
51
//регистры, куда выбираются операнды для последующего исполнения
52
reg [7:0]alu_operand0;
53
reg [7:0]alu_operand1;
54
reg [2:0]alu_cmd;
55
 
56
reg [2:0]sel_cmd;
57
reg [7:0]alu_result;
58
 
59
//флаги для условных переходов
60
reg flag_z;
61
reg flag_c;
62
 
63
reg flag_z_fixed;
64
reg flag_c_fixed;
65
 
66
//операнд "число" может быть закодирован в коде команды
67
reg sel_imm;
68
wire [7:0]immediate; assign immediate = { opcode[11:8],opcode[3:0] };
69
 
70
//get operand from register pool according to opcode source register index
71
//выбор операнда источника
72
wire [2:0]src_reg_idx;  assign src_reg_idx = opcode[2:0];
73
reg [7:0]source_val;
74
always @*
75
begin
76
        case(src_reg_idx)
77
        0: source_val = register[0];
78
        1: source_val = register[1];
79
        2: source_val = register[2];
80
        3: source_val = register[3];
81
        4: source_val = port0;
82
        5: source_val = port1;
83
        6: source_val = port2;
84
        7: source_val = port2;
85
        endcase
86
end
87
 
88
//get operand from register pool according to opcode destination register index
89
//выбор операнда приемника
90
wire [2:0]dest_reg_idx; assign dest_reg_idx = opcode[6:4];
91
reg [7:0]dest_val;
92
always @*
93
begin
94
        case(dest_reg_idx)
95
        0: dest_val = register[0];
96
        1: dest_val = register[1];
97
        2: dest_val = register[2];
98
        3: dest_val = register[3];
99
        4: dest_val = port0;
100
        5: dest_val = port1;
101
        6: dest_val = port2;
102
        7: dest_val = port2;
103
        endcase
104
end
105
 
106
//назначение основных команд ALU (Арифметико-Логического Устройства)
107
parameter CMD_LSR = 3'b000;
108
parameter CMD_CP  = 3'b001;
109
parameter CMD_SUB = 3'b010;
110
parameter CMD_ADD = 3'b011;
111
parameter CMD_AND = 3'b100;
112
parameter CMD_EOR = 3'b101;
113
parameter CMD_OR  = 3'b110;
114
parameter CMD_MOV = 3'b111;
115
 
116
//decode fetched operation
117
//select operands and unify commands (i.e. CP and CPI are similar, SUB and SUBI are similar etc..)
118
//расшифровка кода операции и трансляция похожих команд к единому кодированию
119
//Например: команда SUBI чем-то похожа на SUB
120
//Внимание! Производится только ЧАСТИЧНОЕ/НЕПОЛНОЕ декодирование!
121
//Допускается использование только выбраных команд!
122
always @*
123
begin
124
        if( (opcode[15:14]==2'b00) && (opcode[13:12]!=2'b11) )
125
        begin
126
                sel_imm = 1'b0;
127
                sel_cmd = {opcode[13],opcode[11:10]};
128
        end
129
        else
130
        if(opcode[15:14]==2'b10)
131
        begin
132
                sel_imm = 1'b0;
133
                sel_cmd = 3'b000;
134
        end
135
        else
136
        begin
137
                sel_imm = 1'b1;
138
                case(opcode[15:12])
139
                4'b0101: sel_cmd = CMD_SUB;
140
                4'b0111: sel_cmd = CMD_AND;
141
                4'b0110: sel_cmd = CMD_OR;
142
                4'b0011: sel_cmd = CMD_CP;
143
                4'b1110: sel_cmd = CMD_MOV;
144
                default: sel_cmd = CMD_CP;
145
                endcase
146
        end
147
end
148
 
149
//fix decoded command
150
//зафиксировать операнды для исполнения
151
always @(posedge clk or posedge reset)
152
begin
153
        if(reset)
154
        begin
155
                alu_operand0 <= 0;
156
                alu_operand1 <= 0;
157
                alu_cmd <= 0;
158
        end
159
        else
160
        begin
161
                if(opcode_ready)
162
                begin
163
                        alu_operand0 <= dest_val;
164
 
165
                        if(sel_imm)
166
                                alu_operand1 <= immediate;
167
                        else
168
                                alu_operand1 <= source_val;
169
 
170
                        alu_cmd <= sel_cmd;
171
                end
172
        end
173
end
174
 
175
//ALU
176
//Арифметико-Логическое Устройство
177
always @*
178
begin
179
        case(alu_cmd)
180
                CMD_CP,
181
                CMD_SUB:
182
                        begin
183
                                { flag_c, alu_result } = alu_operand0 - alu_operand1;
184
                                flag_z = ~(|alu_result);
185
                        end
186
                CMD_AND:
187
                        begin
188
                                alu_result = alu_operand0 & alu_operand1;
189
                                flag_z = ~(|alu_result);
190
                                flag_c = flag_c_fixed; //flag C not changed
191
                        end
192
                CMD_OR:
193
                        begin
194
                                alu_result = alu_operand0 | alu_operand1;
195
                                flag_z = ~(|alu_result);
196
                                flag_c = flag_c_fixed; //flag C not changed
197
                        end
198
                CMD_MOV:
199
                        begin
200
                                alu_result = alu_operand1;
201
                                flag_c = flag_c_fixed;
202
                                flag_z = flag_z_fixed;
203
                        end
204
                CMD_ADD:
205
                        begin
206
                                { flag_c, alu_result } = alu_operand0 + alu_operand1;
207
                                flag_z = ~(|alu_result);
208
                        end
209
                CMD_EOR:
210
                        begin
211
                                alu_result = alu_operand0 ^ alu_operand1;
212
                                flag_c = flag_c_fixed; //flag C not changed
213
                                flag_z = ~(|alu_result);
214
                        end
215
                CMD_LSR:
216
                        begin
217
                                alu_result = alu_operand0 >>  1;
218
                                flag_c = alu_operand0[0];
219
                                flag_z = ~(|alu_result);
220
                        end
221
                endcase
222
end
223
 
224
//присвоение результата вычисления ALU в регистр-приемник
225
always @(posedge clk or posedge reset)
226
begin
227
        if(reset)
228
        begin
229
                //reset registers and flags
230
                flag_z_fixed <= 1'b0;
231
                flag_c_fixed <= 1'b0;
232
 
233
                register[0] <= 0;
234
                register[1] <= 0;
235
                register[2] <= 0;
236
                register[3] <= 0;
237
 
238
                port0 <= 0;
239
                port1 <= 0;
240
        end
241
        else
242
        begin
243
                //fix result only if command not a CP and not BRANCH
244
                //результат присваивается только если команда не CP и не переход
245
                if( fix_result & (alu_cmd != CMD_CP)  & (opcode[15:12]!=4'b1111) )
246
                begin
247
                        case(dest_reg_idx)
248
                        0: register[0] <= alu_result;
249
                        1: register[1] <= alu_result;
250
                        2: register[2] <= alu_result;
251
                        3: register[3] <= alu_result;
252
                        4: port0 <= alu_result;
253
                        5: port1 <= alu_result;
254
                        endcase
255
                end
256
 
257
                //fix alu flags always except BRANCH
258
                //флаги исполнения команды фиксируем всегда, кроме переходов
259
                if( fix_result & (opcode[15:12]!=4'b1111) )
260
                begin
261
                        flag_z_fixed <= flag_z;
262
                        flag_c_fixed <= flag_c;
263
                end
264
        end
265
end
266
 
267
//вычисление необходимости условного перехода
268
wire [1:0]branch_id;
269
assign branch_id = {opcode[10],opcode[0]};
270
 
271
wire need_jump;
272
assign need_jump = ( opcode[15:12]==4'b1111 ) &
273
                                (((branch_id==2'b01) & flag_z_fixed ) |
274
                                ( (branch_id==2'b11) & (~flag_z_fixed) ) |
275
                                ( (branch_id==2'b00) & flag_c_fixed ) |
276
                                ( (branch_id==2'b10) & (~flag_c_fixed) ));
277
 
278
//управление указателем на код команды во флешке UFM
279
always @(posedge clk or posedge reset)
280
begin
281
        if(reset)
282
        begin
283
                ip <= 0;
284
        end
285
        else
286
        begin
287
                if(arclkshift)
288
                begin
289
                        //последовательно выдвигаем адрес
290
                        ip <= {ip[7:0],ip[8]};
291
                end
292
                else
293
                if(addr_inc)
294
                begin
295
                        //go next instruction
296
                        //переход к следующей инструкции
297
                        ip <= ip + 1'b1;
298
                end
299
                else
300
                begin
301
                        //fix instruction pointer
302
                        //jump on condition
303
                        //изменение указатели при условном переходе
304
                        if( need_jump & opcode_ready )
305
                                ip <= ip + {opcode[9],opcode[9],opcode[9:3]};
306
                end
307
        end
308
end
309
 
310
//UFM (User Flash Memory) reading process
311
//управление встроенной флеш памятью, где у нас хранится программа
312
reg [5:0]ufm_counter;
313
 
314
assign arclkena   = ((ufm_counter<9) | addr_inc) & (~reset);
315
assign arclkshift = (ufm_counter<9)  & (~reset);
316
assign ardout = ip[8];
317
assign drshift    = (ufm_counter>9) & (ufm_counter[4:1]<13) & (~reset);
318
wire opcode_ready; assign opcode_ready = (ufm_counter[4:1]==13);
319
wire addr_inc; assign addr_inc = (ufm_counter[3:0]==15);
320
 
321
wire fix_result; assign fix_result = (ufm_counter==10);
322
 
323
//count UFM read states
324
//считаем такты при чтении из флешки UFM
325
always @(posedge clk or posedge reset)
326
begin
327
        if(reset)
328
                ufm_counter <= 0;
329
        else
330
        begin
331
                if(opcode_ready)
332
                begin
333
                        if(need_jump)
334
                                ufm_counter <= 0;
335
                        else
336
                                ufm_counter <= 10;
337
                end
338
                else
339
                        ufm_counter <= ufm_counter + 1'b1;
340
        end
341
end
342
 
343
//Shift IN data from serial flash of UFM
344
//последовательно принимаем код инструкции от флешки UFM
345
always @(posedge clk or posedge reset)
346
begin
347
        if(reset)
348
                opcode <= 0;
349
        else
350
        begin
351
                if(drshift)
352
                        opcode <= {opcode[14:0],drdin};
353
        end
354
end
355
 
356
endmodule

powered by: WebSVN 2.1.0

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