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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [or32/] [kernel/] [head.S] - Blame information for rev 666

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 666 simons
#include 
2
#include 
3
#include 
4
#include 
5
#include 
6
 
7
#define RAM 0
8
#undef MC_INIT
9
#define MC_INIT 1
10
 
11
        .global __text_start
12
        .global __main
13
        .global ___bss_start
14
        .global __bss_end
15
        .global __ram_start
16
        .global __ram_end
17
        .global __rom_start
18
        .global __rom_end
19
        .global ___data_start
20
        .global __data_end
21
        .global ___data_rom_start
22
 
23
        .global splash_bits
24
        .global __start
25
        .global __stext
26
 
27
        .global __switch
28
        .global _putc
29
 
30
#define SAVE_REGS(mark) \
31
        l.addi  r1,r1,-(INT_FRAME_SIZE); \
32
        l.mfspr r3,r0,SPR_EPCR_BASE; \
33
        l.sw    PC(r1),r3; \
34
        l.mfspr r3,r0,SPR_ESR_BASE; \
35
        l.sw    SR(r1),r3; \
36
        l.lwz   r3,4(r0); /* Read r1 (sp) from tmp location */ \
37
        l.sw    SP(r1),r3; \
38
        l.sw    GPR2(r1),r2; \
39
        l.sw    GPR4(r1),r4; \
40
        l.sw    GPR5(r1),r5; \
41
        l.sw    GPR6(r1),r6; \
42
        l.sw    GPR7(r1),r7; \
43
        l.sw    GPR8(r1),r8; \
44
        l.sw    GPR9(r1),r9; \
45
        l.sw    GPR10(r1),r10; \
46
        l.sw    GPR11(r1),r11; \
47
        l.sw    GPR12(r1),r12; \
48
        l.sw    GPR13(r1),r13; \
49
        l.sw    GPR14(r1),r14; \
50
        l.sw    GPR15(r1),r15; \
51
        l.sw    GPR16(r1),r16; \
52
        l.sw    GPR17(r1),r17; \
53
        l.sw    GPR18(r1),r18; \
54
        l.sw    GPR19(r1),r19; \
55
        l.sw    GPR20(r1),r20; \
56
        l.sw    GPR21(r1),r21; \
57
        l.sw    GPR22(r1),r22; \
58
        l.sw    GPR23(r1),r23; \
59
        l.sw    GPR24(r1),r24; \
60
        l.sw    GPR25(r1),r25; \
61
        l.sw    GPR26(r1),r26; \
62
        l.sw    GPR27(r1),r27; \
63
        l.sw    GPR28(r1),r28; \
64
        l.sw    GPR29(r1),r29; \
65
        l.sw    GPR30(r1),r30; \
66
        l.sw    GPR31(r1),r31; \
67
        l.lwz   r3,0(r0);  /* Read r3 from tmp location */ \
68
        l.sw    GPR3(r1),r3
69
 
70
#define SAVE_INT_REGS(mark) \
71
        l.sw    0(r0),r3;       /* Temporary store r3 to add 0!!! */ \
72
        l.sw    4(r0),r1;       /* Temporary store r1 to add 4!!! */ \
73
        l.mfspr r3,r0,SPR_SR; \
74
        l.addi  r1,r0,-1; \
75
        l.xori  r1,r1,(SPR_SR_IEE | SPR_SR_TEE); \
76
        l.and   r3,r3,r1; \
77
        l.mtspr r0,r3,SPR_SR; \
78
        l.lwz   r1,4(r0); \
79
        l.mfspr r3,r0,SPR_ESR_BASE; /* Interrupt from user/system mode */ \
80
        l.andi  r3,r3,SPR_SR_SM; \
81
        l.sfeqi r3,SPR_SR_SM; \
82
        l.bf    10f; /* SIMON */ /* Branch if SUPV */ \
83
        l.nop; \
84
        l.movhi r3,hi(_current_set); \
85
        l.ori   r3,r3,lo(_current_set); \
86
        l.lwz   r3,(0)(r3); \
87
        l.sw    TSS+TSS_USP(r3),r1; \
88
        l.mfspr r1,r0,SPR_EPCR_BASE; \
89
        l.sw    TSS+TSS_PC(r3),r1; \
