Welcome to mirror list, hosted at ThFree Co, Russian Federation.

or1k-support.h « include « or1k « libgloss - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c29b064bed654912aa82bf77958cd1c78619c9ea (plain)
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
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
/* Copyright (c) 2014 Authors
 *
 * Contributor Julius Baxter <julius.baxter@orsoc.se>
 * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
 *
 * The authors hereby grant permission to use, copy, modify, distribute,
 * and license this software and its documentation for any purpose, provided
 * that existing copyright notices are retained in all copies and that this
 * notice is included verbatim in any distributions. No written agreement,
 * license, or royalty fee is required for any of the authorized uses.
 * Modifications to this software may be copyrighted by their authors
 * and need not follow the licensing terms described here, provided that
 * the new terms are clearly indicated on the first page of each file where
 * they apply.
 */

/* -------------------------------------------------------------------------- */
/* This program is commented throughout in a fashion suitable for processing
with Doxygen. */
/* -------------------------------------------------------------------------- */

#include <stdint.h>

#ifndef __OR1K_SUPPORT_H__
#define __OR1K_SUPPORT_H__

/*!
* \defgroup or1k_macros OR1K macros
* @{
*/

/*!
* Access byte-sized memory mapped register
*
* Used to access a byte-sized memory mapped register. It avoids usage errors
* when not defining register addresses volatile and handles casting correctly.
*
* Example for both read and write:
*
* \code
* uint8_t status = REG8(IPBLOCK_STATUS_REG_ADDR);
* REG8(IPBLOCK_ENABLE) = 1;
* \endcode
*
* \param add Register address
*/
#define REG8(add) *((volatile unsigned char *) (add))

/*!
* Access halfword-sized memory mapped register
*
* Used to access a 16 byte-sized memory mapped register. It avoids usage errors
* when not defining register addresses volatile and handles casting correctly.
*
* See REG8() for an example.
*
* \param add Register address
*/
#define REG16(add) *((volatile unsigned short *) (add))

/*!
* Access word-sized memory mapped register
*
* Used to access a word-sized memory mapped register. It avoids usage errors
* when not defining register addresses volatile and handles casting correctly.
*
* See REG8() for an example.
*
* \param add Register address
*/
#define REG32(add) *((volatile unsigned long *) (add))
/*!
* @}
*/

/*!
* \defgroup or1k_interrupts OR1K interrupt control
*
* Interrupt control function prototypes
*
* @{
*/

/*! Function pointer to interrupt handler functions */
typedef void (*or1k_interrupt_handler_fptr)(void* data);

/*!
* Add interrupt handler for interrupt line
*
* Registers a callback function for a certain interrupt line.
*
* \param line Interrupt line/id to register a handler for
* \param handler Handler to register
* \param data Data value passed to the handler
*/
void or1k_interrupt_handler_add(uint32_t line,
		or1k_interrupt_handler_fptr handler,
		void* data);

/*!
* Enable interrupts from a given line
*
* Unmask the given interrupt line. It is also important to enable interrupts
* in general, e.g., using or1k_interrupts_enable().
*
* \param line Interrupt line to enable
*/
void or1k_interrupt_enable(int line);

/*!
* Disable interrupts from a given line
*
* Mask given interrupt line. It can be unmasked using or1k_interrupt_enable().
*
* \param line Interrupt line to disable
*/
void or1k_interrupt_disable(int line);

/*!
* Disable interrupts
*
* This disables the interrupt exception. This is sufficient to disable all
* interrupts. It does not change the mask register (which is modified using
* or1k_interrupt_enable() and or1k_interrupt_disable()).
*
* The interrupt exception can be enabled using or1k_interrupts_enable().
*
* Finally, the status of the interrupt exception enable flag is returned by
* this function. That allows to call this function even if interrupts are
* already disabled. To restore the value of the interrupt exception enable
* flag, use the or1k_interrupts_restore() function. That way you avoid to
* accidentally enable interrupts. Example:
*
* \code
* void f() {
*   uint32_t interrupt_status = or1k_interrupts_disable();
*   // do something
*   or1k_interrupts_restore(status);
* }
* \endcode
*
* This code will preserve the original status of the interrupt enable flag.
*
* \return Interrupt exception enable flag before call
*/
uint32_t or1k_interrupts_disable(void);

