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

Subversion Repositories motion_estimation_processor

[/] [motion_estimation_processor/] [trunk/] [src_me/] [me_control_unit.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 eejlny
----------------------------------------------------------------------------
2
--  This file is a part of the LM VHDL IP LIBRARY
3
--  Copyright (C) 2009 Jose Nunez-Yanez
4
--
5
--  This program is free software; you can redistribute it and/or modify
6
--  it under the terms of the GNU General Public License as published by
7
--  the Free Software Foundation; either version 2 of the License, or
8
--  (at your option) any later version.
9
--
10
--  See the file COPYING for the full details of the license.
11
--
12
--  The license allows free and unlimited use of the library and tools for research and education purposes. 
13
--  The full LM core supports many more advanced motion estimation features and it is available under a 
14
--  low-cost commercial license. See the readme file to learn more or contact us at 
15
--  eejlny@byacom.co.uk or www.byacom.co.uk
16
--------------------------------------
17
--  entity       = me_control_unit  --
18
--  version      = 1.0              --
19
--  last update  = 20/07/09         --
20
--  author       = Jose Nunez       --
21
--------------------------------------
22
 
23
 
24
-- main control unit for the motion estimation process
25
 
26
library IEEE;
27
use IEEE.std_logic_1164.all;
28
use IEEE.std_logic_unsigned."+";
29
use IEEE.std_logic_unsigned."-";
30
use IEEE.std_logic_unsigned."=";
31
use IEEE.std_logic_unsigned.">";
32
use IEEE.std_logic_unsigned."<";
33
use IEEE.std_logic_unsigned.">=";
34
use IEEE.Numeric_STD.all;
35
use work.config.all;
36
 
37
 
38
entity me_control_unit is
39
generic ( integer_pipeline_count : integer := 1);
40
 port ( clk : in std_logic;
41
        clear : in std_logic;
42
        reset : in std_logic;
43
        start : in std_logic;
44
        range_ok : in std_logic; --keep track of the mv range
45
          best_sad_in : in std_logic_vector(15 downto 0); -- to make SAD-based decisions
46
          mv_length_in : in std_logic_vector(15 downto 0); -- to make LENGTH-based decisions
47
        mode_in : in mode_type;
48
             qp_on : in std_logic; -- qp on
49
          mvc_done : in std_logic; -- all motion vector candidates evaluated
50
          mvc_to_do : in std_logic_vector(3 downto 0);
51
        partition_count_out : out std_logic_vector(3 downto 0); --identify the partition active
52
          start_pipelines : out std_logic_vector((integer_pipeline_count-1) downto 0);
53
          active_pipelines : out std_logic_vector((integer_pipeline_count-1) downto 0); -- so sad selector ignores the non active ones
54
        shift_concatenate_valid : in std_logic; -- valid output from the concantenate unit 
55
        interpolation_done : in std_logic; -- interpolation completes
56
        interpolate_data_request : in std_logic; -- interpolator requests data
57
        instruction_address : out std_logic_vector(7 downto 0); -- address to fetch next instruction
58
          instruction_opcode : in std_logic_vector(3 downto 0); -- opcode
59
        point_count : in std_logic_vector(7 downto 0); -- how many points to test
60
        point_address : in std_logic_vector(7 downto 0); -- which is the first point to test
61
        calculate_sad_done : in std_logic; -- signals when the distance engine has finished
62
          distance_engine_active : in std_logic; -- signals when distance engine is not running
63
        next_point : out std_logic_vector(7 downto 0); -- next point address to ROM
64
        line_offset : out std_logic_vector(5 downto 0); -- multiple line reading
65
          enable_concatenate_unit : out std_logic;
66
            -- enable_dist_engine : out std_logic;
67
        write_register : out std_logic;
68
           best_eu : in std_logic_vector(3 downto 0); -- best execution unit
69
        load_mv : out std_logic;
70
        update : out std_logic;
71
          instruction_zero : out std_logic; -- program completes after hitting instruction zero points
72
        all_done : out std_logic; -- fp part completes or program completes
73
          partition_done : out std_logic;
74
        qpel_loc_x : in std_logic_vector(1 downto 0); -- detect qp mode
75
        qpel_loc_y : in std_logic_vector(1 downto 0);
76
        start_qp : out std_logic;
77
        enable_hp_inter : out std_logic; -- start the interpolation core
78
       --  write_block1 : out std_logic;
79
      --  next_rm_address_ready : in std_logic;
80
        next_rm_addresss : in std_logic_vector(13 downto 0); --physical address for reference (macroblock upper left corner 
81
        rm_address : out std_logic_vector(13 downto 0) -- reference memory read from address
82
          --cm_address : out std_logic_vector(4 downto 0);  -- address to extract 4x4 blocks from current macroblock
83
        --  rma_address : out std_logic_vector(4 downto 0); -- reference macroblock write to address
84
  --   rma_we : out std_logic
85
      );
86
end;
87
 
88
architecture struct of me_control_unit is
89
 
90
 
91
 
92
type state_type is (terminate,idle,fetch_instruction,access_point_memory,next_phy_address_ready,update_mv,wait_for_distance_engine,wait_for_distance_engine2,enable_concatenate_2,enable_concatenate,wait_for_phy_address,wait_for_phy_address2); -- me control unit states
93
 
94
type state_register_type is record
95
 
96
        state : state_type;
97
        partition_count : std_logic_vector(3 downto 0); -- to keep track of the sub-partitions
98
        best_eu : std_logic_vector(3 downto 0); -- for jump conditions
99
          qp_mode : std_logic; -- processing a fraction instruction
100
      invalidate : std_logic; -- flag to invalidate instructions that follow jumps
101
           enable_concatenate_unit : std_logic;
102
           data_block : std_logic_vector(1 downto 0); --9 data blocks of 8 rows and 8 pixels for interpolation    
103
           enable_hp_inter : std_logic;
104
      instruction_address : std_logic_vector(7 downto 0); --counter keeps track of next instruction to execute
105
      instruction_opcode : std_logic_vector(3 downto 0);
106
        point_count : std_logic_vector(7 downto 0);  --register stores the number of points to test
107
        point_address : std_logic_vector(7 downto 0); -- register stores the first address of the points to test 
108
      points_tested : std_logic_vector(7 downto 0); -- counter that keeps track of the number of points tested
109
      phy_address : std_logic_vector(13 downto 0); -- address for the reference memory
110
      phy_address_ready : std_logic_vector(13 downto 0); -- stores a ready copy of the next reference memory address
111
      --rma_address : std_logic_vector(4 downto 0); -- address for the reference macroblock memory
112
      line_offset : std_logic_vector(5 downto 0); -- reading of multiple lines control
113
      line_count : std_logic_vector(4 downto 0); -- counter to keep track of the number of lines loaded in reference macroblock
114
      interpolation_done : std_logic; -- remember when interpolation has been done so not to do it again
115
        active_pipelines_r : std_logic_vector((integer_pipeline_count-1) downto 0);
116
        condition_bit : std_logic; -- condition bit for jump instructions
117
  --    calculate_sad_done : std_logic;
118
      --write_block1 : std_logic; -- flag
119
end record;
120
 
121
signal r, r_in: state_register_type; -- state register
122
signal finish : std_logic;
123
 
124
 
125
begin
126
 
127
 
128
--rma_address <= (others => '0'); -- reference macroblock write to address
129
--cm_address <= (others => '0');  -- address to extract 4x4 blocks from current macroblock
130
all_done <= finish;
131
 
132
control: process(mvc_done,mvc_to_do,range_ok,instruction_opcode,best_eu,mode_in,r,qpel_loc_x,qpel_loc_y,interpolation_done,interpolate_data_request,start,next_rm_addresss,shift_concatenate_valid,calculate_sad_done,point_address,point_count)
133
 
134
variable v : state_register_type;
135
variable vfinish,vstart,vrma_we,vload_mv,vupdate,vstart_qp,vpartition_done,vinstruction_zero : std_logic;
136
variable vwrite_register,venable_dist_engine : std_logic;
137
variable vrm_address : std_logic_vector(13 downto 0); -- generate rm address as soon as possible
138
variable vstart_pipelines : std_logic_vector((integer_pipeline_count-1) downto 0);
139
 
140
begin
141
 
142
--v.calculate_sad_done := calculate_sad_done;
143
vstart_qp := '0';
144
vpartition_done := '0';
145
vfinish := '0';
146
vinstruction_zero := '0'; --instruction zero points hit
147
v.qp_mode := r.qp_mode;
148
v.partition_count := r.partition_count;
149
v.data_block := r.data_block;
150
v.invalidate := r.invalidate;
151
v.best_eu := r.best_eu;
152
v.points_tested := r.points_tested;
153
v.instruction_address := r.instruction_address;
154
v.phy_address_ready := next_rm_addresss;
155
v.line_offset := r.line_offset;
156
v.point_count := r.point_count;
157
v.point_address := r.point_address;
158
v.phy_address := r.phy_address;
159
v.line_count := r.line_count;
160
v.enable_concatenate_unit := r.enable_concatenate_unit;
161
v.enable_hp_inter := r.enable_hp_inter;
162
v.instruction_opcode := (others =>'0');
163
--vnext_rm_address_ready := next_rm_address_ready;
164
v.state := r.state;
165
v.interpolation_done := r.interpolation_done;
166
vstart := start;
167
vload_mv := '0';
168
vrma_we := '0';
169
vupdate := '0';
170
vwrite_register := '0';
171
venable_dist_engine := '0';
172
vrm_address := r.phy_address;
173
vstart_pipelines :=  (others => '0'); -- all pipelines disable
174
v.active_pipelines_r := r.active_pipelines_r;
175
v.condition_bit := r.condition_bit;
176
 
177
-- std_logic_vector(to_unsigned(,integer_pipeline_count));
178
 
179
 
180
 
181
case v.state is
182
 
183
        when idle =>  -- first state, waiting for command register bit 31 to go high
184
                if (vstart = '1') then
185
                        v.state := fetch_instruction;
186
                        v.interpolation_done := '0';
187
                        --if (mvc_done = '1') then  -- first evaluate all the mvcs
188
                                v.instruction_address := v.instruction_address + x"01";
189
                        --end if;
190
                end if;
191
 
192
        when fetch_instruction => -- execute instructions in the program firmware memory 
193
                --v.instruction_address := v.instruction_address + x"01";
194
                v.point_count := point_count;
195
      v.point_address := point_address;
196
                v.instruction_opcode := instruction_opcode;
197
              case v.instruction_opcode is
198
                        when "0000" => --full pel pattern instruction
199
                                if (v.invalidate = '0') then
200
                                if (v.point_count = x"00") then -- finish => all instructions executed
201
                                                v.state := terminate;
202
                                                v.instruction_address := (others => '0');
203
                                                v.condition_bit := '0'; -- reset condition bit
204
                                                --vfinish := '1'; -- clear the state when completing program
205
                                        else
206
                                                v.state := access_point_memory;
207
                                        end if;
208
                                else
209
                                    v.invalidate := '0'; -- clear flag
210
                                    v.instruction_address := v.instruction_address + x"01";
211
                                end if;
212
                        when "0001" => -- fractional pel pattern instruction
213
                                if CFG_PIPELINE_COUNT_QP = 1 then
214
                                        if (v.invalidate = '0') then
215
                                                v.state := access_point_memory;
216
                                                v.qp_mode := '1';
217
                                        else
218
                                                v.invalidate := '0'; -- clear flag
219
                                                v.instruction_address := v.instruction_address + x"01";
220
                                        end if;
221
                                end if;
222
                        when "0010" => -- condional jump instruction (if best_eu == field A in instruction (point count) jumpp to point_address
223
                            if (v.best_eu = point_count(3 downto 0)) then
224
                                v.instruction_address := point_address;
225
                                  v.invalidate := '1'; -- invalidate the next instruction so it does not execute
226
                             else
227
                                  v.instruction_address := v.instruction_address + x"01";
228
                                  v.invalidate := '0';
229
                             end if;
230
                        when "0100" => -- conditional jump to label (if condition bit set jump to label)
231
                             if (v.condition_bit = '1') then
232
                                  v.instruction_address := point_address;
233
                                  v.invalidate := '1'; -- invalidate the next instruction so it does not execute
234
                             else
235
                                  v.instruction_address := v.instruction_address + x"01";
236
                                  v.invalidate := '0';
237
                             end if;
238
                             v.condition_bit := '0'; -- reset condition bit
239
                        when "0101" => -- compare (if less than set condition bit)
240
                                 if (point_count(7 downto 6) = "00") then -- reg field
241
                                        if (best_sad_in < point_count(5 downto 0) & point_address(7 downto 0)) then
242
                                                v.condition_bit := '1'; -- set condition bit
243
                                end if;
244
                                 else
245
                                        if (mv_length_in(14 downto 7) & mv_length_in(6 downto 0)) < (point_count(5 downto 0) & point_address(7 downto 0)) then
246
                                                v.condition_bit := '1'; -- set condition bit
247
                                end if;
248
                                 end if;
249
                             v.instruction_address := v.instruction_address + x"01";
250
                        when "0110" => -- compare (if greater than set condition bit)
251
                                 if (point_count(7 downto 6) = "00") then -- reg field
252
                                if (best_sad_in > point_count(5 downto 0) & point_address(7 downto 0)) then
253
                                                v.condition_bit := '1'; -- set condition bit
254
                                end if;
255
                                 else
256
                                        if (mv_length_in(14 downto 7) & mv_length_in(6 downto 0)) > (point_count(5 downto 0) & point_address(7 downto 0)) then
257
                                                v.condition_bit := '1'; -- set condition bit
258
                                end if;
259
                                 end if;
260
                             v.instruction_address := v.instruction_address + x"01";
261
                        when others => null;
262
                        end case;
263
                        -- unconditional jump
264
                        -- conditional jump if condition bit
265
                        -- compare instruction (less than)
266
        when access_point_memory =>
267
                v.enable_concatenate_unit := '0';
268
                 v.state := wait_for_phy_address;
269
              if (r.qp_mode = '0') then   --only use slave fp pipelines if not qp mode
270
                v.active_pipelines_r(0) := '1';
271
                vstart_pipelines(0) := '1';
272
                for i in 1 to integer_pipeline_count-1 loop
273
                                                if (v.point_count-v.points_tested > i) then
274
                                                        vstart_pipelines(i) := '1';
275
                                                        v.active_pipelines_r(i) := '1';
276
                                                else
277
                                                        vstart_pipelines(i) := '0';
278
                                                        v.active_pipelines_r(i) := '0';
279
                                        end if;
280
                end loop;
281
                end if;
282
        when wait_for_phy_address =>-- waiting for translation to finish
283
          if (range_ok = '1')then
284
                        v.state := wait_for_phy_address2;
285
                        if CFG_PIPELINE_COUNT_QP = 1 then
286
                        if (r.qp_mode = '1' and r.interpolation_done = '0') then -- jump if mvx or mvy qp instruction are qp fractional
287
                                v.enable_hp_inter := '1';
288
                                v.instruction_address := v.instruction_address + x"FF"; -- -1
289
                                --v.qp_mode := '1';
290
                                -- v.state := inter_wait_for_phy_address2;
291
                                end if;
292
                        end if;
293
          else     --bypass point calculation if range is not good
294
                        v.point_address := v.point_address + std_logic_vector(to_unsigned(integer_pipeline_count,8));  -- next point memory position
295
                    v.points_tested := v.points_tested + std_logic_vector(to_unsigned(integer_pipeline_count,8)); -- new point ajusted depending of the number of integer pipelines
296
                    if (v.points_tested >= r.point_count) then -- current instruction completes
297
                           v.state := wait_for_distance_engine2;
298
                           v.points_tested := (others => '0');
299
                    else
300
                           v.state := access_point_memory;
301
                    end if;
302
          end if;
303
        when wait_for_phy_address2 => -- two cycles to get phy address
304
                 v.phy_address := next_rm_addresss; -- store phy address in register
305
                 v.line_offset := v.line_offset + "000001"; -- +1 to increase the y component
306
                 v.state := next_phy_address_ready;
307
                -- v.point_address := v.point_address + std_logic_vector(to_unsigned(integer_pipeline_count,8));  -- next 
308
 
309
 
310
 
311
    when next_phy_address_ready => -- start accessing reference memory
312
                v.enable_concatenate_unit := '0';
313
                v.phy_address := (v.phy_address(13 downto 3) + "00000000001") & next_rm_addresss(2 downto 0); -- plus 1 to read again part of the data (simple alignment)
314
        v.state := enable_concatenate;
315
 
316
                --v.point_address := v.point_address + std_logic_vector(to_unsigned(integer_pipeline_count,8));  -- next point memory position
317
                --vload_mv := '1'; -- load mv candidate in distance engine for future use
318
        when enable_concatenate =>
319
                v.phy_address := v.phy_address + "00000000001000";
320
                v.enable_concatenate_unit := '1';
321
               -- if (shift_concatenate_valid = '1') then -- first part of line
322
                   v.state := enable_concatenate_2;
323
                   v.line_offset := v.line_offset + "000001"; -- +1 to increase the y componenent
324
                        if (r.line_count = "01111") then
325
 
326
 
327
                                v.line_offset := (others => '0');
328
                        end if;
329
                        if (r.line_count = "01110") then
330
                                vload_mv := '1'; -- load mv candidate in distance engine for future use
331
                                v.point_address := v.point_address + std_logic_vector(to_unsigned(integer_pipeline_count,8));  -- next 
332
                        end if;
333
 
334
               -- end if;   
335
           when enable_concatenate_2 =>
336
                --      if (r.line_offset = "10000") then
337
                --              v.line_offset := (others => '0'); 
338
                --      end if;
339
            --    v.phy_address := (v.phy_address(13 downto 3) + "00000000010") & "000";
340
              --  v.enable_concatenate_unit := '1';
341
            --    if (shift_concatenate_valid = '1') then -- second part of line
342
                        v.enable_concatenate_unit := '1';
343
                    --v.state := enable_interpolate;
344
                    v.line_count := v.line_count + "00001";
345
                    --vrm_address := next_rm_addresss(12 downto 3) & "000"; -- set to "000" so the first new access does not interfere with the concatenation of the last bytes in the previous access        
346
                    vrm_address := r.phy_address_ready;
347
                    v.phy_address := next_rm_addresss + "00000000001000"; -- (plus 1 as well?) store phy address in register
348
                       --v.phy_address := (v.phy_address(11 downto 3) + "000000001") & next_rm_addresss(2 downto 0)
349
                    v.state := enable_concatenate; -- next line  
350
              --  end if; 
351
                 if (r.line_count = "01110") then
352
                                v.line_offset := (others => '0');
353
                                --v.point_address := v.point_address + std_logic_vector(to_unsigned(integer_pipeline_count,8));  -- next 
354
                        end if;
355
                if (r.line_count = "01111") then -- all the lines done
356
                         --v.enable_concatenate_unit := '0';
357
                        --v.point_address := v.point_address + std_logic_vector(to_unsigned(integer_pipeline_count,8));  -- next point memory position
358
                        v.points_tested := v.points_tested + std_logic_vector(to_unsigned(integer_pipeline_count,8)); -- new point ajusted depending of the number of integer pipelines
359
                        v.line_count := (others=>'0');
360
                            v.phy_address := next_rm_addresss; -- store phy address in register
361
                          v.line_offset := v.line_offset + "000001"; -- +1 to increase the y component
362
                        if (v.points_tested >= r.point_count) then -- current instruction completes
363
                           v.state := wait_for_distance_engine;
364
                           v.points_tested := (others => '0');
365
                                 v.line_offset := (others => '0');
366
                                -- v.point_address := point_address; -- start accesing point memory earlier
367
                        else
368
                           v.state := next_phy_address_ready; -- access should be ready;  
369
                                 if (r.qp_mode = '0') then   --only use slave fp pipelines if not qp mode
370
                                        v.active_pipelines_r(0) := '1';
371
                                        vstart_pipelines(0) := '1';
372
                                        for i in 1 to integer_pipeline_count-1 loop
373
                                                if (v.point_count-v.points_tested > i) then
374
                                                        vstart_pipelines(i) := '1';
375
                                                        v.active_pipelines_r(i) := '1';
376
                                                else
377
                                                        vstart_pipelines(i) := '0';
378
                                                        v.active_pipelines_r(i) := '0';
379
                                        end if;
380
                                        end loop;
381
                                end if;
382
                        end if;
383
                      --  v.line_offset := (others => '0'); 
384
                end if;
385
         when   wait_for_distance_engine=>
386
                v.enable_concatenate_unit := '0';
387
                if (calculate_sad_done= '1') then
388
                   v.state := update_mv;
389
                end if;
390
        when wait_for_distance_engine2 =>
391
             v.enable_concatenate_unit := '0';
392
             if (distance_engine_active = '0') then
393
                  v.state := update_mv;
394
             end if;
395
        when update_mv =>
396
                vupdate := '1';
397
              v.best_eu := best_eu; --update the condition bit
398
                v.state := fetch_instruction;
399
                --if (mvc_done = '1') then  -- first evaluate all the mvcs
400
                        v.instruction_address := v.instruction_address + x"01"; -- start reading the next instruction when arriving in fetch instruction state
401
                --end if;
402
        when terminate =>
403
           if (qp_on = '0') then -- qp must have finished
404
                    --  if (mode_in = m16x16) then
405
                                vfinish := '1';
406
                                vinstruction_zero := '1';
407
                        v.state := idle;
408
                        vpartition_done := '1';
409
                end if;
410
              --v.state := idle;
411
          when others => null;
412
 
413
end case;
414
 
415
if (interpolation_done = '1') then
416
        v.interpolation_done := '1';
417
end if;
418
 
419
r_in <= v;
420
partition_count_out <= r.partition_count;
421
write_register <= vwrite_register;
422
load_mv <= vload_mv;
423
update <= vupdate;
424
rm_address <= vrm_address;
425
finish <= vfinish;
426
start_qp <= vstart_qp;
427
start_pipelines <= vstart_pipelines; --enable extra pipelines as required
428
partition_done <= vpartition_done;
429
instruction_zero <= vinstruction_zero;
430
 
431
end process control;
432
 
433
instruction_address <= r.instruction_address;
434
next_point <= r.point_address;
435
line_offset <= r.line_offset;
436
enable_hp_inter <= r.enable_hp_inter;
437
enable_concatenate_unit <= r_in.enable_concatenate_unit when r.enable_hp_inter = '0' else r.enable_concatenate_unit;
438
active_pipelines <= r.active_pipelines_r;
439
 
440
 
441
-- sequential part
442
 
443
regs: process (clk,clear)
444
 
445
begin
446
 
447
if (clear = '1') then
448
        r.partition_count <= (others => '0');
449
        r.state <= idle;
450
        r.qp_mode <= '0';
451
   r.instruction_address <= (others => '0');
452
   r.point_count <= (others => '0');
453
        r.point_address <= (others => '0');
454
        r.phy_address <= (others => '0');
455
        r.phy_address_ready <= (others => '0');
456
        r.line_count <= (others => '0');
457
   r.line_offset <= (others => '0');
458
   r.points_tested <= (others => '0');
459
        r.enable_hp_inter <= '0';
460
        r.data_block <= (others => '0');
461
        r.interpolation_done <= '0';
462
        r.invalidate <= '0';
463
        r.enable_concatenate_unit <= '0';
464
         r.best_eu <= (others => '0');
465
        r.active_pipelines_r <= (others => '0');
466
        r.condition_bit <= '0';
467
  -- r.calculate_sad_done <= '0';
468
elsif rising_edge(clk) then
469
        if (reset = '1') then
470
        r.partition_count <= (others => '0');
471
                r.state <= idle;
472
                r.invalidate <= '0';
473
                        r.qp_mode <= '0';
474
                r.instruction_address <= (others => '0');
475
          r.point_count <= (others => '0');
476
                r.point_address <= (others => '0');
477
           r.phy_address <= (others => '0');
478
          r.best_eu <= (others => '0');
479
           r.phy_address_ready <= (others => '0');
480
           r.line_count <= (others => '0');
481
           r.line_offset <= (others => '0');
482
           r.points_tested <= (others => '0');
483
           r.enable_hp_inter <= '0';
484
           r.data_block <= (others => '0');
485
           r.interpolation_done <= '0';
486
           r.enable_concatenate_unit <= '0';
487
        r.active_pipelines_r <= (others => '0');
488
        r.condition_bit <= '0';
489
        --   r.calculate_sad_done <= '0';
490
        else
491
                r <= r_in;
492
        end if;
493
end if;
494
 
495
end process regs;
496
 
497
end;
498
 
499
 
500
 
501
 
502
 
503
 
504
 
505
 
506
 
507
 

powered by: WebSVN 2.1.0

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