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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [sparc/] [kernel/] [unaligned.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/* $Id: unaligned.c,v 1.23 2001/12/21 00:54:31 davem Exp $
2
 * unaligned.c: Unaligned load/store trap handling with special
3
 *              cases for the kernel to do them more quickly.
4
 *
5
 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
6
 * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7
 */
8
 
9
 
10
#include <linux/kernel.h>
11
#include <linux/sched.h>
12
#include <linux/mm.h>
13
#include <linux/module.h>
14
#include <asm/ptrace.h>
15
#include <asm/processor.h>
16
#include <asm/system.h>
17
#include <asm/uaccess.h>
18
#include <linux/smp.h>
19
#include <linux/smp_lock.h>
20
 
21
/* #define DEBUG_MNA */
22
 
23
enum direction {
24
        load,    /* ld, ldd, ldh, ldsh */
25
        store,   /* st, std, sth, stsh */
26
        both,    /* Swap, ldstub, etc. */
27
        fpload,
28
        fpstore,
29
        invalid,
30
};
31
 
32
#ifdef DEBUG_MNA
33
static char *dirstrings[] = {
34
  "load", "store", "both", "fpload", "fpstore", "invalid"
35
};
36
#endif
37
 
38
static inline enum direction decode_direction(unsigned int insn)
39
{
40
        unsigned long tmp = (insn >> 21) & 1;
41
 
42
        if(!tmp)
43
                return load;
44
        else {
45
                if(((insn>>19)&0x3f) == 15)
46
                        return both;
47
                else
48
                        return store;
49
        }
50
}
51
 
52
/* 8 = double-word, 4 = word, 2 = half-word */
53
static inline int decode_access_size(unsigned int insn)
54
{
55
        insn = (insn >> 19) & 3;
56
 
57
        if(!insn)
58
                return 4;
59
        else if(insn == 3)
60
                return 8;
61
        else if(insn == 2)
62
                return 2;
63
        else {
64
                printk("Impossible unaligned trap. insn=%08x\n", insn);
65
                die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs);
66
                return 4; /* just to keep gcc happy. */
67
        }
68
}
69
 
70
/* 0x400000 = signed, 0 = unsigned */
71
static inline int decode_signedness(unsigned int insn)
72
{
73
        return (insn & 0x400000);
74
}
75
 
76
static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
77
                                       unsigned int rd)
78
{
79
        if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
80
                /* Wheee... */
81
                __asm__ __volatile__("save %sp, -0x40, %sp\n\t"
82
                                     "save %sp, -0x40, %sp\n\t"
83
                                     "save %sp, -0x40, %sp\n\t"
84
                                     "save %sp, -0x40, %sp\n\t"
85
                                     "save %sp, -0x40, %sp\n\t"
86
                                     "save %sp, -0x40, %sp\n\t"
87
                                     "save %sp, -0x40, %sp\n\t"
88
                                     "restore; restore; restore; restore;\n\t"
89
                                     "restore; restore; restore;\n\t");
90
        }
91
}
92
 
93
static inline int sign_extend_imm13(int imm)
94
{
95
        return imm << 19 >> 19;
96
}
97
 
98
static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
99
{
100
        struct reg_window *win;
101
 
102
        if(reg < 16)
103
                return (!reg ? 0 : regs->u_regs[reg]);
104
 
105
        /* Ho hum, the slightly complicated case. */
106
        win = (struct reg_window *) regs->u_regs[UREG_FP];
107
        return win->locals[reg - 16]; /* yes, I know what this does... */
108
}
109
 
110
static inline unsigned long safe_fetch_reg(unsigned int reg, struct pt_regs *regs)
111
{
112
        struct reg_window __user *win;
113
        unsigned long ret;
114
 
115
        if (reg < 16)
116
                return (!reg ? 0 : regs->u_regs[reg]);
117
 
118
        /* Ho hum, the slightly complicated case. */
119
        win = (struct reg_window __user *) regs->u_regs[UREG_FP];
120
 
121
        if ((unsigned long)win & 3)
122
                return -1;
123
 
124
        if (get_user(ret, &win->locals[reg - 16]))
125
                return -1;
126
 
127
        return ret;
128
}
129
 
130
static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
131
{
132
        struct reg_window *win;
133
 
134
        if(reg < 16)
135
                return &regs->u_regs[reg];
136
        win = (struct reg_window *) regs->u_regs[UREG_FP];
137
        return &win->locals[reg - 16];
138
}
139
 
140
static unsigned long compute_effective_address(struct pt_regs *regs,
141
                                               unsigned int insn)
