summaryrefslogtreecommitdiff
path: root/src/systemc/tests/systemc/misc/stars/star110089/star110089.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/tests/systemc/misc/stars/star110089/star110089.cpp')
-rw-r--r--src/systemc/tests/systemc/misc/stars/star110089/star110089.cpp403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/systemc/tests/systemc/misc/stars/star110089/star110089.cpp b/src/systemc/tests/systemc/misc/stars/star110089/star110089.cpp
new file mode 100644
index 000000000..912af5eab
--- /dev/null
+++ b/src/systemc/tests/systemc/misc/stars/star110089/star110089.cpp
@@ -0,0 +1,403 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ star110089.cpp --
+
+ Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ MODIFICATION LOG - modifiers, enter your name, affiliation, date and
+ changes you are making here.
+
+ Name, Affiliation, Date:
+ Description of Modification:
+
+ *****************************************************************************/
+
+/***********************************************************************
+
+Things I had to do to make this work with the SystemC compiler
+
+Remove LP_STATS-related #ifdefs
+
+Added SystemC module interface. Odd function wrapper, wait()s.
+
+Removed use of pointers into lp_table (replaced with array references).
+
+Global variables are not allowed, so move lp_table into the function.
+
+Pointers appear to have problems, so comment out test of the "dev" field.
+
+The LP_POLLED macro checks lp_table[minor].dev->port->irq (three dereferences),
+which is not synthesizable. I replaced it with a constant.
+
+w_ctr writes to the control I/O port. We want to observe this, so added
+a port to the module, made the function a member function (not just static).
+
+Want to observe successive values on the control port, so added a wait() after
+it is written.
+
+Adding the main do loop (there's an if () return statement earlier)
+gives "WAITs not balanced" errors, even without any wait() statements
+at all. Adding them doesn't appear to help (Evidentally, I'm not
+adding them correctly.)
+
+How to model memory? Specifically, how to model copy_from_user() and
+accesses to buffer memory? I'll create address, data, and read/write ports
+for each memory space, memory access functions that toggle these ports,
+and finally a replacement for copy_from_user().
+
+Pointers seem to be broken (BC gives the inscrutable
+
+ Error: Width mismatch on port 'n5[1]' of reference to 'group1' in
+ 'lp_write_buf.db:loop_117_design'. (LINK-3)
+
+so I'll use a pchar_t type as a replacement.
+
+The const declarations don't work now with typedef unsigned int pchar_t, so
+I removed them.
+
+Was getting "unschedulable" errors until I inserted a few wait() statements.
+(Very unhelpful diagnostics.)
+
+Inserting and removing wait()s at will seems to help, but I'm still getting
+width mismatch errors.
+
+The width mismatch errors are due to a SystemC compiler bug. Adding
+-Xgroup_idx_logic=0 to the command line eliminates them.
+
+Many "mismatched clock" statements appear to be due to the use of nested
+return stataments. BC doesn't support exits from any more than a single
+level of loop nesting, so whatever hack the SystemC people did is not solid.
+
+if statements with a return in one branch seems to cause unsolvable wait
+balance problems. I'll rewrite many of them to put the code in the "else"
+branch.
+
+For if-then with a return within a loop, I appear to need to add an error
+flag and checks for it.
+
+Doing this makes the system schedulable, but even these few lines of code
+turn into over 1 MB of .db file, take 300MB of core and ten minutes to run.
+This corresponds to roughly 140 lines of C code: four conditionals, two
+nested loops, and one function call.
+
+***********************************************************************/
+
+typedef unsigned int pchar_t;
+
+/**********************************************************************
+
+SystemC-specific things
+
+**********************************************************************/
+
+#include "systemc.h"
+
+SC_MODULE(lp_write_buf) {
+ sc_in_clk clk;
+ sc_in<bool> reset;
+ sc_in<unsigned> minor;
+ sc_in<unsigned> buf; /* a pointer */
+ sc_in<int> count;
+
+ sc_out<int> result; /* return code */
+ sc_out<bool> result_ready; /* return flag */
+
+ sc_out<char> control; /* printer control port */
+
+ sc_inout<unsigned> user_addr; /* user memory address */
+ sc_in<char> user_read_data; /* user data value */
+ sc_out<bool> user_read; /* user memory read flag */
+
+ sc_out<unsigned> kernel_addr; /* kernel memory address */
+ sc_in<char> kernel_read_data; /* kernel data value */
+ sc_out<char> kernel_write_data; /* kernel data value */
+ sc_out<bool> kernel_read;
+ sc_out<bool> kernel_write;
+
+ sc_out<bool> invalid_read; /* debugging flag: should never be true */
+
+ void lp_write_buf_body();
+ int lp_write_buf_f(unsigned int minor, pchar_t buf, int count);
+
+ /* User and kernel memory operations */
+ char read_from_user(unsigned a);
+ char read_from_kernel(unsigned a);
+ void write_to_kernel(unsigned a, char d);
+
+ int copy_from_user(pchar_t, pchar_t, unsigned long);
+
+ /* Output verification */
+ void check_read_address();
+
+ SC_CTOR(lp_write_buf)
+ {
+ SC_CTHREAD(lp_write_buf_body, clk.pos());
+ reset_signal_is(reset,true);
+ SC_CTHREAD(check_read_address, clk.pos());
+ reset_signal_is(reset,true);
+ }
+};
+
+void lp_write_buf::check_read_address()
+{
+ /* This causes the systemC compiler a fatal internal error */
+ for (;;) {
+ invalid_read = user_addr < buf || user_addr >= buf + count;
+ wait();
+ }
+}
+
+
+void lp_write_buf::lp_write_buf_body()
+{
+ unsigned dummy; /* These three statements compensate for BC weirdness */
+ dummy = 0;
+ wait();
+ for (;;) {
+ result = 0; result_ready = 0;
+ unsigned res = lp_write_buf_f(minor, buf, count);
+ result = (int) res; result_ready = 1;
+ wait();
+ result_ready = 0;
+ wait();
+ }
+}
+
+char lp_write_buf::read_from_user(unsigned a)
+{
+ char d;
+ user_addr = a;
+ user_read = 1;
+ wait();
+ d = user_read_data;
+ user_read = 0;
+ wait();
+ return d;
+}
+
+char lp_write_buf::read_from_kernel(unsigned a)
+{
+ char d;
+ kernel_addr = a;
+ kernel_read = 1;
+ wait();
+ d = kernel_read_data;
+ kernel_read = 0;
+ wait();
+ return d;
+}
+
+void lp_write_buf::write_to_kernel(unsigned a, char d)
+{
+ kernel_addr = a;
+ kernel_write_data = d;
+ kernel_write = 1;
+ wait();
+ kernel_write = 0;
+ wait();
+}
+
+int lp_write_buf::copy_from_user(pchar_t src, pchar_t dest,
+ unsigned long count)
+{
+ for ( ; count > 0 ; count--)
+ write_to_kernel(dest++, read_from_user(src++));
+ /* What about an error? */
+ return 0;
+}
+
+/********************************************************************
+ "Normal" C begins here
+ ********************************************************************/
+
+#define ENXIO 6 /* No such device or address */
+#define EFAULT 14 /* Bad address */
+
+// #define NULL 0
+
+#define LP_PINTEN 0x10 /* high to read data in or-ed with data out */
+#define LP_PSELECP 0x08 /* inverted output, active low */
+#define LP_PINITP 0x04 /* unchanged output, active low */
+#define LP_PAUTOLF 0x02 /* inverted output, active low */
+#define LP_PSTROBE 0x01 /* short high output on raising edge */
+
+/* #define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) */
+#define LP_POLLED(minor) 1
+
+#define w_ctr(dev,val) (control = (val))
+
+#define LP_NO 3
+#define LP_BUFFER_SIZE 32
+
+struct lp_struct {
+ /* struct pardevice *dev; */
+ pchar_t dev;
+ unsigned long flags;
+ unsigned int chars;
+ unsigned int time;
+ /* unsigned int wait; */
+ pchar_t lp_buffer;
+ /* struct wait_queue *wait_q; */
+ unsigned int last_error;
+ volatile unsigned int irq_detected:1;
+ volatile unsigned int irq_missed:1;
+};
+
+/* Write count bytes starting at buf in user space to the parallel port
+ defined by the minor device number */
+
+int lp_write_buf::lp_write_buf_f(unsigned int minor,
+ pchar_t buf, int count)
+{
+ int err;
+ struct lp_struct lp_table[LP_NO];
+
+ /* Added to fake a device */
+ lp_table[minor].dev = 5;
+
+ unsigned long copy_size;
+ unsigned long total_bytes_written = 0;
+ unsigned long bytes_written;
+ /* Removed because pointers are prohibited */
+ /* struct lp_struct *lp = &lp_table[minor]; */
+
+ if (minor >= LP_NO) {
+ wait();
+ return -ENXIO;
+ } else {
+
+ /* if (lp->dev == NULL) */ /* Removed because of a pointer */
+ /* The following causes a BC error (bad matching width of n15[1]) */
+ if (lp_table[minor].dev == 0) {
+ wait();
+ return -ENXIO;
+ } else {
+
+ lp_table[minor].last_error = 0;
+ lp_table[minor].irq_detected = 0;
+ lp_table[minor].irq_missed = 1;
+
+ if (LP_POLLED(minor))
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ else
+ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
+
+ err = 0;
+ wait();
+ do {
+ wait();
+ bytes_written = 0;
+ copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
+
+
+ /* Adding this gives width mismatch errors */
+ if (copy_from_user(lp_table[minor].lp_buffer, buf, copy_size)) {
+ wait();
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ // return -EFAULT;
+ err = -EFAULT;
+ } else {
+
+ /** Fake! **/
+ bytes_written = copy_size;
+
+#if 0
+
+ while (copy_size) {
+ if (lp_char(lp->lp_buffer[bytes_written], minor)) {
+ --copy_size;
+ ++bytes_written;
+ } else {
+ int rc = total_bytes_written + bytes_written;
+
+
+ if (signal_pending(current))
+ {
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ if (total_bytes_written + bytes_written)
+ return total_bytes_written + bytes_written;
+ else
+ return -EINTR;
+ }
+
+ if (lp_check_status(minor))
+ {
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ return rc ? rc : -EIO;
+ }
+
+ if (LP_POLLED(minor) ||
+ lp_table[minor].irq_missed)
+ {
+ lp_polling:
+ current->state = TASK_INTERRUPTIBLE;
+ lp_schedule(minor, LP_TIME(minor));
+ } else {
+ cli();
+ if (LP_PREEMPTED(minor))
+ {
+ /*
+ * We can' t sleep on the interrupt
+ * since another pardevice need the port.
+ * We must check this in a cli() protected
+ * envinroment to avoid parport sharing
+ * starvation.
+ */
+ sti();
+ goto lp_polling;
+ }
+ if (!lp_table[minor].irq_detected)
+ interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);
+ sti();
+ }
+ }
+ }
+
+#endif
+
+ total_bytes_written += bytes_written;
+ buf += bytes_written;
+ count -= bytes_written;
+
+ wait();
+ }
+
+ } while (count > 0 && err >= 0);
+
+ wait();
+
+ if (err >= 0 ) {
+
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ return total_bytes_written;
+ } else {
+ return err;
+ }
+
+ }
+ }
+}
+