/*!
* Enable interrupt exception
*
* Enable the interrupt exception. Beside the interrupt exception, it is also
* necessary to enable the individual interrupt lines using
* or1k_interrupt_enable().
*
* You should avoid using this function together with or1k_interrupts_disable()
* to guard atomic blocks as it unconditionally enables the interrupt
* exception (see documentation of or1k_interrupts_disable()).
*/
void or1k_interrupts_enable(void);

/*!
* Restore interrupt exception enable flag
*
* This function restores the given status to the processor.
* or1k_interrupts_restore(0) is identical to or1k_interrupts_disable() and
* or1k_interrupts_restore(SPR_SR_IEE) is identical to or1k_interrupts_enable().
*
* It is for example used to guard an atomic block and restore the original
* status of the interrupt exception enable flag as returned by
* or1k_interrupts_disable(). See the documentation of or1k_interrupts_disable()
* for a usage example.
*
* \param status Status of the flag to restore
*/
void or1k_interrupts_restore(uint32_t status);

/*!
 * Disable timer and interrupt exception
 *
 * This function disables the timer and interrupt exception to guard critical
 * sections. It returns the status of the enable bits before the critical
 * section, that is restored with or1k_critical_end().
 *
 * Example:
 * \code
 * ...
 * uint32_t status = or1k_critical_start();
 * // critical part
 * or1k_critical_end(status);
 * ...
 * \endcode
 *
 * \return Status of timer and interrupt exception at time of call
 */
uint32_t or1k_critical_begin();

/*!
 * Enable timer and interrupt exception
 *
 * Restore the timer and interrupt exception enable. The restore value is the
 * return value from or1k_critical_start().
 *
 * \param restore Interrupt and timer exception enable restore value
 */
void or1k_critical_end(uint32_t restore);
/*!
* @}
*/

/*!
* \defgroup or1k_exception Exception handling
* @{
*/
/*! Function pointer to an exception handler function */
typedef void (*or1k_exception_handler_fptr)(void);

/*!
* Register exception handler
*
* Register an exception handler for the given exception id. This handler is
* in the following then called when the exception occurs. You can thereby
* individually handle those exceptions.
*
* \param id Exception id
* \param handler Handler callback
*/
void or1k_exception_handler_add(int id, or1k_exception_handler_fptr handler);
/*!
* @}
*/

/*!
* \defgroup or1k_spr SPR access
* @{
*/

/*!
* Move value to special purpose register
*
* Move data value to a special purpose register
*
* \param spr SPR identifier, see spr-defs.h for macros
* \param value value to move to SPR
*/
static inline void or1k_mtspr (uint32_t spr, uint32_t value)
{
	__asm__ __volatile__ ("l.mtspr\t\t%0,%1,0": : "r" (spr), "r" (value));
}

/*!
* Copy value from special purpose register
*
* Copy a data value from the given special purpose register.
*
* \param spr SPR identifier, see spr-defs.h for macros
* \return SPR data value
*/
static inline uint32_t or1k_mfspr (uint32_t spr) {
	uint32_t value;
	__asm__ __volatile__ ("l.mfspr\t\t%0,%1,0" : "=r" (value) : "r" (spr));
	return value;
}
/*!
* @}
*/

/*!
* \defgroup or1k_util Miscellaneous utility functions
*
* @{
*/

/*!
* Report value to simulator
*
* Uses the built-in simulator functionality.
*
* \param value Value to report
*/
void or1k_report (unsigned long int value);

/*!
* Get (pseudo) random number
*
* This should return pseudo-random numbers, based on a Galois LFSR.
*
* \return (Pseudo) Random number
*/
unsigned long int or1k_rand(void);

/*!
 * Register UART callback
 *
 * This function sets a callback function that is called when a character is
 * received via UART. The callback function has no return and a gets the
 * character as parameter. When a character is received, the function is called.
 *
 * Example (UART echo):
 * \code
 * void uart_in(char c) {
 *   printf("%c", c); // Echo
 * }
 *
 * int main() {
 *   or1k_uart_set_read_cb(&uart_in);
 *   or1k_interrupts_enable();
 *
 *   while (1) {}
 * }
 * \endcode
 */
void or1k_uart_set_read_cb(void (*cb)(char c));
/*!
* @}
*/

/*!
* \defgroup or1k_cache Cache control
*
* @{
*/

/*!
* Enable instruction cache
*/
void or1k_icache_enable(void);

/*!
* Disable instruction cache
*/
void or1k_icache_disable(void);

