112855Sgabeblack@google.com/***************************************************************************** 212855Sgabeblack@google.com 312855Sgabeblack@google.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 412855Sgabeblack@google.com more contributor license agreements. See the NOTICE file distributed 512855Sgabeblack@google.com with this work for additional information regarding copyright ownership. 612855Sgabeblack@google.com Accellera licenses this file to you under the Apache License, Version 2.0 712855Sgabeblack@google.com (the "License"); you may not use this file except in compliance with the 812855Sgabeblack@google.com License. You may obtain a copy of the License at 912855Sgabeblack@google.com 1012855Sgabeblack@google.com http://www.apache.org/licenses/LICENSE-2.0 1112855Sgabeblack@google.com 1212855Sgabeblack@google.com Unless required by applicable law or agreed to in writing, software 1312855Sgabeblack@google.com distributed under the License is distributed on an "AS IS" BASIS, 1412855Sgabeblack@google.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1512855Sgabeblack@google.com implied. See the License for the specific language governing 1612855Sgabeblack@google.com permissions and limitations under the License. 1712855Sgabeblack@google.com 1812855Sgabeblack@google.com *****************************************************************************/ 1912855Sgabeblack@google.com 2012855Sgabeblack@google.com/***************************************************************************** 2112855Sgabeblack@google.com 2212855Sgabeblack@google.com star110089.cpp -- 2312855Sgabeblack@google.com 2412855Sgabeblack@google.com Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15 2512855Sgabeblack@google.com 2612855Sgabeblack@google.com *****************************************************************************/ 2712855Sgabeblack@google.com 2812855Sgabeblack@google.com/***************************************************************************** 2912855Sgabeblack@google.com 3012855Sgabeblack@google.com MODIFICATION LOG - modifiers, enter your name, affiliation, date and 3112855Sgabeblack@google.com changes you are making here. 3212855Sgabeblack@google.com 3312855Sgabeblack@google.com Name, Affiliation, Date: 3412855Sgabeblack@google.com Description of Modification: 3512855Sgabeblack@google.com 3612855Sgabeblack@google.com *****************************************************************************/ 3712855Sgabeblack@google.com 3812855Sgabeblack@google.com/*********************************************************************** 3912855Sgabeblack@google.com 4012855Sgabeblack@google.comThings I had to do to make this work with the SystemC compiler 4112855Sgabeblack@google.com 4212855Sgabeblack@google.comRemove LP_STATS-related #ifdefs 4312855Sgabeblack@google.com 4412855Sgabeblack@google.comAdded SystemC module interface. Odd function wrapper, wait()s. 4512855Sgabeblack@google.com 4612855Sgabeblack@google.comRemoved use of pointers into lp_table (replaced with array references). 4712855Sgabeblack@google.com 4812855Sgabeblack@google.comGlobal variables are not allowed, so move lp_table into the function. 4912855Sgabeblack@google.com 5012855Sgabeblack@google.comPointers appear to have problems, so comment out test of the "dev" field. 5112855Sgabeblack@google.com 5212855Sgabeblack@google.comThe LP_POLLED macro checks lp_table[minor].dev->port->irq (three dereferences), 5312855Sgabeblack@google.comwhich is not synthesizable. I replaced it with a constant. 5412855Sgabeblack@google.com 5512855Sgabeblack@google.comw_ctr writes to the control I/O port. We want to observe this, so added 5612855Sgabeblack@google.coma port to the module, made the function a member function (not just static). 5712855Sgabeblack@google.com 5812855Sgabeblack@google.comWant to observe successive values on the control port, so added a wait() after 5912855Sgabeblack@google.comit is written. 6012855Sgabeblack@google.com 6112855Sgabeblack@google.comAdding the main do loop (there's an if () return statement earlier) 6212855Sgabeblack@google.comgives "WAITs not balanced" errors, even without any wait() statements 6312855Sgabeblack@google.comat all. Adding them doesn't appear to help (Evidentally, I'm not 6412855Sgabeblack@google.comadding them correctly.) 6512855Sgabeblack@google.com 6612855Sgabeblack@google.comHow to model memory? Specifically, how to model copy_from_user() and 6712855Sgabeblack@google.comaccesses to buffer memory? I'll create address, data, and read/write ports 6812855Sgabeblack@google.comfor each memory space, memory access functions that toggle these ports, 6912855Sgabeblack@google.comand finally a replacement for copy_from_user(). 7012855Sgabeblack@google.com 7112855Sgabeblack@google.comPointers seem to be broken (BC gives the inscrutable 7212855Sgabeblack@google.com 7312855Sgabeblack@google.com Error: Width mismatch on port 'n5[1]' of reference to 'group1' in 7412855Sgabeblack@google.com 'lp_write_buf.db:loop_117_design'. (LINK-3) 7512855Sgabeblack@google.com 7612855Sgabeblack@google.comso I'll use a pchar_t type as a replacement. 7712855Sgabeblack@google.com 7812855Sgabeblack@google.comThe const declarations don't work now with typedef unsigned int pchar_t, so 7912855Sgabeblack@google.comI removed them. 8012855Sgabeblack@google.com 8112855Sgabeblack@google.comWas getting "unschedulable" errors until I inserted a few wait() statements. 8212855Sgabeblack@google.com(Very unhelpful diagnostics.) 8312855Sgabeblack@google.com 8412855Sgabeblack@google.comInserting and removing wait()s at will seems to help, but I'm still getting 8512855Sgabeblack@google.comwidth mismatch errors. 8612855Sgabeblack@google.com 8712855Sgabeblack@google.comThe width mismatch errors are due to a SystemC compiler bug. Adding 8812855Sgabeblack@google.com-Xgroup_idx_logic=0 to the command line eliminates them. 8912855Sgabeblack@google.com 9012855Sgabeblack@google.comMany "mismatched clock" statements appear to be due to the use of nested 9112855Sgabeblack@google.comreturn stataments. BC doesn't support exits from any more than a single 9212855Sgabeblack@google.comlevel of loop nesting, so whatever hack the SystemC people did is not solid. 9312855Sgabeblack@google.com 9412855Sgabeblack@google.comif statements with a return in one branch seems to cause unsolvable wait 9512855Sgabeblack@google.combalance problems. I'll rewrite many of them to put the code in the "else" 9612855Sgabeblack@google.combranch. 9712855Sgabeblack@google.com 9812855Sgabeblack@google.comFor if-then with a return within a loop, I appear to need to add an error 9912855Sgabeblack@google.comflag and checks for it. 10012855Sgabeblack@google.com 10112855Sgabeblack@google.comDoing this makes the system schedulable, but even these few lines of code 10212855Sgabeblack@google.comturn into over 1 MB of .db file, take 300MB of core and ten minutes to run. 10312855Sgabeblack@google.comThis corresponds to roughly 140 lines of C code: four conditionals, two 10412855Sgabeblack@google.comnested loops, and one function call. 10512855Sgabeblack@google.com 10612855Sgabeblack@google.com***********************************************************************/ 10712855Sgabeblack@google.com 10812855Sgabeblack@google.comtypedef unsigned int pchar_t; 10912855Sgabeblack@google.com 11012855Sgabeblack@google.com/********************************************************************** 11112855Sgabeblack@google.com 11212855Sgabeblack@google.comSystemC-specific things 11312855Sgabeblack@google.com 11412855Sgabeblack@google.com**********************************************************************/ 11512855Sgabeblack@google.com 11612855Sgabeblack@google.com#include "systemc.h" 11712855Sgabeblack@google.com 11812855Sgabeblack@google.comSC_MODULE(lp_write_buf) { 11912855Sgabeblack@google.com sc_in_clk clk; 12012855Sgabeblack@google.com sc_in<bool> reset; 12112855Sgabeblack@google.com sc_in<unsigned> minor; 12212855Sgabeblack@google.com sc_in<unsigned> buf; /* a pointer */ 12312855Sgabeblack@google.com sc_in<int> count; 12412855Sgabeblack@google.com 12512855Sgabeblack@google.com sc_out<int> result; /* return code */ 12612855Sgabeblack@google.com sc_out<bool> result_ready; /* return flag */ 12712855Sgabeblack@google.com 12812855Sgabeblack@google.com sc_out<char> control; /* printer control port */ 12912855Sgabeblack@google.com 13012855Sgabeblack@google.com sc_inout<unsigned> user_addr; /* user memory address */ 13112855Sgabeblack@google.com sc_in<char> user_read_data; /* user data value */ 13212855Sgabeblack@google.com sc_out<bool> user_read; /* user memory read flag */ 13312855Sgabeblack@google.com 13412855Sgabeblack@google.com sc_out<unsigned> kernel_addr; /* kernel memory address */ 13512855Sgabeblack@google.com sc_in<char> kernel_read_data; /* kernel data value */ 13612855Sgabeblack@google.com sc_out<char> kernel_write_data; /* kernel data value */ 13712855Sgabeblack@google.com sc_out<bool> kernel_read; 13812855Sgabeblack@google.com sc_out<bool> kernel_write; 13912855Sgabeblack@google.com 14012855Sgabeblack@google.com sc_out<bool> invalid_read; /* debugging flag: should never be true */ 14112855Sgabeblack@google.com 14212855Sgabeblack@google.com void lp_write_buf_body(); 14312855Sgabeblack@google.com int lp_write_buf_f(unsigned int minor, pchar_t buf, int count); 14412855Sgabeblack@google.com 14512855Sgabeblack@google.com /* User and kernel memory operations */ 14612855Sgabeblack@google.com char read_from_user(unsigned a); 14712855Sgabeblack@google.com char read_from_kernel(unsigned a); 14812855Sgabeblack@google.com void write_to_kernel(unsigned a, char d); 14912855Sgabeblack@google.com 15012855Sgabeblack@google.com int copy_from_user(pchar_t, pchar_t, unsigned long); 15112855Sgabeblack@google.com 15212855Sgabeblack@google.com /* Output verification */ 15312855Sgabeblack@google.com void check_read_address(); 15412855Sgabeblack@google.com 15512855Sgabeblack@google.com SC_CTOR(lp_write_buf) 15612855Sgabeblack@google.com { 15712855Sgabeblack@google.com SC_CTHREAD(lp_write_buf_body, clk.pos()); 15812855Sgabeblack@google.com reset_signal_is(reset,true); 15912855Sgabeblack@google.com SC_CTHREAD(check_read_address, clk.pos()); 16012855Sgabeblack@google.com reset_signal_is(reset,true); 16112855Sgabeblack@google.com } 16212855Sgabeblack@google.com}; 16312855Sgabeblack@google.com 16412855Sgabeblack@google.comvoid lp_write_buf::check_read_address() 16512855Sgabeblack@google.com{ 16612855Sgabeblack@google.com /* This causes the systemC compiler a fatal internal error */ 16712855Sgabeblack@google.com for (;;) { 16812855Sgabeblack@google.com invalid_read = user_addr < buf || user_addr >= buf + count; 16912855Sgabeblack@google.com wait(); 17012855Sgabeblack@google.com } 17112855Sgabeblack@google.com} 17212855Sgabeblack@google.com 17312855Sgabeblack@google.com 17412855Sgabeblack@google.comvoid lp_write_buf::lp_write_buf_body() 17512855Sgabeblack@google.com{ 17612855Sgabeblack@google.com unsigned dummy; /* These three statements compensate for BC weirdness */ 17712855Sgabeblack@google.com dummy = 0; 17812855Sgabeblack@google.com wait(); 17912855Sgabeblack@google.com for (;;) { 18012855Sgabeblack@google.com result = 0; result_ready = 0; 18112855Sgabeblack@google.com unsigned res = lp_write_buf_f(minor, buf, count); 18212855Sgabeblack@google.com result = (int) res; result_ready = 1; 18312855Sgabeblack@google.com wait(); 18412855Sgabeblack@google.com result_ready = 0; 18512855Sgabeblack@google.com wait(); 18612855Sgabeblack@google.com } 18712855Sgabeblack@google.com} 18812855Sgabeblack@google.com 18912855Sgabeblack@google.comchar lp_write_buf::read_from_user(unsigned a) 19012855Sgabeblack@google.com{ 19112855Sgabeblack@google.com char d; 19212855Sgabeblack@google.com user_addr = a; 19312855Sgabeblack@google.com user_read = 1; 19412855Sgabeblack@google.com wait(); 19512855Sgabeblack@google.com d = user_read_data; 19612855Sgabeblack@google.com user_read = 0; 19712855Sgabeblack@google.com wait(); 19812855Sgabeblack@google.com return d; 19912855Sgabeblack@google.com} 20012855Sgabeblack@google.com 20112855Sgabeblack@google.comchar lp_write_buf::read_from_kernel(unsigned a) 20212855Sgabeblack@google.com{ 20312855Sgabeblack@google.com char d; 20412855Sgabeblack@google.com kernel_addr = a; 20512855Sgabeblack@google.com kernel_read = 1; 20612855Sgabeblack@google.com wait(); 20712855Sgabeblack@google.com d = kernel_read_data; 20812855Sgabeblack@google.com kernel_read = 0; 20912855Sgabeblack@google.com wait(); 21012855Sgabeblack@google.com return d; 21112855Sgabeblack@google.com} 21212855Sgabeblack@google.com 21312855Sgabeblack@google.comvoid lp_write_buf::write_to_kernel(unsigned a, char d) 21412855Sgabeblack@google.com{ 21512855Sgabeblack@google.com kernel_addr = a; 21612855Sgabeblack@google.com kernel_write_data = d; 21712855Sgabeblack@google.com kernel_write = 1; 21812855Sgabeblack@google.com wait(); 21912855Sgabeblack@google.com kernel_write = 0; 22012855Sgabeblack@google.com wait(); 22112855Sgabeblack@google.com} 22212855Sgabeblack@google.com 22312855Sgabeblack@google.comint lp_write_buf::copy_from_user(pchar_t src, pchar_t dest, 22412855Sgabeblack@google.com unsigned long count) 22512855Sgabeblack@google.com{ 22612855Sgabeblack@google.com for ( ; count > 0 ; count--) 22712855Sgabeblack@google.com write_to_kernel(dest++, read_from_user(src++)); 22812855Sgabeblack@google.com /* What about an error? */ 22912855Sgabeblack@google.com return 0; 23012855Sgabeblack@google.com} 23112855Sgabeblack@google.com 23212855Sgabeblack@google.com/******************************************************************** 23312855Sgabeblack@google.com "Normal" C begins here 23412855Sgabeblack@google.com ********************************************************************/ 23512855Sgabeblack@google.com 23612855Sgabeblack@google.com#define ENXIO 6 /* No such device or address */ 23712855Sgabeblack@google.com#define EFAULT 14 /* Bad address */ 23812855Sgabeblack@google.com 23912855Sgabeblack@google.com// #define NULL 0 24012855Sgabeblack@google.com 24112855Sgabeblack@google.com#define LP_PINTEN 0x10 /* high to read data in or-ed with data out */ 24212855Sgabeblack@google.com#define LP_PSELECP 0x08 /* inverted output, active low */ 24312855Sgabeblack@google.com#define LP_PINITP 0x04 /* unchanged output, active low */ 24412855Sgabeblack@google.com#define LP_PAUTOLF 0x02 /* inverted output, active low */ 24512855Sgabeblack@google.com#define LP_PSTROBE 0x01 /* short high output on raising edge */ 24612855Sgabeblack@google.com 24712855Sgabeblack@google.com/* #define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) */ 24812855Sgabeblack@google.com#define LP_POLLED(minor) 1 24912855Sgabeblack@google.com 25012855Sgabeblack@google.com#define w_ctr(dev,val) (control = (val)) 25112855Sgabeblack@google.com 25212855Sgabeblack@google.com#define LP_NO 3 25312855Sgabeblack@google.com#define LP_BUFFER_SIZE 32 25412855Sgabeblack@google.com 25512855Sgabeblack@google.comstruct lp_struct { 25612855Sgabeblack@google.com /* struct pardevice *dev; */ 25712855Sgabeblack@google.com pchar_t dev; 25812855Sgabeblack@google.com unsigned long flags; 25912855Sgabeblack@google.com unsigned int chars; 26012855Sgabeblack@google.com unsigned int time; 26112855Sgabeblack@google.com /* unsigned int wait; */ 26212855Sgabeblack@google.com pchar_t lp_buffer; 26312855Sgabeblack@google.com /* struct wait_queue *wait_q; */ 26412855Sgabeblack@google.com unsigned int last_error; 26512855Sgabeblack@google.com volatile unsigned int irq_detected:1; 26612855Sgabeblack@google.com volatile unsigned int irq_missed:1; 26712855Sgabeblack@google.com}; 26812855Sgabeblack@google.com 26912855Sgabeblack@google.com/* Write count bytes starting at buf in user space to the parallel port 27012855Sgabeblack@google.com defined by the minor device number */ 27112855Sgabeblack@google.com 27212855Sgabeblack@google.comint lp_write_buf::lp_write_buf_f(unsigned int minor, 27312855Sgabeblack@google.com pchar_t buf, int count) 27412855Sgabeblack@google.com{ 27512855Sgabeblack@google.com int err; 27612855Sgabeblack@google.com struct lp_struct lp_table[LP_NO]; 27712855Sgabeblack@google.com 27812855Sgabeblack@google.com /* Added to fake a device */ 27912855Sgabeblack@google.com lp_table[minor].dev = 5; 28012855Sgabeblack@google.com 28112855Sgabeblack@google.com unsigned long copy_size; 28212855Sgabeblack@google.com unsigned long total_bytes_written = 0; 28312855Sgabeblack@google.com unsigned long bytes_written; 28412855Sgabeblack@google.com /* Removed because pointers are prohibited */ 28512855Sgabeblack@google.com /* struct lp_struct *lp = &lp_table[minor]; */ 28612855Sgabeblack@google.com 28712855Sgabeblack@google.com if (minor >= LP_NO) { 28812855Sgabeblack@google.com wait(); 28912855Sgabeblack@google.com return -ENXIO; 29012855Sgabeblack@google.com } else { 29112855Sgabeblack@google.com 29212855Sgabeblack@google.com /* if (lp->dev == NULL) */ /* Removed because of a pointer */ 29312855Sgabeblack@google.com /* The following causes a BC error (bad matching width of n15[1]) */ 29412855Sgabeblack@google.com if (lp_table[minor].dev == 0) { 29512855Sgabeblack@google.com wait(); 29612855Sgabeblack@google.com return -ENXIO; 29712855Sgabeblack@google.com } else { 29812855Sgabeblack@google.com 29912855Sgabeblack@google.com lp_table[minor].last_error = 0; 30012855Sgabeblack@google.com lp_table[minor].irq_detected = 0; 30112855Sgabeblack@google.com lp_table[minor].irq_missed = 1; 30212855Sgabeblack@google.com 30312855Sgabeblack@google.com if (LP_POLLED(minor)) 30412855Sgabeblack@google.com w_ctr(minor, LP_PSELECP | LP_PINITP); 30512855Sgabeblack@google.com else 30612855Sgabeblack@google.com w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); 30712855Sgabeblack@google.com 30812855Sgabeblack@google.com err = 0; 30912855Sgabeblack@google.com wait(); 31012855Sgabeblack@google.com do { 31112855Sgabeblack@google.com wait(); 31212855Sgabeblack@google.com bytes_written = 0; 31312855Sgabeblack@google.com copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); 31412855Sgabeblack@google.com 31512855Sgabeblack@google.com 31612855Sgabeblack@google.com /* Adding this gives width mismatch errors */ 31712855Sgabeblack@google.com if (copy_from_user(lp_table[minor].lp_buffer, buf, copy_size)) { 31812855Sgabeblack@google.com wait(); 31912855Sgabeblack@google.com w_ctr(minor, LP_PSELECP | LP_PINITP); 32012855Sgabeblack@google.com // return -EFAULT; 32112855Sgabeblack@google.com err = -EFAULT; 32212855Sgabeblack@google.com } else { 32312855Sgabeblack@google.com 32412855Sgabeblack@google.com /** Fake! **/ 32512855Sgabeblack@google.com bytes_written = copy_size; 32612855Sgabeblack@google.com 32712855Sgabeblack@google.com#if 0 32812855Sgabeblack@google.com 32912855Sgabeblack@google.com while (copy_size) { 33012855Sgabeblack@google.com if (lp_char(lp->lp_buffer[bytes_written], minor)) { 33112855Sgabeblack@google.com --copy_size; 33212855Sgabeblack@google.com ++bytes_written; 33312855Sgabeblack@google.com } else { 33412855Sgabeblack@google.com int rc = total_bytes_written + bytes_written; 33512855Sgabeblack@google.com 33612855Sgabeblack@google.com 33712855Sgabeblack@google.com if (signal_pending(current)) 33812855Sgabeblack@google.com { 33912855Sgabeblack@google.com w_ctr(minor, LP_PSELECP | LP_PINITP); 34012855Sgabeblack@google.com if (total_bytes_written + bytes_written) 34112855Sgabeblack@google.com return total_bytes_written + bytes_written; 34212855Sgabeblack@google.com else 34312855Sgabeblack@google.com return -EINTR; 34412855Sgabeblack@google.com } 34512855Sgabeblack@google.com 34612855Sgabeblack@google.com if (lp_check_status(minor)) 34712855Sgabeblack@google.com { 34812855Sgabeblack@google.com w_ctr(minor, LP_PSELECP | LP_PINITP); 34912855Sgabeblack@google.com return rc ? rc : -EIO; 35012855Sgabeblack@google.com } 35112855Sgabeblack@google.com 35212855Sgabeblack@google.com if (LP_POLLED(minor) || 35312855Sgabeblack@google.com lp_table[minor].irq_missed) 35412855Sgabeblack@google.com { 35512855Sgabeblack@google.com lp_polling: 35612855Sgabeblack@google.com current->state = TASK_INTERRUPTIBLE; 35712855Sgabeblack@google.com lp_schedule(minor, LP_TIME(minor)); 35812855Sgabeblack@google.com } else { 35912855Sgabeblack@google.com cli(); 36012855Sgabeblack@google.com if (LP_PREEMPTED(minor)) 36112855Sgabeblack@google.com { 36212855Sgabeblack@google.com /* 36312855Sgabeblack@google.com * We can' t sleep on the interrupt 36412855Sgabeblack@google.com * since another pardevice need the port. 36512855Sgabeblack@google.com * We must check this in a cli() protected 36612855Sgabeblack@google.com * envinroment to avoid parport sharing 36712855Sgabeblack@google.com * starvation. 36812855Sgabeblack@google.com */ 36912855Sgabeblack@google.com sti(); 37012855Sgabeblack@google.com goto lp_polling; 37112855Sgabeblack@google.com } 37212855Sgabeblack@google.com if (!lp_table[minor].irq_detected) 37312855Sgabeblack@google.com interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT); 37412855Sgabeblack@google.com sti(); 37512855Sgabeblack@google.com } 37612855Sgabeblack@google.com } 37712855Sgabeblack@google.com } 37812855Sgabeblack@google.com 37912855Sgabeblack@google.com#endif 38012855Sgabeblack@google.com 38112855Sgabeblack@google.com total_bytes_written += bytes_written; 38212855Sgabeblack@google.com buf += bytes_written; 38312855Sgabeblack@google.com count -= bytes_written; 38412855Sgabeblack@google.com 38512855Sgabeblack@google.com wait(); 38612855Sgabeblack@google.com } 38712855Sgabeblack@google.com 38812855Sgabeblack@google.com } while (count > 0 && err >= 0); 38912855Sgabeblack@google.com 39012855Sgabeblack@google.com wait(); 39112855Sgabeblack@google.com 39212855Sgabeblack@google.com if (err >= 0 ) { 39312855Sgabeblack@google.com 39412855Sgabeblack@google.com w_ctr(minor, LP_PSELECP | LP_PINITP); 39512855Sgabeblack@google.com return total_bytes_written; 39612855Sgabeblack@google.com } else { 39712855Sgabeblack@google.com return err; 39812855Sgabeblack@google.com } 39912855Sgabeblack@google.com 40012855Sgabeblack@google.com } 40112855Sgabeblack@google.com } 40212855Sgabeblack@google.com} 40312855Sgabeblack@google.com 404