90
        l.lwz   r1,TSS+TSS_KSP(r3); \
91
        l.addi  r1,r1,-(INT_FRAME_SIZE); \
92
        l.sw    TSS+TSS_REGS(r3),r1; \
93
        l.lwz   r1,TSS+TSS_KSP(r3); \
94
10:     SAVE_REGS(mark)
95
 
96
#define RETURN_FROM_INT(mark) \
97
90:     l.addi  r4,r0,-1;       /* Disable interrupts */ \
98
        l.xori  r4,r4,(SPR_SR_IEE | SPR_SR_TEE); \
99
        l.mfspr r3,r0,SPR_SR; \
100
        l.and   r3,r3,r4; \
101
        l.mtspr r0,r3,SPR_SR; \
102
        l.movhi r2,hi(_intr_count); \
103
        l.ori   r2,r2,lo(_intr_count); \
104
        l.lwz   r3,(0)(r2); \
105
        l.sfeqi r3,0; \
106
        l.bnf   00f; \
107
        l.nop; \
108
        l.movhi r4,hi(_bh_mask); \
109
        l.ori   r4,r4,lo(_bh_mask); \
110
        l.lwz   r4,(0)(r4); \
111
        l.movhi r5,hi(_bh_active); \
112
        l.ori   r5,r5,lo(_bh_active); \
113
        l.lwz   r5,(0)(r5); \
114
        l.and   r4,r4,r5; \
115
        l.sfeqi r4,0; \
116
        l.bf    00f; \
117
        l.nop; \
118
        l.addi  r3,r3,1; \
119
        l.sw    (0)(r2),r3; \
120
        l.jal   _do_bottom_half; \
121
        l.nop; \
122
        l.movhi r2,hi(_intr_count); \
123
        l.ori   r2,r2,lo(_intr_count); \
124
        l.lwz   r3,(0)(r2); \
125
        l.addi  r3,r3,-1; \
126
        l.sw    0(r2),r3; \
127
00:     l.lwz   r2,SR(r1); \
128
        l.andi  r3,r2,SPR_SR_SM; \
129
        l.sfeqi r3,0; \
130
        l.bnf   10f; /* SIMON */ /* Branch if SUPV */ \
131
        l.nop; \
132
        l.andi  r3,r2,SPR_SR_ICE; \
133
        l.sfeqi r3,0; \
134
        l.bf    05f; /* Branch if IC disabled */ \
135
        l.nop; \
136
        l.jal   _ic_invalidate; \
137
        l.nop; \
138
05:     l.movhi r3,hi(_current_set); /* need to save kernel stack pointer */ \
139
        l.ori   r3,r3,lo(_current_set); \
140
        l.lwz   r3,(0)(r3); \
141
        l.addi  r4,r1,INT_FRAME_SIZE; \
142
        l.sw    TSS+TSS_KSP(r3),r4; \
143
        l.lwz   r4,STATE(r3); /* If state != 0, can't run */ \
144
        l.sfeqi r4,0; \
145
        l.bf    06f; \
146
        l.nop; \
147
        l.jal   _schedule; \
148
        l.nop; \
149
        l.j     90b; \
150
        l.nop; \
151
06:     l.lwz   r4,COUNTER(r3); \
152
        l.sfeqi r4,0; \
153
        l.bnf   07f; \
154
        l.nop; \
155
        l.jal   _schedule; \
156
        l.nop; \
157
        l.j     90b; \
158
        l.nop; \
159
07:     l.addi  r5,r0,-1; \
160
        l.lwz   r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
161
        l.xor   r4,r4,r5; \
162
        l.lwz   r5,SIGNAL(r3); \
163
        l.and   r5,r5,r4; \
164
        l.sfeqi r5,0; \
165
        l.bf    10f; \
166
        l.nop; \
167
        l.addi  r3,r4,0; \
168
        l.addi  r4,r1,0; \
169
        l.jal   _do_signal; \
170
        l.nop; \
171
10:     l.lwz   r3,PC(r1); \
172
        l.mtspr r0,r3,SPR_EPCR_BASE; \
173
        l.lwz   r3,SR(r1); \
174
        l.mtspr r0,r3,SPR_ESR_BASE; \