142
{
143
        unsigned int rs1 = (insn >> 14) & 0x1f;
144
        unsigned int rs2 = insn & 0x1f;
145
        unsigned int rd = (insn >> 25) & 0x1f;
146
 
147
        if(insn & 0x2000) {
148
                maybe_flush_windows(rs1, 0, rd);
149
                return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
150
        } else {
151
                maybe_flush_windows(rs1, rs2, rd);
152
                return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
153
        }
154
}
155
 
156
unsigned long safe_compute_effective_address(struct pt_regs *regs,
157
                                             unsigned int insn)
158
{
159
        unsigned int rs1 = (insn >> 14) & 0x1f;
160
        unsigned int rs2 = insn & 0x1f;
161
        unsigned int rd = (insn >> 25) & 0x1f;
162
 
163
        if(insn & 0x2000) {
164
                maybe_flush_windows(rs1, 0, rd);
165
                return (safe_fetch_reg(rs1, regs) + sign_extend_imm13(insn));
166
        } else {
167
                maybe_flush_windows(rs1, rs2, rd);
168
                return (safe_fetch_reg(rs1, regs) + safe_fetch_reg(rs2, regs));
169
        }
170
}
171
 
172
/* This is just to make gcc think panic does return... */
173
static void unaligned_panic(char *str)
174
{
175
        panic(str);
176
}
177
 
178
#define do_integer_load(dest_reg, size, saddr, is_signed, errh) ({              \
179
__asm__ __volatile__ (                                                          \
180
        "cmp    %1, 8\n\t"                                                      \
181
        "be     9f\n\t"                                                         \
182
        " cmp   %1, 4\n\t"                                                      \
183
        "be     6f\n"                                                           \
184
"4:\t"  " ldub  [%2], %%l1\n"                                                   \
185
"5:\t"  "ldub   [%2 + 1], %%l2\n\t"                                             \
186
        "sll    %%l1, 8, %%l1\n\t"                                              \
187
        "tst    %3\n\t"                                                         \
188
        "be     3f\n\t"                                                         \
189
        " add   %%l1, %%l2, %%l1\n\t"                                           \
190
        "sll    %%l1, 16, %%l1\n\t"                                             \
191
        "sra    %%l1, 16, %%l1\n"                                               \
192
"3:\t"  "b      0f\n\t"                                                         \
193
        " st    %%l1, [%0]\n"                                                   \
194
"6:\t"  "ldub   [%2 + 1], %%l2\n\t"                                             \
195
        "sll    %%l1, 24, %%l1\n"                                               \
196
"7:\t"  "ldub   [%2 + 2], %%g7\n\t"                                             \
197
        "sll    %%l2, 16, %%l2\n"                                               \
198
"8:\t"  "ldub   [%2 + 3], %%g1\n\t"                                             \
199
        "sll    %%g7, 8, %%g7\n\t"                                              \
200
        "or     %%l1, %%l2, %%l1\n\t"                                           \
201
        "or     %%g7, %%g1, %%g7\n\t"                                           \
202
        "or     %%l1, %%g7, %%l1\n\t"                                           \
203
        "b      0f\n\t"                                                         \
204
        " st    %%l1, [%0]\n"                                                   \
205
"9:\t"  "ldub   [%2], %%l1\n"                                                   \
206
"10:\t" "ldub   [%2 + 1], %%l2\n\t"                                             \
207
        "sll    %%l1, 24, %%l1\n"                                               \
208
"11:\t" "ldub   [%2 + 2], %%g7\n\t"                                             \
209
        "sll    %%l2, 16, %%l2\n"                                               \
210
"12:\t" "ldub   [%2 + 3], %%g1\n\t"                                             \
211
        "sll    %%g7, 8, %%g7\n\t"                                              \
212
        "or     %%l1, %%l2, %%l1\n\t"                                           \
213
        "or     %%g7, %%g1, %%g7\n\t"                                           \
214
        "or     %%l1, %%g7, %%g7\n"                                             \
215
"13:\t" "ldub   [%2 + 4], %%l1\n\t"                                             \
216
        "st     %%g7, [%0]\n"                                                   \
217
"14:\t" "ldub   [%2 + 5], %%l2\n\t"                                             \
218
        "sll    %%l1, 24, %%l1\n"                                               \
219
"15:\t" "ldub   [%2 + 6], %%g7\n\t"                                             \
220
        "sll    %%l2, 16, %%l2\n"                                               \
221
"16:\t" "ldub   [%2 + 7], %%g1\n\t"                                             \
222
        "sll    %%g7, 8, %%g7\n\t"                                              \
223
        "or     %%l1, %%l2, %%l1\n\t"                                           \
224
        "or     %%g7, %%g1, %%g7\n\t"                                           \
225
        "or     %%l1, %%g7, %%g7\n\t"                                           \
226
        "st     %%g7, [%0 + 4]\n"                                               \
227
"0:\n\n\t"                                                                      \
228
        ".section __ex_table,#alloc\n\t"                                        \
229
        ".word  4b, " #errh "\n\t"                                              \
230
        ".word  5b, " #errh "\n\t"                                              \
231
        ".word  6b, " #errh "\n\t"                                              \
232
        ".word  7b, " #errh "\n\t"                                              \
233
        ".word  8b, " #errh "\n\t"                                              \
234
        ".word  9b, " #errh "\n\t"                                              \
235
        ".word  10b, " #errh "\n\t"                                             \
236
        ".word  11b, " #errh "\n\t"                                             \
237
        ".word  12b, " #errh "\n\t"                                             \
238
        ".word  13b, " #errh "\n\t"                                             \
239
        ".word  14b, " #errh "\n\t"                                             \
240
        ".word  15b, " #errh "\n\t"                                             \
241
        ".word  16b, " #errh "\n\n\t"                                           \
242
        ".previous\n\t"                                                         \
243
        : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed)            \
