star110089.cpp revision 12855:588919e0e4aa
1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 star110089.cpp -- 23 24 Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15 25 26 *****************************************************************************/ 27 28/***************************************************************************** 29 30 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 31 changes you are making here. 32 33 Name, Affiliation, Date: 34 Description of Modification: 35 36 *****************************************************************************/ 37 38/*********************************************************************** 39 40Things I had to do to make this work with the SystemC compiler 41 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