175
        l.lwz   r2,GPR2(r1); \
176
        l.lwz   r3,GPR3(r1); \
177
        l.lwz   r4,GPR4(r1); \
178
        l.lwz   r5,GPR5(r1); \
179
        l.lwz   r6,GPR6(r1); \
180
        l.lwz   r7,GPR7(r1); \
181
        l.lwz   r8,GPR8(r1); \
182
        l.lwz   r9,GPR9(r1); \
183
        l.lwz   r10,GPR10(r1); \
184
        l.lwz   r11,GPR11(r1); \
185
        l.lwz   r12,GPR12(r1); \
186
        l.lwz   r13,GPR13(r1); \
187
        l.lwz   r14,GPR14(r1); \
188
        l.lwz   r15,GPR15(r1); \
189
        l.lwz   r16,GPR16(r1); \
190
        l.lwz   r17,GPR17(r1); \
191
        l.lwz   r18,GPR18(r1); \
192
        l.lwz   r19,GPR19(r1); \
193
        l.lwz   r20,GPR20(r1); \
194
        l.lwz   r21,GPR21(r1); \
195
        l.lwz   r22,GPR22(r1); \
196
        l.lwz   r23,GPR23(r1); \
197
        l.lwz   r24,GPR24(r1); \
198
        l.lwz   r25,GPR25(r1); \
199
        l.lwz   r26,GPR26(r1); \
200
        l.lwz   r27,GPR27(r1); \
201
        l.lwz   r28,GPR28(r1); \
202
        l.lwz   r29,GPR29(r1); \
203
        l.lwz   r30,GPR30(r1); \
204
        l.lwz   r31,GPR31(r1); \
205
        l.lwz   r1,SP(r1); \
206
        l.rfe; \
207
        l.nop
208
 
209
        .bss
210
sys_stack:
211
        .space  4*4096
212
sys_stack_top:
213
#if !(RAM)
214
        .section .romvec
215
        .org    0x100
216
 
217
        l.movhi r3,hi(__start)
218
        l.ori   r3,r3,lo(__start)
219
        l.jr    r3
220
        l.nop
221
 
222
        .org    0x200
223
 
224
        l.nop
225
        l.rfe
226
        l.nop
227
 
228
        .org    0x300
229
 
230
        l.nop
231
        l.j     _dpfault
232
        l.nop
233
 
234
        .org    0x400
235
 
236
        l.nop
237
        l.j     _ipfault
238
        l.nop
239
 
240
        .org    0x500
241
 
242
        l.nop
243
        l.j     _tick
244
        l.nop
245
 
246
        .org    0x800
247
 
248
        l.nop
249
        l.j     _ext_int
250
        l.nop
251
 
252
        .org    0x900
253
 
254
        l.nop
255
        l.j     _dtlbmiss
256
        l.nop
257
 
258
        .org    0xa00
259
 
260
        l.nop
261
        l.j     _itlbmiss
262
        l.nop
263
 
264
        .org    0xb00
265
 
266
        l.nop
267
        l.j     _sys_call
268
        l.nop
269
 
270
        .org    0xc00
271
 
272
        l.nop
273
        l.j     _sys_call
274
        l.nop
275
#endif
276
        .section .ramvec
277
        .org    0x100
278
 
279
        l.movhi r3,hi(__start)
280
        l.ori   r3,r3,lo(__start)
281
        l.jr    r3
282
        l.nop
283
 
284
        .org    0x200
285
 
286
        l.nop
287
        l.rfe
288
        l.nop
289
 
290
        .org    0x300
291
 
292
        l.nop
293
        l.j     _dpfault
294
        l.nop
295
 
296
        .org    0x400
297
 
298
        l.nop
299
        l.j     _ipfault
300
        l.nop
301
 
302
        .org    0x500
303
 
304
        l.nop
305
        l.j     _tick
306
        l.nop
307
 
308
        .org    0x800
309
 
310
        l.nop
311
        l.j     _ext_int
312
        l.nop
313
 
314
        .org    0x900
315
 
316
        l.nop
317
        l.j     _dtlbmiss
318
        l.nop
319
 
320
        .org    0xa00
321
 
322
        l.nop
323
        l.j     _itlbmiss
324
        l.nop
325
 
