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