-
Notifications
You must be signed in to change notification settings - Fork 1
/
datapath_aubie_v1.vhd
491 lines (443 loc) · 20.9 KB
/
datapath_aubie_v1.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
-- datapath_aubie.vhd
-- entity reg_file (lab 2)
use work.dlx_types.all;
use work.bv_arithmetic.all;
entity reg_file is
generic(prop_delay : Time := 5 ns);
port (
data_in : in dlx_word;
readnotwrite: in bit;
clock : in bit;
data_out : out dlx_word;
reg_number : in register_index
);
end entity reg_file;
---------------------------------------------
-- BEGIN Defining ARCHITECTURE "reg_file" --
---------------------------------------------
architecture behavior of reg_file is
----------------------------------------------------------
-- Type Define (Act as 'storage' for our process) --
-- reg_type: defines a data structure for --
-- an array of 32-bit words --
----------------------------------------------------------
type reg_type is array (0 to 31) of dlx_word;
begin
reg_file_process: process(readnotwrite, clock, reg_number, data_in) is
----------------------------------------------------------------------
-- NOTE: Process accepts only input signals from our defined entity --
----------------------------------------------------------------------
----------------------------------------------------------
-- Variable (Act as 'storage' for our process) --
-- registers: implements reg_type and initializes --
-- registers we use for this process --
----------------------------------------------------------
variable registers: reg_type;
begin
-- Start process
if (clock = '1') then
if (readnotwrite = '1') then
---------------------------------------------------------------
-- [Performing "READ" Operation (readnotwrite = '1')] --
-- Here, we simply ignore 'data_in' and copy value in --
-- registers at index --> reg_number to data_out port signal --
---------------------------------------------------------------
data_out <= registers(bv_to_integer(reg_number)) after prop_delay;
else
------------------------------------------------------
-- [Performing "WRITE" Operation] --
-- Value from 'data_in' is copied into registers at --
-- register index --> 'reg_number' --
------------------------------------------------------
registers(bv_to_integer(reg_number)) := data_in;
------------------------------------------------------
-- NOTE: No prop_delay is applied because we don't --
-- want to delay variable assignments. --
------------------------------------------------------
end if;
end if;
end process reg_file_process;
end architecture behavior;
-- entity alu (lab 3)
use work.dlx_types.all;
use work.bv_arithmetic.all;
entity alu is
generic(prop_delay : Time := 5 ns);
port(
operand1 : in dlx_word;
operand2 : in dlx_word;
operation : in alu_operation_code;
result : out dlx_word;
error : out error_code
);
end entity alu;
-- alu_operation_code values
-- 0000 unsigned add
-- 0001 signed add
-- 0010 2's compl add
-- 0011 2's compl sub
-- 0100 2's compl mul
-- 0101 2's compl divide
-- 0110 logical and
-- 0111 bitwise and
-- 1000 logical or
-- 1001 bitwise or
-- 1010 logical not (op1)
-- 1011 bitwise not (op1)
-- 1101-1111 output all zeros
-- error code values
-- 0000 = no error
-- 0001 = overflow (too big positive)
-- 0010 = underflow (too small neagative)
-- 0011 = divide by zero
architecture behavior of ALU is
-- Define any types here that will be used
begin
alu_process: process(operand1, operand2, operation) is
-- Declare any local variables here
variable temp_result: dlx_word := x"00000000";
variable logical_true: dlx_word := x"00000001";
variable logical_false: dlx_word := x"00000000";
variable overflow_flag_set: boolean;
variable div_by_zero: boolean;
variable op1_logical_status: bit; -- 0 means false; 1 means true
variable op2_logical_status: bit; -- 0 means false; 1 means true
begin
error <= "0000"; -- Default value for port signal output error
case(operation) is
when "0000" => -- UNSIGNED ADD
bv_addu(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
error <= "0001";
end if;
result <= temp_result;
when "0001" => -- UNSIGNED SUBTRACT
bv_subu(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
error <= "0010";
-- Unsigned subtract is only concerned with underflow
end if;
result <= temp_result;
when "0010" => -- TWO'S COMPLEMENT ADD
bv_add(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
-- IF (+A) + (+B) = -C
if (operand1(31) = '0') AND (operand2(31) = '0') then
if (temp_result(31) = '1') then
error <= "0001"; -- overflow occurred
end if;
-- (-A) + (-B) = +C
elsif (operand1(31) = '1') AND (operand2(31) = '1') then
if (temp_result(31) = '0') then
error <= "0010"; -- underflow occurred
end if;
end if;
end if;
result <= temp_result;
when "0011" => -- TWO'S COMPLEMENT SUBTRACT
bv_sub(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
-- IF (-A) - (+B) = +C
if (operand1(31) = '1') AND (operand2(31) = '0') then
if (temp_result(31) = '0') then
error <= "0010"; -- underflow occurred
end if;
-- IF (+A) - (-B) = -C
elsif (operand1(31) = '0') AND (operand2(31) = '1') then
if (temp_result(31) = '1') then
error <= "0001"; -- overflow occurred
end if;
end if;
end if;
result <= temp_result;
when "0100" => -- TWO'S COMPLEMENT MULTIPLY - (2 underflow Conditions + 2 overflow conditions)
bv_mult(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
if (operand1(31) = '1') AND (operand2(31) = '0') then -- (-A x +B) = +C
error <= "0010"; -- underflow
elsif (operand1(31) = '0') AND (operand2(31) = '1') then -- (+A x -B) = +C
error <= "0010"; -- underflow
else -- (+A x +B) = -C OR (-A x -B) = -C
error <= "0001"; -- overflow
end if;
end if;
result <= temp_result;
when "0101" => -- TWO'S COMPLEMENT DIVIDE
----------------------------------------------------------------------------------------
-- The only way a two's complement divide can underflow is if you divide the most
-- negative value by -ve 1. Divide underflow occurs when the divisor is much smaller
-- than the dividend. The result is almost zero. Test with 80000000 / FFFFFFFF
-- (Quotient will be smaller than the dividend)
-- NOTE: For grading purposes, this condition will not be tested but must be implemented
-----------------------------------------------------------------------------------------
bv_div(operand1, operand2, temp_result, div_by_zero, overflow_flag_set);
if div_by_zero then
error <= "0011"; --
elsif overflow_flag_set then
error <= "0010"; -- only an underflow can occur with divide (see note above)
end if;
result <= temp_result;
when "0110" => -- PERFORM LOGICAL AND
------------------------------------------------------------------------
-- For logical operations, anything resulting in a non-zero value is 1,
-- for true. Anything resulting in all zeroes is assigned 0, false.
-- Logical operation always results in true (1) or false (0).
------------------------------------------------------------------------
op1_logical_status := '0'; -- Default logical status for operand1
op2_logical_status := '0'; -- Default logical status for operand2
-- check if operand1 is a non-zero value --
for i in 31 downto 0 loop
-- If non-zero value, operand1 is logical true;
if (operand1(i) = '1') then
op1_logical_status := '1';
exit;
end if;
end loop;
-- check if operand2 is a non-zero value
for i in 31 downto 0 loop
-- If non-zero value, operand2 is logical true;
if (operand2(i) = '1') then
op2_logical_status := '1';
exit;
end if;
end loop;
-- IF operand statuses result in --> '1' && '1' = '1'
if ((op1_logical_status AND op2_logical_status) = '1') then
result <= logical_true; -- The result is logical true x"00000001"
else
result <= logical_false; -- Else result is logical false x"00000000"
end if;
when "0111" => -- PERFORM BITWISE AND
for i in 31 downto 0 loop
temp_result(i) := operand1(i) AND operand2(i);
end loop;
result <= temp_result;
when "1000" => -- PERFORM LOGICAL OR
------------------------------------------------------------------------
-- For logical operations, anything resulting in a non-zero value is 1,
-- for true. Anything resulting in a zero is assigned 0, false.
-- Logical operation always results in true (1) or false (0).
------------------------------------------------------------------------
op1_logical_status := '0'; -- Default logical status for operand 1
op2_logical_status := '0'; -- Default logical status for operand 2
-- check if operand1 is a non-zero value --
for i in 31 downto 0 loop
-- If non-zero value, operand1 is logical true;
if (operand1(i) = '1') then
op1_logical_status := '1';
exit;
end if;
end loop;
-- check if operand2 is a non-zero value
for i in 31 downto 0 loop
-- If non-zero value, operand2 is logical true;
if (operand2(i) = '1') then
op2_logical_status := '1';
exit;
end if;
end loop;
-- IF operand statuses result in --> ('1'||'1' OR '1'||'0' OR '0'||'1' ) = '1'
if ((op1_logical_status OR op2_logical_status) = '1') then
result <= logical_true; -- The result is logical true x"00000001"
else
result <= logical_false; -- Else result is logical false x"00000000"
end if;
when "1001" => -- PERFORM BITWISE OR
for i in 31 downto 0 loop
temp_result(i) := operand1(i) OR operand2(i);
end loop;
result <= temp_result;
when "1010" => -- PERFORM LOGICAL NOT OF OPERAND1 (ignore operand2)
temp_result := logical_true; -- Initially assigned to true (i.e. 32'h00000001)
for i in 31 downto 0 loop
if (NOT operand1(i) = '0') then -- i.e. IF operand1 is non-zero
temp_result := logical_false; -- logical NOT resulted in false; Therefore, NOT(operand1) = false
exit;
end if;
end loop;
result <= temp_result;
when "1011" => -- PERFORM BITWISE NOT OF OPERAND1 (ignore operand2)
for i in 31 downto 0 loop
temp_result(i) := NOT operand1(i);
end loop;
result <= temp_result;
when "1100" => -- CHECK IF OPERAND1 is zero
temp_result := logical_false;
if (operand1 = x"00000000") then
temp_result := logical_true;
end if;
result <= temp_result;
when others => -- 1101 thru 1111 outputs all zeroes
result <= x"00000000";
end case;
end process alu_process;
end architecture behavior;
-- entity dlx_register (lab 3)
use work.dlx_types.all;
entity dlx_register is
generic(prop_delay : Time := 5 ns);
port(
in_val : in dlx_word;
clock : in bit;
out_val : out dlx_word
);
end entity dlx_register;
---------------------------------------------
-- BEGIN Defining ARCHITECTURE "dlx_register" --
---------------------------------------------
architecture behavior of dlx_register is
begin
dlx_reg_process: process(in_val, clock) is
----------------------------------------------------------------------
-- NOTE: Process accepts only input signals from our defined entity --
----------------------------------------------------------------------
begin
-- Start process
if (clock = '1') then
out_val <= in_val after prop_delay;
end if;
end process dlx_reg_process;
end architecture behavior;
-- entity pcplusone
use work.dlx_types.all;
use work.bv_arithmetic.all;
entity pcplusone is
generic(prop_delay: Time := 5 ns);
port (
input : in dlx_word;
clock : in bit;
output: out dlx_word
);
end entity pcplusone;
architecture behavior of pcplusone is
begin
plusone: process(input, clock) is -- add clock input to make it execute
variable newpc: dlx_word;
variable error: boolean;
begin
if clock'event and clock = '1' then
bv_addu(input,"00000000000000000000000000000001",newpc,error);
output <= newpc after prop_delay;
end if;
end process plusone;
end architecture behavior;
-- entity mux
use work.dlx_types.all;
entity mux is
generic(prop_delay : Time := 5 ns);
port (
input_1 : in dlx_word;
input_0 : in dlx_word;
which : in bit;
output : out dlx_word
);
end entity mux;
architecture behavior of mux is
begin
muxProcess : process(input_1, input_0, which) is
begin
if (which = '1') then
output <= input_1 after prop_delay;
else
output <= input_0 after prop_delay;
end if;
end process muxProcess;
end architecture behavior;
-- end entity mux
-- entity threeway_mux
use work.dlx_types.all;
entity threeway_mux is
generic(prop_delay : Time := 5 ns);
port (
input_2 : in dlx_word;
input_1 : in dlx_word;
input_0 : in dlx_word;
which : in threeway_muxcode;
output : out dlx_word
);
end entity threeway_mux;
architecture behavior of threeway_mux is
begin
muxProcess : process(input_1, input_0, which) is
begin
if (which = "10" or which = "11" ) then
output <= input_2 after prop_delay;
elsif (which = "01") then
output <= input_1 after prop_delay;
else
output <= input_0 after prop_delay;
end if;
end process muxProcess;
end architecture behavior;
-- end entity mux
-- entity memory
use work.dlx_types.all;
use work.bv_arithmetic.all;
entity memory is
port (
address : in dlx_word;
readnotwrite : in bit;
data_out : out dlx_word;
data_in : in dlx_word;
clock : in bit
);
end memory;
architecture behavior of memory is
begin -- behavior
mem_behav: process(address,clock) is
-- note that there is storage only for the first 1k of the memory, to speed
-- up the simulation
type memtype is array (0 to 1024) of dlx_word;
variable data_memory : memtype;
begin
-- fill this in by hand to put some values in there
-- some instructions
data_memory(0) := X"30200000"; --LD R4, 0x100 = 256
data_memory(1) := X"00000100"; -- address 0x100 for previous instruction
-- R4 = Contents of Mem Addr x100 = x"5500FF00"
data_memory(2) := X"30080000"; -- LD R1, 0x101 = 257
data_memory(3) := X"00000101"; -- address 0x101 for previous instruction
-- R1 = Contents of Mem Addd x101 = x"AA00FF00"
data_memory(4) := X"30100000"; -- LD R2, 0x102 = 258
data_memory(5) := X"00000102"; -- address 0x102 for previous instruction
-- R2 = Contents of Mem Addr x102 = x"00000001"
data_memory(6) := "00000000000110000100010000000000"; -- ADDU R3,R1 R2
-- R3 = Contents of (R1 + R2) = x"AA00FF01"
data_memory(7) := "00100000000000001100000000000000"; -- STO R3, 0x103
data_memory(8) := x"00000103"; -- address 0x103 for previous instruction
-- Mem Addr x"103" = data_memory(259) := contents of R3 = x"AA00FF01"
data_memory(9) := "00110001000000000000000000000000"; -- LDI R0, 0x104
data_memory(10) := x"00000104"; -- #Imm value 0x104 for previous instruction
-- Contents of R0 = x"00000104"
data_memory(11) := "00100010000000001100000000000000"; -- STOR (R0), R3
-- Contents of Mem Addr specifed by R0 (x104 = 260) = Contents of R3 = x"AA00FF01"
data_memory(12) := "00110010001010000000000000000000"; -- LDR R5, (R0)
-- Contents of R5 = Contents specified by Mem Addr[Contents of R0] = x"AA00FF01"
data_memory(13) := x"40000000"; -- JMP to 261 = x"105"
data_memory(14) := x"00000105"; -- Address to jump to for previous instruction
-- JMP to Mem Addr x"105" is an Add Operation --> ADDU R11, R1 R2 => Contents of R11 = x"AA00FF01"
-- note that this code runs every time an input signal to memory changes,
-- so for testing, write to some other locations besides these
data_memory(256) := "01010101000000001111111100000000"; -- x"100" = 256
data_memory(257) := "10101010000000001111111100000000"; -- x"101" = 257
data_memory(258) := "00000000000000000000000000000001"; -- x"102" = 258
-- We Jumped here from Addr 14 = x"0000000E"
data_memory(261) := x"00584400"; -- ADDU R11,R1,R2
data_memory(262) := x"4101C000"; -- JZ R7, 267 = x"10B" -- If R7 == 0, GOTO Addr 267
data_memory(263) := x"0000010B"; -- Address to jump to for previous instruction
-- JZ to Mem Addr x"10B" is an Add Operation --> ADDU R12, R1 R2 => Contents of R12 = x"AA00FF01"
-- We jumped here from Addr 263 = x"00000107"
data_memory(267) := x"00604400"; -- ADDU R12, R1 R2
data_memory(268) := x"10000000"; -- NOOP
if clock = '1' then
if readnotwrite = '1' then
-- do a read
data_out <= data_memory(bv_to_natural(address)) after 5 ns;
else
-- do a write
data_memory(bv_to_natural(address)) := data_in;
end if;
end if;
end process mem_behav;
end behavior;
-- end entity memory