326
        .org    0xb00
327
 
328
        l.nop
329
        l.j     _sys_call
330
        l.nop
331
 
332
        .org    0xc00
333
 
334
        l.nop
335
        l.j     _sys_call
336
        l.nop
337
 
338
 
339
        .text
340
__start:
341
__stext:
342
        l.addi  r3,r0,SPR_SR_SM
343
        l.mtspr r0,r3,SPR_SR
344
#if 1
345
 
346
        /* Init uart */
347
        l.jal   _ua_init
348
        l.nop
349
 
350
        /* Jump to flash original location */
351
        l.movhi r3,hi(__flsh_start)
352
        l.ori   r3,r3,lo(__flsh_start)
353
        l.jr    r3
354
        l.nop
355
 
356
__flsh_start:
357
 
358
#if MC_INIT
359
        /* Init memory controller */
360
        l.movhi r3,hi(MC_BASE_ADD)
361
        l.ori   r3,r3,lo(MC_BASE_ADD)
362
 
363
        l.addi  r4,r3,MC_CSC(0)
364
        l.movhi r5,hi(FLASH_BASE_ADD)
365
        l.srai  r5,r5,5
366
        l.ori   r5,r5,0x0005
367
        l.sw    0(r4),r5
368
 
369
        l.addi  r4,r3,MC_TMS(0)
370
        l.movhi r5,0xffff
371
        l.ori   r5,r5,0xffff
372
        l.sw    0(r4),r5
373
 
374
        l.addi  r4,r3,MC_BA_MASK
375
        l.addi  r5,r0,0xff
376
        l.sw    0(r4),r5
377
 
378
        l.addi  r4,r3,MC_CSC(1)
379
        l.movhi r5,hi(SRAM_BASE_ADD)
380
        l.srai  r5,r5,5
381
        l.ori   r5,r5,0x0025
382
        l.sw    0(r4),r5
383
 
384
        l.addi  r4,r3,MC_TMS(1)
385
        l.movhi r5,0xffff
386
        l.ori   r5,r5,0xffff
387
        l.sw    0(r4),r5
388
#endif
389
#endif
390
 
391
#if ICACHE
392
        l.jal   _ic_enable
393
        l.nop
394
#endif
395
 
396
#if DCACHE
397
        l.jal   _dc_enable
398
        l.nop
399
#endif
400
 
401
        l.movhi r1, hi(sys_stack_top)           /* stack setup */
402
        l.ori   r1,r1,lo(sys_stack_top)
403
 
404
#if 1
405
        /* Copy data segment from ROM to RAM */
406
        l.movhi r3, hi(___data_rom_start)
407
        l.ori   r3,r3,lo(___data_rom_start)
408
 
409
        l.movhi r4, hi(___data_start)
410
        l.ori   r4,r4,lo(___data_start)
411
 
412
        l.movhi r5, hi(__data_end)
413
        l.ori   r5,r5,lo(__data_end)
414
 
415
        /* Copy %r3 to %r4 until %r4 == %r5 */
416
1:
417
        l.sfeq  r3,r4
418
        l.bf    3f
419
        l.nop
420
2:
421
        l.sfgeu r4,r5
422
        l.bf    1f
423
        l.nop
424
        l.lwz   r8,0(r3)
425
        l.sw    0(r4),r8
426
        l.addi  r3,r3,4
427
        l.j     2b
428
        l.addi  r4,r4,4
429
 
430
        /* Copy ramvec segment from ROM to RAM */
431
1:
432
        l.movhi r4, hi(__ramvec_start)
433
        l.ori   r4,r4,lo(__ramvec_start)
434
 
435
        l.movhi r5, hi(__ramvec_end)
436
        l.ori   r5,r5,lo(__ramvec_end)
437
 
438
        /* Copy %r3 to %r4 until %r4 == %r5 */
439
2:
440
        l.sfgeu r4,r5
441
        l.bf    1f
442
        l.nop
443
        l.lwz   r8,0(r3)
444
        l.sw    0(r4),r8
445
        l.addi  r3,r3,4
446
        l.j     2b
447
        l.addi  r4,r4,4
448
#if 0
449
        /* Copy initrd segment from ROM to RAM */
450
1:
451
        l.movhi r4, hi(__initrd_start)
