star110089.cpp revision 12855:588919e0e4aa
12847Sksewell@umich.edu/*****************************************************************************
25596Sgblack@eecs.umich.edu
32847Sksewell@umich.edu  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
42847Sksewell@umich.edu  more contributor license agreements.  See the NOTICE file distributed
52847Sksewell@umich.edu  with this work for additional information regarding copyright ownership.
62847Sksewell@umich.edu  Accellera licenses this file to you under the Apache License, Version 2.0
72847Sksewell@umich.edu  (the "License"); you may not use this file except in compliance with the
82847Sksewell@umich.edu  License.  You may obtain a copy of the License at
92847Sksewell@umich.edu
102847Sksewell@umich.edu    http://www.apache.org/licenses/LICENSE-2.0
112847Sksewell@umich.edu
122847Sksewell@umich.edu  Unless required by applicable law or agreed to in writing, software
132847Sksewell@umich.edu  distributed under the License is distributed on an "AS IS" BASIS,
142847Sksewell@umich.edu  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
152847Sksewell@umich.edu  implied.  See the License for the specific language governing
162847Sksewell@umich.edu  permissions and limitations under the License.
172847Sksewell@umich.edu
182847Sksewell@umich.edu *****************************************************************************/
192847Sksewell@umich.edu
202847Sksewell@umich.edu/*****************************************************************************
212847Sksewell@umich.edu
222847Sksewell@umich.edu  star110089.cpp --
232847Sksewell@umich.edu
242847Sksewell@umich.edu  Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15
252847Sksewell@umich.edu
262847Sksewell@umich.edu *****************************************************************************/
272847Sksewell@umich.edu
285596Sgblack@eecs.umich.edu/*****************************************************************************
292847Sksewell@umich.edu
302847Sksewell@umich.edu  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
312847Sksewell@umich.edu  changes you are making here.
322847Sksewell@umich.edu
332847Sksewell@umich.edu      Name, Affiliation, Date:
345596Sgblack@eecs.umich.edu  Description of Modification:
356658Snate@binkert.org
365596Sgblack@eecs.umich.edu *****************************************************************************/
375596Sgblack@eecs.umich.edu
385596Sgblack@eecs.umich.edu/***********************************************************************
395596Sgblack@eecs.umich.edu
402847Sksewell@umich.eduThings I had to do to make this work with the SystemC compiler
415596Sgblack@eecs.umich.edu
425596Sgblack@eecs.umich.eduRemove LP_STATS-related #ifdefs
435596Sgblack@eecs.umich.edu
445596Sgblack@eecs.umich.eduAdded SystemC module interface.  Odd function wrapper, wait()s.
455596Sgblack@eecs.umich.edu
465596Sgblack@eecs.umich.eduRemoved use of pointers into lp_table (replaced with array references).
475596Sgblack@eecs.umich.edu
485596Sgblack@eecs.umich.eduGlobal variables are not allowed, so move lp_table into the function.
495596Sgblack@eecs.umich.edu
505596Sgblack@eecs.umich.eduPointers appear to have problems, so comment out test of the "dev" field.
515596Sgblack@eecs.umich.edu
525596Sgblack@eecs.umich.eduThe LP_POLLED macro checks lp_table[minor].dev->port->irq (three dereferences),
535596Sgblack@eecs.umich.eduwhich is not synthesizable.  I replaced it with a constant.
545596Sgblack@eecs.umich.edu
555596Sgblack@eecs.umich.eduw_ctr writes to the control I/O port.  We want to observe this, so added
565596Sgblack@eecs.umich.edua port to the module, made the function a member function (not just static).
575596Sgblack@eecs.umich.edu
585596Sgblack@eecs.umich.eduWant to observe successive values on the control port, so added a wait() after
595596Sgblack@eecs.umich.eduit is written.
605596Sgblack@eecs.umich.edu
615596Sgblack@eecs.umich.eduAdding the main do loop (there's an if () return statement earlier)
625596Sgblack@eecs.umich.edugives "WAITs not balanced" errors, even without any wait() statements
635596Sgblack@eecs.umich.eduat all.  Adding them doesn't appear to help (Evidentally, I'm not
645596Sgblack@eecs.umich.eduadding them correctly.)
655596Sgblack@eecs.umich.edu
665596Sgblack@eecs.umich.eduHow to model memory?  Specifically, how to model copy_from_user() and
675596Sgblack@eecs.umich.eduaccesses to buffer memory?  I'll create address, data, and read/write ports
685596Sgblack@eecs.umich.edufor each memory space, memory access functions that toggle these ports,
695596Sgblack@eecs.umich.eduand finally a replacement for copy_from_user().
705596Sgblack@eecs.umich.edu
715596Sgblack@eecs.umich.eduPointers seem to be broken (BC gives the inscrutable
725596Sgblack@eecs.umich.edu
735596Sgblack@eecs.umich.edu    Error: Width mismatch on port 'n5[1]' of reference to 'group1' in
745596Sgblack@eecs.umich.edu   'lp_write_buf.db:loop_117_design'. (LINK-3)
755596Sgblack@eecs.umich.edu
765596Sgblack@eecs.umich.eduso I'll use a pchar_t type as a replacement.
777720Sgblack@eecs.umich.edu
787720Sgblack@eecs.umich.eduThe const declarations don't work now with typedef unsigned int pchar_t, so
797720Sgblack@eecs.umich.eduI removed them.
805596Sgblack@eecs.umich.edu
815596Sgblack@eecs.umich.eduWas getting "unschedulable" errors until I inserted a few wait() statements.
827720Sgblack@eecs.umich.edu(Very unhelpful diagnostics.)
837720Sgblack@eecs.umich.edu
847720Sgblack@eecs.umich.eduInserting and removing wait()s at will seems to help, but I'm still getting
855596Sgblack@eecs.umich.eduwidth mismatch errors.
865596Sgblack@eecs.umich.edu
875596Sgblack@eecs.umich.eduThe width mismatch errors are due to a SystemC compiler bug.  Adding
885596Sgblack@eecs.umich.edu-Xgroup_idx_logic=0 to the command line eliminates them.
895596Sgblack@eecs.umich.edu
905596Sgblack@eecs.umich.eduMany "mismatched clock" statements appear to be due to the use of nested
915596Sgblack@eecs.umich.edureturn stataments.  BC doesn't support exits from any more than a single
925596Sgblack@eecs.umich.edulevel of loop nesting, so whatever hack the SystemC people did is not solid.
935596Sgblack@eecs.umich.edu
945596Sgblack@eecs.umich.eduif statements with a return in one branch seems to cause unsolvable wait
955596Sgblack@eecs.umich.edubalance problems.  I'll rewrite many of them to put the code in the "else"
965596Sgblack@eecs.umich.edubranch.
975596Sgblack@eecs.umich.edu
985596Sgblack@eecs.umich.eduFor if-then with a return within a loop, I appear to need to add an error
995596Sgblack@eecs.umich.eduflag and checks for it.
1005596Sgblack@eecs.umich.edu
1015596Sgblack@eecs.umich.eduDoing this makes the system schedulable, but even these few lines of code
1025596Sgblack@eecs.umich.eduturn into over 1 MB of .db file, take 300MB of core and ten minutes to run.
1035596Sgblack@eecs.umich.eduThis corresponds to roughly 140 lines of C code: four conditionals, two
1045596Sgblack@eecs.umich.edunested loops, and one function call.
1055596Sgblack@eecs.umich.edu
1065596Sgblack@eecs.umich.edu***********************************************************************/
1075596Sgblack@eecs.umich.edu
1085596Sgblack@eecs.umich.edutypedef unsigned int pchar_t;
1095596Sgblack@eecs.umich.edu
1105596Sgblack@eecs.umich.edu/**********************************************************************
1115596Sgblack@eecs.umich.edu
1125596Sgblack@eecs.umich.eduSystemC-specific things
1135596Sgblack@eecs.umich.edu
1145596Sgblack@eecs.umich.edu**********************************************************************/
1155596Sgblack@eecs.umich.edu
1165596Sgblack@eecs.umich.edu#include "systemc.h"
1175596Sgblack@eecs.umich.edu
1185596Sgblack@eecs.umich.eduSC_MODULE(lp_write_buf) {
1195596Sgblack@eecs.umich.edu  sc_in_clk         clk;
1205596Sgblack@eecs.umich.edu  sc_in<bool>       reset;
1215596Sgblack@eecs.umich.edu  sc_in<unsigned>   minor;
1225596Sgblack@eecs.umich.edu  sc_in<unsigned>   buf;   /* a pointer */
1235596Sgblack@eecs.umich.edu  sc_in<int>        count;
1245596Sgblack@eecs.umich.edu
1255596Sgblack@eecs.umich.edu  sc_out<int>       result;       /* return code */
1265596Sgblack@eecs.umich.edu  sc_out<bool>      result_ready; /* return flag */
1275596Sgblack@eecs.umich.edu
1285596Sgblack@eecs.umich.edu  sc_out<char>      control;      /* printer control port */
1295596Sgblack@eecs.umich.edu
1305596Sgblack@eecs.umich.edu  sc_inout<unsigned>  user_addr;	  /* user memory address */
1315596Sgblack@eecs.umich.edu  sc_in<char>       user_read_data; /* user data value */
1325596Sgblack@eecs.umich.edu  sc_out<bool>      user_read;    /* user memory read flag */
1335596Sgblack@eecs.umich.edu
1345596Sgblack@eecs.umich.edu  sc_out<unsigned>  kernel_addr;  /* kernel memory address */
1355596Sgblack@eecs.umich.edu  sc_in<char>       kernel_read_data; /* kernel data value */
1365596Sgblack@eecs.umich.edu  sc_out<char>      kernel_write_data; /* kernel data value */
1375596Sgblack@eecs.umich.edu  sc_out<bool>      kernel_read;
1385596Sgblack@eecs.umich.edu  sc_out<bool>      kernel_write;
1395596Sgblack@eecs.umich.edu
1405596Sgblack@eecs.umich.edu  sc_out<bool>      invalid_read; /* debugging flag: should never be true */
1415596Sgblack@eecs.umich.edu
1425596Sgblack@eecs.umich.edu  void lp_write_buf_body();
1435596Sgblack@eecs.umich.edu  int lp_write_buf_f(unsigned int minor,  pchar_t buf, int count);
1445596Sgblack@eecs.umich.edu
1455596Sgblack@eecs.umich.edu  /* User and kernel memory operations */
1465596Sgblack@eecs.umich.edu  char read_from_user(unsigned a);
1475596Sgblack@eecs.umich.edu  char read_from_kernel(unsigned a);
1485596Sgblack@eecs.umich.edu  void write_to_kernel(unsigned a, char d);
1495596Sgblack@eecs.umich.edu
1505596Sgblack@eecs.umich.edu  int copy_from_user(pchar_t,  pchar_t, unsigned long);
1515596Sgblack@eecs.umich.edu
1525596Sgblack@eecs.umich.edu  /* Output verification */
1535596Sgblack@eecs.umich.edu  void check_read_address();
1545596Sgblack@eecs.umich.edu
1555596Sgblack@eecs.umich.edu  SC_CTOR(lp_write_buf)
1565596Sgblack@eecs.umich.edu  {
1575596Sgblack@eecs.umich.edu    SC_CTHREAD(lp_write_buf_body, clk.pos());
1585596Sgblack@eecs.umich.edu    reset_signal_is(reset,true);
1595596Sgblack@eecs.umich.edu    SC_CTHREAD(check_read_address, clk.pos());
1605596Sgblack@eecs.umich.edu    reset_signal_is(reset,true);
1615596Sgblack@eecs.umich.edu  }
1625596Sgblack@eecs.umich.edu};
1635596Sgblack@eecs.umich.edu
1645596Sgblack@eecs.umich.eduvoid lp_write_buf::check_read_address()
1655596Sgblack@eecs.umich.edu{
1665596Sgblack@eecs.umich.edu  /* This causes the systemC compiler a fatal internal error */
1675596Sgblack@eecs.umich.edu  for (;;) {
1685596Sgblack@eecs.umich.edu    invalid_read = user_addr < buf || user_addr >= buf + count;
1695596Sgblack@eecs.umich.edu    wait();
1705596Sgblack@eecs.umich.edu  }
1715596Sgblack@eecs.umich.edu}
1725702Ssaidi@eecs.umich.edu
1735702Ssaidi@eecs.umich.edu
1745596Sgblack@eecs.umich.eduvoid lp_write_buf::lp_write_buf_body()
1755596Sgblack@eecs.umich.edu{
1765702Ssaidi@eecs.umich.edu  unsigned dummy; /* These three statements compensate for BC weirdness */
1772935Sksewell@umich.edu  dummy = 0;
1785596Sgblack@eecs.umich.edu  wait();
1795596Sgblack@eecs.umich.edu  for (;;) {
1802848Sksewell@umich.edu    result = 0; result_ready = 0;
1812847Sksewell@umich.edu    unsigned res = lp_write_buf_f(minor, buf, count);
1825596Sgblack@eecs.umich.edu    result = (int) res; result_ready = 1;
1835596Sgblack@eecs.umich.edu    wait();
1845596Sgblack@eecs.umich.edu    result_ready = 0;
1855596Sgblack@eecs.umich.edu    wait();
1865596Sgblack@eecs.umich.edu  }
1875596Sgblack@eecs.umich.edu}
1885596Sgblack@eecs.umich.edu
1895596Sgblack@eecs.umich.educhar lp_write_buf::read_from_user(unsigned a)
1905596Sgblack@eecs.umich.edu{
1915596Sgblack@eecs.umich.edu  char d;
1925596Sgblack@eecs.umich.edu  user_addr = a;
1935596Sgblack@eecs.umich.edu  user_read = 1;
1945596Sgblack@eecs.umich.edu  wait();
1955596Sgblack@eecs.umich.edu  d = user_read_data;
1965596Sgblack@eecs.umich.edu  user_read = 0;
1975596Sgblack@eecs.umich.edu  wait();
1985596Sgblack@eecs.umich.edu  return d;
1995596Sgblack@eecs.umich.edu}
2005596Sgblack@eecs.umich.edu
2015596Sgblack@eecs.umich.educhar lp_write_buf::read_from_kernel(unsigned a)
2025596Sgblack@eecs.umich.edu{
2035596Sgblack@eecs.umich.edu  char d;
2045596Sgblack@eecs.umich.edu  kernel_addr = a;
2055596Sgblack@eecs.umich.edu  kernel_read = 1;
2065596Sgblack@eecs.umich.edu  wait();
2075596Sgblack@eecs.umich.edu  d = kernel_read_data;
2085596Sgblack@eecs.umich.edu  kernel_read = 0;
2095596Sgblack@eecs.umich.edu  wait();
2105596Sgblack@eecs.umich.edu  return d;
2115596Sgblack@eecs.umich.edu}
2125596Sgblack@eecs.umich.edu
2135596Sgblack@eecs.umich.eduvoid lp_write_buf::write_to_kernel(unsigned a, char d)
2145596Sgblack@eecs.umich.edu{
2155596Sgblack@eecs.umich.edu  kernel_addr = a;
2165596Sgblack@eecs.umich.edu  kernel_write_data = d;
2175596Sgblack@eecs.umich.edu  kernel_write = 1;
2185596Sgblack@eecs.umich.edu  wait();
2195596Sgblack@eecs.umich.edu  kernel_write = 0;
2205596Sgblack@eecs.umich.edu  wait();
2215596Sgblack@eecs.umich.edu}
2225596Sgblack@eecs.umich.edu
2235596Sgblack@eecs.umich.eduint lp_write_buf::copy_from_user(pchar_t src,  pchar_t dest,
2245596Sgblack@eecs.umich.edu				 unsigned long count)
2255596Sgblack@eecs.umich.edu{
2265596Sgblack@eecs.umich.edu  for ( ; count > 0 ; count--)
2275596Sgblack@eecs.umich.edu    write_to_kernel(dest++, read_from_user(src++));
2285596Sgblack@eecs.umich.edu  /* What about an error? */
2295596Sgblack@eecs.umich.edu  return 0;
2305596Sgblack@eecs.umich.edu}
2315596Sgblack@eecs.umich.edu
2325596Sgblack@eecs.umich.edu/********************************************************************
2335596Sgblack@eecs.umich.edu  "Normal" C begins here
2345596Sgblack@eecs.umich.edu ********************************************************************/
2355596Sgblack@eecs.umich.edu
2365596Sgblack@eecs.umich.edu#define	ENXIO		 6	/* No such device or address */
2375596Sgblack@eecs.umich.edu#define	EFAULT		14	/* Bad address */
2385596Sgblack@eecs.umich.edu
2395596Sgblack@eecs.umich.edu// #define NULL             0
2405596Sgblack@eecs.umich.edu
2415596Sgblack@eecs.umich.edu#define LP_PINTEN	0x10  /* high to read data in or-ed with data out */
2425596Sgblack@eecs.umich.edu#define LP_PSELECP	0x08  /* inverted output, active low */
2435596Sgblack@eecs.umich.edu#define LP_PINITP	0x04  /* unchanged output, active low */
2445596Sgblack@eecs.umich.edu#define LP_PAUTOLF	0x02  /* inverted output, active low */
2455596Sgblack@eecs.umich.edu#define LP_PSTROBE	0x01  /* short high output on raising edge */
2465596Sgblack@eecs.umich.edu
2475596Sgblack@eecs.umich.edu/* #define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) */
2485596Sgblack@eecs.umich.edu#define LP_POLLED(minor) 1
2495596Sgblack@eecs.umich.edu
2505596Sgblack@eecs.umich.edu#define w_ctr(dev,val) (control = (val))
2515596Sgblack@eecs.umich.edu
2525596Sgblack@eecs.umich.edu#define LP_NO 3
2535596Sgblack@eecs.umich.edu#define LP_BUFFER_SIZE 32
2545596Sgblack@eecs.umich.edu
2555596Sgblack@eecs.umich.edustruct lp_struct {
2565596Sgblack@eecs.umich.edu  /* struct pardevice *dev; */
2575596Sgblack@eecs.umich.edu  pchar_t dev;
2585596Sgblack@eecs.umich.edu  unsigned long flags;
2595596Sgblack@eecs.umich.edu  unsigned int chars;
2605596Sgblack@eecs.umich.edu  unsigned int time;
2615596Sgblack@eecs.umich.edu  /*	unsigned int wait; */
2625596Sgblack@eecs.umich.edu  pchar_t lp_buffer;
2635596Sgblack@eecs.umich.edu  /* struct wait_queue *wait_q; */
2645596Sgblack@eecs.umich.edu  unsigned int last_error;
2655596Sgblack@eecs.umich.edu  volatile unsigned int irq_detected:1;
2665596Sgblack@eecs.umich.edu  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