/*!
* Flush instruction cache
*
* Invalidate instruction cache entry
*
* \param entry Entry to invalidate
*/
void or1k_icache_flush(uint32_t entry);

/*!
* Enable data cache
*/
void or1k_dcache_enable(void);

/*!
* Disable data cache
*/
void or1k_dcache_disable(void);

/*!
* Flush data cache
*
* Invalidate data cache entry
*
* \param entry Entry to invalidate
*/
void or1k_dcache_flush(unsigned long entry);
/*!
* @}
*/

/*!
* \defgroup or1k_mmu MMU control
* @{
*/

/*!
* Enable instruction MMU
*/
void or1k_immu_enable(void);

/*!
* Disable instruction MMU
*/
void or1k_immu_disable(void);

/*!
* Enable data MMU
*/
void or1k_dmmu_enable(void);

/*!
* Disable data MMU
*/
void or1k_dmmu_disable(void);
/*!
* @}
*/

/*!
* \defgroup or1k_timer Timer control
*
* The tick timer can be used for time measurement, operating system scheduling
* etc. By default it is initialized to continuously count the ticks of a
* certain period after calling or1k_timer_init(). The period can later be
* changed using or1k_timer_set_period().
*
* The timer is controlled using or1k_timer_enable(), or1k_timer_disable(),
* or1k_timer_restore(), or1k_timer_pause(). After initialization it is required
* to enable the timer the first time using or1k_timer_enable().
* or1k_timer_disable() only disables the tick timer interrupts, it does not
* disable the timer counting. If you plan to use a pair of or1k_timer_disable()
* and or1k_timer_enable() to protect sections of your code against interrupts
* you should use or1k_timer_disable() and or1k_timer_restore(), as it may be
* possible that the timer interrupt was not enabled before disabling it,
* enable would then start it unconditionally. or1k_timer_pause() pauses the
* counting.
*
* In the default mode you can get the tick value using or1k_timer_get_ticks()
* and reset this value using or1k_timer_reset_ticks().
*
* Example for using the default mode:
*
* \code
* int main() {
*   uint32_t ticks = 0;
*   uint32_t timerstate;
*   or1k_timer_init(100);
*   or1k_timer_enable();
*   while (1) {
*     while (ticks == or1k_timer_get_ticks()) { }
*     timerstate = or1k_timer_disable();
*     // do something atomar
*     or1k_timer_restore(timerstate);
*     if (ticks == 100) {
*       printf("A second elapsed\n");
*       or1k_timer_reset_ticks();
*       ticks = 0;
*     }
*   }
* }
* \endcode
*
* It is possible to change the mode of the tick timer using
* or1k_timer_set_mode(). Allowed values are the correct bit pattern (including
* the bit positions) for the TTMR register, it is recommended to use the macros
* defined in spr-defs.h. For example, implementing an operating system with
* scheduling decisions of varying duration favors the implementation of single
* run tick timer. Here, each quantum is started before leaving the operating
* system kernel. The counter can be restarted with or1k_timer_reset().
* Example:
*
* \code
* void tick_handler(void) {
*   // Make schedule decision
*   // and set new thread
*   or1k_timer_reset();
*   // End of exception, new thread will run
* }
*
* int main() {
*   // Configure operating system and start threads..
*
*   // Configure timer
*   or1k_timer_init(50);
*   or1k_timer_set_handler(&tick_handler);
*   or1k_timer_set_mode(SPR_TTMR_SR);
*   or1k_timer_enable();
*
*   // Schedule first thread and die..
* }
* \endcode
*
* @{
*/

/*!
* Initialize tick timer
*
* This initializes the tick timer in default mode (see \ref or1k_timer for
* details).
*
* \param hz Initial period of the tick timer
* \return 0 if successful, -1 if timer not present
*/
int or1k_timer_init(unsigned int hz);

/*!
* Set period of timer
*
* Set the period of the timer to a value in Hz. The frequency from the board
* support package is used to determine the match value.
*/
void or1k_timer_set_period(uint32_t hz);

/*!
* Replace the timer interrupt handler
*
* By default the tick timer is used to handle timer ticks. The user can replace
* this with an own handler for example when implementing an operating system.
*
* \param handler The callback function pointer to the handler
*/
void or1k_timer_set_handler(void (*handler)(void));