452
        l.ori   r4,r4,lo(__initrd_start)
453
 
454
        l.movhi r5, hi(__initrd_end)
455
        l.ori   r5,r5,lo(__initrd_end)
456
 
457
        /* Copy %r3 to %r4 until %r4 == %r5 */
458
2:
459
        l.sfgeu r4,r5
460
        l.bf    1f
461
        l.nop
462
        l.lwz   r8,0(r3)
463
        l.sw    0(r4),r8
464
        l.addi  r3,r3,4
465
        l.j     2b
466
        l.addi  r4,r4,4
467
#endif
468
#endif
469
1:
470
3:
471
        l.movhi r3, hi(___bss_start)
472
        l.ori   r3,r3,lo(___bss_start)
473
 
474
        l.movhi r4, hi(end)
475
        l.ori   r4,r4,lo(end)
476
 
477
        /* Copy 0 to %r3 until %r3 == %r4 */
478
1:
479
        l.sfgeu r3,r4
480
        l.bf    1f
481
        l.nop
482
        l.sw    0(r3),r0
483
        l.j     1b
484
        l.addi  r3,r3,4
485
1:
486
 
487
#if IMMU
488
        l.jal   _immu_enable
489
        l.nop
490
#endif
491
 
492
#if DMMU
493
        l.jal   _dmmu_enable
494
        l.nop
495
#endif
496
 
497
        l.j     _start_kernel
498
        l.nop
499
 
500
_exit:
501
        l.j     _exit
502
        l.nop
503
 
504
_dpfault:
505
 
506
 
507
_ipfault:
508
 
509
_tick:
510
        SAVE_INT_REGS(0x0500)
511
        l.addi  r3,r1,0
512
        l.jal   _timer_interrupt
513
        l.nop
514
        RETURN_FROM_INT(0x500)
515
 
516
_ext_int:
517
        SAVE_INT_REGS(0x0800)
518
        l.addi  r3,r1,0
519
        l.jal   _handle_IRQ
520
        l.nop
521
        RETURN_FROM_INT(0x800)
522
 
523
_dtlbmiss:
524
        l.sw    0(r0),r3
525
        l.sw    4(r0),r4
526
        l.sw    8(r0),r5
527
        l.mfspr r3,r0,SPR_EEAR_BASE
528
        l.srli  r4,r3,DMMU_PAGE_ADD_BITS
529
        l.andi  r4,r4,DMMU_SET_ADD_MASK
530
        l.addi  r5,r0,-1
531
        l.xori  r5,r5,DMMU_PAGE_ADD_MASK
532
        l.and   r5,r3,r5
533
        l.ori   r5,r5,SPR_DTLBMR_V
534
        l.mtspr r4,r5,SPR_DTLBMR_BASE(0)
535
        l.movhi r5,hi(SPR_DTLBTR_PPN)
536
        l.ori   r5,r5,lo(SPR_DTLBTR_PPN)
537
        l.and   r5,r3,r5
538
        l.ori   r5,r5,DTLBTR_NO_LIMIT
539
        l.movhi r3,0x8000
540
        l.sfgeu r5,r3
541
        l.bnf   1f
542
        l.nop
543
        l.ori   r5,r5,SPR_DTLBTR_CI
544
1:      l.mtspr r4,r5,SPR_DTLBTR_BASE(0)
545
        l.lwz   r3,0(r0)
546
        l.lwz   r4,4(r0)
547
        l.lwz   r5,8(r0)
548
        l.rfe
549
        l.nop
550
 
551
 
552
_itlbmiss:
553
        l.sw    0(r0),r3
554
        l.sw    4(r0),r4
555
        l.sw    8(r0),r5
556
        l.mfspr r3,r0,SPR_EEAR_BASE
557
        l.srli  r4,r3,IMMU_PAGE_ADD_BITS
558
        l.andi  r4,r4,IMMU_SET_ADD_MASK
559
        l.addi  r5,r0,-1
560
        l.xori  r5,r5,IMMU_PAGE_ADD_MASK
561
        l.and   r5,r3,r5
562
        l.ori   r5,r5,SPR_ITLBMR_V
563
        l.mtspr r4,r5,SPR_ITLBMR_BASE(0)