244
        : "l1", "l2", "g7", "g1", "cc");                                        \
245
})
246
 
247
#define store_common(dst_addr, size, src_val, errh) ({                          \
248
__asm__ __volatile__ (                                                          \
249
        "ld     [%2], %%l1\n"                                                   \
250
        "cmp    %1, 2\n\t"                                                      \
251
        "be     2f\n\t"                                                         \
252
        " cmp   %1, 4\n\t"                                                      \
253
        "be     1f\n\t"                                                         \
254
        " srl   %%l1, 24, %%l2\n\t"                                             \
255
        "srl    %%l1, 16, %%g7\n"                                               \
256
"4:\t"  "stb    %%l2, [%0]\n\t"                                                 \
257
        "srl    %%l1, 8, %%l2\n"                                                \
258
"5:\t"  "stb    %%g7, [%0 + 1]\n\t"                                             \
259
        "ld     [%2 + 4], %%g7\n"                                               \
260
"6:\t"  "stb    %%l2, [%0 + 2]\n\t"                                             \
261
        "srl    %%g7, 24, %%l2\n"                                               \
262
"7:\t"  "stb    %%l1, [%0 + 3]\n\t"                                             \
263
        "srl    %%g7, 16, %%l1\n"                                               \
264
"8:\t"  "stb    %%l2, [%0 + 4]\n\t"                                             \
265
        "srl    %%g7, 8, %%l2\n"                                                \
266
"9:\t"  "stb    %%l1, [%0 + 5]\n"                                               \
267
"10:\t" "stb    %%l2, [%0 + 6]\n\t"                                             \
268
        "b      0f\n"                                                           \
269
"11:\t" " stb   %%g7, [%0 + 7]\n"                                               \
270
"1:\t"  "srl    %%l1, 16, %%g7\n"                                               \
271
"12:\t" "stb    %%l2, [%0]\n\t"                                                 \
272
        "srl    %%l1, 8, %%l2\n"                                                \
273
"13:\t" "stb    %%g7, [%0 + 1]\n"                                               \
274
"14:\t" "stb    %%l2, [%0 + 2]\n\t"                                             \
275
        "b      0f\n"                                                           \
276
"15:\t" " stb   %%l1, [%0 + 3]\n"                                               \
277
"2:\t"  "srl    %%l1, 8, %%l2\n"                                                \
278
"16:\t" "stb    %%l2, [%0]\n"                                                   \
279
"17:\t" "stb    %%l1, [%0 + 1]\n"                                               \
280
"0:\n\n\t"                                                                      \
281
        ".section __ex_table,#alloc\n\t"                                        \
282
        ".word  4b, " #errh "\n\t"                                              \
283
        ".word  5b, " #errh "\n\t"                                              \
284
        ".word  6b, " #errh "\n\t"                                              \
285
        ".word  7b, " #errh "\n\t"                                              \
286
        ".word  8b, " #errh "\n\t"                                              \
287
        ".word  9b, " #errh "\n\t"                                              \
288
        ".word  10b, " #errh "\n\t"                                             \
289
        ".word  11b, " #errh "\n\t"                                             \
290
        ".word  12b, " #errh "\n\t"                                             \
291
        ".word  13b, " #errh "\n\t"                                             \
292
        ".word  14b, " #errh "\n\t"                                             \
293
        ".word  15b, " #errh "\n\t"                                             \
294
        ".word  16b, " #errh "\n\t"                                             \
295
        ".word  17b, " #errh "\n\n\t"                                           \
296
        ".previous\n\t"                                                         \
297
        : : "r" (dst_addr), "r" (size), "r" (src_val)                           \
298
        : "l1", "l2", "g7", "g1", "cc");                                        \