/*!
* Set timer mode
*
* The timer has different modes (see architecture manual). The default is to
* automatically restart counting (SPR_TTMR_RT), others are single run
* (SPR_TTMR_SR) and continuous run (SPR_TTMR_CR).
*
* \param mode a valid mode (use definitions from spr-defs.h as it is important
* that those are also at the correct position in the bit field!)
*/
void or1k_timer_set_mode(uint32_t mode);

/*!
* Enable timer interrupt
*
* Enable the timer interrupt exception, independent of the status before.
* If you want to enable the timer conditionally, for example to implement a
* non-interruptible sequence of code, you should use or1k_timer_restore(). See
* the description of or1k_timer_disable() for more details.
*
* The enable will also restore the mode if the timer was paused previously.
*/
void or1k_timer_enable(void);

/*!
* Disable timer interrupt
*
* This disables the timer interrupt exception and returns the state of the
* interrupt exception enable flag before the call. This can be used with
* or1k_timer_restore() to implement sequences of code that are not allowed to
* be interrupted. Using or1k_timer_enable() will unconditionally enable the
* interrupt independent of the state before calling or1k_timer_disable().
* For an example see \ref or1k_timer.
*
* \return Status of timer interrupt before call
*/
uint32_t or1k_timer_disable(void);

/*!
* Restore timer interrupt exception flag
*
* Restores the timer interrupt exception flag as returned by
* or1k_timer_disable(). See the description of or1k_timer_disable() and \ref
* or1k_timer for details and an example.
*
* \param sr_tee Status of timer interrupt
*/
void or1k_timer_restore(uint32_t sr_tee);

/*!
* Pause timer counter
*
* Pauses the counter of the tick timer. The counter will hold its current value
* and it can be started again with or1k_timer_enable() which will restore the
* configured mode.
*/
void or1k_timer_pause(void);

/*!
* Reset timer counter
*/
void or1k_timer_reset(void);

/*!
* Get timer ticks
*
* Get the global ticks of the default configuration. This will increment the
* tick counter according to the preconfigured period.
*
* \return Current value of ticks
*/
unsigned long or1k_timer_get_ticks(void);

/*!
* Reset timer ticks
*
* Resets the timer ticks in default configuration to 0.
*/
void or1k_timer_reset_ticks(void);
/*!
* @}
*/

/*!
 * \defgroup or1k_multicore Multicore and Synchronization Support
 *
 * @{
 */

/*!
 * Compiled with multicore support
 *
 * \return 1 if compiled with multicore support, 0 otherwise
 */
uint32_t or1k_has_multicore_support(void);

/*!
 * Read core identifier
 *
 * \return Core identifier
 */
uint32_t or1k_coreid(void);

/*!
 * Read number of cores
 *
 * \return Total number of cores
 */
uint32_t or1k_numcores(void);

/*!
 * Load linked
 *
 * Load a value from the given address and link it. If the following
 * or1k_sync_sc() goes to the same address and there was no conflicting access
 * between loading and storing, the value is written back, else the write fails.
 *
 * \param address Address to load value from
 * \return Value read from the address
 */
uint32_t or1k_sync_ll(void *address);

/**
 * Store conditional
 *
 * Conditionally store a value to the address. The address must have been read
 * before using or1k_sync_ll() and there must be no other load link after that,
 * otherwise this will always fail. In case there was no other write to the same
 * address in between the load link and the store conditional, the store is
 * successful, otherwise it will also fail.
 *
 * \param address Address to conditionally store to
 * \param value Value to write to address
 * \return 1 if success, 0 if fail
 */
int or1k_sync_sc(void *address, uint32_t value);

/*!
 * Compare and Swap
 *
 * Loads a data item from the memory and compares a given value to it. If the
 * values match, a new value is written to the memory, if they mismatch, the
 * operation is aborted. The whole operation is atomic, i.e., it is guaranteed
 * that no other core changes the value between the read and the write.
 *
 * \param address Address to operate on
 * \param compare Compare value
 * \param swap New value to write
 * \return The value read from memory (can be used to check for success)
 */
uint32_t or1k_sync_cas(void *address, uint32_t compare, uint32_t swap);

/*!
 * Test and Set Lock
 *
 * Check for a lock on an address. This means, if there is 0 at an address it
 * will overwrite it with 1 and return 0. If the lock was already set (value
 * 1 read from address), the function returns 1. The operation is atomic.
 *
 * \param address Address of the lock
 * \return 0 if success, 1 if failed
 */
int or1k_sync_tsl(void *address);
/*!
 * @}
 */

#endif /* __NEWLIB_OR1K_SUPPORT_H__ */