URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/or1ksim/testsuite
- from Rev 432 to Rev 433
- ↔ Reverse comparison
Rev 432 → Rev 433
/test-code-or1k/int-logger/int-logger.c
0,0 → 1,185
/* int-logger.c. Test of Or1ksim handling of interrupts |
|
Copyright (C) 2010 Embecosm Limited |
|
Contributors various OpenCores participants |
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com> |
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify it |
under the terms of the GNU General Public License as published by the Free |
Software Foundation; either version 3 of the License, or (at your option) |
any later version. |
|
This program is distributed in the hope that it will be useful, but WITHOUT |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
more details. |
|
You should have received a copy of the GNU General Public License along |
with this program. If not, see <http: www.gnu.org/licenses/>. */ |
|
/* ---------------------------------------------------------------------------- |
This code is commented throughout for use with Doxygen. |
--------------------------------------------------------------------------*/ |
|
#include "support.h" |
#include "spr-defs.h" |
#include "board.h" |
|
|
/* --------------------------------------------------------------------------*/ |
/*!Write a memory mapped register |
|
@param[in] addr Memory mapped address |
@param[in] value Value to set */ |
/* --------------------------------------------------------------------------*/ |
static void |
setreg (unsigned long addr, |
unsigned char value) |
{ |
*((volatile unsigned char *) addr) = value; |
|
} /* setreg () */ |
|
|
/* --------------------------------------------------------------------------*/ |
/*!Read a memory mapped register |
|
@param[in] addr Memory mapped address |
|
@return Value read */ |
/* --------------------------------------------------------------------------*/ |
unsigned long |
getreg (unsigned long addr) |
{ |
return *((volatile unsigned char *) addr); |
|
} /* getreg () */ |
|
|
/* --------------------------------------------------------------------------*/ |
/*!Count the number of ones in a register |
|
SIMD Within A Register (SWAR) algorithm from Aggregate Magic Algorithms |
(http://aggregate.org/MAGIC/) from the University of Kentucky. |
|
32-bit recursive reduction using SWAR. First step is mapping 2-bit |
values into sum of 2 1-bit values in sneaky way. |
|
@param[in] x The 32-bit register whose bits are to be counted. |
|
@return The number of bits that are set to 1. */ |
/* --------------------------------------------------------------------------*/ |
static int |
ones32 (unsigned long int x) |
{ |
x -= ((x >> 1) & 0x55555555); |
x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); |
x = (((x >> 4) + x) & 0x0f0f0f0f); |
x += (x >> 8); |
x += (x >> 16); |
|
return (x & 0x0000003f); |
|
} /* ones32 () */ |
|
/* --------------------------------------------------------------------------*/ |
/*!Count the number of ones in a register |
|
SIMD Within A Register (SWAR) algorithm from Aggregate Magic Algorithms |
(http://aggregate.org/MAGIC/) from the University of Kentucky. |
|
Compute the log to base 2 of a supplied numger. In this case we know it will |
be an exact power of 2. We return -1 if asked for log (0). |
|
@param[in] x The 32-bit register whose log to base 2 we want. |
|
@return The log to base 2 of the argument, or -1 if the argument was |
zero. */ |
/* --------------------------------------------------------------------------*/ |
static int |
int_log2 (unsigned int x) |
{ |
x |= (x >> 1); |
x |= (x >> 2); |
x |= (x >> 4); |
x |= (x >> 8); |
x |= (x >> 16); |
|
return ones32 (x) - 1; |
|
} /* int_log2 () */ |
|
|
/* --------------------------------------------------------------------------*/ |
/*!Generic interrupt handler |
|
This should receive the interrupt exception. Report the value in PICSR. |
|
Potentially PICSR has multiple bits set, so we report the least significant |
bit. This is consistent with an approach which gives highest priority to |
any NMI lines (0 or 1). |
|
It is up to the external agent to clear the interrupt. We prompt it by |
writing the number of the interrupt we have just received. */ |
/* --------------------------------------------------------------------------*/ |
static void |
interrupt_handler () |
{ |
unsigned long int picsr = mfspr (SPR_PICSR); |
|
printf ("PICSR = 0x%08lx\n", picsr); |
setreg (GENERIC_BASE, int_log2 (picsr & -picsr)); |
|
} /* interrupt_handler () */ |
|
|
/* --------------------------------------------------------------------------*/ |
/*!Main program to set up interrupt handler |
|
We make a series of read upcalls, after 500 us and then every 1000us, which |
prompt some interrupts being set and cleared. By doing this, our upcalls |
should always be well clear of any calling function interrupt generation, |
which is on millisecond boundaries. |
|
A read upcall is a request to trigger an interrupt. We will subsequently |
use a write upcall in the interrupt handler to request clearing of the |
interrupt. |
|
@return The return code from the program (always zero). */ |
/* --------------------------------------------------------------------------*/ |
int |
main () |
{ |
printf ("Starting interrupt handler\n"); |
excpt_int = (unsigned long)interrupt_handler; |
|
/* Enable interrupts */ |
printf ("Enabling interrupts.\n"); |
mtspr (SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE); |
mtspr (SPR_PICMR, 0xffffffff); |
|
/* Loop forever, upcalling at the desired intervals. */ |
unsigned long int start = read_timer (); |
|
while (1) |
{ |
static long int end_time = 500; |
|
while ((read_timer () - start) < end_time) |
{ |
} |
|
/* Read to request an interrupt */ |
(void)getreg (GENERIC_BASE); |
|
/* Wait 1000us before next upcall. */ |
end_time += 1000; |
} |
|
/* We don't actually ever return */ |
return 0; |
|
} /* main () */ |
test-code-or1k/int-logger/int-logger.c
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: test-code/lib-inttest/lib-inttest.c
===================================================================
--- test-code/lib-inttest/lib-inttest.c (nonexistent)
+++ test-code/lib-inttest/lib-inttest.c (revision 433)
@@ -0,0 +1,285 @@
+/* lib-inttest.c. Test of Or1ksim library interrupt funcs.
+
+ Copyright (C) 1999-2006 OpenCores
+ Copyright (C) 2010 Embecosm Limited
+
+ Contributors various OpenCores participants
+ Contributor Jeremy Bennett
+
+ This file is part of OpenRISC 1000 Architectural Simulator.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see . */
+
+/* ----------------------------------------------------------------------------
+ This code is commented throughout for use with Doxygen.
+ --------------------------------------------------------------------------*/
+
+#include
+#include
+#include
+#include
+
+#include "or1ksim.h"
+
+
+/*! Number of interrupts in PIC */
+#define NUM_INTS 32
+
+/*! Number of the PICSR SPR. */
+#define SPR_PICSR 0x4802
+
+/*! Flag indicating if we are using level sensitive interrupts */
+static int level_sensitive_p;
+
+/*! Vector of interrupt numbers. */
+static int *intv;
+
+/*! Count of interrupts. */
+static int intc = 0;
+
+/*! Next interrupt */
+static int next_int = 0;
+
+
+/* --------------------------------------------------------------------------*/
+/*!Read upcall
+
+ Upcall from Or1ksim to read a word from an external peripheral. If called
+ this will trigger an interrupt.
+
+ We may get an end case where we are asked for an interrupt, but have no
+ more to give. We silently ignore this - it is just due to allowing the
+ target program enough time to finish.
+
+ @param[in] class_ptr A handle pass back from the initalization. Intended
+ for C++ callers, not used here.
+ @param[in] addr Address to read from. Ignored here.
+ @param[in] mask Byte mask for the read. Ignored here.
+ @param[out] rdata Buffer for the data read. Ignored here.
+ @param[in] data_len Number of bytes in mask and rdata.
+
+ @return Zero on success, non-zero on failure. Always zero here. */
+/* --------------------------------------------------------------------------*/
+static int
+read_upcall (void *class_ptr,
+ unsigned long int addr,
+ unsigned char mask[],
+ unsigned char rdata[],
+ int data_len)
+{
+ if (next_int < intc)
+ {
+ int inum = intv[next_int++];
+
+ printf ("Triggering interrupt %d\n", inum);
+
+ if (level_sensitive_p)
+ {
+ or1ksim_interrupt_set (inum);
+ }
+ else
+ {
+ or1ksim_interrupt (inum);
+ }
+ }
+
+ return 0; /* Success */
+
+} /* read_upcall () */
+
+
+/* --------------------------------------------------------------------------*/
+/*!Write upcall
+
+ Upcall from Or1ksim to write a word to an external peripheral. If called
+ this will clear an interrupt. The data is the number of the interrupt to
+ clear.
+
+ @param[in] class_ptr A handle pass back from the initalization. Intended
+ for C++ callers, not used here.
+ @param[in] addr Address to write to. Ignored here.
+ @param[in] mask Byte mask for the write. Ignored here.
+ @param[in] wdata The data to write. Ignored here.
+ @param[in] data_len Number of bytes in mask and rdata.
+
+ @return Zero on success, non-zero on failure. Always zero here. */
+/* --------------------------------------------------------------------------*/
+static int
+write_upcall (void *class_ptr,
+ unsigned long int addr,
+ unsigned char mask[],
+ unsigned char wdata[],
+ int data_len)
+{
+ /* Extract the inum */
+ int inum = wdata[0];
+
+ printf ("Clearing interrupt %d\n", inum);
+
+ if (level_sensitive_p)
+ {
+ or1ksim_interrupt_clear (inum);
+ }
+ else
+ {
+ unsigned long int picsr;
+
+ if (!or1ksim_read_spr (SPR_PICSR, &picsr))
+ {
+ fprintf (stderr, "ERROR failed to read PICSR: Exiting.\n");
+ exit (1);
+ }
+
+ picsr &= ~(1UL << inum);
+ printf ("Cleared PICSR is 0x%08lx\n", picsr);
+
+ if (!or1ksim_write_spr (SPR_PICSR, picsr))
+ {
+ fprintf (stderr, "ERROR failed to write PICSR: Exiting.\n");
+ exit (1);
+ }
+ }
+
+ return 0; /* Success */
+
+} /* write_upcall () */
+
+
+/* --------------------------------------------------------------------------*/
+/*!Main program
+
+ Build an or1ksim program using the library which loads a program and config
+ from the command line, and then drives interrupts. Usage:
+
+ lib-inttest -l|-e ...
+
+ is run continuously. It requests that the next interrupt event be
+ triggered by a read upcall. Clearing an interrupt occurs when a write
+ upcall is received.
+
+ The third argument specifies whether the level senstive (-l) or edge
+ triggered (-e) mechanism should be used for setting and clearing
+ interrupts.
+
+ @param[in] argc Number of elements in argv
+ @param[in] argv Vector of program name and arguments
+
+ @return Return code for the program. */
+/* --------------------------------------------------------------------------*/
+int
+main (int argc,
+ char *argv[])
+{
+ const int INT_OFF = 4; /* Offset in argv of interrupts */
+ int i; /* General counter */
+
+ /* Parse args */
+ if (argc < (INT_OFF + 1))
+ {
+ fprintf (stderr,
+ "usage: lib-inttest-level -l|-e "
+ " ...\n");
+ return 1;
+ }
+
+ /* What type of interrupt? */
+ if (0 == strcmp ("-l", argv[3]))
+ {
+ level_sensitive_p = 1;
+ }
+ else if (0 == strcmp ("-e", argv[3]))
+ {
+ level_sensitive_p = 0;
+ }
+ else
+ {
+ fprintf (stderr, "ERROR: Must specify -l or -e: exiting\n");
+ exit (1);
+ }
+
+ /* Get all the interrupts sorted out into the vector. We hold them with one
+ greater than absolute value, so we can distinguish between +0 and -0. */
+ intv = malloc ((argc - INT_OFF) * sizeof (int));
+
+ for (i = INT_OFF; i < argc; i++)
+ {
+ int inum = atoi (argv[i]);
+
+ if ((inum <= 0) || (NUM_INTS <= inum))
+ {
+ printf ("Warning: Invalid interrupt # %d to raise: Exiting.\n", inum);
+ exit (1);
+ }
+
+ intv[i - INT_OFF] = inum;
+ }
+
+ /* Global counters */
+ intc = argc - INT_OFF;
+ next_int = 0;
+
+ /* Dummy argv array to pass arguments to or1ksim_init. Varies depending on
+ whether an image file is specified. */
+ int dummy_argc;
+ char *dummy_argv[5];
+
+ dummy_argv[0] = "libsim";
+ dummy_argv[1] = "-q";
+ dummy_argv[2] = "-f";
+ dummy_argv[3] = argv[1];
+ dummy_argv[4] = argv[2];
+
+ dummy_argc = 5;
+
+ /* Initialize the program. Put the initialization message afterwards, or it
+ will get swamped by the Or1ksim header. */
+ if (0 == or1ksim_init (dummy_argc, dummy_argv, NULL, &read_upcall,
+ &write_upcall))
+ {
+ printf ("Initalization succeeded.\n");
+ }
+ else
+ {
+ printf ("ERROR: Initalization failed.\n");
+ free (intv);
+ exit (1);
+ }
+
+ /* Run in bursts of 1ms until all interrupts have been set and cleared. */
+ do
+ {
+ if (OR1KSIM_RC_OK != or1ksim_run (1.0e-3))
+ {
+ printf ("ERROR: run failed\n");
+ free (intv);
+ exit (1);
+ }
+ }
+ while (next_int < intc);
+
+ /* One more burst to allow the device driver time to complete. */
+ if (OR1KSIM_RC_OK != or1ksim_run (1.0e-3))
+ {
+ printf ("ERROR: run failed\n");
+ free (intv);
+ exit (1);
+ }
+
+ /* All interrupts should have been handled. */
+ free (intv);
+
+ printf ("Test completed successfully.\n");
+ return 0;
+
+} /* main () */
test-code/lib-inttest/lib-inttest.c
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property