299
})
300
 
301
#define do_integer_store(reg_num, size, dst_addr, regs, errh) ({                \
302
        unsigned long *src_val;                                                 \
303
        static unsigned long zero[2] = { 0, };                                   \
304
                                                                                \
305
        if (reg_num) src_val = fetch_reg_addr(reg_num, regs);                   \
306
        else {                                                                  \
307
                src_val = &zero[0];                                              \
308
                if (size == 8)                                                  \
309
                        zero[1] = fetch_reg(1, regs);                           \
310
        }                                                                       \
311
        store_common(dst_addr, size, src_val, errh);                            \
312
})
313
 
314
extern void smp_capture(void);
315
extern void smp_release(void);
316
 
317
#define do_atomic(srcdest_reg, mem, errh) ({                                    \
318
        unsigned long flags, tmp;                                               \
319
                                                                                \
320
        smp_capture();                                                          \
321
        local_irq_save(flags);                                                  \
322
        tmp = *srcdest_reg;                                                     \
323
        do_integer_load(srcdest_reg, 4, mem, 0, errh);                           \
324
        store_common(mem, 4, &tmp, errh);                                       \
325
        local_irq_restore(flags);                                               \
326
        smp_release();                                                          \
327
})
328
 
329
static inline void advance(struct pt_regs *regs)
330
{
331
        regs->pc   = regs->npc;
332
        regs->npc += 4;
333
}
334
 
335
static inline int floating_point_load_or_store_p(unsigned int insn)
336
{
337
        return (insn >> 24) & 1;
338
}
339
 
340
static inline int ok_for_kernel(unsigned int insn)
341
{
342
        return !floating_point_load_or_store_p(insn);
343
}
344
 
345
void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault");
346
 
347
void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
348
{
349
        unsigned long g2 = regs->u_regs [UREG_G2];
350
        unsigned long fixup = search_extables_range(regs->pc, &g2);
351
 
352
        if (!fixup) {
353
                unsigned long address = compute_effective_address(regs, insn);
354
                if(address < PAGE_SIZE) {
355
                        printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
356
                } else
357
                        printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
358
                printk(KERN_ALERT " at virtual address %08lx\n",address);
359
                printk(KERN_ALERT "current->{mm,active_mm}->context = %08lx\n",
360
                        (current->mm ? current->mm->context :
361
                        current->active_mm->context));
362
                printk(KERN_ALERT "current->{mm,active_mm}->pgd = %08lx\n",
363
                        (current->mm ? (unsigned long) current->mm->pgd :
364
                        (unsigned long) current->active_mm->pgd));
365
                die_if_kernel("Oops", regs);
366
                /* Not reached */
367
        }
368
        regs->pc = fixup;
369
        regs->npc = regs->pc + 4;
370
        regs->u_regs [UREG_G2] = g2;
371
}
372
 
373
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
374
{
375
        enum direction dir = decode_direction(insn);
376
        int size = decode_access_size(insn);
377
 
378
        if(!ok_for_kernel(insn) || dir == both) {
379
                printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
380
                       regs->pc);
381
                unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
382
 
383
                __asm__ __volatile__ ("\n"
384
"kernel_unaligned_trap_fault:\n\t"
385
                "mov    %0, %%o0\n\t"
386
                "call   kernel_mna_trap_fault\n\t"
387
                " mov   %1, %%o1\n\t"
388
                :
389
                : "r" (regs), "r" (insn)
390
                : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
391
                  "g1", "g2", "g3", "g4", "g5", "g7", "cc");
392
        } else {
393
                unsigned long addr = compute_effective_address(regs, insn);
394
 
395
#ifdef DEBUG_MNA
396
                printk("KMNA: pc=%08lx [dir=%s addr=%08lx size=%d] retpc[%08lx]\n",
397
                       regs->pc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]);
398
#endif
399
                switch(dir) {
400
                case load:
401
                        do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
402
                                        size, (unsigned long *) addr,
403
                                        decode_signedness(insn),
404
                                        kernel_unaligned_trap_fault);
405
                        break;
406
 
407
                case store:
408
                        do_integer_store(((insn>>25)&0x1f), size,
409
                                         (unsigned long *) addr, regs,
410
                                         kernel_unaligned_trap_fault);
411
                        break;
412
#if 0 /* unsupported */
413
                case both:
414
                        do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
415
                                  (unsigned long *) addr,
416
                                  kernel_unaligned_trap_fault);
417
                        break;
418
#endif
419
                default:
420
                        panic("Impossible kernel unaligned trap.");
421
                        /* Not reached... */
422
                }
423
                advance(regs);
424
        }
425
}
426
 
427
static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
428
                              enum direction dir)
429
{
430
        unsigned int reg;
431
        int check = (dir == load) ? VERIFY_READ : VERIFY_WRITE;
432
        int size = ((insn >> 19) & 3) == 3 ? 8 : 4;
433
 
434
        if ((regs->pc | regs->npc) & 3)
435
                return 0;
436
 
437
        /* Must access_ok() in all the necessary places. */
438
#define WINREG_ADDR(regnum) \
439
        ((void __user *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))
440
 
441
        reg = (insn >> 25) & 0x1f;
442
        if (reg >= 16) {
443
                if (!access_ok(check, WINREG_ADDR(reg - 16), size))
444
                        return -EFAULT;
445
        }
446
        reg = (insn >> 14) & 0x1f;
447
        if (reg >= 16) {
448
                if (!access_ok(check, WINREG_ADDR(reg - 16), size))
449
                        return -EFAULT;
450
        }
451
        if (!(insn & 0x2000)) {
452
                reg = (insn & 0x1f);
453
                if (reg >= 16) {
454
                        if (!access_ok(check, WINREG_ADDR(reg - 16), size))
455
                                return -EFAULT;
456
                }
457
        }
458
#undef WINREG_ADDR
459
        return 0;
460
}
461
 
462
void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault");
463
 
464
void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
465
{
466
        siginfo_t info;
467
 
468
        info.si_signo = SIGBUS;
469
        info.si_errno = 0;
470
        info.si_code = BUS_ADRALN;
471
        info.si_addr = (void __user *)safe_compute_effective_address(regs, insn);
472
        info.si_trapno = 0;
473
        send_sig_info(SIGBUS, &info, current);
474
}
475
 
476
asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
477
{
478
        enum direction dir;
479
 
480
        lock_kernel();
481
        if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) ||
482
           (((insn >> 30) & 3) != 3))
483
                goto kill_user;
484
        dir = decode_direction(insn);
485
        if(!ok_for_user(regs, insn, dir)) {
486
                goto kill_user;
487
        } else {
488
                int size = decode_access_size(insn);
489
                unsigned long addr;
490
 
491
                if(floating_point_load_or_store_p(insn)) {
492
                        printk("User FPU load/store unaligned unsupported.\n");
493
                        goto kill_user;
494
                }
495
 
496
                addr = compute_effective_address(regs, insn);
497
                switch(dir) {
498
                case load:
499
                        do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
500
                                        size, (unsigned long *) addr,
501
                                        decode_signedness(insn),
502
                                        user_unaligned_trap_fault);
503
                        break;
504
 
505
                case store:
506
                        do_integer_store(((insn>>25)&0x1f), size,
507
                                         (unsigned long *) addr, regs,
508
                                         user_unaligned_trap_fault);
509
                        break;
510
 
511
                case both:
512
#if 0 /* unsupported */
513
                        do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
514
                                  (unsigned long *) addr,
515
                                  user_unaligned_trap_fault);
516
#else
517
                        /*
518
                         * This was supported in 2.4. However, we question
519
                         * the value of SWAP instruction across word boundaries.
520
                         */
521
                        printk("Unaligned SWAP unsupported.\n");
522
                        goto kill_user;
523
#endif
524
                        break;
525
 
526
                default:
527
                        unaligned_panic("Impossible user unaligned trap.");
528
 
529
                        __asm__ __volatile__ ("\n"
530
"user_unaligned_trap_fault:\n\t"
531
                        "mov    %0, %%o0\n\t"
532
                        "call   user_mna_trap_fault\n\t"
533
                        " mov   %1, %%o1\n\t"
534
                        :
535
                        : "r" (regs), "r" (insn)
536
                        : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
537
                          "g1", "g2", "g3", "g4", "g5", "g7", "cc");
538
                        goto out;
539
                }
540
                advance(regs);
541
                goto out;
542
        }
543
 
544
kill_user:
545
        user_mna_trap_fault(regs, insn);
546
out:
547
        unlock_kernel();
548
}

powered by: WebSVN 2.1.0

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