star110089.cpp revision 12855:588919e0e4aa
112771Sqtt2@cornell.edu/*****************************************************************************
212771Sqtt2@cornell.edu
312771Sqtt2@cornell.edu  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412771Sqtt2@cornell.edu  more contributor license agreements.  See the NOTICE file distributed
512771Sqtt2@cornell.edu  with this work for additional information regarding copyright ownership.
612771Sqtt2@cornell.edu  Accellera licenses this file to you under the Apache License, Version 2.0
712771Sqtt2@cornell.edu  (the "License"); you may not use this file except in compliance with the
812771Sqtt2@cornell.edu  License.  You may obtain a copy of the License at
912771Sqtt2@cornell.edu
1012771Sqtt2@cornell.edu    http://www.apache.org/licenses/LICENSE-2.0
1112771Sqtt2@cornell.edu
1212771Sqtt2@cornell.edu  Unless required by applicable law or agreed to in writing, software
1312771Sqtt2@cornell.edu  distributed under the License is distributed on an "AS IS" BASIS,
1412771Sqtt2@cornell.edu  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512771Sqtt2@cornell.edu  implied.  See the License for the specific language governing
1612771Sqtt2@cornell.edu  permissions and limitations under the License.
1712771Sqtt2@cornell.edu
1812771Sqtt2@cornell.edu *****************************************************************************/
1912771Sqtt2@cornell.edu
2012771Sqtt2@cornell.edu/*****************************************************************************
2112771Sqtt2@cornell.edu
2212771Sqtt2@cornell.edu  star110089.cpp --
2312771Sqtt2@cornell.edu
2412771Sqtt2@cornell.edu  Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15
2512771Sqtt2@cornell.edu
2612771Sqtt2@cornell.edu *****************************************************************************/
2712771Sqtt2@cornell.edu
2812771Sqtt2@cornell.edu/*****************************************************************************
2912771Sqtt2@cornell.edu
3012771Sqtt2@cornell.edu  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3112771Sqtt2@cornell.edu  changes you are making here.
3212771Sqtt2@cornell.edu
3312771Sqtt2@cornell.edu      Name, Affiliation, Date:
3412771Sqtt2@cornell.edu  Description of Modification:
3512771Sqtt2@cornell.edu
3612771Sqtt2@cornell.edu *****************************************************************************/
3712771Sqtt2@cornell.edu
3812771Sqtt2@cornell.edu/***********************************************************************
3912771Sqtt2@cornell.edu
4012771Sqtt2@cornell.eduThings I had to do to make this work with the SystemC compiler
4112771Sqtt2@cornell.edu
42Remove LP_STATS-related #ifdefs
43
44Added SystemC module interface.  Odd function wrapper, wait()s.
45
46Removed use of pointers into lp_table (replaced with array references).
47
48Global variables are not allowed, so move lp_table into the function.
49
50Pointers appear to have problems, so comment out test of the "dev" field.
51
52The LP_POLLED macro checks lp_table[minor].dev->port->irq (three dereferences),
53which is not synthesizable.  I replaced it with a constant.
54
55w_ctr writes to the control I/O port.  We want to observe this, so added
56a port to the module, made the function a member function (not just static).
57
58Want to observe successive values on the control port, so added a wait() after
59it is written.
60
61Adding the main do loop (there's an if () return statement earlier)
62gives "WAITs not balanced" errors, even without any wait() statements
63at all.  Adding them doesn't appear to help (Evidentally, I'm not
64adding them correctly.)
65
66How to model memory?  Specifically, how to model copy_from_user() and
67accesses to buffer memory?  I'll create address, data, and read/write ports
68for each memory space, memory access functions that toggle these ports,
69and finally a replacement for copy_from_user().
70
71Pointers seem to be broken (BC gives the inscrutable
72
73    Error: Width mismatch on port 'n5[1]' of reference to 'group1' in
74   'lp_write_buf.db:loop_117_design'. (LINK-3)
75
76so I'll use a pchar_t type as a replacement.
77
78The const declarations don't work now with typedef unsigned int pchar_t, so
79I removed them.
80
81Was getting "unschedulable" errors until I inserted a few wait() statements.
82(Very unhelpful diagnostics.)
83
84Inserting and removing wait()s at will seems to help, but I'm still getting
85width mismatch errors.
86
87The width mismatch errors are due to a SystemC compiler bug.  Adding
88-Xgroup_idx_logic=0 to the command line eliminates them.
89
90Many "mismatched clock" statements appear to be due to the use of nested
91return stataments.  BC doesn't support exits from any more than a single
92level of loop nesting, so whatever hack the SystemC people did is not solid.
93
94if statements with a return in one branch seems to cause unsolvable wait
95balance problems.  I'll rewrite many of them to put the code in the "else"
96branch.
97
98For if-then with a return within a loop, I appear to need to add an error
99flag and checks for it.
100
101Doing this makes the system schedulable, but even these few lines of code
102turn into over 1 MB of .db file, take 300MB of core and ten minutes to run.
103This corresponds to roughly 140 lines of C code: four conditionals, two
104nested loops, and one function call.
105
106***********************************************************************/
107
108typedef unsigned int pchar_t;
109
110/**********************************************************************
111
112SystemC-specific things
113
114**********************************************************************/
115
116#include "systemc.h"
117
118SC_MODULE(lp_write_buf) {
119  sc_in_clk         clk;
120  sc_in<bool>       reset;
121  sc_in<unsigned>   minor;
122  sc_in<unsigned>   buf;   /* a pointer */
123  sc_in<int>        count;
124
125  sc_out<int>       result;       /* return code */
126  sc_out<bool>      result_ready; /* return flag */
127
128  sc_out<char>      control;      /* printer control port */
129
130  sc_inout<unsigned>  user_addr;	  /* user memory address */
131  sc_in<char>       user_read_data; /* user data value */
132  sc_out<bool>      user_read;    /* user memory read flag */
133
134  sc_out<unsigned>  kernel_addr;  /* kernel memory address */
135  sc_in<char>       kernel_read_data; /* kernel data value */
136  sc_out<char>      kernel_write_data; /* kernel data value */
137  sc_out<bool>      kernel_read;
138  sc_out<bool>      kernel_write;
139
140  sc_out<bool>      invalid_read; /* debugging flag: should never be true */
141
142  void lp_write_buf_body();
143  int lp_write_buf_f(unsigned int minor,  pchar_t buf, int count);
144
145  /* User and kernel memory operations */
146  char read_from_user(unsigned a);
147  char read_from_kernel(unsigned a);
148  void write_to_kernel(unsigned a, char d);
149
150  int copy_from_user(pchar_t,  pchar_t, unsigned long);
151
152  /* Output verification */
153  void check_read_address();
154
155  SC_CTOR(lp_write_buf)
156  {
157    SC_CTHREAD(lp_write_buf_body, clk.pos());
158    reset_signal_is(reset,true);
159    SC_CTHREAD(check_read_address, clk.pos());
160    reset_signal_is(reset,true);
161  }
162};
163
164void lp_write_buf::check_read_address()
165{
166  /* This causes the systemC compiler a fatal internal error */
167  for (;;) {
168    invalid_read = user_addr < buf || user_addr >= buf + count;
169    wait();
170  }
171}
172
173
174void lp_write_buf::lp_write_buf_body()
175{
176  unsigned dummy; /* These three statements compensate for BC weirdness */
177  dummy = 0;
178  wait();
179  for (;;) {
180    result = 0; result_ready = 0;
181    unsigned res = lp_write_buf_f(minor, buf, count);
182    result = (int) res; result_ready = 1;
183    wait();
184    result_ready = 0;
185    wait();
186  }
187}
188
189char lp_write_buf::read_from_user(unsigned a)
190{
191  char d;
192  user_addr = a;
193  user_read = 1;
194  wait();
195  d = user_read_data;
196  user_read = 0;
197  wait();
198  return d;
199}
200
201char lp_write_buf::read_from_kernel(unsigned a)
202{
203  char d;
204  kernel_addr = a;
205  kernel_read = 1;
206  wait();
207  d = kernel_read_data;
208  kernel_read = 0;
209  wait();
210  return d;
211}
212
213void lp_write_buf::write_to_kernel(unsigned a, char d)
214{
215  kernel_addr = a;
216  kernel_write_data = d;
217  kernel_write = 1;
218  wait();
219  kernel_write = 0;
220  wait();
221}
222
223int lp_write_buf::copy_from_user(pchar_t src,  pchar_t dest,
224				 unsigned long count)
225{
226  for ( ; count > 0 ; count--)
227    write_to_kernel(dest++, read_from_user(src++));
228  /* What about an error? */
229  return 0;
230}
231
232/********************************************************************
233  "Normal" C begins here
234 ********************************************************************/
235
236#define	ENXIO		 6	/* No such device or address */
237#define	EFAULT		14	/* Bad address */
238
239// #define NULL             0
240
241#define LP_PINTEN	0x10  /* high to read data in or-ed with data out */
242#define LP_PSELECP	0x08  /* inverted output, active low */
243#define LP_PINITP	0x04  /* unchanged output, active low */
244#define LP_PAUTOLF	0x02  /* inverted output, active low */
245#define LP_PSTROBE	0x01  /* short high output on raising edge */
246
247/* #define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) */
248#define LP_POLLED(minor) 1
249
250#define w_ctr(dev,val) (control = (val))
251
252#define LP_NO 3
253#define LP_BUFFER_SIZE 32
254
255struct lp_struct {
256  /* struct pardevice *dev; */
257  pchar_t dev;
258  unsigned long flags;
259  unsigned int chars;
260  unsigned int time;
261  /*	unsigned int wait; */
262  pchar_t lp_buffer;
263  /* struct wait_queue *wait_q; */
264  unsigned int last_error;
265  volatile unsigned int irq_detected:1;
266  volatile unsigned int irq_missed:1;
267};
268
269/* Write count bytes starting at buf in user space to the parallel port
270   defined by the minor device number */
271
272int lp_write_buf::lp_write_buf_f(unsigned int minor,
273				 pchar_t buf, int count)
274{
275  int err;
276  struct lp_struct lp_table[LP_NO];
277
278  /* Added to fake a device */
279  lp_table[minor].dev = 5;
280
281  unsigned long copy_size;
282  unsigned long total_bytes_written = 0;
283  unsigned long bytes_written;
284  /* Removed because pointers are prohibited */
285  /* struct lp_struct *lp = &lp_table[minor]; */
286
287  if (minor >= LP_NO) {
288    wait();
289    return -ENXIO;
290  } else {
291
292    /*   if (lp->dev == NULL) */ /* Removed because of a pointer */
293    /* The following causes a BC error (bad matching width of n15[1]) */
294    if (lp_table[minor].dev == 0) {
295      wait();
296      return -ENXIO;
297    } else {
298
299      lp_table[minor].last_error = 0;
300      lp_table[minor].irq_detected = 0;
301      lp_table[minor].irq_missed = 1;
302
303      if (LP_POLLED(minor))
304	w_ctr(minor, LP_PSELECP | LP_PINITP);
305      else
306	w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
307
308      err = 0;
309      wait();
310      do {
311	wait();
312	bytes_written = 0;
313	copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
314
315
316	/* Adding this gives width mismatch errors */
317	if (copy_from_user(lp_table[minor].lp_buffer, buf, copy_size)) {
318	  wait();
319	  w_ctr(minor, LP_PSELECP | LP_PINITP);
320	  // return -EFAULT;
321	  err = -EFAULT;
322	} else {
323
324	/** Fake! **/
325	bytes_written = copy_size;
326
327#if 0
328
329	while (copy_size) {
330	  if (lp_char(lp->lp_buffer[bytes_written], minor)) {
331	    --copy_size;
332	    ++bytes_written;
333	  } else {
334	    int rc = total_bytes_written + bytes_written;
335
336
337	    if (signal_pending(current))
338	      {
339		w_ctr(minor, LP_PSELECP | LP_PINITP);
340		if (total_bytes_written + bytes_written)
341		  return total_bytes_written + bytes_written;
342		else
343		  return -EINTR;
344	      }
345
346	    if (lp_check_status(minor))
347	      {
348		w_ctr(minor, LP_PSELECP | LP_PINITP);
349		return rc ? rc : -EIO;
350	      }
351
352	    if (LP_POLLED(minor) ||
353		lp_table[minor].irq_missed)
354	      {
355	      lp_polling:
356		current->state = TASK_INTERRUPTIBLE;
357		lp_schedule(minor, LP_TIME(minor));
358	      } else {
359		cli();
360		if (LP_PREEMPTED(minor))
361		  {
362		    /*
363		     * We can' t sleep on the interrupt
364		     * since another pardevice need the port.
365		     * We must check this in a cli() protected
366		     * envinroment to avoid parport sharing
367		     * starvation.
368		     */
369		    sti();
370		    goto lp_polling;
371		  }
372		if (!lp_table[minor].irq_detected)
373		  interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);
374		sti();
375	      }
376	  }
377	}
378
379#endif
380
381	total_bytes_written += bytes_written;
382	buf += bytes_written;
383	count -= bytes_written;
384
385	wait();
386	}
387
388      } while (count > 0 && err >= 0);
389
390      wait();
391
392      if (err >= 0 ) {
393
394	w_ctr(minor, LP_PSELECP | LP_PINITP);
395	return total_bytes_written;
396      } else {
397	return err;
398      }
399
400    }
401  }
402}
403
404