564
        l.movhi r5,hi(SPR_ITLBTR_PPN)
565
        l.ori   r5,r5,lo(SPR_ITLBTR_PPN)
566
        l.and   r5,r3,r5
567
        l.ori   r5,r5,ITLBTR_NO_LIMIT
568
        l.mtspr r4,r5,SPR_ITLBTR_BASE(0)
569
        l.lwz   r3,0(r0)
570
        l.lwz   r4,4(r0)
571
        l.lwz   r5,8(r0)
572
        l.rfe
573
        l.nop
574
 
575
_sys_call:
576
        SAVE_INT_REGS(0x0c00)
577
        l.lwz   r2,PC(r1)
578
/*      l.addi  r2,r2,4                 /* EPCR was pointing to l.sys instruction, we have to incremet it */
579
        l.sw    PC(r1),r2
580
        l.movhi r2,hi(_sys_call_table)
581
        l.ori   r2,r2,lo(_sys_call_table)
582
        l.slli  r11,r11,2
583
        l.add   r2,r2,r11
584
        l.lwz   r2,0(r2)
585
        l.addi  r8,r1,0                 /* regs pointer */
586
        l.jalr  r2
587
        l.nop
588
        l.sw    GPR11(r1),r11           /* save return value */
589
 
590
        RETURN_FROM_INT(0xc00)
591
 
592
/*
593
 * This routine switches between two different tasks.  The process
594
 * state of one is saved on its kernel stack.  Then the state
595
 * of the other is restored from its kernel stack.  The memory
596
 * management hardware is updated to the second process's state.
597
 * Finally, we can return to the second process, via the 'return'.
598
 *
599
 * Note: there are two ways to get to the "going out" portion
600
 * of this code; either by coming in via the entry (_switch)
601
 * or via "fork" which must set up an environment equivalent
602
 * to the "_switch" path.  If you change this (or in particular, the
603
 * SAVE_REGS macro), you'll have to change the fork code also.
604
 */
605
__switch:
606
        l.sw    0(r0),r3                /* Temporary store r3 to add 0!!! */
607
        l.sw    4(r0),r1                /* Temporary store r1 to add 4!!! */
608
        l.mtspr r0,r9,SPR_EPCR_BASE     /* Link register to EPCR */
609
        l.mfspr r3,r0,SPR_SR            /* From SR to ESR */
610
        l.mtspr r0,r3,SPR_ESR_BASE
611
        SAVE_REGS(0x0FF0)
612
        l.sw    TSS_KSP(r3),r1          /* Set old stack pointer */
613
        l.lwz   r1,TSS_KSP(r4)          /* Load new stack pointer */
614
        RETURN_FROM_INT(0xFF0)
615
 
616
_ua_init:
617
        l.movhi r3,0x9c00
618
 
619
        l.addi r4,r0,0x7
620
        l.sb 0x2(r3),r4
621
 
622
        l.addi r4,r0,0x0
623
        l.sb 0x1(r3),r4
624
 
625
        l.addi r4,r0,0x3
626
        l.sb 0x3(r3),r4
627
 
628
        l.lbz  r5,3(r3)
629
        l.ori r4,r5,0x80
630
        l.sb  0x3(r3),r4
631
        l.sb  0x1(r3),r0
632
        l.addi  r4,r0,0x82
633
        l.sb  0x0(r3),r4
634
        l.sb  0x3(r3),r5
635
 
636
        l.jr  r9
637
        l.nop
638
 
639
_putc:
640
        l.movhi r4,0x9c00
641
 
642
        l.addi  r6,r0,0x20
643
1:      l.lbz   r5,5(r4)
644
        l.andi  r5,r5,0x20
645
        l.sfeq  r5,r6
646
        l.bnf   1b
647
        l.nop
648
 
649
        l.sb    0(r4),r3
650
 
651
        l.addi  r6,r0,0x60
652
1:      l.lbz   r5,5(r4)
653
        l.andi  r5,r5,0x60
654
        l.sfeq  r5,r6
655
        l.bnf   1b
656
        l.nop
657
 
658
        l.jr    r9
659
        l.nop
660
 
661
 
662
        .data
663
env:
664
        .long   0

powered by: WebSVN 2.1.0

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