diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/COPYING Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/COPYING.LESSER --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/COPYING.LESSER Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/Doxyfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/Doxyfile Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,1538 @@ +# Doxyfile 1.5.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = DRAMSimII + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = .99.14b + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = HIERARCHIES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 1000 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/README Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,4 @@ +to install DRAMsimII as a module for M5 +1. make sure the DRAMSimII directory is in /src/mem/ or somewhere similar, M5 searches the src subdir for SConscript files to locate add-on modules +to run M5 with DRAMsimII as the memory system +2. dramsim.py is copied to /configs/examples/ as there are other files in this path that this script depends on diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/GemsFDTD.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/GemsFDTD.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/459.GemsFDTD/data/test/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/459.GemsFDTD/exe/GemsFDTD_base.alpha-gcc410-glibc236 +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the blackscholes benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./blackscholes 4 /parsec/install/inputs/blackscholes/in_16.txt /parsec/install/inputs/blackscholes/prices.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the blackscholes benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./blackscholes 4 /parsec/install/inputs/blackscholes/in_64K.txt /parsec/install/inputs/blackscholes/prices.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the blackscholes benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./blackscholes 4 /parsec/install/inputs/blackscholes/in_16K.txt /parsec/install/inputs/blackscholes/prices.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the blackscholes benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./blackscholes 4 /parsec/install/inputs/blackscholes/in_4K.txt /parsec/install/inputs/blackscholes/prices.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/blackscholes_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the blackscholes benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./blackscholes 4 /parsec/install/inputs/blackscholes/in_4.txt /parsec/install/inputs/blackscholes/prices.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the bodytrack benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./bodytrack /parsec/install/inputs/bodytrack/sequenceB_1 4 1 100 3 0 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the bodytrack benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./bodytrack /parsec/install/inputs/bodytrack/sequenceB_4 4 4 4000 5 0 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the bodytrack benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./bodytrack /parsec/install/inputs/bodytrack/sequenceB_2 4 2 2000 5 0 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the bodytrack benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./bodytrack /parsec/install/inputs/bodytrack/sequenceB_1 4 1 1000 5 0 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/bodytrack_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the bodytrack benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./bodytrack /parsec/install/inputs/bodytrack/sequenceB_1 4 1 5 1 0 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/bzip2.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/bzip2.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /benchmarks/401.bzip2/data/all/input +echo bzip2 +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/401.bzip2/exe/bzip2_base.alpha-gcc410-glibc236 input.combined 1\ +echo Done. +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/cactusADM.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/cactusADM.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/436.cactusADM/data/test/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/436.cactusADM/exe/cactusADM_base.alpha-gcc410-glibc236 benchADM.par +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/calculix.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/calculix.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,11 @@ +#!/bin/sh + +cd /benchmarks/454.calculix/data/train/input +echo Calculix +/sbin/m5 resetstats +/sbin/m5 switchcpu + +#/benchmarks/454.calculix/exe/calculix_base.alpha-gcc410-glibc236 -i beampic +/benchmarks/454.calculix/exe/calculix_base.alpha-gcc410-glibc236 -i stairs +echo Done. +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/calculix_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/calculix_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,17 @@ +#!/bin/sh + +cd /benchmarks/454.calculix/data/train/input +echo Calculix +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/454.calculix/exe/calculix_base.alpha-gcc410-glibc236 -i stairs& + i=$(($i-1)) +done +wait +#/benchmarks/454.calculix/exe/calculix_base.alpha-gcc410-glibc236 -i beampic + +echo Done. +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the canneal benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./canneal 4 100 300 /parsec/install/inputs/canneal/100.nets 2 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the canneal benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./canneal 4 15000 2000 /parsec/install/inputs/canneal/400000.nets 128 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the canneal benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./canneal 4 15000 2000 /parsec/install/inputs/canneal/200000.nets 64 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the canneal benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./canneal 4 10000 2000 /parsec/install/inputs/canneal/100000.nets 32 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/canneal_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the canneal benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./canneal 4 5 100 /parsec/install/inputs/canneal/10.nets 1 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dealII.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dealII.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,6 @@ +#!/bin/sh + +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/447.dealII/exe/dealII_base.alpha-gcc410-glibc236 8 +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dealII_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dealII_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/447.dealII/exe/dealII_base.alpha-gcc410-glibc236 8& + i=$(($i-1)) +done +wait + +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the dedup benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./dedup -c -p -f -t 4 -i /parsec/install/inputs/dedup/hamlet.dat -o /parsec/install/inputs/dedup/output.dat.ddp +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the dedup benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./dedup -c -p -f -t 4 -i /parsec/install/inputs/dedup/medial.dat -o /parsec/install/inputs/dedup/output.dat.ddp +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the dedup benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./dedup -c -p -f -t 4 -i /parsec/install/inputs/dedup/mediam.dat -o /parsec/install/inputs/dedup/output.dat.ddp +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the dedup benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./dedup -c -p -f -t 4 -i /parsec/install/inputs/dedup/medias.dat -o /parsec/install/inputs/dedup/output.dat.ddp +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/dedup_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the dedup benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./dedup -c -p -f -t 4 -i /parsec/install/inputs/dedup/test.dat -o /parsec/install/inputs/dedup/output.dat.ddp +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the facesim benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./facesim -timing -threads 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the facesim benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./facesim -timing -threads 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the facesim benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./facesim -timing -threads 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the facesim benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./facesim -timing -threads 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/facesim_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the facesim benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./facesim -h +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the ferret benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./ferret /parsec/install/inputs/ferret/coreld lsh /parsec/install/inputs/ferret/queriesd 5 5 4 /parsec/install/inputs/ferret/output.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the ferret benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./ferret /parsec/install/inputs/ferret/corell lsh /parsec/install/inputs/ferret/queriesl 10 20 4 /parsec/install/inputs/ferret/output.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the ferret benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./ferret /parsec/install/inputs/ferret/corelm lsh /parsec/install/inputs/ferret/queriesm 10 20 4 /parsec/install/inputs/ferret/output.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the ferret benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./ferret /parsec/install/inputs/ferret/corels lsh /parsec/install/inputs/ferret/queriess 10 20 4 /parsec/install/inputs/ferret/output.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/ferret_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the ferret benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./ferret /parsec/install/inputs/ferret/corelt lsh /parsec/install/inputs/ferret/queriest 1 1 4 /parsec/install/inputs/ferret/output.txt +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the fluidanimate benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./fluidanimate 4 3 /parsec/install/inputs/fluidanimate/in_15K.fluid /parsec/install/inputs/fluidanimate/out.fluid +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the fluidanimate benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./fluidanimate 4 5 /parsec/install/inputs/fluidanimate/in_300K.fluid /parsec/install/inputs/fluidanimate/out.fluid +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the fluidanimate benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./fluidanimate 4 5 /parsec/install/inputs/fluidanimate/in_100K.fluid /parsec/install/inputs/fluidanimate/out.fluid +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the fluidanimate benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./fluidanimate 4 5 /parsec/install/inputs/fluidanimate/in_35K.fluid /parsec/install/inputs/fluidanimate/out.fluid +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/fluidanimate_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the fluidanimate benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./fluidanimate 4 1 /parsec/install/inputs/fluidanimate/in_5K.fluid /parsec/install/inputs/fluidanimate/out.fluid +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the freqmine benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./freqmine /parsec/install/inputs/freqmine/T10I4D100K_1k.dat 3 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the freqmine benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./freqmine /parsec/install/inputs/freqmine/kosarak_990k.dat 790 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the freqmine benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./freqmine /parsec/install/inputs/freqmine/kosarak_500k.dat 410 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the freqmine benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./freqmine /parsec/install/inputs/freqmine/kosarak_250k.dat 220 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/freqmine_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the freqmine benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./freqmine /parsec/install/inputs/freqmine/T10I4D100K_3.dat 1 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/gobmk.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/gobmk.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/445.gobmk/data/all/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/445.gobmk/exe/gobmk_base.alpha-gcc410-glibc236 --quiet --mode gtp < /benchmarks/445.gobmk/data/test/input/connection.tst +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/gobmk_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/gobmk_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +cd /benchmarks/445.gobmk/data/all/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/445.gobmk/exe/gobmk_base.alpha-gcc410-glibc236 --quiet --mode gtp < /benchmarks/445.gobmk/data/test/input/connection.tst& + i=$(($i-1)) +done +wait +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/lbm.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/lbm.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /benchmarks/470.lbm/data/test/input +echo "LBM Test" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/470.lbm/exe/lbm_base.alpha-gcc410-glibc236 5 reference.dat 0 1 100_100_130_cf_a.of +echo "LBM Done" +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/lbmLong.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/lbmLong.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /benchmarks/470.lbm/data/ref/input +echo "LBM Ref" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/470.lbm/exe/lbm_base.alpha-gcc410-glibc236 5 reference.dat 0 1 100_100_130_ldc.of +echo "LBM Ref done" +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/libquantum.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/libquantum.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/462.libquantum +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/462.libquantum/exe/libquantum_base.alpha-gcc410-glibc236 129 5 +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/mcf.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/mcf.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,8 @@ +#!/bin/sh + +echo "MCF Test" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/429.mcf/exe/mcf_base.alpha-gcc410-glibc236 /benchmarks/429.mcf/data/test/input/inp.in +echo Done. +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/mcfLong.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/mcfLong.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,8 @@ +#!/bin/sh + +echo "MCF Ref" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/429.mcf/exe/mcf_base.alpha-gcc410-glibc236 /benchmarks/429.mcf/data/ref/input/inp.in +echo "MCF Ref done" +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/mcf_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/mcf_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,15 @@ +#!/bin/sh + +echo "MCF Test" +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/429.mcf/exe/mcf_base.alpha-gcc410-glibc236 /benchmarks/429.mcf/data/test/input/inp.in& + i=$(($i-1)) +done +wait + +echo Done. +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/milc.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/milc.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /benchmarks/433.milc/data/test/input +echo "MILC Test" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/433.milc/exe/milc_base.alpha-gcc410-glibc236 < su3imp.in +echo done +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/milcLong.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/milcLong.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /benchmarks/433.milc/data/ref/input +echo "MILC Ref" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/433.milc/exe/milc_base.alpha-gcc410-glibc236 < su3imp.in +echo "MILC Ref done" +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/milc_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/milc_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,16 @@ +#!/bin/sh + +cd /benchmarks/433.milc/data/test/input +echo "MILC Test" +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/433.milc/exe/milc.alpha < su3imp.in& + i=$(($i-1)) +done +wait + +echo done +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/namd.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/namd.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/444.namd/data/all/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/444.namd/exe/namd_base.alpha-gcc410-glibc236 --input namd.input --iterations 1 --output namd.out +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/omnetpp.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/omnetpp.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/471.omnetpp/data/ref/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/471.omnetpp/exe/omnetpp_base.alpha-gcc410-glibc236 omnetpp.ini +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/povray.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/povray.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,7 @@ +#!/bin/sh + +cd /benchmarks/453.povray/data/all/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/453.povray/exe/povray_base.alpha-gcc410-glibc236 /benchmarks/453.povray/data/ref/input/SPEC-benchmark-ref.ini +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/povray_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/povray_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +cd /benchmarks/453.povray/data/all/input +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/453.povray/exe/povray_base.alpha-gcc410-glibc236 /benchmarks/453.povray/data/ref/input/SPEC-benchmark-ref.ini& + i=$(($i-1)) +done +wait +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the rtview benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./rtview /parsec/install/inputs/rtview/bunny.obj -nodisplay -automove -nthreads 4 -frames 1 -res 16 16 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the rtview benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./rtview /parsec/install/inputs/rtview/happy_buddha.obj -nodisplay -automove -nthreads 4 -frames 3 -res 1920 1080 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the rtview benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./rtview /parsec/install/inputs/rtview/happy_buddha.obj -nodisplay -automove -nthreads 4 -frames 3 -res 960 540 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the rtview benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./rtview /parsec/install/inputs/rtview/happy_buddha.obj -nodisplay -automove -nthreads 4 -frames 3 -res 480 270 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/rtview_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the rtview benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./rtview /parsec/install/inputs/rtview/octahedron.obj -nodisplay -automove -nthreads 4 -frames 1 -res 1 1 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/sjeng.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/sjeng.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,8 @@ +#!/bin/sh + +#cd /benchmarks/458.sjeng/data/test/input +echo sjeng +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/458.sjeng/exe/sjeng_base.alpha-gcc410-glibc236 /benchmarks/458.sjeng/data/test/input/test.txt +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/sjeng_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/sjeng_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,14 @@ +#!/bin/sh + +#cd /benchmarks/458.sjeng/data/test/input +echo sjeng +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/458.sjeng/exe/sjeng_base.alpha-gcc410-glibc236 /benchmarks/458.sjeng/data/test/input/test.txt& + i=$(($i-1)) +done +wait +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/soplex.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/soplex.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,8 @@ +#!/bin/sh + +#cd /benchmarks/450.soplex/data/ref/input +echo SOPLEX +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/450.soplex/exe/soplex_base.alpha-gcc410-glibc236 -m10000 /benchmarks/450.soplex/data/ref/input/ref.mps +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/stream.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/stream.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,6 @@ +#!/bin/sh + +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/stream-short-opt.bak +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/stream_4.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/stream_4.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +/sbin/m5 resetstats +/sbin/m5 switchcpu +i=4 +while [ $i -gt 0 ] +do + /benchmarks/stream-short-opt.bak& + i=$(($i-1)) +done +wait + +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the streamcluster benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./streamcluster 3 10 3 16 16 10 none /parsec/install/inputs/streamcluster/output.txt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the streamcluster benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./streamcluster 10 20 128 16384 16384 1000 none /parsec/install/inputs/streamcluster/output.txt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the streamcluster benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./streamcluster 10 20 64 8192 8192 1000 none /parsec/install/inputs/streamcluster/output.txt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the streamcluster benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./streamcluster 10 20 32 4096 4096 1000 none /parsec/install/inputs/streamcluster/output.txt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/streamcluster_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the streamcluster benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./streamcluster 2 5 1 10 10 5 none /parsec/install/inputs/streamcluster/output.txt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the swaptions benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./swaptions -ns 3 -sm 50 -nt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the swaptions benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./swaptions -ns 64 -sm 20000 -nt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the swaptions benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./swaptions -ns 32 -sm 10000 -nt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the swaptions benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./swaptions -ns 16 -sm 5000 -nt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/swaptions_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the swaptions benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./swaptions -ns 1 -sm 5 -nt 4 +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +# File to run the vips benchmark + +export IM_CONCURRENCY=4 +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./vips im_benchmark /parsec/install/inputs/vips/barbados_256x288.v /parsec/install/inputs/vips/output.v +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +# File to run the vips benchmark + +export IM_CONCURRENCY=4 +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./vips im_benchmark /parsec/install/inputs/vips/bigben_2662x5500.v /parsec/install/inputs/vips/output.v +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +# File to run the vips benchmark + +export IM_CONCURRENCY=4 +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./vips im_benchmark /parsec/install/inputs/vips/vulture_2336x2336.v /parsec/install/inputs/vips/output.v +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/vips_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +# File to run the vips benchmark + +export IM_CONCURRENCY=4 +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./vips im_benchmark /parsec/install/inputs/vips/pomegranate_1600x1200.v /parsec/install/inputs/vips/output.v +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/vips_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/vips_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,13 @@ +#!/bin/sh + +# File to run the vips benchmark + +export IM_CONCURRENCY=4 +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./vips im_benchmark /parsec/install/inputs/vips/barbados_256x288.v /parsec/install/inputs/vips/output.v +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simdev.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simdev.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the x264 benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./x264 --quiet --qp 20 --partitions b8x8,i4x4 --ref 5 --direct auto --b-pyramid --weightb --mixed-refs --no-fast-pskip --me umh --subme 7 --analyse b8x8,i4x4 --threads 4 -o /parsec/install/inputs/x264/eledream.264 /parsec/install/inputs/x264/eledream_64x36_3.y4m +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simlarge.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simlarge.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the x264 benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./x264 --quiet --qp 20 --partitions b8x8,i4x4 --ref 5 --direct auto --b-pyramid --weightb --mixed-refs --no-fast-pskip --me umh --subme 7 --analyse b8x8,i4x4 --threads 4 -o /parsec/install/inputs/x264/eledream.264 /parsec/install/inputs/x264/eledream_640x360_128.y4m +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simmedium.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simmedium.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the x264 benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./x264 --quiet --qp 20 --partitions b8x8,i4x4 --ref 5 --direct auto --b-pyramid --weightb --mixed-refs --no-fast-pskip --me umh --subme 7 --analyse b8x8,i4x4 --threads 4 -o /parsec/install/inputs/x264/eledream.264 /parsec/install/inputs/x264/eledream_640x360_32.y4m +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simsmall.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/x264_4c_simsmall.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the x264 benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./x264 --quiet --qp 20 --partitions b8x8,i4x4 --ref 5 --direct auto --b-pyramid --weightb --mixed-refs --no-fast-pskip --me umh --subme 7 --analyse b8x8,i4x4 --threads 4 -o /parsec/install/inputs/x264/eledream.264 /parsec/install/inputs/x264/eledream_640x360_8.y4m +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/x264_4c_test.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/x264_4c_test.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,12 @@ +#!/bin/sh + +# File to run the x264 benchmark + +cd /parsec/install/bin +/sbin/m5 switchcpu +/sbin/m5 dumpstats +/sbin/m5 resetstats +./x264 --quiet --qp 20 --partitions b8x8,i4x4 --ref 5 --direct auto --b-pyramid --weightb --mixed-refs --no-fast-pskip --me umh --subme 7 --analyse b8x8,i4x4 --threads 4 -o /parsec/install/inputs/x264/eledream.264 /parsec/install/inputs/x264/eledream_32x18_1.y4m +echo "Done :D" +/sbin/m5 exit +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/xalancbmk.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/xalancbmk.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,11 @@ +#!/bin/sh + +cd /benchmarks/483.xalancbmk/data/test/input +#cd /benchmarks/483.xalancbmk/data/train/input +echo "Xalan Test" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/483.xalancbmk/exe/Xalan_base.alpha-gcc410-glibc236 -v test.xml xalanc.xsl +#/benchmarks/483.xalancbmk/exe/Xalan_base.alpha-gcc410-glibc236 -v allbooks.xml xalanc.xsl > /dev/null +echo Done. +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/boot/xalancbmkLong.rcS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/boot/xalancbmkLong.rcS Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /benchmarks/483.xalancbmk/data/ref/input +echo "Xalan Ref" +/sbin/m5 resetstats +/sbin/m5 switchcpu +/benchmarks/483.xalancbmk/exe/Xalan_base.alpha-gcc410-glibc236 -v t5.xml xalanc.xsl +echo "Xalan Ref done" +/sbin/m5 exit diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/Benchmarks.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/Benchmarks.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,111 @@ +# Copyright (c) 2006-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +from SysPaths import * + +class SysConfig: + def __init__(self, script=None, mem=None, disk=None): + self.scriptname = script + self.diskname = disk + self.memsize = mem + + def script(self): + if self.scriptname: + return script(self.scriptname) + else: + return '' + + def mem(self): + if self.memsize: + return self.memsize + else: + return '128MB' + + def disk(self): + if self.diskname: + return disk(self.diskname) + else: + return env.get('LINUX_IMAGE', disk('linux-latest.img')) + +# Benchmarks are defined as a key in a dict which is a list of SysConfigs +# The first defined machine is the test system, the others are driving systems + +Benchmarks = { + 'PovrayBench': [SysConfig('povray-bench.rcS', '512MB', 'povray.img')], + 'PovrayAutumn': [SysConfig('povray-autumn.rcS', '512MB', 'povray.img')], + + 'NetperfStream': [SysConfig('netperf-stream-client.rcS'), + SysConfig('netperf-server.rcS')], + 'NetperfStreamUdp': [SysConfig('netperf-stream-udp-client.rcS'), + SysConfig('netperf-server.rcS')], + 'NetperfUdpLocal': [SysConfig('netperf-stream-udp-local.rcS')], + 'NetperfStreamNT': [SysConfig('netperf-stream-nt-client.rcS'), + SysConfig('netperf-server.rcS')], + 'NetperfMaerts': [SysConfig('netperf-maerts-client.rcS'), + SysConfig('netperf-server.rcS')], + 'SurgeStandard': [SysConfig('surge-server.rcS', '512MB'), + SysConfig('surge-client.rcS', '256MB')], + 'SurgeSpecweb': [SysConfig('spec-surge-server.rcS', '512MB'), + SysConfig('spec-surge-client.rcS', '256MB')], + 'Nhfsstone': [SysConfig('nfs-server-nhfsstone.rcS', '512MB'), + SysConfig('nfs-client-nhfsstone.rcS')], + 'Nfs': [SysConfig('nfs-server.rcS', '900MB'), + SysConfig('nfs-client-dbench.rcS')], + 'NfsTcp': [SysConfig('nfs-server.rcS', '900MB'), + SysConfig('nfs-client-tcp.rcS')], + 'IScsiInitiator': [SysConfig('iscsi-client.rcS', '512MB'), + SysConfig('iscsi-server.rcS', '512MB')], + 'IScsiTarget': [SysConfig('iscsi-server.rcS', '512MB'), + SysConfig('iscsi-client.rcS', '512MB')], + 'Validation': [SysConfig('iscsi-server.rcS', '512MB'), + SysConfig('iscsi-client.rcS', '512MB')], + 'Ping': [SysConfig('ping-server.rcS',), + SysConfig('ping-client.rcS')], + + 'ValAccDelay': [SysConfig('devtime.rcS', '512MB')], + 'ValAccDelay2': [SysConfig('devtimewmr.rcS', '512MB')], + 'ValMemLat': [SysConfig('micro_memlat.rcS', '512MB')], + 'ValMemLat2MB': [SysConfig('micro_memlat2mb.rcS', '512MB')], + 'ValMemLat8MB': [SysConfig('micro_memlat8mb.rcS', '512MB')], + 'ValMemLat': [SysConfig('micro_memlat8.rcS', '512MB')], + 'ValTlbLat': [SysConfig('micro_tlblat.rcS', '512MB')], + 'ValSysLat': [SysConfig('micro_syscall.rcS', '512MB')], + 'ValCtxLat': [SysConfig('micro_ctx.rcS', '512MB')], + 'ValStream': [SysConfig('micro_stream.rcS', '512MB')], + 'ValStreamScale': [SysConfig('micro_streamscale.rcS', '512MB')], + 'ValStreamCopy': [SysConfig('micro_streamcopy.rcS', '512MB')], + + 'MutexTest': [SysConfig('mutex-test.rcS', '128MB')], + + 'bnAn': [SysConfig('/z/saidi/work/m5.newmem.head/configs/boot/bn-app.rcS', + '128MB', '/z/saidi/work/bottleneck/bnimg.img')] +} + +benchs = Benchmarks.keys() +benchs.sort() +DefinedBenchmarks = ", ".join(benchs) diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/CacheConfig.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/CacheConfig.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,65 @@ +# Copyright (c) 2010 Advanced Micro Devices, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Lisa Hsu + +# Configure the M5 cache hierarchy config in one place +# + +import m5 +from m5.objects import * +from Caches import * + +def config_cache(options, system): + if options.l2cache: + system.l2cache = L2Cache(size='2MB') + system.tol2bus = Bus() + system.l2cache.cpu_side = system.tol2bus.port + system.l2cache.mem_side = system.membus.port + system.l2cache.num_cpus = options.num_cpus + + elif options.l3cache: + system.l3cache = L3Cache() + system.tol3bus = Bus() + system.l3cache.cpu_side = system.tol3bus.port + system.l3cache.mem_side = system.membus.port + system.l3cache.num_cpus = options.num_cpus + + for i in xrange(options.num_cpus): + if options.l1cache: + system.cpu[i].addPrivateSplitL1Caches(L1Cache(), L1Cache()) + system.cpu[i].connectMemPorts(system.membus) + + elif options.l2cache: + system.cpu[i].addPrivateSplitL1Caches(L1Cache(), L1Cache()) + system.cpu[i].connectMemPorts(system.tol2bus) + + elif options.l3cache: + system.cpu[i].addTwoLevelCacheHierarchy(L1Cache(), L1Cache(), L2Cache()) + system.cpu[i].connectMemPorts(system.tol3bus) + + + return system diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/Caches.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/Caches.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,69 @@ +# Copyright (c) 2006-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Lisa Hsu + +from m5.objects import * + +class L1Cache(BaseCache): + size = '32kB' + assoc = 4 + block_size = 64 + latency = '.9375ns' + num_cpus = 1 + mshrs = 10 + tgts_per_mshr = 5 + +class L2Cache(BaseCache): + size = '256kB' + assoc = 8 + block_size = 64 + latency = '3.4375ns' + num_cpus = 1 + mshrs = 20 + tgts_per_mshr = 12 + +class L3Cache(BaseCache): + size = '8MB' + assoc = 16 + block_size = 64 + latency = '12.25ns' + num_cpus = 4 + mshrs = 24 + tgts_per_mshr = 12 + prefetch_policy='ghb' + prefetch_degree=3 + prefetcher_size=256 + + +class IOCache(BaseCache): + assoc = 8 + block_size = 64 + latency = '10ns' + mshrs = 20 + size = '1kB' + tgts_per_mshr = 12 + forward_snoops = False diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/FSConfig.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/FSConfig.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,465 @@ +# Copyright (c) 2006-2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Kevin Lim + +from m5.objects import * +from Benchmarks import * + +class CowIdeDisk(IdeDisk): + image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + + def childImage(self, ci): + self.image.child.image_file = ci + +class MemBus(Bus): + badaddr_responder = BadAddr() + default = Self.badaddr_responder.pio + +def makeDramSimLinuxAlphaSystem(mem_mode, mdesc=None, extraParameters="", settingsFilename="", benchmarkName=None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + self = LinuxAlphaSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1, clock='3333MHz') + self.bridge = Bridge(delay='5ns', nack_delay='1ns') + + if mdesc.scriptname != None: + outFile = mdesc.scriptname.split('.')[0] + elif benchmarkName != None: + outFile = benchmarkName + else: + outFile = '' + + self.physmem = M5dramSystem(range=AddrRange(mdesc.mem())) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.iobus) + self.tsunami.ide.pio = self.iobus.port + self.tsunami.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(),read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + + +def makeLinuxAlphaSystem(mem_mode, mdesc = None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + + self = LinuxAlphaSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.iobus) + self.tsunami.ide.pio = self.iobus.port + self.tsunami.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +def makeLinuxAlphaRubySystem(mem_mode, mdesc = None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + + physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self = LinuxAlphaSystem(physmem = physmem) + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + + # Create pio bus to connect all device pio ports to rubymem's pio port + self.piobus = Bus(bus_id=0) + + # + # Pio functional accesses from devices need direct access to memory + # RubyPort currently does support functional accesses. Therefore provide + # the piobus a direct connection to physical memory + # + self.piobus.port = physmem.port + + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.piobus) + self.tsunami.ide.pio = self.piobus.port + self.tsunami.ethernet.pio = self.piobus.port + + # + # store the dma devices for later connection to dma ruby ports + # + self.dma_devices = [self.tsunami.ide, self.tsunami.ethernet] + + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +def makeSparcSystem(mem_mode, mdesc = None): + class CowMmDisk(MmDisk): + image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + + def childImage(self, ci): + self.image.child.image_file = ci + + self = SparcSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.t1000 = T1000() + self.t1000.attachOnChipIO(self.membus) + self.t1000.attachIO(self.iobus) + self.physmem = PhysicalMemory(range = AddrRange(Addr('1MB'), size = '64MB'), zero = True) + self.physmem2 = PhysicalMemory(range = AddrRange(Addr('2GB'), size ='256MB'), zero = True) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.physmem2.port = self.membus.port + self.rom.port = self.membus.port + self.nvram.port = self.membus.port + self.hypervisor_desc.port = self.membus.port + self.partition_desc.port = self.membus.port + self.intrctrl = IntrControl() + self.disk0 = CowMmDisk() + self.disk0.childImage(disk('disk.s10hw2')) + self.disk0.pio = self.iobus.port + self.reset_bin = binary('reset_new.bin') + self.hypervisor_bin = binary('q_new.bin') + self.openboot_bin = binary('openboot_new.bin') + self.nvram_bin = binary('nvram1') + self.hypervisor_desc_bin = binary('1up-hv.bin') + self.partition_desc_bin = binary('1up-md.bin') + + return self + +def makeLinuxMipsSystem(mem_mode, mdesc = None): + class BaseMalta(Malta): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + + self = LinuxMipsSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.physmem = PhysicalMemory(range = AddrRange('1GB')) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.malta = BaseMalta() + self.malta.attachIO(self.iobus) + self.malta.ide.pio = self.iobus.port + self.malta.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('mips/vmlinux') + self.console = binary('mips/console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +def x86IOAddress(port): + IO_address_space_base = 0x8000000000000000 + return IO_address_space_base + port; + +def makeX86System(mem_mode, numCPUs = 1, mdesc = None, self = None): + if self == None: + self = X86System() + + if not mdesc: + # generic system + mdesc = SysConfig() + mdesc.diskname = 'x86root.img' + self.readfile = mdesc.script() + + self.mem_mode = mem_mode + + # Physical memory + self.membus = MemBus(bus_id=1) + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self.physmem.port = self.membus.port + + # North Bridge + self.iobus = Bus(bus_id=0) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + + # Platform + self.pc = Pc() + self.pc.attachIO(self.iobus) + + self.intrctrl = IntrControl() + + # Disks + disk0 = CowIdeDisk(driveID='master') + disk2 = CowIdeDisk(driveID='master') + disk0.childImage(mdesc.disk()) + disk2.childImage(disk('linux-bigswap2.img')) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + # Add in a Bios information structure. + structures = [X86SMBiosBiosInformation()] + self.smbios_table.structures = structures + + # Set up the Intel MP table + for i in xrange(numCPUs): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i == 0)) + self.intel_mp_table.add_entry(bp) + io_apic = X86IntelMPIOAPIC( + id = numCPUs, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + self.intel_mp_table.add_entry(io_apic) + isa_bus = X86IntelMPBus(bus_id = 0, bus_type='ISA') + self.intel_mp_table.add_entry(isa_bus) + pci_bus = X86IntelMPBus(bus_id = 1, bus_type='PCI') + self.intel_mp_table.add_entry(pci_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=0, + subtractive_decode=True, parent_bus=1) + self.intel_mp_table.add_entry(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + self.intel_mp_table.add_entry(pci_dev4_inta); + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + self.intel_mp_table.add_entry(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + self.intel_mp_table.add_entry(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + + +def makeLinuxX86System(mem_mode, numCPUs = 1, mdesc = None): + self = LinuxX86System() + + # Build up a generic x86 system and then specialize it for Linux + makeX86System(mem_mode, numCPUs, mdesc, self) + + # We assume below that there's at least 1MB of memory. We'll require 2 + # just to avoid corner cases. + assert(self.physmem.range.second.getValue() >= 0x200000) + + # Mark the first megabyte of memory as reserved + self.e820_table.entries.append(X86E820Entry( + addr = 0, + size = '1MB', + range_type = 2)) + + # Mark the rest as available + self.e820_table.entries.append(X86E820Entry( + addr = 0x100000, + size = '%dB' % (self.physmem.range.second - 0x100000 + 1), + range_type = 1)) + + # Command line + self.boot_osflags = 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923 ' + \ + 'root=/dev/hda1' + return self + + +def makeDualRoot(testSystem, driveSystem, dumpfile): + self = Root() + self.testsys = testSystem + self.drivesys = driveSystem + self.etherlink = EtherLink() + self.etherlink.int0 = Parent.testsys.tsunami.ethernet.interface + self.etherlink.int1 = Parent.drivesys.tsunami.ethernet.interface + + if dumpfile: + self.etherdump = EtherDump(file=dumpfile) + self.etherlink.dump = Parent.etherdump + + return self + +def setMipsOptions(TestCPUClass): + #CP0 Configuration + TestCPUClass.CoreParams.CP0_PRId_CompanyOptions = 0 + TestCPUClass.CoreParams.CP0_PRId_CompanyID = 1 + TestCPUClass.CoreParams.CP0_PRId_ProcessorID = 147 + TestCPUClass.CoreParams.CP0_PRId_Revision = 0 + + #CP0 Interrupt Control + TestCPUClass.CoreParams.CP0_IntCtl_IPTI = 7 + TestCPUClass.CoreParams.CP0_IntCtl_IPPCI = 7 + + # Config Register + #TestCPUClass.CoreParams.CP0_Config_K23 = 0 # Since TLB + #TestCPUClass.CoreParams.CP0_Config_KU = 0 # Since TLB + TestCPUClass.CoreParams.CP0_Config_BE = 0 # Little Endian + TestCPUClass.CoreParams.CP0_Config_AR = 1 # Architecture Revision 2 + TestCPUClass.CoreParams.CP0_Config_AT = 0 # MIPS32 + TestCPUClass.CoreParams.CP0_Config_MT = 1 # TLB MMU + #TestCPUClass.CoreParams.CP0_Config_K0 = 2 # Uncached + + #Config 1 Register + TestCPUClass.CoreParams.CP0_Config1_M = 1 # Config2 Implemented + TestCPUClass.CoreParams.CP0_Config1_MMU = 63 # TLB Size + # ***VERY IMPORTANT*** + # Remember to modify CP0_Config1 according to cache specs + # Examine file ../common/Cache.py + TestCPUClass.CoreParams.CP0_Config1_IS = 1 # I-Cache Sets Per Way, 16KB cache, i.e., 1 (128) + TestCPUClass.CoreParams.CP0_Config1_IL = 5 # I-Cache Line Size, default in Cache.py is 64, i.e 5 + TestCPUClass.CoreParams.CP0_Config1_IA = 1 # I-Cache Associativity, default in Cache.py is 2, i.e, a value of 1 + TestCPUClass.CoreParams.CP0_Config1_DS = 2 # D-Cache Sets Per Way (see below), 32KB cache, i.e., 2 + TestCPUClass.CoreParams.CP0_Config1_DL = 5 # D-Cache Line Size, default is 64, i.e., 5 + TestCPUClass.CoreParams.CP0_Config1_DA = 1 # D-Cache Associativity, default is 2, i.e. 1 + TestCPUClass.CoreParams.CP0_Config1_C2 = 0 # Coprocessor 2 not implemented(?) + TestCPUClass.CoreParams.CP0_Config1_MD = 0 # MDMX ASE not implemented in Mips32 + TestCPUClass.CoreParams.CP0_Config1_PC = 1 # Performance Counters Implemented + TestCPUClass.CoreParams.CP0_Config1_WR = 0 # Watch Registers Implemented + TestCPUClass.CoreParams.CP0_Config1_CA = 0 # Mips16e NOT implemented + TestCPUClass.CoreParams.CP0_Config1_EP = 0 # EJTag Not Implemented + TestCPUClass.CoreParams.CP0_Config1_FP = 0 # FPU Implemented + + #Config 2 Register + TestCPUClass.CoreParams.CP0_Config2_M = 1 # Config3 Implemented + TestCPUClass.CoreParams.CP0_Config2_TU = 0 # Tertiary Cache Control + TestCPUClass.CoreParams.CP0_Config2_TS = 0 # Tertiary Cache Sets Per Way + TestCPUClass.CoreParams.CP0_Config2_TL = 0 # Tertiary Cache Line Size + TestCPUClass.CoreParams.CP0_Config2_TA = 0 # Tertiary Cache Associativity + TestCPUClass.CoreParams.CP0_Config2_SU = 0 # Secondary Cache Control + TestCPUClass.CoreParams.CP0_Config2_SS = 0 # Secondary Cache Sets Per Way + TestCPUClass.CoreParams.CP0_Config2_SL = 0 # Secondary Cache Line Size + TestCPUClass.CoreParams.CP0_Config2_SA = 0 # Secondary Cache Associativity + + + #Config 3 Register + TestCPUClass.CoreParams.CP0_Config3_M = 0 # Config4 Not Implemented + TestCPUClass.CoreParams.CP0_Config3_DSPP = 1 # DSP ASE Present + TestCPUClass.CoreParams.CP0_Config3_LPA = 0 # Large Physical Addresses Not supported in Mips32 + TestCPUClass.CoreParams.CP0_Config3_VEIC = 0 # EIC Supported + TestCPUClass.CoreParams.CP0_Config3_VInt = 0 # Vectored Interrupts Implemented + TestCPUClass.CoreParams.CP0_Config3_SP = 0 # Small Pages Supported (PageGrain reg. exists) + TestCPUClass.CoreParams.CP0_Config3_MT = 0 # MT Not present + TestCPUClass.CoreParams.CP0_Config3_SM = 0 # SmartMIPS ASE Not implemented + TestCPUClass.CoreParams.CP0_Config3_TL = 0 # TraceLogic Not implemented + + #SRS Ctl - HSS + TestCPUClass.CoreParams.CP0_SrsCtl_HSS = 3 # Four shadow register sets implemented + + + #TestCPUClass.CoreParams.tlb = TLB() + #TestCPUClass.CoreParams.UnifiedTLB = 1 diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/FSConfig.py.orig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/FSConfig.py.orig Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,469 @@ +# Copyright (c) 2006-2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Kevin Lim + +from m5.objects import * +from Benchmarks import * + +class CowIdeDisk(IdeDisk): + image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + + def childImage(self, ci): + self.image.child.image_file = ci + +class MemBus(Bus): + badaddr_responder = BadAddr() + default = Self.badaddr_responder.pio + +def makeDramSimLinuxAlphaSystem(mem_mode, mdesc=None, extraParameters="", settingsFilename="", benchmarkName=None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + self = LinuxAlphaSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1, clock='4000MHz') + self.bridge = Bridge(delay='2ns', nack_delay='1ns') + + if mdesc.scriptname != None: + outFile = mdesc.scriptname.split('.')[0] + elif benchmarkName != None: + outFile = benchmarkName + else: + outFile = '' + + self.physmem = M5dramSystem(extraParameters=extraParameters, + settingsFile=settingsFilename, + outFilename=outFile, + commandLine=outFile, + range=AddrRange(mdesc.mem())) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.iobus) + self.tsunami.ide.pio = self.iobus.port + self.tsunami.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(),read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + + +def makeLinuxAlphaSystem(mem_mode, mdesc = None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + + self = LinuxAlphaSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.iobus) + self.tsunami.ide.pio = self.iobus.port + self.tsunami.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +def makeLinuxAlphaRubySystem(mem_mode, mdesc = None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + + physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self = LinuxAlphaSystem(physmem = physmem) + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + + # Create pio bus to connect all device pio ports to rubymem's pio port + self.piobus = Bus(bus_id=0) + + # + # Pio functional accesses from devices need direct access to memory + # RubyPort currently does support functional accesses. Therefore provide + # the piobus a direct connection to physical memory + # + self.piobus.port = physmem.port + + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.piobus) + self.tsunami.ide.pio = self.piobus.port + self.tsunami.ethernet.pio = self.piobus.port + + # + # store the dma devices for later connection to dma ruby ports + # + self.dma_devices = [self.tsunami.ide, self.tsunami.ethernet] + + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +def makeSparcSystem(mem_mode, mdesc = None): + class CowMmDisk(MmDisk): + image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + + def childImage(self, ci): + self.image.child.image_file = ci + + self = SparcSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.t1000 = T1000() + self.t1000.attachOnChipIO(self.membus) + self.t1000.attachIO(self.iobus) + self.physmem = PhysicalMemory(range = AddrRange(Addr('1MB'), size = '64MB'), zero = True) + self.physmem2 = PhysicalMemory(range = AddrRange(Addr('2GB'), size ='256MB'), zero = True) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.physmem2.port = self.membus.port + self.rom.port = self.membus.port + self.nvram.port = self.membus.port + self.hypervisor_desc.port = self.membus.port + self.partition_desc.port = self.membus.port + self.intrctrl = IntrControl() + self.disk0 = CowMmDisk() + self.disk0.childImage(disk('disk.s10hw2')) + self.disk0.pio = self.iobus.port + self.reset_bin = binary('reset_new.bin') + self.hypervisor_bin = binary('q_new.bin') + self.openboot_bin = binary('openboot_new.bin') + self.nvram_bin = binary('nvram1') + self.hypervisor_desc_bin = binary('1up-hv.bin') + self.partition_desc_bin = binary('1up-md.bin') + + return self + +def makeLinuxMipsSystem(mem_mode, mdesc = None): + class BaseMalta(Malta): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + + self = LinuxMipsSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.physmem = PhysicalMemory(range = AddrRange('1GB')) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.malta = BaseMalta() + self.malta.attachIO(self.iobus) + self.malta.ide.pio = self.iobus.port + self.malta.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('mips/vmlinux') + self.console = binary('mips/console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +def x86IOAddress(port): + IO_address_space_base = 0x8000000000000000 + return IO_address_space_base + port; + +def makeX86System(mem_mode, numCPUs = 1, mdesc = None, self = None): + if self == None: + self = X86System() + + if not mdesc: + # generic system + mdesc = SysConfig() + mdesc.diskname = 'x86root.img' + self.readfile = mdesc.script() + + self.mem_mode = mem_mode + + # Physical memory + self.membus = MemBus(bus_id=1) + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self.physmem.port = self.membus.port + + # North Bridge + self.iobus = Bus(bus_id=0) + self.bridge = Bridge(delay='50ns', nack_delay='4ns') + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + + # Platform + self.pc = Pc() + self.pc.attachIO(self.iobus) + + self.intrctrl = IntrControl() + + # Disks + disk0 = CowIdeDisk(driveID='master') + disk2 = CowIdeDisk(driveID='master') + disk0.childImage(mdesc.disk()) + disk2.childImage(disk('linux-bigswap2.img')) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + # Add in a Bios information structure. + structures = [X86SMBiosBiosInformation()] + self.smbios_table.structures = structures + + # Set up the Intel MP table + for i in xrange(numCPUs): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i == 0)) + self.intel_mp_table.add_entry(bp) + io_apic = X86IntelMPIOAPIC( + id = numCPUs, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + self.intel_mp_table.add_entry(io_apic) + isa_bus = X86IntelMPBus(bus_id = 0, bus_type='ISA') + self.intel_mp_table.add_entry(isa_bus) + pci_bus = X86IntelMPBus(bus_id = 1, bus_type='PCI') + self.intel_mp_table.add_entry(pci_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=0, + subtractive_decode=True, parent_bus=1) + self.intel_mp_table.add_entry(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + self.intel_mp_table.add_entry(pci_dev4_inta); + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + self.intel_mp_table.add_entry(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + self.intel_mp_table.add_entry(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + + +def makeLinuxX86System(mem_mode, numCPUs = 1, mdesc = None): + self = LinuxX86System() + + # Build up a generic x86 system and then specialize it for Linux + makeX86System(mem_mode, numCPUs, mdesc, self) + + # We assume below that there's at least 1MB of memory. We'll require 2 + # just to avoid corner cases. + assert(self.physmem.range.second.getValue() >= 0x200000) + + # Mark the first megabyte of memory as reserved + self.e820_table.entries.append(X86E820Entry( + addr = 0, + size = '1MB', + range_type = 2)) + + # Mark the rest as available + self.e820_table.entries.append(X86E820Entry( + addr = 0x100000, + size = '%dB' % (self.physmem.range.second - 0x100000 + 1), + range_type = 1)) + + # Command line + self.boot_osflags = 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923 ' + \ + 'root=/dev/hda1' + return self + + +def makeDualRoot(testSystem, driveSystem, dumpfile): + self = Root() + self.testsys = testSystem + self.drivesys = driveSystem + self.etherlink = EtherLink() + self.etherlink.int0 = Parent.testsys.tsunami.ethernet.interface + self.etherlink.int1 = Parent.drivesys.tsunami.ethernet.interface + + if dumpfile: + self.etherdump = EtherDump(file=dumpfile) + self.etherlink.dump = Parent.etherdump + + return self + +def setMipsOptions(TestCPUClass): + #CP0 Configuration + TestCPUClass.CoreParams.CP0_PRId_CompanyOptions = 0 + TestCPUClass.CoreParams.CP0_PRId_CompanyID = 1 + TestCPUClass.CoreParams.CP0_PRId_ProcessorID = 147 + TestCPUClass.CoreParams.CP0_PRId_Revision = 0 + + #CP0 Interrupt Control + TestCPUClass.CoreParams.CP0_IntCtl_IPTI = 7 + TestCPUClass.CoreParams.CP0_IntCtl_IPPCI = 7 + + # Config Register + #TestCPUClass.CoreParams.CP0_Config_K23 = 0 # Since TLB + #TestCPUClass.CoreParams.CP0_Config_KU = 0 # Since TLB + TestCPUClass.CoreParams.CP0_Config_BE = 0 # Little Endian + TestCPUClass.CoreParams.CP0_Config_AR = 1 # Architecture Revision 2 + TestCPUClass.CoreParams.CP0_Config_AT = 0 # MIPS32 + TestCPUClass.CoreParams.CP0_Config_MT = 1 # TLB MMU + #TestCPUClass.CoreParams.CP0_Config_K0 = 2 # Uncached + + #Config 1 Register + TestCPUClass.CoreParams.CP0_Config1_M = 1 # Config2 Implemented + TestCPUClass.CoreParams.CP0_Config1_MMU = 63 # TLB Size + # ***VERY IMPORTANT*** + # Remember to modify CP0_Config1 according to cache specs + # Examine file ../common/Cache.py + TestCPUClass.CoreParams.CP0_Config1_IS = 1 # I-Cache Sets Per Way, 16KB cache, i.e., 1 (128) + TestCPUClass.CoreParams.CP0_Config1_IL = 5 # I-Cache Line Size, default in Cache.py is 64, i.e 5 + TestCPUClass.CoreParams.CP0_Config1_IA = 1 # I-Cache Associativity, default in Cache.py is 2, i.e, a value of 1 + TestCPUClass.CoreParams.CP0_Config1_DS = 2 # D-Cache Sets Per Way (see below), 32KB cache, i.e., 2 + TestCPUClass.CoreParams.CP0_Config1_DL = 5 # D-Cache Line Size, default is 64, i.e., 5 + TestCPUClass.CoreParams.CP0_Config1_DA = 1 # D-Cache Associativity, default is 2, i.e. 1 + TestCPUClass.CoreParams.CP0_Config1_C2 = 0 # Coprocessor 2 not implemented(?) + TestCPUClass.CoreParams.CP0_Config1_MD = 0 # MDMX ASE not implemented in Mips32 + TestCPUClass.CoreParams.CP0_Config1_PC = 1 # Performance Counters Implemented + TestCPUClass.CoreParams.CP0_Config1_WR = 0 # Watch Registers Implemented + TestCPUClass.CoreParams.CP0_Config1_CA = 0 # Mips16e NOT implemented + TestCPUClass.CoreParams.CP0_Config1_EP = 0 # EJTag Not Implemented + TestCPUClass.CoreParams.CP0_Config1_FP = 0 # FPU Implemented + + #Config 2 Register + TestCPUClass.CoreParams.CP0_Config2_M = 1 # Config3 Implemented + TestCPUClass.CoreParams.CP0_Config2_TU = 0 # Tertiary Cache Control + TestCPUClass.CoreParams.CP0_Config2_TS = 0 # Tertiary Cache Sets Per Way + TestCPUClass.CoreParams.CP0_Config2_TL = 0 # Tertiary Cache Line Size + TestCPUClass.CoreParams.CP0_Config2_TA = 0 # Tertiary Cache Associativity + TestCPUClass.CoreParams.CP0_Config2_SU = 0 # Secondary Cache Control + TestCPUClass.CoreParams.CP0_Config2_SS = 0 # Secondary Cache Sets Per Way + TestCPUClass.CoreParams.CP0_Config2_SL = 0 # Secondary Cache Line Size + TestCPUClass.CoreParams.CP0_Config2_SA = 0 # Secondary Cache Associativity + + + #Config 3 Register + TestCPUClass.CoreParams.CP0_Config3_M = 0 # Config4 Not Implemented + TestCPUClass.CoreParams.CP0_Config3_DSPP = 1 # DSP ASE Present + TestCPUClass.CoreParams.CP0_Config3_LPA = 0 # Large Physical Addresses Not supported in Mips32 + TestCPUClass.CoreParams.CP0_Config3_VEIC = 0 # EIC Supported + TestCPUClass.CoreParams.CP0_Config3_VInt = 0 # Vectored Interrupts Implemented + TestCPUClass.CoreParams.CP0_Config3_SP = 0 # Small Pages Supported (PageGrain reg. exists) + TestCPUClass.CoreParams.CP0_Config3_MT = 0 # MT Not present + TestCPUClass.CoreParams.CP0_Config3_SM = 0 # SmartMIPS ASE Not implemented + TestCPUClass.CoreParams.CP0_Config3_TL = 0 # TraceLogic Not implemented + + #SRS Ctl - HSS + TestCPUClass.CoreParams.CP0_SrsCtl_HSS = 3 # Four shadow register sets implemented + + + #TestCPUClass.CoreParams.tlb = TLB() + #TestCPUClass.CoreParams.UnifiedTLB = 1 diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/Options.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/Options.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,105 @@ +# Copyright (c) 2006-2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Lisa Hsu + +# system options +parser.add_option("-d", "--detailed", action="store_true") +parser.add_option("-t", "--timing", action="store_true") +parser.add_option("--inorder", action="store_true") +parser.add_option("-n", "--num-cpus", type="int", default=1) +parser.add_option("--caches", action="store_true") +parser.add_option("--l1cache", action="store_true") +parser.add_option("--l2cache", action="store_true") +parser.add_option("--l3cache", action="store_true") +parser.add_option("--fastmem", action="store_true") +parser.add_option("--clock", action="store", type="string", default='1GHz') +parser.add_option("--num-dirs", type="int", default=1) +parser.add_option("--num-l2caches", type="int", default=1) +parser.add_option("--topology", type="string", default="Crossbar", + help="check src/mem/ruby/network/topologies for complete set") +parser.add_option("--mesh-rows", type="int", default=1, + help="the number of rows in the mesh topology") +parser.add_option("--garnet-network", type="string", default=None, + help="'fixed'|'flexible'") +parser.add_option("--numa-high-bit", type="int", default=None, + help="high order address bit to use for numa mapping") + +# ruby sparse memory options +parser.add_option("--use-map", action="store_true", default=False) +parser.add_option("--map-levels", type="int", default=4) + +# Run duration options +parser.add_option("-m", "--maxtick", type="int", default=m5.MaxTick, + metavar="T", + help="Stop after T ticks") +parser.add_option("--maxtime", type="float") +parser.add_option("--maxinsts", type="int") +parser.add_option("--prog_intvl", type="int") + + +# Checkpointing options +###Note that performing checkpointing via python script files will override +###checkpoint instructions built into binaries. +parser.add_option("--take-checkpoints", action="store", type="string", + help=" will take checkpoint at cycle M and every N cycles thereafter") +parser.add_option("--max-checkpoints", action="store", type="int", + help="the maximum number of checkpoints to drop", default=5) +parser.add_option("--checkpoint-dir", action="store", type="string", + help="Place all checkpoints in this absolute directory") +parser.add_option("-r", "--checkpoint-restore", action="store", type="int", + help="restore from checkpoint ") +parser.add_option("--checkpoint-at-end", action="store_true", + help="take a checkpoint at end of run") + + +# CPU Switching - default switch model goes from a checkpoint +# to a timing simple CPU with caches to warm up, then to detailed CPU for +# data measurement +parser.add_option("-s", "--standard-switch", action="store_true", + help="switch from timing CPU to Detailed CPU") +parser.add_option("-w", "--warmup", action="store", type="int", + help="if -s, then this is the warmup period. else, this is ignored", + default=5000000000) +parser.add_option("--profile", help="CPU profile interval") + +# Fastforwarding and simpoint related materials +parser.add_option("-W", "--warmup-insts", action="store", type="int", + default=None, + help="Warmup period in total instructions (requires --standard-switch)") +parser.add_option("-I", "--max-inst", action="store", type="int", default=None, + help="Total number of instructions to simulate (default: run forever)") +parser.add_option("--bench", action="store", type="string", default=None, + help="base names for --take-checkpoint and --checkpoint-restore") +parser.add_option("-F", "--fast-forward", action="store", type="string", + default=None, + help="Number of instructions to fast forward before switching") +parser.add_option("-S", "--simpoint", action="store_true", default=False, + help="""Use workload simpoints as an instruction offset for +--checkpoint-restore or --take-checkpoint.""") +parser.add_option("--at-instruction", action="store_true", default=False, + help="""Treate value of --checkpoint-restore or --take-checkpoint as a +number of instructions.""") diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/Simulation.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/Simulation.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,374 @@ +# Copyright (c) 2006-2008 The Regents of The University of Michigan +# Copyright (c) 2010 Advanced Micro Devices, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Lisa Hsu + +from os import getcwd +from os.path import join as joinpath + +import m5 +from m5.defines import buildEnv +from m5.objects import * +from m5.util import * + +addToPath('../common') + +def setCPUClass(options): + + atomic = False + if options.timing: + class TmpClass(TimingSimpleCPU): pass + elif options.detailed: + if not options.caches: + print "O3 CPU must be used with caches" + sys.exit(1) + class TmpClass(DerivO3CPU): pass + elif options.inorder: + if not options.caches: + print "InOrder CPU must be used with caches" + sys.exit(1) + class TmpClass(InOrderCPU): pass + else: + class TmpClass(AtomicSimpleCPU): pass + atomic = True + + CPUClass = None + test_mem_mode = 'atomic' + + if not atomic: + if options.checkpoint_restore != None or options.fast_forward: + CPUClass = TmpClass + class TmpClass(AtomicSimpleCPU): pass + else: + test_mem_mode = 'timing' + + return (TmpClass, test_mem_mode, CPUClass) + + +def run(options, root, testsys, cpu_class): + if options.maxtick: + maxtick = options.maxtick + elif options.maxtime: + simtime = m5.ticks.seconds(simtime) + print "simulating for: ", simtime + maxtick = simtime + else: + maxtick = m5.MaxTick + + if options.checkpoint_dir: + cptdir = options.checkpoint_dir + elif m5.options.outdir: + cptdir = m5.options.outdir + else: + cptdir = getcwd() + + if options.fast_forward and options.checkpoint_restore != None: + fatal("Can't specify both --fast-forward and --checkpoint-restore") + + if options.standard_switch and not options.caches: + fatal("Must specify --caches when using --standard-switch") + + np = options.num_cpus + max_checkpoints = options.max_checkpoints + switch_cpus = None + + if options.prog_intvl: + for i in xrange(np): + testsys.cpu[i].progress_interval = options.prog_intvl + + if options.maxinsts: + for i in xrange(np): + testsys.cpu[i].max_insts_any_thread = options.maxinsts + + if cpu_class: + switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) + for i in xrange(np)] + + for i in xrange(np): + if options.fast_forward: + testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) + switch_cpus[i].system = testsys + if not buildEnv['FULL_SYSTEM']: + switch_cpus[i].workload = testsys.cpu[i].workload + switch_cpus[i].clock = testsys.cpu[0].clock + # simulation period + if options.max_inst: + switch_cpus[i].max_insts_any_thread = options.max_inst + + testsys.switch_cpus = switch_cpus + switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] + + if options.standard_switch: + switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) + for i in xrange(np)] + switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) + for i in xrange(np)] + + for i in xrange(np): + switch_cpus[i].system = testsys + switch_cpus_1[i].system = testsys + if not buildEnv['FULL_SYSTEM']: + switch_cpus[i].workload = testsys.cpu[i].workload + switch_cpus_1[i].workload = testsys.cpu[i].workload + switch_cpus[i].clock = testsys.cpu[0].clock + switch_cpus_1[i].clock = testsys.cpu[0].clock + + # if restoring, make atomic cpu simulate only a few instructions + if options.checkpoint_restore != None: + testsys.cpu[i].max_insts_any_thread = 1 + # Fast forward to specified location if we are not restoring + elif options.fast_forward: + testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) + # Fast forward to a simpoint (warning: time consuming) + elif options.simpoint: + if testsys.cpu[i].workload[0].simpoint == 0: + fatal('simpoint not found') + testsys.cpu[i].max_insts_any_thread = \ + testsys.cpu[i].workload[0].simpoint + # No distance specified, just switch + else: + testsys.cpu[i].max_insts_any_thread = 1 + + # warmup period + if options.warmup_insts: + switch_cpus[i].max_insts_any_thread = options.warmup_insts + + # simulation period + if options.max_inst: + switch_cpus_1[i].max_insts_any_thread = options.max_inst + + if not options.caches: + # O3 CPU must have a cache to work. + print "O3 CPU must be used with caches" + sys.exit(1) + + testsys.switch_cpus = switch_cpus + testsys.switch_cpus_1 = switch_cpus_1 + switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] + switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] + + # set the checkpoint in the cpu before m5.instantiate is called + if options.take_checkpoints != None and \ + (options.simpoint or options.at_instruction): + offset = int(options.take_checkpoints) + # Set an instruction break point + if options.simpoint: + for i in xrange(np): + if testsys.cpu[i].workload[0].simpoint == 0: + fatal('no simpoint for testsys.cpu[%d].workload[0]', i) + checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset + testsys.cpu[i].max_insts_any_thread = checkpoint_inst + # used for output below + options.take_checkpoints = checkpoint_inst + else: + options.take_checkpoints = offset + # Set all test cpus with the right number of instructions + # for the upcoming simulation + for i in xrange(np): + testsys.cpu[i].max_insts_any_thread = offset + + checkpoint_dir = None + if options.checkpoint_restore != None: + from os.path import isdir, exists + from os import listdir + import re + + if not isdir(cptdir): + fatal("checkpoint dir %s does not exist!", cptdir) + + if options.at_instruction or options.simpoint: + inst = options.checkpoint_restore + if options.simpoint: + # assume workload 0 has the simpoint + if testsys.cpu[0].workload[0].simpoint == 0: + fatal('Unable to find simpoint') + inst += int(testsys.cpu[0].workload[0].simpoint) + + checkpoint_dir = joinpath(cptdir, + "cpt.%s.%s" % (options.bench, inst)) + if not exists(checkpoint_dir): + fatal("Unable to find checkpoint directory %s", checkpoint_dir) + else: + dirs = listdir(cptdir) + expr = re.compile('cpt\.([0-9]*)') + cpts = [] + for dir in dirs: + match = expr.match(dir) + if match: + cpts.append(match.group(1)) + + cpts.sort(lambda a,b: cmp(long(a), long(b))) + + cpt_num = options.checkpoint_restore + + if cpt_num > len(cpts): + fatal('Checkpoint %d not found', cpt_num) + + ## Adjust max tick based on our starting tick + maxtick = maxtick - int(cpts[cpt_num - 1]) + checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) + + m5.instantiate(checkpoint_dir) + + if options.standard_switch or cpu_class: + if options.standard_switch: + print "Switch at instruction count:%s" % \ + str(testsys.cpu[0].max_insts_any_thread) + exit_event = m5.simulate() + elif cpu_class and options.fast_forward: + print "Switch at instruction count:%s" % \ + str(testsys.cpu[0].max_insts_any_thread) + exit_event = m5.simulate() + else: + print "Switch at curTick count:%s" % str(10000) + exit_event = m5.simulate(10000) + print "Switched CPUS @ cycle = %s" % (m5.curTick()) + + # when you change to Timing (or Atomic), you halt the system + # given as argument. When you are finished with the system + # changes (including switchCpus), you must resume the system + # manually. You DON'T need to resume after just switching + # CPUs if you haven't changed anything on the system level. + + m5.changeToTiming(testsys) + m5.switchCpus(switch_cpu_list) + m5.resume(testsys) + + if options.standard_switch: + print "Switch at instruction count:%d" % \ + (testsys.switch_cpus[0].max_insts_any_thread) + + #warmup instruction count may have already been set + if options.warmup_insts: + exit_event = m5.simulate() + else: + exit_event = m5.simulate(options.warmup) + print "Switching CPUS @ cycle = %s" % (m5.curTick()) + print "Simulation ends instruction count:%d" % \ + (testsys.switch_cpus_1[0].max_insts_any_thread) + m5.drain(testsys) + m5.switchCpus(switch_cpu_list1) + m5.resume(testsys) + + num_checkpoints = 0 + exit_cause = '' + + # If we're taking and restoring checkpoints, use checkpoint_dir + # option only for finding the checkpoints to restore from. This + # lets us test checkpointing by restoring from one set of + # checkpoints, generating a second set, and then comparing them. + if options.take_checkpoints and options.checkpoint_restore: + if m5.options.outdir: + cptdir = m5.options.outdir + else: + cptdir = getcwd() + + # Checkpoints being taken via the command line at and at + # subsequent periods of . Checkpoint instructions + # received from the benchmark running are ignored and skipped in + # favor of command line checkpoint instructions. + if options.take_checkpoints != None : + if options.at_instruction or options.simpoint: + checkpoint_inst = int(options.take_checkpoints) + + # maintain correct offset if we restored from some instruction + if options.checkpoint_restore != None: + checkpoint_inst += options.checkpoint_restore + + print "Creating checkpoint at inst:%d" % (checkpoint_inst) + exit_event = m5.simulate() + print "exit cause = %s" % (exit_event.getCause()) + + # skip checkpoint instructions should they exist + while exit_event.getCause() == "checkpoint": + exit_event = m5.simulate() + + if exit_event.getCause() == \ + "a thread reached the max instruction count": + m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ + (options.bench, checkpoint_inst))) + print "Checkpoint written." + num_checkpoints += 1 + + if exit_event.getCause() == "user interrupt received": + exit_cause = exit_event.getCause(); + else: + when, period = options.take_checkpoints.split(",", 1) + when = int(when) + period = int(period) + + exit_event = m5.simulate(when) + while exit_event.getCause() == "checkpoint": + exit_event = m5.simulate(when - m5.curTick()) + + if exit_event.getCause() == "simulate() limit reached": + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + num_checkpoints += 1 + + sim_ticks = when + exit_cause = "maximum %d checkpoints dropped" % max_checkpoints + while num_checkpoints < max_checkpoints and \ + exit_event.getCause() == "simulate() limit reached": + if (sim_ticks + period) > maxtick: + exit_event = m5.simulate(maxtick - sim_ticks) + exit_cause = exit_event.getCause() + break + else: + exit_event = m5.simulate(period) + sim_ticks += period + while exit_event.getCause() == "checkpoint": + exit_event = m5.simulate(sim_ticks - m5.curTick()) + if exit_event.getCause() == "simulate() limit reached": + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + num_checkpoints += 1 + + if exit_event.getCause() != "simulate() limit reached": + exit_cause = exit_event.getCause(); + + else: # no checkpoints being taken via this script + if options.fast_forward: + m5.stats.reset() + print "**** REAL SIMULATION ****" + exit_event = m5.simulate(maxtick) + + while exit_event.getCause() == "checkpoint": + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + num_checkpoints += 1 + if num_checkpoints == max_checkpoints: + exit_cause = "maximum %d checkpoints dropped" % max_checkpoints + break + + exit_event = m5.simulate(maxtick - m5.curTick()) + exit_cause = exit_event.getCause() + + if exit_cause == '': + exit_cause = exit_event.getCause() + print 'Exiting @ cycle %i because %s' % (m5.curTick(), exit_cause) + + if options.checkpoint_at_end: + m5.checkpoint(joinpath(cptdir, "cpt.%d")) + diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/common/SysPaths.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/common/SysPaths.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,71 @@ +# Copyright (c) 2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +import os, sys +from os.path import isdir, join as joinpath +from os import environ as env + +config_path = os.path.dirname(os.path.abspath(__file__)) +config_root = os.path.dirname(config_path) + +def disk(file): + system() + return joinpath(disk.dir, file) + +def binary(file): + system() + return joinpath(binary.dir, file) + +def script(file): + system() + return joinpath(script.dir, file) + +def system(): + if not system.dir: + try: + path = env['M5_PATH'].split(':') + except KeyError: + path = [ '/dist/m5/system', '/n/poolfs/z/dist/m5/system' ] + + for system.dir in path: + if os.path.isdir(system.dir): + break + else: + raise ImportError, "Can't find a path to system files." + + if not binary.dir: + binary.dir = joinpath(system.dir, 'binaries') + if not disk.dir: + disk.dir = joinpath(system.dir, 'disks') + if not script.dir: + script.dir = joinpath(config_root, 'boot') + +system.dir = None +binary.dir = None +disk.dir = None +script.dir = None diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/example/dramsim.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/example/dramsim.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,151 @@ +# Simple test script +# +# "m5 test.py" + +import m5 +from m5.objects import * +import os, optparse, sys +m5.AddToPath('../common') +import Simulation +from Caches import * +from specbench import * +import string + +# Get paths we might need. It's expected this file is in m5/configs/example. +config_path = os.path.dirname(os.path.abspath(__file__)) +config_root = os.path.dirname(config_path) +m5_root = os.path.dirname(config_root) + +parser = optparse.OptionParser() + +# Benchmark options +parser.add_option("-c", "--cmd", + default=os.path.join(m5_root, "tests/test-progs/hello/bin/alpha/linux/hello"), + help="The binary to run in syscall emulation mode.") +parser.add_option("-o", "--options", default="", + help="The options to pass to the binary, use \" \" around the entire\ + string.") + +parser.add_option("-i", "--input", default="", + help="A file of input to give to the binary.") + +parser.add_option("-f", "--DRAMsimConfig", + default=os.path.join(m5_root, "/home/crius/m5/src/mem/DRAMsimII/memoryDefinitions/DDR2-800-4-4-4-25E.xml"), + help="The DRAMsimII config file.") + +parser.add_option("-b", "--benchmark", + default=None, help="Choose the number from the following:\nperlbench\nbzip2\ngcc\nbwaves\ngamess\nmcf\nmilc\nzeusmp\ngromacs\ncactusADM\nleslie3d\nnamd\ngobmk\ndealII\nsoplex\npovray\ncalculix\nhmmer\nsjeng\nGemsFDTD\nlibquantum\nh264ref\ntonto\nlbm\nomnetpp\nastar\nwrf\nsphinx3\nxalancbmk\n998.specrand_i\n999.specrand_f") + +parser.add_option("--simple", action="store_true") + +parser.add_option("--mp", + default="", help="Override default memory parameters with this switch") +parser.add_option("--revert", default=None) + + +execfile(os.path.join(config_root, "common", "Options.py")) + +(options, args) = parser.parse_args() + +if options.simple == True: + options.detailed = False + options.l2cache = False + options.caches = False +else: + options.detailed = True + options.l2cache = True + options.caches = True + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +memorySize = '512MB' + +if options.benchmark is not None: + try: + cmdLine = cmdLineDict[options.benchmark] + process = liveProcessDict[options.benchmark] + executable = [cmdLineDict[options.benchmark]] + if options.benchmark in alternateMemorySize: + memorySize = alternateMemorySize[options.benchmark] + + except KeyError: + print "Unknown benchmark.\n" + sys.exit() +else: + process = LiveProcess() + process.executable = options.cmd + process.cmd = [options.cmd] + options.options.split() + if options.input != "": + process.input = options.input + + executable = options.cmd.split("/") + + if options.input != "": + cmdInput = " <%s" % options.input + else: + cmdInput = "" + cmdLine = executable[len(executable) - 1] + " " + options.options + cmdInput + + +if options.detailed: + #check for SMT workload + workloads = options.cmd.split(';') + if len(workloads) > 1: + process = [] + smt_idx = 0 + inputs = [] + + if options.input != "": + inputs = options.input.split(';') + + for wrkld in workloads: + smt_process = LiveProcess() + smt_process.executable = wrkld + smt_process.cmd = wrkld + " " + options.options + if inputs and inputs[smt_idx]: + smt_process.input = inputs[smt_idx] + process += [smt_process, ] + smt_idx += 1 + +(CPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options) + +CPUClass.clock = '3GHz' + +np = options.num_cpus + +if options.revert: + print 'not using ds2' + system = System(cpu=[CPUClass(cpu_id=i) for i in xrange(np)], + physmem= PhysicalMemory(range=AddrRange(memorySize)), + membus=Bus(), mem_mode=test_mem_mode) +else: + system = System(cpu=[CPUClass(cpu_id=i) for i in xrange(np)], + physmem=M5dramSystem(extraParameters=options.mp, + settingsFile=options.DRAMsimConfig, + outFilename=executable.pop(), + commandLine=cmdLine, + range=AddrRange(memorySize)), + membus=Bus(), mem_mode=test_mem_mode) + +system.physmem.port = system.membus.port + +for i in xrange(np): + if options.caches: + system.cpu[i].addPrivateSplitL1Caches(L1Cache(size='64kB', assoc=2), + L1Cache(size='64kB', assoc=2)) + if options.l2cache: + system.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='ghb', prefetch_degree=3, prefetcher_size=256, tgts_per_mshr=24, prefetch_cache_check_push=False) + #system.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs = 32, prefetch_policy = 'none', prefetch_degree = 3, prefetcher_size = 256, tgts_per_mshr=24, prefetch_cache_check_push=False) + system.tol2bus = Bus() + system.l2.cpu_side = system.tol2bus.port + system.l2.mem_side = system.membus.port + system.cpu[i].connectMemPorts(system.tol2bus) + else: + system.cpu[i].connectMemPorts(system.membus) + system.cpu[i].workload = process + +root = Root(system=system) + +Simulation.run(options, root, system, FutureClass) diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/example/dramsimfs16-16.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/example/dramsimfs16-16.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,287 @@ +# Copyright (c) 2006-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +import optparse +import os +import sys + +import m5 +from m5.defines import buildEnv +from m5.objects import * +from m5.util import addToPath, fatal + +if not buildEnv['FULL_SYSTEM']: + m5.panic("This script requires full-system mode (*_FS).") + +m5.util.addToPath('../common') + +from FSConfig import * +from SysPaths import * +from Benchmarks import * +import Simulation +from Caches import * + +#update Benchmarks to support our benchmarks +Benchmarks['shutdown'] = [SysConfig('shutdown.rcS', '256MB')] +Benchmarks['lbm'] = [SysConfig('lbm.rcS', '1024MB')] +Benchmarks['lbmLong'] = [SysConfig('lbmLong.rcS', '1024MB')] +Benchmarks['stream'] = [SysConfig('stream.rcS', '512MB')] +Benchmarks['streamLong'] = [SysConfig('streamLong.rcS', '768MB')] +Benchmarks['mcf'] = [SysConfig('mcf.rcS', '1500MB')] +Benchmarks['mcfLong'] = [SysConfig('mcfLong.rcS', '1500MB')] +Benchmarks['soplex'] = [SysConfig('soplex.rcS', '768MB')] +Benchmarks['bzip2'] = [SysConfig('bzip2.rcS', '512MB')] +Benchmarks['milc'] = [SysConfig('milc.rcS', '512MB')] +Benchmarks['milcLong'] = [SysConfig('milcLong.rcS', '512MB')] +Benchmarks['cactusADM'] = [SysConfig('cactusADM.rcS', '512MB')] +Benchmarks['namd'] = [SysConfig('namd.rcS', '512MB')] +Benchmarks['gobmk'] = [SysConfig('gobmk.rcS', '512MB')] +Benchmarks['dealII'] = [SysConfig('dealII.rcS', '512MB')] +Benchmarks['povray'] = [SysConfig('povray.rcS', '512MB')] +Benchmarks['calculix'] = [SysConfig('calculix.rcS', '512MB')] +Benchmarks['hmmer'] = [SysConfig('hmmer.rcS', '512MB')] +Benchmarks['sjeng'] = [SysConfig('sjeng.rcS', '512MB')] +Benchmarks['GemsFDTD'] = [SysConfig('GemsFDTD.rcS', '512MB')] +Benchmarks['libquantum'] = [SysConfig('libquantum.rcS', '512MB')] +Benchmarks['omnetpp'] = [SysConfig('omnetpp.rcS', '512MB')] +Benchmarks['xalancbmk'] = [SysConfig('xalancbmk.rcS', '512MB')] +Benchmarks['xalancbmkLong'] = [SysConfig('xalancbmkLong.rcS', '512MB')] + +benchs = Benchmarks.keys() +benchs.sort() +DefinedBenchmarks = ", ".join(benchs) + + +def makeDramSimLinuxAlphaSystem(mem_mode, mdesc=None, extraParameters="", settingsFilename="", revert=None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + self = LinuxAlphaSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1, clock='2600MHz') + self.bridge = Bridge(delay='5ns', nack_delay='1ns') + # use the memory size established by the benchmark definition in Benchmarks.py + jobnumber = '' + if 'PBS_JOBID' in os.environ: + jobnumber = os.environ['PBS_JOBID'].split('.')[0] + + outFile = '' if mdesc.scriptname == None else mdesc.scriptname.split('.')[0] + jobnumber + + if revert is not None: + print "reverting to use PhysicalMemory" + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + else: + print "using DRAMsimII" + self.physmem = M5dramSystem(extraParameters=extraParameters, + settingsFile=settingsFilename, + outFilename=outFile, + commandLine=outFile, + range=AddrRange(mdesc.mem())) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.iobus) + self.tsunami.ide.pio = self.iobus.port + self.tsunami.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(), + read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +# Get paths we might need. It's expected this file is in m5/configs/example. +config_path = os.path.dirname(os.path.abspath(__file__)) +config_root = os.path.dirname(config_path) + +parser = optparse.OptionParser() + +# System options +parser.add_option("--kernel", action="store", type="string") +parser.add_option("--script", action="store", type="string") + +# Benchmark options +parser.add_option("--dual", action="store_true", + help="Simulate two systems attached with an ethernet link") +parser.add_option("-b", "--benchmark", action="store", type="string", + dest="benchmark", + help="Specify the benchmark to run. Available benchmarks: %s"\ + % DefinedBenchmarks) + +# DRAMsimII specific options +parser.add_option("-f", "--DRAMsimConfig", + default="", + help="The DRAMsimII config file.") + +parser.add_option("--mp", + default="", help="Override default memory parameters with this switch") + +parser.add_option("--revert", action="store_true") + +parser.add_option("--nopre", action="store_true") + +# Metafile options +parser.add_option("--etherdump", action="store", type="string", dest="etherdump", + help="Specify the filename to dump a pcap capture of the" \ + "ethernet traffic") + + +execfile(os.path.join(config_root, "common", "Options.py")) + +(options, args) = parser.parse_args() + +options.l2cache = True +options.caches = True +options.detailed = True + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +# driver system CPU is always simple... note this is an assignment of +# a class, not an instance. +DriveCPUClass = AtomicSimpleCPU +drive_mem_mode = 'atomic' + +# system under test can be any CPU +(TestCPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options) + +TestCPUClass.clock = '6GHz' +DriveCPUClass.clock = '6GHz' + +if options.benchmark: + try: + bm = Benchmarks[options.benchmark] + except KeyError: + print "Error benchmark %s has not been defined." % options.benchmark + print "Valid benchmarks are: %s" % DefinedBenchmarks + sys.exit(1) +else: + if options.dual: + bm = [SysConfig(), SysConfig()] + else: + bm = [SysConfig()] + +np = options.num_cpus + +if buildEnv['TARGET_ISA'] == "alpha": + test_sys = makeDramSimLinuxAlphaSystem(test_mem_mode, bm[0], options.mp, options.DRAMsimConfig, options.revert) +elif buildEnv['TARGET_ISA'] == "mips": + test_sys = makeLinuxMipsSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "sparc": + test_sys = makeSparcSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "x86": + test_sys = makeLinuxX86System(test_mem_mode, bm[0]) +else: + m5.panic("incapable of building non-alpha or non-sparc full system!") + +if options.kernel is not None: + test_sys.kernel = binary(options.kernel) + +if options.script is not None: + test_sys.readfile = options.script + +if options.l2cache: + if options.nopre is True: + print "no prefetcher" + test_sys.l2 = L2Cache(size='6MB', assoc=24, latency="4ns", mshrs = 32) + else: + #test_sys.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='ghb', prefetch_degree=3, prefetcher_size=256, tgts_per_mshr=24, prefetch_cache_check_push=False) + #test_sys.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='stride', prefetch_degree=2, prefetcher_size=64, prefetch_cache_check_push=True) + #test_sys.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='ghb', prefetch_degree=2, prefetcher_size=16) + test_sys.l2 = L2Cache(size = '6MB', assoc=24, latency="6ns", mshrs = 22, tgts_per_mshr = 12) + + test_sys.tol2bus = Bus() + test_sys.l2.cpu_side = test_sys.tol2bus.port + test_sys.l2.mem_side = test_sys.membus.port + +test_sys.cpu = [TestCPUClass(cpu_id=i) for i in xrange(np)] + +if options.caches or options.l2cache: + test_sys.bridge.filter_ranges_a=[AddrRange(0, Addr.max)] + test_sys.bridge.filter_ranges_b=[AddrRange(0, size='8GB')] + test_sys.iocache = IOCache(addr_range=AddrRange(0, size='8GB')) + test_sys.iocache.cpu_side = test_sys.iobus.port + test_sys.iocache.mem_side = test_sys.membus.port + +for i in xrange(np): + if options.caches: + test_sys.cpu[i].addPrivateSplitL1Caches(L1Cache(size = '64kB', latency="500ps", mshrs = 12, tgts_per_mshr = 6), + L1Cache(size = '64kB', latency="500ps", prefetch_policy='ghb', prefetch_degree=2, prefetcher_size=16)) + #test_sys.cpu[i].addPrivateSplitL1Caches(L1Cache(size = '64kB', latency="500ps"), + # L1Cache(size = '64kB', latency="500ps")) + if options.l2cache: + test_sys.cpu[i].connectMemPorts(test_sys.tol2bus) + else: + test_sys.cpu[i].connectMemPorts(test_sys.membus) + + if options.fastmem: + test_sys.cpu[i].physmem_port = test_sys.physmem.port + +if buildEnv['TARGET_ISA'] == 'mips': + setMipsOptions(TestCPUClass) + +if len(bm) == 2: + if m5.build_env['TARGET_ISA'] == 'alpha': + drive_sys = makeLinuxAlphaSystem(drive_mem_mode, bm[1]) + elif m5.build_env['TARGET_ISA'] == 'mips': + drive_sys = makeLinuxMipsSystem(drive_mem_mode, bm[1]) + elif m5.build_env['TARGET_ISA'] == 'sparc': + drive_sys = makeSparcSystem(drive_mem_mode, bm[1]) + elif m5.build.env['TARGET_ISA'] == 'x86': + drive_sys = makeX86System(drive_mem_mode, bm[1]) + drive_sys.cpu = DriveCPUClass(cpu_id=0) + drive_sys.cpu.connectMemPorts(drive_sys.membus) + if options.fastmem: + drive_sys.cpu.physmem_port = drive_sys.physmem.port + if options.kernel is not None: + drive_sys.kernel = binary(options.kernel) + + root = makeDualRoot(test_sys, drive_sys, options.etherdump) +elif len(bm) == 1: + root = Root(system=test_sys) +else: + print "Error I don't know how to create more than 2 systems." + sys.exit(1) + +Simulation.run(options, root, test_sys, FutureClass) diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/example/fs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/example/fs.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,192 @@ +# Copyright (c) 2006-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +import optparse +import os +import sys + +import m5 +from m5.defines import buildEnv +from m5.objects import * +from m5.util import addToPath, fatal + +if not buildEnv['FULL_SYSTEM']: + fatal("This script requires full-system mode (*_FS).") + +addToPath('../common') + +from FSConfig import * +from SysPaths import * +from Benchmarks import * +import Simulation +import CacheConfig +from Caches import * + +# Get paths we might need. It's expected this file is in m5/configs/example. +config_path = os.path.dirname(os.path.abspath(__file__)) +config_root = os.path.dirname(config_path) + +parser = optparse.OptionParser() + +# System options +parser.add_option("--kernel", action="store", type="string") +parser.add_option("--script", action="store", type="string") + +# Benchmark options +parser.add_option("--dual", action="store_true", + help="Simulate two systems attached with an ethernet link") +parser.add_option("-b", "--benchmark", action="store", type="string", + dest="benchmark", + help="Specify the benchmark to run. Available benchmarks: %s"\ + % DefinedBenchmarks) + +# Metafile options +parser.add_option("--etherdump", action="store", type="string", dest="etherdump", + help="Specify the filename to dump a pcap capture of the" \ + "ethernet traffic") + +# DRAMsimII specific options +parser.add_option("-f", "--DRAMsimConfig", + default="", + help="The DRAMsimII config file.") + +parser.add_option("--mp", + default="", help="Override default memory parameters with this switch") + +parser.add_option("--revert", action="store_true") + +parser.add_option("--nopre", action="store_true") + +parser.add_option("--benchmarkName", default="") + +parser.add_option("--memsize", default=None) + +# more options +execfile(os.path.join(config_root, "common", "Options.py")) + +(options, args) = parser.parse_args() + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +# driver system CPU is always simple... note this is an assignment of +# a class, not an instance. +DriveCPUClass = AtomicSimpleCPU +drive_mem_mode = 'atomic' + +# system under test can be any CPU +(TestCPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options) + +TestCPUClass.clock = '4GHz' +DriveCPUClass.clock = '4GHz' + +if options.benchmark: + try: + bm = Benchmarks[options.benchmark] + except KeyError: + print "Error benchmark %s has not been defined." % options.benchmark + print "Valid benchmarks are: %s" % DefinedBenchmarks + sys.exit(1) +else: + if options.dual: + bm = [SysConfig(), SysConfig()] + else: + bm = [SysConfig()] + +np = options.num_cpus + +if buildEnv['TARGET_ISA'] == "alpha": + if options.revert: + print "info: using PhysicalMemory" + test_sys = makeLinuxAlphaSystem(test_mem_mode, bm[0]) + else: + print "info: using DRAMsimII" + if options.memsize is not None: + sc = SysConfig(mem=options.memsize) + else: + sc = SysConfig(mem="512MB") + test_sys = makeDramSimLinuxAlphaSystem(test_mem_mode, sc, options.mp, options.DRAMsimConfig, options.benchmarkName) + +elif buildEnv['TARGET_ISA'] == "mips": + test_sys = makeLinuxMipsSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "sparc": + test_sys = makeSparcSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "x86": + test_sys = makeLinuxX86System(test_mem_mode, np, bm[0]) +else: + fatal("incapable of building non-alpha or non-sparc full system!") + +if options.kernel is not None: + test_sys.kernel = binary(options.kernel) + +if options.script is not None: + test_sys.readfile = options.script + +test_sys.cpu = [TestCPUClass(cpu_id=i) for i in xrange(np)] + +CacheConfig.config_cache(options, test_sys) + +if options.caches or options.l1cache or options.l2cache or options.l3cache: + test_sys.bridge.filter_ranges_a=[AddrRange(0, Addr.max)] + test_sys.bridge.filter_ranges_b=[AddrRange(0, size='8GB')] + test_sys.iocache = IOCache(addr_range=AddrRange(0, size='8GB')) + test_sys.iocache.cpu_side = test_sys.iobus.port + test_sys.iocache.mem_side = test_sys.membus.port + +for i in xrange(np): + if options.fastmem: + test_sys.cpu[i].physmem_port = test_sys.physmem.port + +if buildEnv['TARGET_ISA'] == 'mips': + setMipsOptions(TestCPUClass) + +if len(bm) == 2: + if buildEnv['TARGET_ISA'] == 'alpha': + drive_sys = makeLinuxAlphaSystem(drive_mem_mode, bm[1]) + elif buildEnv['TARGET_ISA'] == 'mips': + drive_sys = makeLinuxMipsSystem(drive_mem_mode, bm[1]) + elif buildEnv['TARGET_ISA'] == 'sparc': + drive_sys = makeSparcSystem(drive_mem_mode, bm[1]) + elif buildEnv['TARGET_ISA'] == 'x86': + drive_sys = makeX86System(drive_mem_mode, np, bm[1]) + drive_sys.cpu = DriveCPUClass(cpu_id=0) + drive_sys.cpu.connectMemPorts(drive_sys.membus) + if options.fastmem: + drive_sys.cpu.physmem_port = drive_sys.physmem.port + if options.kernel is not None: + drive_sys.kernel = binary(options.kernel) + + root = makeDualRoot(test_sys, drive_sys, options.etherdump) +elif len(bm) == 1: + root = Root(system=test_sys) +else: + print "Error I don't know how to create more than 2 systems." + sys.exit(1) + +Simulation.run(options, root, test_sys, FutureClass) diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/example/fsM5.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/example/fsM5.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,190 @@ +# Copyright (c) 2010 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Copyright (c) 2006-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +import optparse +import os +import sys + +import m5 +from m5.defines import buildEnv +from m5.objects import * +from m5.util import addToPath, fatal + +if not buildEnv['FULL_SYSTEM']: + fatal("This script requires full-system mode (*_FS).") + +addToPath('../common') + +from FSConfig import * +from SysPaths import * +from Benchmarks import * +import Simulation +import CacheConfig +from Caches import * + +# Get paths we might need. It's expected this file is in m5/configs/example. +config_path = os.path.dirname(os.path.abspath(__file__)) +config_root = os.path.dirname(config_path) + +parser = optparse.OptionParser() + +# System options +parser.add_option("--kernel", action = "store", type = "string") +parser.add_option("--script", action = "store", type = "string") +if buildEnv['TARGET_ISA'] == "arm": + parser.add_option("--bare-metal", action = "store_true", + help = "Provide the raw system without the linux specific bits") + parser.add_option("--machine-type", action = "store", type = "choice", + choices = ArmMachineType.map.keys(), default = "RealView_PBX") +# Benchmark options +parser.add_option("--dual", action = "store_true", + help = "Simulate two systems attached with an ethernet link") +parser.add_option("-b", "--benchmark", action = "store", type = "string", + dest = "benchmark", + help = "Specify the benchmark to run. Available benchmarks: %s"\ + % DefinedBenchmarks) + +# Metafile options +parser.add_option("--etherdump", action = "store", type = "string", dest = "etherdump", + help = "Specify the filename to dump a pcap capture of the" \ + "ethernet traffic") + +execfile(os.path.join(config_root, "common", "Options.py")) + +(options, args) = parser.parse_args() + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +# driver system CPU is always simple... note this is an assignment of +# a class, not an instance. +DriveCPUClass = AtomicSimpleCPU +drive_mem_mode = 'atomic' + +# system under test can be any CPU +(TestCPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options) + +TestCPUClass.clock = '5GHz' +DriveCPUClass.clock = '5GHz' + +if options.benchmark: + try: + bm = Benchmarks[options.benchmark] + except KeyError: + print "Error benchmark %s has not been defined." % options.benchmark + print "Valid benchmarks are: %s" % DefinedBenchmarks + sys.exit(1) +else: + if options.dual: + bm = [SysConfig(), SysConfig()] + else: + bm = [SysConfig()] + +np = options.num_cpus + +if buildEnv['TARGET_ISA'] == "alpha": + test_sys = makeLinuxAlphaSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "mips": + test_sys = makeLinuxMipsSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "sparc": + test_sys = makeSparcSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "x86": + test_sys = makeLinuxX86System(test_mem_mode, np, bm[0]) +elif buildEnv['TARGET_ISA'] == "arm": + test_sys = makeLinuxArmSystem(test_mem_mode, bm[0], + bare_metal = options.bare_metal, machine_type = options.machine_type) +else: + fatal("incapable of building non-alpha or non-sparc full system!") + +if options.kernel is not None: + test_sys.kernel = binary(options.kernel) + +if options.script is not None: + test_sys.readfile = options.script + +test_sys.cpu = [TestCPUClass(cpu_id = i) for i in xrange(np)] + +CacheConfig.config_cache(options, test_sys) + +if options.caches or options.l2cache: + if bm[0]: + mem_size = bm[0].mem() + else: + mem_size = SysConfig().mem() + test_sys.bridge.filter_ranges_a = [AddrRange(0, Addr.max)] + test_sys.bridge.filter_ranges_b = [AddrRange(mem_size)] + test_sys.iocache = IOCache(addr_range = mem_size) + test_sys.iocache.cpu_side = test_sys.iobus.port + test_sys.iocache.mem_side = test_sys.membus.port + +for i in xrange(np): + if options.fastmem: + test_sys.cpu[i].physmem_port = test_sys.physmem.port + +if buildEnv['TARGET_ISA'] == 'mips': + setMipsOptions(TestCPUClass) + +if len(bm) == 2: + if buildEnv['TARGET_ISA'] == 'alpha': + drive_sys = makeLinuxAlphaSystem(drive_mem_mode, bm[1]) + elif buildEnv['TARGET_ISA'] == 'mips': + drive_sys = makeLinuxMipsSystem(drive_mem_mode, bm[1]) + elif buildEnv['TARGET_ISA'] == 'sparc': + drive_sys = makeSparcSystem(drive_mem_mode, bm[1]) + elif buildEnv['TARGET_ISA'] == 'x86': + drive_sys = makeX86System(drive_mem_mode, np, bm[1]) + elif buildEnv['TARGET_ISA'] == 'arm': + drive_sys = makeLinuxArmSystem(drive_mem_mode, bm[1]) + drive_sys.cpu = DriveCPUClass(cpu_id = 0) + drive_sys.cpu.connectMemPorts(drive_sys.membus) + if options.fastmem: + drive_sys.cpu.physmem_port = drive_sys.physmem.port + if options.kernel is not None: + drive_sys.kernel = binary(options.kernel) + + root = makeDualRoot(test_sys, drive_sys, options.etherdump) +elif len(bm) == 1: + root = Root(system = test_sys) +else: + print "Error I don't know how to create more than 2 systems." + sys.exit(1) + +Simulation.run(options, root, test_sys, FutureClass) diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/example/fsNehalem.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/example/fsNehalem.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,287 @@ +# Copyright (c) 2006-2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +import optparse +import os +import sys + +import m5 +from m5.defines import buildEnv +from m5.objects import * +from m5.util import addToPath, fatal + +if not buildEnv['FULL_SYSTEM']: + m5.panic("This script requires full-system mode (*_FS).") + +m5.util.addToPath('../common') + +from FSConfig import * +from SysPaths import * +from Benchmarks import * +import Simulation +from Caches import * + +#update Benchmarks to support our benchmarks +Benchmarks['shutdown'] = [SysConfig('shutdown.rcS', '256MB')] +Benchmarks['lbm'] = [SysConfig('lbm.rcS', '1024MB')] +Benchmarks['stream'] = [SysConfig('stream.rcS', '512MB')] +Benchmarks['streamLong'] = [SysConfig('streamLong.rcS', '768MB')] +Benchmarks['mcf'] = [SysConfig('mcf.rcS', '1500MB')] +Benchmarks['soplex'] = [SysConfig('soplex.rcS', '768MB')] +Benchmarks['bzip2'] = [SysConfig('bzip2.rcS', '512MB')] +Benchmarks['milc'] = [SysConfig('milc.rcS', '512MB')] +Benchmarks['milcLong'] = [SysConfig('milcLong.rcS', '512MB')] +Benchmarks['mcfLong'] = [SysConfig('mcfLong.rcS', '2GB')] +Benchmarks['cactusADM'] = [SysConfig('cactusADM.rcS', '512MB')] +Benchmarks['namd'] = [SysConfig('namd.rcS', '512MB')] +Benchmarks['gobmk'] = [SysConfig('gobmk.rcS', '512MB')] +Benchmarks['dealII'] = [SysConfig('dealII.rcS', '512MB')] +Benchmarks['povray'] = [SysConfig('povray.rcS', '512MB')] +Benchmarks['calculix'] = [SysConfig('calculix.rcS', '512MB')] +Benchmarks['hmmer'] = [SysConfig('hmmer.rcS', '512MB')] +Benchmarks['sjeng'] = [SysConfig('sjeng.rcS', '512MB')] +Benchmarks['GemsFDTD'] = [SysConfig('GemsFDTD.rcS', '512MB')] +Benchmarks['libquantum'] = [SysConfig('libquantum.rcS', '512MB')] +Benchmarks['omnetpp'] = [SysConfig('omnetpp.rcS', '512MB')] +Benchmarks['xalancbmk'] = [SysConfig('xalancbmk.rcS', '512MB')] + +benchs = Benchmarks.keys() +benchs.sort() +DefinedBenchmarks = ", ".join(benchs) + + +def makeDramSimLinuxAlphaSystem(mem_mode, mdesc=None, extraParameters="", settingsFilename="", revert=None): + class BaseTsunami(Tsunami): + ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0) + ide = IdeController(disks=[Parent.disk0, Parent.disk2], + pci_func=0, pci_dev=0, pci_bus=0) + self = LinuxAlphaSystem() + if not mdesc: + # generic system + mdesc = SysConfig() + self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) + self.membus = MemBus(bus_id=1, clock='2600MHz') + self.bridge = Bridge(delay='5ns', nack_delay='1ns') + # use the memory size established by the benchmark definition in Benchmarks.py + #if 'PBS_JOBID' in os.environ: + # jobnumber = os.environ['PBS_JOBID'].split('.')[0] + #else: + jobnumber = '' + + outFile = '' if mdesc.scriptname == None else mdesc.scriptname.split('.')[0] + jobnumber + + if revert is not None: + print "reverting to use PhysicalMemory" + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + else: + print "using DRAMsimII" + self.physmem = M5dramSystem(extraParameters=extraParameters, + settingsFile=settingsFilename, + outFilename=outFile, + commandLine=outFile, + range=AddrRange(mdesc.mem())) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port + self.physmem.port = self.membus.port + self.disk0 = CowIdeDisk(driveID='master') + self.disk2 = CowIdeDisk(driveID='master') + self.disk0.childImage(mdesc.disk()) + self.disk2.childImage(disk('linux-bigswap2.img')) + self.tsunami = BaseTsunami() + self.tsunami.attachIO(self.iobus) + self.tsunami.ide.pio = self.iobus.port + self.tsunami.ethernet.pio = self.iobus.port + self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(),read_only = True)) + self.intrctrl = IntrControl() + self.mem_mode = mem_mode + self.terminal = Terminal() + self.kernel = binary('vmlinux') + self.pal = binary('ts_osfpal') + self.console = binary('console') + self.boot_osflags = 'root=/dev/hda1 console=ttyS0' + + return self + +# Get paths we might need. It's expected this file is in m5/configs/example. +config_path = os.path.dirname(os.path.abspath(__file__)) +config_root = os.path.dirname(config_path) + +parser = optparse.OptionParser() + +# System options +parser.add_option("--kernel", action="store", type="string") +parser.add_option("--script", action="store", type="string") + +# Benchmark options +parser.add_option("--dual", action="store_true", + help="Simulate two systems attached with an ethernet link") +parser.add_option("-b", "--benchmark", action="store", type="string", + dest="benchmark", + help="Specify the benchmark to run. Available benchmarks: %s"\ + % DefinedBenchmarks) + +# DRAMsimII specific options +parser.add_option("-f", "--DRAMsimConfig", + default="", + help="The DRAMsimII config file.") + +parser.add_option("--mp", + default="", help="Override default memory parameters with this switch") + +parser.add_option("--revert", action="store_true") + +parser.add_option("--nopre", action="store_true") + +# Metafile options +parser.add_option("--etherdump", action="store", type="string", dest="etherdump", + help="Specify the filename to dump a pcap capture of the" \ + "ethernet traffic") + + +execfile(os.path.join(config_root, "common", "Options.py")) + +(options, args) = parser.parse_args() + +options.l2cache = True +options.caches = True +options.detailed = False + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +# driver system CPU is always simple... note this is an assignment of +# a class, not an instance. +DriveCPUClass = AtomicSimpleCPU +drive_mem_mode = 'atomic' + +# system under test can be any CPU +(TestCPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options) + +TestCPUClass.clock = '6GHz' +DriveCPUClass.clock = '6GHz' + +if options.benchmark: + try: + bm = Benchmarks[options.benchmark] + except KeyError: + print "Error benchmark %s has not been defined." % options.benchmark + print "Valid benchmarks are: %s" % DefinedBenchmarks + sys.exit(1) +else: + if options.dual: + bm = [SysConfig(), SysConfig()] + else: + bm = [SysConfig('','512MB')] + +np = options.num_cpus + +if buildEnv['TARGET_ISA'] == "alpha": + test_sys = makeDramSimLinuxAlphaSystem(test_mem_mode, bm[0], options.mp, options.DRAMsimConfig, options.revert) +elif buildEnv['TARGET_ISA'] == "mips": + test_sys = makeLinuxMipsSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "sparc": + test_sys = makeSparcSystem(test_mem_mode, bm[0]) +elif buildEnv['TARGET_ISA'] == "x86": + test_sys = makeLinuxX86System(test_mem_mode, bm[0]) +else: + m5.panic("incapable of building non-alpha or non-sparc full system!") + +if options.kernel is not None: + test_sys.kernel = binary(options.kernel) + +if options.script is not None: + test_sys.readfile = options.script + +if options.l2cache: + if options.nopre is True: + print "no prefetcher" + test_sys.l2 = L2Cache(size='512kB', assoc=16, latency="4ns", mshrs = 32) + else: + #print "using prefetcher" + #test_sys.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='ghb', prefetch_degree=3, prefetcher_size=256, tgts_per_mshr=24, prefetch_cache_check_push=False) + #test_sys.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='stride', prefetch_degree=2, prefetcher_size=64, prefetch_cache_check_push=True) + #test_sys.l2 = L2Cache(size='1MB', assoc=16, latency="7ns", mshrs=32, prefetch_policy='ghb', prefetch_degree=2, prefetcher_size=16) + test_sys.l2 = L2Cache(size='8MB', assoc=16, latency="49ns") + #test_sys.l2 = L2Cache(size='8MB', assoc=16, latency="49ns", mshrs=32, prefetch_policy='ghb', prefetch_degree=3, prefetcher_size=256, tgts_per_mshr=24) + + test_sys.tol2bus = Bus() + test_sys.l2.cpu_side = test_sys.tol2bus.port + test_sys.l2.mem_side = test_sys.membus.port + +test_sys.cpu = [TestCPUClass(cpu_id=i) for i in xrange(np)] + +if options.caches or options.l2cache: + test_sys.bridge.filter_ranges_a=[AddrRange(0, Addr.max)] + test_sys.bridge.filter_ranges_b=[AddrRange(0, size='8GB')] + test_sys.iocache = IOCache(addr_range=AddrRange(0, size='8GB')) + test_sys.iocache.cpu_side = test_sys.iobus.port + test_sys.iocache.mem_side = test_sys.membus.port + +for i in xrange(np): + if options.caches: + test_sys.cpu[i].addPrivateSplitL1Caches(L1Cache(size = '32kB', latency="4ns", mshrs = 12, tgts_per_mshr = 6), + L1Cache(size = '32kB', latency="4ns", prefetch_policy='ghb', prefetch_degree=2, prefetcher_size=16)) + #test_sys.cpu[i].addPrivateSplitL1Caches(L1Cache(size = '64kB', latency="500ps"), + # L1Cache(size = '64kB', latency="500ps")) + if options.l2cache: + test_sys.cpu[i].connectMemPorts(test_sys.tol2bus) + else: + test_sys.cpu[i].connectMemPorts(test_sys.membus) + + if options.fastmem: + test_sys.cpu[i].physmem_port = test_sys.physmem.port + +if buildEnv['TARGET_ISA'] == 'mips': + setMipsOptions(TestCPUClass) + +if len(bm) == 2: + if m5.build_env['TARGET_ISA'] == 'alpha': + drive_sys = makeLinuxAlphaSystem(drive_mem_mode, bm[1]) + elif m5.build_env['TARGET_ISA'] == 'mips': + drive_sys = makeLinuxMipsSystem(drive_mem_mode, bm[1]) + elif m5.build_env['TARGET_ISA'] == 'sparc': + drive_sys = makeSparcSystem(drive_mem_mode, bm[1]) + elif m5.build.env['TARGET_ISA'] == 'x86': + drive_sys = makeX86System(drive_mem_mode, bm[1]) + drive_sys.cpu = DriveCPUClass(cpu_id=0) + drive_sys.cpu.connectMemPorts(drive_sys.membus) + if options.fastmem: + drive_sys.cpu.physmem_port = drive_sys.physmem.port + if options.kernel is not None: + drive_sys.kernel = binary(options.kernel) + + root = makeDualRoot(test_sys, drive_sys, options.etherdump) +elif len(bm) == 1: + root = Root(system=test_sys) +else: + print "Error I don't know how to create more than 2 systems." + sys.exit(1) +print "running" +Simulation.run(options, root, test_sys, FutureClass) diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/m5/configs/runme --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/m5/configs/runme Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,1 @@ +./build/ALPHA_FS/m5.fast ./configs/example/fs.py -n 4 --script=./configs/boot/bodytrack_4c_simsmall.rcS --detailed --caches --l3cache -F 5000000000 \ No newline at end of file diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Address.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Address.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,120 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef ADDRESS_HH +#define ADDRESS_HH +#pragma once + +#include "globals.hh" + +namespace DRAMsimII +{ + + /// @brief This class logically represents several interpretations of a memory address + /// @details A class to store various representations of an address + /// The same address may be represented as a virtual address, physical address, + /// or as channel, rank, bank, column and row identifiers + class Address + { + public: + // This section defines the address mapping scheme + // The scheme dictates how a memory address is converted + // to rank, bank, row, col, byte + enum AddressMappingScheme + { + CLOSE_PAGE_BASELINE, + SDRAM_BASE_MAP, + SDRAM_HIPERF_MAP, + CLOSE_PAGE_BASELINE_OPT, + CLOSE_PAGE_LOW_LOCALITY, + CLOSE_PAGE_HIGH_LOCALITY, + INTEL845G_MAP, + BURGER_BASE_MAP + }; + + protected: + static unsigned channelAddressDepth; ///< the number of bits to represent all channels + static unsigned rankAddressDepth; ///< the number of bits to represent all ranks + static unsigned bankAddressDepth; ///< the number of bits to represent all banks + static unsigned rowAddressDepth; ///< the number of bits to represent all rows + static unsigned columnAddressDepth; ///< the number of bits to represent all columns + static unsigned columnSizeDepth; ///< the minimum block that can be addressed + static unsigned rowLowAddressDepth; ///< the number of bits to represent the lower portion of the row + static unsigned rowHighAddressDepth; ///< the number of bits to represent the upper portion of the row + static unsigned columnLowAddressDepth; ///< the number of bits to represent the lower portion of a column + static unsigned columnHighAddressDepth; ///< the number of bits to represent the upper portion of a column + static unsigned rankCount; ///< the number of ranks per DIMM + static AddressMappingScheme mappingScheme; ///< the mapping scheme to convert physical to logical addresses + + unsigned virtualAddress; ///< the virtual address + PhysicalAddress physicalAddress; ///< the physical address + + unsigned channel; ///< the enumerated channel id + unsigned dimm; ///< the dimm id + unsigned rank; ///< the rank id + unsigned bank; ///< the bank id + unsigned row; ///< the row id + unsigned column; ///< the column id + + // functions + bool addressTranslation(); + bool reverseAddressTranslation(); + public: + + // functions + PhysicalAddress static highestAddress(); + + // accessors + PhysicalAddress getPhysicalAddress() const { return physicalAddress; } + unsigned getChannel() const { return channel; } + unsigned getDimm() const { return dimm; } + unsigned getRank() const { return rank; } + unsigned getBank() const { return bank; } + unsigned getRow() const { return row; } + unsigned getColumn() const { return column; } + + // mutators + void setPhysicalAddress(PhysicalAddress pa) { physicalAddress = pa; addressTranslation(); } + void setAddress(const unsigned channel, const unsigned rank, const unsigned bank, const unsigned row, const unsigned column); + void setAddress(const Address &rhs); + void setChannel(const unsigned value) { channel = value; } + void setRank(const unsigned value) { dimm = value / rankCount; rank = value; } + void setBank(const unsigned value) { bank = value; } + void setRow(const unsigned value) { row = value; } + void setColumn(const unsigned value) { column = value; } + + // constructor + Address(); ///< the no-arg constructor + explicit Address(PhysicalAddress pA); ///< the constructor based on a physical address + explicit Address(const unsigned channel, const unsigned rank, const unsigned bank, const unsigned row, const unsigned column); + + // initialize + void static initialize(const Settings &dramSettings); + void static initialize(const SystemConfiguration &systemConfig); + PhysicalAddress static maxAddress(); + + // friend + friend std::ostream &DRAMsimII::operator<<(std::ostream &os, const Address&); + + // overloads + bool operator==(const Address& right) const; + bool operator!=(const Address& right) const; + }; + + std::ostream& operator<<(std::ostream&, const Address::AddressMappingScheme&); + +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Address.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Address.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,852 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include "Address.hh" +#include "Settings.hh" +#include "SystemConfiguration.hh" + +#include +#include +#include +#include +#include + +using std::cerr; +using std::pow; +using std::endl; +using std::setbase; +using std::setw; +using std::hex; +using namespace DRAMsimII; + +// static member declaration +unsigned Address::channelAddressDepth; +unsigned Address::rankAddressDepth; +unsigned Address::bankAddressDepth; +unsigned Address::rowAddressDepth; +unsigned Address::columnAddressDepth; +unsigned Address::columnSizeDepth; +unsigned Address::columnLowAddressDepth; +unsigned Address::columnHighAddressDepth; +unsigned Address::rowLowAddressDepth; +unsigned Address::rowHighAddressDepth; +unsigned Address::rankCount; +Address::AddressMappingScheme Address::mappingScheme; + +Address::Address(): + virtualAddress(UINT_MAX), physicalAddress(PHYSICAL_ADDRESS_MAX), channel(UINT_MAX), dimm(UINT_MAX), + rank(UINT_MAX), bank(UINT_MAX), row(UINT_MAX), column(UINT_MAX) +{ +} + +Address::Address(PhysicalAddress pA) : + virtualAddress(0), physicalAddress(pA), channel(0), dimm(0), rank(0), bank(0), row(0), column(0) +{ +#ifndef NDEBUG + bool result = +#endif + addressTranslation(); +#ifndef NDEBUG + assert(result); +#endif + +#ifdef DEBUG + unsigned oldCh = channel, oldDimm = dimm, oldRk = rank, oldBk = bank, oldRow = row, oldCol = column; + reverseAddressTranslation(); + assert(oldCh == channel && oldDimm == dimm && oldRk == rank && oldBk == bank && oldRow == row && oldCol == column); + if (result) + { + assert((physicalAddress >> columnSizeDepth) == (pA >> columnSizeDepth)); + } +#endif +} + +Address::Address(const unsigned channel, const unsigned rank, const unsigned bank, const unsigned row, + const unsigned column) : + virtualAddress(0), physicalAddress(0x00), channel(channel), dimm(rank / rankCount), rank(rank), bank(bank), row( + row), column(column) +{ + reverseAddressTranslation(); + +#ifdef DEBUG + PhysicalAddress pA = physicalAddress; + addressTranslation(); + assert((physicalAddress >> columnSizeDepth) == (pA >> columnSizeDepth)); + assert(this->channel == channel && this->rank == rank && this->bank == bank && this->row == row && this->column == column); +#endif +} + +PhysicalAddress Address::maxAddress() +{ + return (1LL << (channelAddressDepth + rankAddressDepth + bankAddressDepth + rowAddressDepth + columnAddressDepth + + columnSizeDepth)) - 1; +} + +void Address::initialize(const Settings &_settings) +{ + channelAddressDepth = log2(_settings.channelCount); + rankCount = _settings.rankCount; + rankAddressDepth = log2(_settings.rankCount * _settings.dimmCount); + bankAddressDepth = log2(_settings.bankCount); + rowAddressDepth = log2(_settings.rowCount); + columnAddressDepth = log2(_settings.columnCount); + //FIXME: shouldn't this already be set appropriately? + columnSizeDepth = log2(_settings.dramType == DRDRAM ? 16 : _settings.columnSize); + mappingScheme = _settings.addressMappingScheme; + //unsigned cachelineDepth = log2(_settings.cacheLineSize); + // assume the cacheline size is 64B + unsigned cachelineDepth = log2(64); + assert(cachelineDepth > columnSizeDepth); + columnLowAddressDepth = cachelineDepth - columnSizeDepth; + columnHighAddressDepth = columnAddressDepth - columnLowAddressDepth; + assert(rowAddressDepth > 3); + rowLowAddressDepth = 3; + rowHighAddressDepth = rowAddressDepth - 3; +} + +void Address::initialize(const SystemConfiguration &systemConfig) +{ + channelAddressDepth = log2(systemConfig.getChannelCount()); + rankAddressDepth = log2(systemConfig.getRankCount()); + bankAddressDepth = log2(systemConfig.getBankCount()); + rowAddressDepth = log2(systemConfig.getRowCount()); + columnAddressDepth = log2(systemConfig.getColumnCount()); + //FIXME: shouldn't this already be set appropriately? + columnSizeDepth = log2(systemConfig.getDRAMType() == DRDRAM ? 16 : systemConfig.getColumnSize()); + mappingScheme = systemConfig.getAddressMappingScheme(); + //unsigned cachelineDepth = log2(systemConfig.getCachelineSize()); + // assume the cacheline size is 64B + unsigned cachelineDepth = log2(64); + assert(cachelineDepth > columnSizeDepth); + columnLowAddressDepth = cachelineDepth - columnSizeDepth; + columnHighAddressDepth = columnAddressDepth - columnLowAddressDepth; + assert(rowAddressDepth > 3); + rankCount = systemConfig.getRankCount(); + rowLowAddressDepth = 3; + rowHighAddressDepth = rowAddressDepth - 3; +} + +bool Address::reverseAddressTranslation() +{ + unsigned columnLow = column & ((1 << columnLowAddressDepth) - 1); + unsigned columnHigh = column >> columnLowAddressDepth; + unsigned shift = columnSizeDepth; + + switch (mappingScheme) + { + case SDRAM_HIPERF_MAP: + + physicalAddress = (PhysicalAddress) columnLow << shift; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + shift += columnHighAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) rank << shift; + shift += rankAddressDepth; + physicalAddress |= (PhysicalAddress) row << shift; + + break; + case SDRAM_BASE_MAP: + + physicalAddress = (PhysicalAddress) columnLow << shift; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + shift += columnHighAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) row << shift; + shift += rowAddressDepth; + physicalAddress |= (PhysicalAddress) rank << shift; + + break; + case CLOSE_PAGE_BASELINE: + + physicalAddress = (PhysicalAddress) columnLow << shift; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) rank << shift; + shift += rankAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + shift += columnHighAddressDepth; + physicalAddress |= (PhysicalAddress) row << shift; + + break; + + case CLOSE_PAGE_BASELINE_OPT: + { + unsigned rowLow = row & 0x07; + unsigned rowHigh = row >> 3; + physicalAddress = (PhysicalAddress) columnLow << shift; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) rowLow << shift; + shift += 3; + physicalAddress |= (PhysicalAddress) rank << shift; + shift += rankAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + shift += columnHighAddressDepth; + physicalAddress |= (PhysicalAddress) rowHigh << shift; + + break; + } + case CLOSE_PAGE_LOW_LOCALITY: + + physicalAddress = (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) rank << shift; + shift += rankAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) columnLow << shift; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) row << shift; + shift += rowAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + + break; + + case CLOSE_PAGE_HIGH_LOCALITY: + + physicalAddress = (PhysicalAddress) columnLow << shift; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) row << shift; + shift += rowAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + shift += columnHighAddressDepth; + physicalAddress |= (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) rank << shift; + + break; + + case INTEL845G_MAP: + + physicalAddress = (PhysicalAddress) column << 10; + shift += columnLowAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += rowAddressDepth; + physicalAddress |= (PhysicalAddress) columnHigh << shift; + shift += columnHighAddressDepth; + physicalAddress |= (PhysicalAddress) channel << shift; + shift += channelAddressDepth; + physicalAddress |= (PhysicalAddress) bank << shift; + shift += bankAddressDepth; + physicalAddress |= (PhysicalAddress) rank << shift; + + break; + + case BURGER_BASE_MAP: + break; + + default: + break; + } + + return true; +} + +////////////////////////////////////////////////////////////////////// +/// @brief converts a given memory request from a physical address to a rank/bank/row/column representation +/// @details converts according to the address mapping scheme in systemConfig +/// @author Joe Gross +/// @return true if the conversion was successful, false if there was some problem +////////////////////////////////////////////////////////////////////// +bool Address::addressTranslation() +{ + if (!physicalAddress) + return false; + + // strip away the byte address portion + PhysicalAddress tempAddress = physicalAddress >> columnSizeDepth; + + switch (mappingScheme) + { + case SDRAM_HIPERF_MAP: + /* + * High performance SDRAM Mapping scheme + * 5 + * |<-------------------->| |<->| |<->| |<--------------->| |<---->| |<---------------->| |<------------------->| + * row id rank bank col_id(high) chan_id col_id(low) column size + * intlog2(cacheline_size) intlog2(channel_width) + * - intlog2(channel_width) + * Rationale is as follows: From LSB to MSB + * min column size is the channel width, and individual byes within that "unit" is not addressable, so strip it out and throw it away. + * Then strip out a few bits of phys_addr address for the low order bits of col_id. We basically want consecutive cachelines to + * map to different channels. + * Then strip out the bits for channel id. + * Then strip out the bits for the high order bits of the column id. + * Then strip out the bank_id. + * Then strip out the rank_id. + * What remains must be the row_id + * + * As applied to system (1 dram channel, 64 bit wide. 4 ranks of 256 Mbit chips, each x16. 512 MB system) + * + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<------------------------------->| |<->| |<->| |<------------------------>| |<--->| + * row id rank bank Column id (8B wide) + * id id 2KB * 4 / 8B Byte Addr + * + * As applied to system (2 dram channel, 64 bit wide each. 1 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<------------------------------->| |<->| |<->| |<---------------->| ^ |<--->| |<--->| + * row id rank bank Column id high chan col_id (8B wide) + * id id 2KB * 4 / 8B id low Byte Addr + * + * As applied to system (1 dram channel, 128 bit wide. 1 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<------------------------------->| |<->| |<->| |<------------------------->| |<------>| + * row id rank bank Column id (16B wide) + * id id 2KB * 4 / 8B Byte Addr + * + * As applied to system (2 dram channel, 128 bit wide each. 2 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<------------------------------->| |<->| |<->| |<------------------->| ^ |<>| |<------>| + * row id rank bank Column id high chan col (16B wide) + * id id 2KB * 4 / 8B id idlo Byte Addr + * + */ + { + PhysicalAddress buffer = tempAddress; + tempAddress >>= columnLowAddressDepth; + unsigned columnLow = tempAddress << columnLowAddressDepth ^ buffer; + + buffer = tempAddress; + tempAddress >>= channelAddressDepth; + channel = (tempAddress << channelAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= columnHighAddressDepth; + unsigned columnHigh = (tempAddress << columnHighAddressDepth) ^ buffer; + + column = (columnHigh << columnLowAddressDepth) | columnLow; + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + bank = (tempAddress << bankAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + rank = (tempAddress << rankAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= rowAddressDepth; + row = (tempAddress << rowAddressDepth) ^ buffer; + } + break; + + case SDRAM_BASE_MAP: + /* + * Basic SDRAM Mapping scheme (As found on user-upgradeable memory systems) + * 5 + * |<---->| |<------------------->| |<->| |<--------------->| |<---->| |<---------------->| |<------------------->| + * rank row id bank col_id(high) chan_id col_id(low) column size + * intlog2(cacheline_size) intlog2(channel_width) + * - intlog2(channel_width) + * Rationale is as follows: From LSB to MSB + * min column size is the channel width, and individual byes within that "unit" is not addressable, so strip it out and throw it away. + * Then strip out a few bits of phys_addr address for the low order bits of col_id. We basically want consecutive cachelines to + * map to different channels. + * Then strip out the bits for channel id. + * Then strip out the bits for the high order bits of the column id. + * Then strip out the bank_id. + * Then strip out the row_id + * What remains must be the rankid + * + * As applied to system (2 dram channel, 64 bit wide each. 1 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<->| |<------------------------------->| |<->| |<---------------->| ^ |<--->| |<--->| + * rank row id bank Column id high chan col_id (8B wide) + * id id 2KB * 4 / 8B id low Byte Addr + * + * As applied to system (1 dram channel, 128 bit wide. 1 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<->| |<------------------------------->| |<->| |<------------------------->| |<------>| + * rank row id bank Column id (16B wide) + * id id 2KB * 4 / 8B id low Byte Addr + * + */ + { + PhysicalAddress buffer = tempAddress; + tempAddress >>= columnLowAddressDepth; + unsigned columnLow = (tempAddress << columnLowAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= channelAddressDepth; + channel = (tempAddress << channelAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= columnHighAddressDepth; + unsigned columnHigh = (tempAddress << columnHighAddressDepth) ^ buffer; + + column = (columnHigh << columnLowAddressDepth) | columnLow; + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + bank = (tempAddress << bankAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= rowAddressDepth; + row = (tempAddress << rowAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + rank = (tempAddress << rankAddressDepth) ^ buffer; + } + break; + + case CLOSE_PAGE_BASELINE: + /* + * High performance closed page SDRAM Mapping scheme + * 5 + * |<------------------>| |<------------>| |<---->| |<---->| |<---->| |<----------------->| |<------------------->| + * row id col_id(high) rank bank chan col_id(low) column size + * intlog2(cacheline_size) intlog2(channel_width) + * - intlog2(channel_width) + * + * Rationale is as follows: From LSB to MSB + * min column size is the channel width, and individual byes within that "unit" is not addressable, so strip it out and throw it away. + * Then strip out a few bits of phys_addr address for the low order bits of col_id. We basically want consecutive cachelines to + * map to different channels. + * Then strip out the bits for channel id. + * Then strip out the bank_id. + * Then strip out the rank_id. + * Then strip out the bits for the high order bits of the column id. + * What remains must be the row_id + * + * As applied to system (1 dram channel, 64 bit wide each. 2 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<------------------------------------->| |<---------------->| ^ |<--->| |<--->| |<--->| + * row id Column id high rank bank col_id (8B wide) + * 1KB / 8B id id low Byte Addr + */ + { + PhysicalAddress buffer = tempAddress; + tempAddress >>= columnLowAddressDepth; + + // strip out the column low address + unsigned columnLow = buffer ^ (tempAddress << columnLowAddressDepth); + + buffer = tempAddress; /* save away original address */ + tempAddress >>= channelAddressDepth; + // strip out the channel address + channel = buffer ^ (tempAddress << channelAddressDepth); + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + // strip out the bank address + bank = buffer ^ (tempAddress << bankAddressDepth); + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + // strip out the rank address + rank = buffer ^ (tempAddress << rankAddressDepth); + + buffer = tempAddress; + tempAddress >>= columnHighAddressDepth; + // strip out the column hi address + unsigned columnHigh = buffer ^ (tempAddress << columnHighAddressDepth); + + column = (columnHigh << columnLowAddressDepth) | columnLow; + + buffer = tempAddress; + tempAddress >>= rowAddressDepth; + // strip out the row address + row = buffer ^ (tempAddress << rowAddressDepth); + } + break; + + case CLOSE_PAGE_BASELINE_OPT: + { + /* + * High performance closed page SDRAM Mapping scheme + * 5 + * |<----------->||<------------>||<------>||<----->||<---->||<---->||<----------------->||<------------------->| + * row_high col_id(high) rank row_lo bank chan col_id(low) column size + * + * intlog2(cacheline_size) intlog2(channel_width) + * - intlog2(channel_width) + * + * Rationale is as follows: From LSB to MSB + * min column size is the channel width, and individual byes within that "unit" is not addressable, so strip it out and throw it away. + * Then strip out a few bits of phys_addr address for the low order bits of col_id. We basically want consecutive cachelines to + * map to different channels. + * Then strip out the bits for channel id. + * Then strip out the bank_id. + * Then strip out the rank_id. + * Then strip out the bits for the high order bits of the column id. + * What remains must be the row_id + * + * As applied to system (1 dram channel, 64 bit wide each. 2 GB system) + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<------------------------------------->| |<---------------->| ^ |<--->| |<--->| |<--->| + * row id Column id high rank bank col_id (8B wide) + * 1KB / 8B id id low Byte Addr + */ + PhysicalAddress buffer = tempAddress; + tempAddress >>= columnLowAddressDepth; + + // strip out the column low address + unsigned columnLow = buffer ^ (tempAddress << columnLowAddressDepth); + + buffer = tempAddress; + tempAddress >>= channelAddressDepth; + // strip out the channel address + channel = buffer ^ (tempAddress << channelAddressDepth); + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + // strip out the bank address + bank = buffer ^ (tempAddress << bankAddressDepth); + + buffer = tempAddress; + tempAddress >>= 3; + unsigned rowLow = buffer ^ (tempAddress << 3); + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + // strip out the rank address + rank = buffer ^ (tempAddress << rankAddressDepth); + + buffer = tempAddress; + tempAddress >>= columnHighAddressDepth; + // strip out the column hi address + unsigned columnHigh = buffer ^ (tempAddress << columnHighAddressDepth); + + column = (columnHigh << columnLowAddressDepth) | columnLow; + + buffer = tempAddress; + tempAddress >>= (rowAddressDepth - 3); + // strip out the row address + unsigned rowHigh = buffer ^ (tempAddress << (rowAddressDepth - 3)); + + row = (rowHigh << 3) | rowLow; + + break; + } + + case CLOSE_PAGE_LOW_LOCALITY: + /* + * High performance closed page SDRAM Mapping scheme for streams with low locality + * 5 + * |<------------------>| |<------------>| |<---------->| |<----->| |<----->| |<------>| |<------------------->| + * col_id(high) row col_id(low) bank rank chan column size + * intlog2(cacheline_size) intlog2(channel_width) + * - intlog2(channel_width) + */ + { + + PhysicalAddress buffer = tempAddress; + tempAddress >>= channelAddressDepth; + // strip out the channel address + channel = buffer ^ (tempAddress << channelAddressDepth); + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + // strip out the rank address + rank = buffer ^ (tempAddress << rankAddressDepth); + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + // strip out the bank address + bank = buffer ^ (tempAddress << bankAddressDepth); + + buffer = tempAddress; + tempAddress >>= columnLowAddressDepth; + // strip out the column low address + unsigned columnLow = buffer ^ (tempAddress << columnLowAddressDepth); + + buffer = tempAddress; + tempAddress >>= rowAddressDepth; + // strip out the row address + row = buffer ^ (tempAddress << rowAddressDepth); + + buffer = tempAddress; + tempAddress >>= columnHighAddressDepth; + // strip out the column hi address + unsigned columnHigh = buffer ^ (tempAddress << columnHighAddressDepth); + + column = (columnHigh << columnLowAddressDepth) | columnLow; + } + break; + + case CLOSE_PAGE_HIGH_LOCALITY: + /* + * High performance closed page SDRAM Mapping scheme for streams with low locality + * 5 + * |<------->| |<------->| |<----->| |<-------------->| |<----->| |<--------------->| |<----------------->| + * rank bank chan col_id(high) row col_id(low) column size + * intlog2(cacheline_size) intlog2(channel_width) + * - intlog2(channel_width) + */ + { + PhysicalAddress buffer = tempAddress; + tempAddress >>= columnLowAddressDepth; + // strip out the column low address + unsigned columnLow = buffer ^ (tempAddress << columnLowAddressDepth); + + buffer = tempAddress; + tempAddress >>= rowAddressDepth; + // strip out the row address + row = buffer ^ (tempAddress << rowAddressDepth); + + buffer = tempAddress; + tempAddress >>= columnHighAddressDepth; + // strip out the column hi address + unsigned columnHigh = buffer ^ (tempAddress << columnHighAddressDepth); + + column = (columnHigh << columnLowAddressDepth) | columnLow; + + buffer = tempAddress; + tempAddress >>= channelAddressDepth; + // strip out the channel address + channel = buffer ^ (tempAddress << channelAddressDepth); + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + // strip out the bank address + bank = buffer ^ (tempAddress << bankAddressDepth); + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + // strip out the rank address + rank = buffer ^ (tempAddress << rankAddressDepth); + } + + break; + + case INTEL845G_MAP: + { + + /* Data comes from Intel's 845G Datasheets. Table 5-5 + * DDR SDRAM mapping only. + * + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * |<->| |<---------------------------------->| |<->| |<------------------------->| |<--->| + * rank row id bank Column id (64 bit wide bus) + * id id 2KB * 4 / 8B Byte addr + * row id goes like this: addr[27:15:26-16] + * rank_id is addr[29:28] This means that no device switching unless memory usage goes above 256MB grainularity + * No need to remap address with variable number of ranks. Address just goes up to rank id, if there is more than XXX MB of memory. + * Drawback to this scheme is that we're not effectively using banks. + */ + //tempAddress = physicalAddress >> 3; + tempAddress = physicalAddress; + + PhysicalAddress buffer = tempAddress; + tempAddress >>= 10; + // 11-3 + column = (tempAddress << 10) ^ buffer; + + buffer = tempAddress; + tempAddress >>= 2; + // 14:13 + bank = (tempAddress << 2) ^ buffer; + + buffer = physicalAddress >> 15; + tempAddress = buffer >> 1; + // 15 + unsigned bit_15 = (tempAddress << 1) ^ buffer; + + buffer = physicalAddress >> 16; + tempAddress = buffer >> 11; + // 26:16 + unsigned bits_26_to_16 = (tempAddress << 11) ^ buffer; + + buffer = physicalAddress >> 27; + tempAddress = buffer >> 1; + // 27 + unsigned bit_27 = (tempAddress << 1) ^ buffer; + + row = (bit_27 << 13) | (bit_15 << 12) | bits_26_to_16; + + buffer = physicalAddress >> 28; + tempAddress = buffer >> 2; + // 29:28 + rank = (tempAddress << 2) ^ buffer; + + // Intel 845G has only a single channel dram controller + channel = 0; + + } + break; + + case BURGER_BASE_MAP: // Good for only Rambus memory really + + // BURGER BASE : + // |<-------------------------------->|<------>|<------>|<---------------->|<----------------->|<----------->| + // row id bank id Rank id Column id Channel id Byte Address + // DRAM page size/ intlog2(chan. count) within packet + // Bus Width used if chan. > 1 + // + // As applied to system (1 chan) using 256 Mbit RDRAM chips: + // 512 rows X 32 banks X 128 columns X 16 bytes per column. + // 16 ranks gets us to 512 MByte. + // + // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // |<---------------------->| |<---------->| |<------->| |<---------------->| |<------>| + // row id bank rank Col id 16 byte + // (512 rows) id id 2KB/16B packet + { + PhysicalAddress buffer = tempAddress; + tempAddress >>= channelAddressDepth; + channel = (tempAddress << channelAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= columnAddressDepth; + column = (tempAddress << columnAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= rankAddressDepth; + rank = (tempAddress << rankAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= bankAddressDepth; + bank = (tempAddress << bankAddressDepth) ^ buffer; + + buffer = tempAddress; + tempAddress >>= rowAddressDepth; + row = (tempAddress << rowAddressDepth) ^ buffer; + + } + break; + + // don't know what this policy is.. Map everything to 0 + default: + cerr << "Unknown address mapping scheme, mapping chan, rank, bank to zero: "; + cerr << mappingScheme; + cerr << endl; + channel = rank = bank = row = column = 0; + return false; + break; + } + + dimm = rank / rankCount; + + // If there is still "stuff" left, the input address is out of range + if (tempAddress) + { + cerr << "Memory address (" << std::hex << physicalAddress + << ") out of range of available physical memory, max(" << highestAddress() << ")" << endl; + return false; + } + + return true; +} + +PhysicalAddress Address::highestAddress() +{ + return ((PhysicalAddress) 1 << (columnLowAddressDepth + columnHighAddressDepth + channelAddressDepth + + rankAddressDepth + bankAddressDepth + rowAddressDepth + columnSizeDepth)) - 1; +} + +void Address::setAddress(const unsigned channel, const unsigned rank, const unsigned bank, const unsigned row, + const unsigned column) +{ + this->channel = channel; + this->rank = rank; + this->bank = bank; + this->column = column; + this->row = row; + this->dimm = rank / rankCount; + + reverseAddressTranslation(); + +#ifdef DEBUG + PhysicalAddress oldPA = physicalAddress; + addressTranslation(); + assert((physicalAddress >> columnSizeDepth) == (oldPA >> columnSizeDepth)); + assert(this->channel == channel && this->rank == rank && this->bank == bank && this->row == row && this->column == column); +#endif + +} + +void Address::setAddress(const Address &rhs) +{ + channel = rhs.channel; + rank = rhs.rank; + bank = rhs.bank; + column = rhs.column; + row = rhs.row; + dimm = rhs.rank / rankCount; +} + +std::ostream &DRAMsimII::operator <<(std::ostream &os, const Address& thisAddress) +{ + return os << "addr[0x" << hex << thisAddress.physicalAddress << "] chan[" << setbase(16) << thisAddress.channel + << "] dimm[" << setbase(16) << thisAddress.dimm << "] rank[" << setbase(16) << thisAddress.rank + << "] bank[" << setbase(16) << thisAddress.bank << "] row[" << setbase(16) << thisAddress.row + << "] col[" << setbase(16) << thisAddress.column << "]"; +} + +std::ostream &DRAMsimII::operator <<(std::ostream &os, const Address::AddressMappingScheme &mappingScheme) +{ + switch (mappingScheme) + { + case Address::BURGER_BASE_MAP: + os << "BBM"; + break; + case Address::SDRAM_HIPERF_MAP: + os << "SDHIPF"; + break; + case Address::SDRAM_BASE_MAP: + os << "SDBAS"; + break; + case Address::CLOSE_PAGE_BASELINE: + os << "CPBAS"; + break; + case Address::CLOSE_PAGE_BASELINE_OPT: + os << "CPBOPT"; + break; + case Address::INTEL845G_MAP: + os << "845G"; + break; + case Address::CLOSE_PAGE_LOW_LOCALITY: + os << "LOLOC"; + break; + case Address::CLOSE_PAGE_HIGH_LOCALITY: + os << "HILOC"; + break; + default: + os << "UNKWN"; + break; + } + return os; +} + +// overloads +bool Address::operator==(const Address& right) const +{ + return channel == right.channel && rank == right.rank && bank == right.bank && row == right.row && column + == right.column; +} + +bool Address::operator!=(const Address& right) const +{ + return !(*this == right); +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Bank.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Bank.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,135 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef BANK_HH +#define BANK_HH + +#include "globals.hh" +#include "command.hh" +#include "Settings.hh" +#include "transaction.hh" +#include "command.hh" +#include "TimingSpecification.hh" +#include "SystemConfiguration.hh" +#include "queue.hh" +#include "Statistics.hh" + +namespace DRAMsimII +{ + /// @brief this class logically represents a bank + /// @details contains per bank queues as well as stats about when events happened + class Bank + { + private: + const TimingSpecification &timing; ///< a reference to the timing specification + const SystemConfiguration &systemConfig;///< reference to the system config to obtain specs + Statistics &statistics; ///< backward pointer to the stats engine + protected: + + // members + Queue perBankQueue; ///< the command priority queue, stores the commands to be executed + tick lastRASTime; ///< when did last RAS command start? + tick lastCASTime; ///< when did last CAS command start? + tick lastCASWTime; ///< when did last CASW command start? + tick lastPrechargeTime; ///< when did last Precharge command start? + unsigned lastCASLength; ///< the length of the last CAS command issued + unsigned lastCASWLength; ///< the length of the last CASW command issued + + tick nextActivateTime; ///< the time at which an ACT may be sent to this rank + tick nextReadTime; ///< the time at which a CAS may be sent to this rank + tick nextWriteTime; ///< the time at which a CASW may be sent to this rank + tick nextPrechargeTime; ///< the time at which a Pre may be sent to this rank + + unsigned openRowID; ///< if the bank is open, what is the row id? + bool activated; ///< if the bank is activated, else precharged + + // stats + unsigned RASCount; ///< the total number of RAS commands in this epoch + unsigned totalRASCount; ///< the number of RAS commands + unsigned CASCount; ///< the total number of CAS commands in this epoch + unsigned totalCASCount; ///< the number of CAS commands + unsigned CASWCount; ///< the total number of CAS+W commands in this epoch + unsigned totalCASWCount; ///< the number of CASW commands + + public: + // functions + void issueRAS(const tick currentTime, const Command *currentCommand); + void issuePRE(const tick currentTime, const Command *currentCommand); + void issueCAS(const tick currentTime, const Command *currentCommand); + void issueCASW(const tick currentTime, const Command *currentCommand); + void issueREF(); + void accumulateAndResetCounts() { totalRASCount += RASCount; totalCASCount += CASCount; totalCASWCount += CASWCount; RASCount = CASWCount = CASCount = 0; } + void resetToTime(const tick time); + tick next(Command::CommandType nextCommandType) const; + + // accessors + tick getLastRasTime() const { return lastRASTime; } + tick getLastCasTime() const { return lastCASTime; } + tick getLastCaswTime() const {return lastCASWTime; } + + tick getLastPrechargeTime() const { return lastPrechargeTime; } + + unsigned getLastCasLength() const { return lastCASLength; } + unsigned getLastCaswLength() const { return lastCASWLength; } + + unsigned getOpenRowID() const { return openRowID; } + bool isActivated() const { return activated; } + + unsigned getRASCount() const { return RASCount; } + unsigned getCASCount() const { return CASCount; } + unsigned getCASWCount() const { return CASWCount; } + + unsigned getTotalRASCount() const { return totalRASCount; } + unsigned getTotalCASCount() const { return totalCASCount; } + unsigned getTotalCASWCount() const { return totalCASWCount; } + + Command *pop() { return perBankQueue.pop(); } + bool push(Command *value) { return perBankQueue.push(value); } + bool insert(Command *value, const int index) { return perBankQueue.insert(value, index); } + const Command *read(const unsigned value) const { return perBankQueue.read(value); } + const inline Command *front() const { return perBankQueue.front(); } + const Command *back() const { return perBankQueue.back(); } + unsigned size() const { return perBankQueue.size(); } + unsigned depth() const { return perBankQueue.depth(); } + Command::CommandType nextCommandType() const { return perBankQueue.front() ? perBankQueue.front()->getCommandType() : Command::INVALID_COMMAND; } + unsigned freeCommandSlots() const { return perBankQueue.freecount(); } + bool aggressiveInsert(Transaction *value, const tick time); + bool openPageAggressiveInsertCheck(const Transaction *value, const tick time) const; + bool closePageAggressiveInsertCheck(const Transaction *value, const tick time) const; + bool isFull() const { return perBankQueue.isFull(); } + bool isEmpty() const; + bool hasNoReadWrite() const; + bool isHighUtilization() const { return perBankQueue.size() > (perBankQueue.depth() / 2);} + void collapse(); + + // constructors + explicit Bank(const Settings& settings, const TimingSpecification &timingVal, const SystemConfiguration &systemConfigVal, Statistics& stats); + Bank(const Bank&, const TimingSpecification &timingVal, const SystemConfiguration &systemConfigVal, Statistics& stats); + Bank(const Bank&); + + // overloads + bool operator==(const Bank& rhs) const; + Bank &operator=(const Bank& rhs); + + friend std::ostream& operator<<(std::ostream& , const Bank&); + + private: + + explicit Bank(const TimingSpecification &timingVal, const SystemConfiguration &systemConfigVal, Statistics &stats); + }; + +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Bank.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Bank.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,578 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include "Bank.hh" +#include + +using std::max; +using std::cerr; +using std::endl; + +using namespace DRAMsimII; + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor with timing spec and system config values +////////////////////////////////////////////////////////////////////////// +Bank::Bank(const Settings& settings, const TimingSpecification &timingVal, const SystemConfiguration &systemConfigVal, Statistics &stats): +timing(timingVal), +systemConfig(systemConfigVal), +statistics(stats), +perBankQueue(settings.perBankQueueDepth), +lastRASTime(-100), +lastCASTime(-100), +lastCASWTime(-100), +lastPrechargeTime(-1ll * settings.tRP), +lastCASLength(8), +lastCASWLength(8), +nextActivateTime(0), +nextReadTime(0), +nextWriteTime(0), +nextPrechargeTime(0), +openRowID(-1), +activated(/*settings.rowBufferManagementPolicy == OPEN_PAGE*/true), // close page starts with RAS, open page starts with Pre +RASCount(0), +totalRASCount(0), +CASCount(0), +totalCASCount(0), +CASWCount(0), +totalCASWCount(0) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief copy constructor with timing spec and sysconfig information +////////////////////////////////////////////////////////////////////////// +Bank::Bank(const Bank &rhs, const TimingSpecification &timingVal, const SystemConfiguration &systemConfigVal, Statistics &stats): +timing(timingVal), +systemConfig(systemConfigVal), +statistics(stats), +perBankQueue(rhs.perBankQueue), +lastRASTime(rhs.lastRASTime), +lastCASTime(rhs.lastCASTime), +lastCASWTime(rhs.lastCASWTime), +lastPrechargeTime(rhs.lastPrechargeTime), +lastCASLength(rhs.lastCASLength), +lastCASWLength(rhs.lastCASWLength), +nextActivateTime(rhs.nextActivateTime), +nextReadTime(rhs.nextReadTime), +nextWriteTime(rhs.nextWriteTime), +nextPrechargeTime(rhs.nextPrechargeTime), +openRowID(rhs.openRowID), +activated(rhs.activated), +RASCount(rhs.RASCount), +totalRASCount(rhs.totalRASCount), +CASCount(rhs.CASCount), +totalCASCount(rhs.totalCASCount), +CASWCount(rhs.CASWCount), +totalCASWCount(rhs.totalCASWCount) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief copy constructor +////////////////////////////////////////////////////////////////////////// +Bank::Bank(const Bank &rhs): +timing(rhs.timing), +systemConfig(rhs.systemConfig), +statistics(rhs.statistics), +perBankQueue(rhs.perBankQueue), +lastRASTime(rhs.lastRASTime), +lastCASTime(rhs.lastCASTime), +lastCASWTime(rhs.lastCASWTime), +lastPrechargeTime(rhs.lastPrechargeTime), +lastCASLength(rhs.lastCASLength), +lastCASWLength(rhs.lastCASWLength), +nextActivateTime(rhs.nextActivateTime), +nextReadTime(rhs.nextReadTime), +nextWriteTime(rhs.nextWriteTime), +nextPrechargeTime(rhs.nextPrechargeTime), +openRowID(rhs.openRowID), +activated(rhs.activated), +RASCount(rhs.RASCount), +totalRASCount(rhs.totalRASCount), +CASCount(rhs.CASCount), +totalCASCount(rhs.totalCASCount), +CASWCount(rhs.CASWCount), +totalCASWCount(rhs.totalCASWCount) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief deserialization constructor +////////////////////////////////////////////////////////////////////////// +Bank::Bank(const TimingSpecification &timingVal, const SystemConfiguration &systemConfigVal, Statistics &stats): +timing(timingVal), +systemConfig(systemConfigVal), +statistics(stats), +perBankQueue(0), +lastRASTime(0), +lastCASTime(0), +lastCASWTime(0), +lastPrechargeTime(0), +lastCASLength(0), +lastCASWLength(0), +nextActivateTime(0), +nextReadTime(0), +nextWriteTime(0), +nextPrechargeTime(0), +openRowID(0), +activated(0), +RASCount(0), +totalRASCount(0), +CASCount(0), +totalCASCount(0), +CASWCount(0), +totalCASWCount(0) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief this logically issues a RAS command and updates all variables to reflect this +////////////////////////////////////////////////////////////////////////// +void Bank::issueRAS(const tick currentTime, const Command *currentCommand) +{ + // make sure activates follow precharges + assert(!activated); + assert(currentTime >= lastPrechargeTime + timing.tRP()); + + activated = true; + + lastRASTime = currentTime; + openRowID = currentCommand->getAddress().getRow(); + RASCount++; + + // calculate when the next few commands can happen + nextActivateTime = max(nextActivateTime, currentTime + timing.tRC()); + nextReadTime = max(nextReadTime, currentTime + timing.tRCD() - timing.tAL()); + nextWriteTime = max(nextWriteTime, currentTime + timing.tRCD() - timing.tAL()); + nextPrechargeTime = max(nextPrechargeTime, currentTime + timing.tRAS()); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief issue a precharge command to this bank +////////////////////////////////////////////////////////////////////////// +void Bank::issuePRE(const tick currentTime, const Command *currentCommand) +{ + switch (currentCommand->getCommandType()) + { + case Command::READ_AND_PRECHARGE: + //lastPrechargeTime = max(currentTime + timing.tAL() + timing.tCAS() + timing.tBurst() + timing.tRTP(), lastRASTime + timing.tRAS()); + // see figure 11.28 in Memory Systems: Cache, DRAM, Disk by Bruce Jacob, et al. + lastPrechargeTime = max(lastPrechargeTime, max(currentTime + (timing.tAL() - timing.tCCD() + timing.tBurst() + timing.tRTP()), lastRASTime + timing.tRAS())); + break; + case Command::WRITE_AND_PRECHARGE: + // see figure 11.29 in Memory Systems: Cache, DRAM, Disk by Bruce Jacob, et al. + // obeys minimum timing, but also supports tRAS lockout + lastPrechargeTime = max(lastPrechargeTime, max(currentTime + (timing.tAL() + timing.tCWD() + timing.tBurst() + timing.tWR()), lastRASTime + timing.tRAS())); + break; + case Command::PRECHARGE: + lastPrechargeTime = max(lastPrechargeTime, currentTime); + break; + default: + cerr << "Unhandled CAS variant" << endl; + break; + } + + // make sure precharges follow activates + // technically, you can pre after pre, but there's no good reason for this + assert(activated == true); + activated = false; + + // calculate when the next few commands can happen + nextActivateTime = max(nextActivateTime, lastPrechargeTime + timing.tRP()); +} + +////////////////////////////////////////////////////////////////////////// +// @brief issue a CAS command to this bank +////////////////////////////////////////////////////////////////////////// +void Bank::issueCAS(const tick currentTime, const Command *currentCommand) +{ + //assert(activated); + assert(openRowID == currentCommand->getAddress().getRow()); + + //lastCASTime = currentTime + timing.tAL(); + lastCASTime = currentTime; + + lastCASLength = currentCommand->getLength(); + + CASCount++; + + // calculate when the next few commands can happen + /// @todo which is correct? + //nextPrechargeTime = max(nextPrechargeTime, currentTime + timing.tAL() + timing.tBurst() + timing.tRTP() - timing.tCCD()); + nextPrechargeTime = max(nextPrechargeTime, currentTime + timing.tAL() + timing.tCAS() + timing.tBurst() + max(0,timing.tRTP() - timing.tCMD())); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief issue a CASW command to this bank +////////////////////////////////////////////////////////////////////////// +void Bank::issueCASW(const tick currentTime, const Command *currentCommand) +{ + //assert(activated); + assert(openRowID == currentCommand->getAddress().getRow()); + + //lastCASWTime = currentTime + timing.tAL(); + lastCASWTime = currentTime; + + lastCASWLength = currentCommand->getLength(); + + CASWCount++; + + // calculate when the next few commands can happen + nextPrechargeTime = max(nextPrechargeTime, currentTime + timing.tAL() + timing.tCWD() + timing.tBurst() + timing.tWR()); + +} + +////////////////////////////////////////////////////////////////////////// +/// @brief issue a refresh command to this bank +////////////////////////////////////////////////////////////////////////// +void Bank::issueREF() +{ + assert(!activated); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns the next time this command type may be issued +////////////////////////////////////////////////////////////////////////// +tick Bank::next(Command::CommandType nextCommandType) const +{ + switch (nextCommandType) + { + case Command::ACTIVATE: + return nextActivateTime; + break; + case Command::READ: + case Command::READ_AND_PRECHARGE: + return nextReadTime; + break; + case Command::WRITE: + case Command::WRITE_AND_PRECHARGE: + return nextWriteTime; + break; + case Command::PRECHARGE: + return nextPrechargeTime; + break; + case Command::REFRESH_ALL: + return 0; + break; + default: + return TICK_MAX; + break; + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief reset statistics so that it appears the last command was not long ago +/// @details choose recent times for the lastX actions so that values are not so +/// large when looking to see when the next available time to execute any dependent +/// command. Often issued just after fast-forwarding finishes in a simulator +////////////////////////////////////////////////////////////////////////// +void Bank::resetToTime(const tick time) +{ + lastRASTime = time - timing.tRC(); + lastPrechargeTime = time - timing.tRP(); + lastCASTime = time - timing.tCAS() - timing.tBurst(); + lastCASWTime = time - timing.tCWD() - timing.tWTR() - timing.tBurst(); + + nextPrechargeTime = lastCASWTime + timing.tAL() + timing.tCWD() + timing.tBurst() + timing.tWR(); + nextPrechargeTime = max(nextPrechargeTime,lastCASTime + timing.tAL() + timing.tCAS() + timing.tBurst() + max(0,timing.tRTP() - timing.tCMD())); + nextActivateTime = lastPrechargeTime + timing.tRP(); + + nextActivateTime = max(nextActivateTime, lastRASTime + timing.tRC()); + nextReadTime = lastRASTime + timing.tRCD() - timing.tAL(); + nextWriteTime = lastRASTime + timing.tRCD() - timing.tAL(); + nextPrechargeTime = max(nextPrechargeTime, lastRASTime + timing.tRAS()); +} + + +////////////////////////////////////////////////////////////////////// +/// @brief check to see if this transaction can be inserted successfully via the open page aggressive insert mechanism +/// @details goes through the per bank queue to see that there is a slot to insert into and that +/// there is a precharge command to the same row that it can insert before +/// also looks for CAS, Pre commands that can be compressed in order to fit this +/// @author Joe Gross +/// @param incomingTransaction the transaction to test +/// @param time the current time, used to check and prevent against starvation of commands +/// @return true if it is able to be inserted, false otherwise +////////////////////////////////////////////////////////////////////// +bool Bank::openPageAggressiveInsertCheck(const Transaction *incomingTransaction, const tick time) const +{ + if (perBankQueue.freecount() >= 3) + { + return true; + } + else + { + unsigned availableSlots = perBankQueue.freecount(); + + // if the queue ends with a R/W(+P), then all that is needed is A, R/W + if (perBankQueue.back()->isReadOrWrite()) + { + if (availableSlots >= 2) + return true; + } + + for (unsigned i = 0; i < perBankQueue.size() - 1; i++) + { + if (perBankQueue[i]->isReadOrWrite() && perBankQueue[i+1] && perBankQueue[i+1]->isBasicPrecharge()) + { + availableSlots++; + if (availableSlots >= 3) + return true; + } + } + + if (availableSlots == 0) + return false; + + const unsigned currentRow = incomingTransaction->getAddress().getRow(); + + // look in the bank_q and see if there's a precharge for this row to insert before + // go from tail to head + for (int currentIndex = perBankQueue.size() - 1; currentIndex >= 0; --currentIndex) + { + const Command *currentCommand = perBankQueue.read(currentIndex); + + // channel, rank, bank, row all match, insert just before this precharge command + if (currentCommand->isReadOrWrite() && (currentCommand->getAddress().getRow() == currentRow)) + { + assert(currentCommand->getAddress().getChannel() == incomingTransaction->getAddress().getChannel()); + assert(currentCommand->getAddress().getRank() == incomingTransaction->getAddress().getRank()); + assert(currentCommand->getAddress().getBank() == incomingTransaction->getAddress().getBank()); + assert(currentCommand->getAddress().getRow() == incomingTransaction->getAddress().getRow()); + + return true; + } + // strict order may add to the end of the queue only + // if this has not happened already then this method of insertion fails + else if (systemConfig.getCommandOrderingAlgorithm() == STRICT_ORDER) + { + return false; + } + // then this command has been delayed by too many times and no more + // commands can preempt it + else if (time - currentCommand->getEnqueueTime() > systemConfig.getSeniorityAgeLimit()) + { + return false; + } + } + // if the correct row is already open, just insert there + // already guaranteed not to have RAW/WAR errors + if (activated && openRowID == currentRow) + { + return true; + } + return false; + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief reduce discrete CAS and Precharge commands to CAS+P to free up space +////////////////////////////////////////////////////////////////////////// +void Bank::collapse() +{ + for (unsigned i = 0; i < perBankQueue.size() - 1; i++) + { + if (perBankQueue[i]->isReadOrWrite() && perBankQueue[i+1] && perBankQueue[i+1]->isBasicPrecharge()) + { + if (perBankQueue[i]->getAddress().getBank() != perBankQueue[i+1]->getAddress().getBank()) + assert(false); + assert(!perBankQueue[i]->isPrecharge()); + perBankQueue[i]->setAutoPrecharge(true); + Command *toDelete = perBankQueue.remove(i+1); + assert(!toDelete->isReadOrWrite() && toDelete->isBasicPrecharge()); + assert(!toDelete->getHost()); + //cerr << *toDelete << endl; + delete toDelete; + } + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief see if there is room to insert a command using the Close Page Aggressive algorithm and then insert +/// @param incomingTransaction the transaction to insert +/// @param time the current time, used to check and prevent against starvation of commands +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +bool Bank::aggressiveInsert(Transaction *incomingTransaction, const tick time) +{ + if (!perBankQueue.isFull()) + { + const unsigned currentRow = incomingTransaction->getAddress().getRow(); + + // go from the end to the beginning to ensure no starvation or RAW/WAR errors + for (int currentIndex = perBankQueue.size() - 1; currentIndex >= 0; --currentIndex) + { + const Command *currentCommand = perBankQueue.read(currentIndex); + + // see if there is an available command to piggyback on + if (currentCommand->isReadOrWrite() && currentCommand->getAddress().getRow() == currentRow) + { + bool needsPrecharge = currentCommand->isPrecharge(); + + if (needsPrecharge) + { + currentCommand->setAutoPrecharge(false); + } + + // if the precharge was stripped from the n-1 command, add it to this one +#ifndef NDEBUG + bool result = +#endif + perBankQueue.insert(new Command(incomingTransaction, time, needsPrecharge, timing.tBurst()), currentIndex + 1); + assert(perBankQueue[currentIndex + 1]->getAddress() == incomingTransaction->getAddress()); + assert(result); + return true; + } + // strict order may add to the end of the queue only + // if this has not happened already then this method of insertion fails + else if (systemConfig.getCommandOrderingAlgorithm() == STRICT_ORDER) + { + return false; + } + else if (time - currentCommand->getEnqueueTime() > systemConfig.getSeniorityAgeLimit()) + { + return false; + } + } + + // if the correct row is already open, just insert there + // already guaranteed not to have RAW/WAR errors + if (activated && openRowID == currentRow) + { +#ifndef NDEBUG + bool result = +#endif + perBankQueue.push_front(new Command(incomingTransaction, time, false, timing.tBurst())); + assert(result); + + return true; + } + } + + return false; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief see if there is room to insert a command using the Close Page Aggressive algorithm +/// @param incomingTransaction the transaction to insert +/// @param time the current time, used to check and prevent against starvation of commands +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +bool Bank::closePageAggressiveInsertCheck(const Transaction *incomingTransaction, const tick time) const +{ + if (!perBankQueue.isFull()) + { + const unsigned currentRow = incomingTransaction->getAddress().getRow(); + // go from the end to the beginning to ensure no starvation or RAW/WAR errors + for (int currentIndex = perBankQueue.size() - 1; currentIndex >= 0; --currentIndex) + { + const Command *currentCommand = perBankQueue[currentIndex]; + // see if there is an available command to piggyback on + if (currentCommand->isReadOrWrite() && currentCommand->getAddress().getRow() == currentRow) + { + assert(currentCommand->getAddress().getChannel() == incomingTransaction->getAddress().getChannel()); + assert(currentCommand->getAddress().getRank() == incomingTransaction->getAddress().getRank()); + assert(currentCommand->getAddress().getBank() == incomingTransaction->getAddress().getBank()); + assert(currentCommand->getAddress().getRow() == incomingTransaction->getAddress().getRow()); + + if (!systemConfig.isAutoPrecharge()) + { + // check that things are in order + assert(perBankQueue[currentIndex + 1]->isPrecharge()); + } + return true; + } + else if (systemConfig.getCommandOrderingAlgorithm() == STRICT_ORDER) + { + return false; + } + // don't starve commands + else if (time - currentCommand->getEnqueueTime() > systemConfig.getSeniorityAgeLimit()) + { + return false; + } + } + if (activated && openRowID == currentRow) + { + return true; + } + } + return false; +} + +bool Bank::isEmpty() const +{ + return perBankQueue.isEmpty(); +} + +bool Bank::hasNoReadWrite() const +{ + for (unsigned i = 0; i < perBankQueue.size(); i++) + { + if (!perBankQueue[i]->isRefresh()) + return false; + } + return true; + +} + +////////////////////////////////////////////////////////////////////////// +/// @brief assignment operator to copy non-reference values +/// @param rhs the incomingTransaction that will be copied into this object +////////////////////////////////////////////////////////////////////////// +Bank& Bank::operator =(const Bank& rhs) +{ + perBankQueue = rhs.perBankQueue; + lastRASTime = rhs.lastRASTime; + lastCASTime = rhs.lastCASTime; + lastCASWTime = rhs.lastCASWTime; + lastPrechargeTime = rhs.lastPrechargeTime; + lastCASLength = rhs.lastCASLength; + lastCASWLength = rhs.lastCASWLength; + openRowID = rhs.openRowID; + activated = rhs.activated; + RASCount = rhs.RASCount; + totalRASCount = rhs.totalRASCount; + CASCount = rhs.CASCount; + totalCASCount = rhs.totalCASCount; + CASWCount = rhs.CASWCount; + totalCASWCount = rhs.totalCASWCount; + nextPrechargeTime = rhs.nextPrechargeTime; + nextWriteTime = rhs.nextWriteTime; + nextReadTime = rhs.nextReadTime; + nextActivateTime = rhs.nextActivateTime; + + return *this; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief equality operator to check values for equality +/// @param rhs the incomingTransaction that will be copied into this object +////////////////////////////////////////////////////////////////////////// +bool Bank::operator==(const Bank& rhs) const +{ + return (timing == rhs.timing && systemConfig == rhs.systemConfig && perBankQueue == rhs.perBankQueue && lastRASTime == rhs.lastRASTime && + lastCASTime == rhs.lastCASTime && lastCASWTime == rhs.lastCASWTime && lastPrechargeTime == rhs.lastPrechargeTime && + lastCASLength == rhs.lastCASLength && lastCASWLength == rhs.lastCASWLength && + openRowID == rhs.openRowID && activated == rhs.activated && RASCount == rhs.RASCount && totalRASCount == rhs.totalRASCount && + CASCount == rhs.CASCount && totalCASCount == rhs.totalCASCount && CASWCount == rhs.CASWCount && totalCASWCount == rhs.totalCASWCount); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief insertion operator to serialize the object in summary +////////////////////////////////////////////////////////////////////////// +std::ostream& DRAMsimII::operator<<(std::ostream& os, const Bank& pc) +{ + return os << "PBQ" << endl << pc.perBankQueue << "last RAS [" << pc.lastRASTime << "] act[" << + pc.activated << "] open row[" << pc.openRowID << "]" << endl; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Channel.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Channel.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,142 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef CHANNEL_HH +#define CHANNEL_HH +#pragma once + +#include "globals.hh" +#include "Rank.hh" +#include "powerConfig.hh" +#include "TimingSpecification.hh" +#include "SystemConfiguration.hh" +#include "Statistics.hh" +#include "queue.hh" +#include "powerConfig.hh" +#include "transaction.hh" +#include "command.hh" + +#include +#include + +namespace DRAMsimII +{ + /// @brief represents a DRAM channel, has individual timing parameters, ranks, banks, clock, etc. + class Channel + { + // members + protected: + + tick time; ///< channel time, allow for channel concurrency + tick lastCommandIssueTime; ///< the last time a command was executed on this channel + const Command *lastCommand; ///< id of the last accessed rank of this channel + TimingSpecification timingSpecification; ///< the timing specs for this channel + Queue transactionQueue; ///< transaction queue for the channel + std::vector refreshCounter; ///< holds the next refresh command time for the rank + const SystemConfiguration &systemConfig; ///< a pointer to common system config values + Statistics &statistics; ///< backward pointer to the stats engine + PowerConfig powerModel; ///< the power model for this channel, retains power stats + unsigned channelID; ///< the ordinal value of this channel (0..n) + std::vector rank; ///< vector of the array of ranks + std::queue > finishedTransactions; ///< the transactions finished this time + std::vector,std::pair > > cprhSequence; ///< the sequence that the command pair rank hopping follows + unsigned lastCprhLocation; ///< index of the last location where a cprh command was chosen from + + // functions + void retireCommand(Command *, const bool isHit); + bool checkForAvailableCommandSlots(const Transaction *trans) const; + bool transaction2commands(Transaction *); + Command *getNextCommand(const Command *useThisCommand = NULL); + + std::pair getNextCPRHValues(const unsigned) const; + void setupCprhValues(); + void setLastCprhLocation(unsigned rank, unsigned bank, bool isActivate); + + Transaction *getTransaction(); + Transaction *getAvailableTransaction(unsigned useThis = UINT_MAX); + + const Transaction *readTransaction(bool) const; + unsigned readAvailableTransaction(bool) const; + + Transaction *createNextRefresh(); + const Transaction *readNextRefresh() const; + + tick nextRefreshTime() const; + tick nextTransactionDecodeTime() const; + tick nextCommandExecuteTime() const; + void executeCommand(Command *thisCommand); + bool canIssue(const Command *thisCommand) const { return earliestExecuteTime(thisCommand) <= time; } + + // functions that may differ for architectures that inherit this + virtual const Command *readNextCommand() const; + virtual tick minProtocolGap(const Command *thisCommand) const; + virtual tick earliestExecuteTime(const Command *thisCommand) const; + virtual tick earliestExecuteTimeLog(const Command *thisCommand) const; + + public: + // constructors + explicit Channel(const Settings& settings, const SystemConfiguration& sysConfig, Statistics& stats); + Channel(const Channel&); + explicit Channel(const Channel& rhs, const SystemConfiguration& systemConfig, Statistics& stats); + virtual ~Channel(); + + // functions + bool enqueue(Transaction *in); + bool isFull() const { return transactionQueue.isFull(); } ///< determines whether there is room for more transactions + unsigned getChannelID() const { return channelID; } ///< return the ordinal of this channel + std::ostream &doPowerCalculation(std::ostream &os); + virtual tick nextTick() const; + void resetToTime(const tick time); + std::queue >::size_type pendingTransactionCount() const { return finishedTransactions.size(); } + void getPendingTransactions(std::queue > &); + void resetStats(); + + virtual void moveToTime(const tick currentTime); + + // accessors + const TimingSpecification& getTimingSpecification() const { return timingSpecification; } ///< returns a reference to access the timing specification + Rank& getRank(const unsigned rankNum) { return rank[rankNum]; } ///< get a reference to this channel's rank n + const Rank& getRank(const unsigned rankNum) const { return rank[rankNum]; } ///< get a const reference to this channel's rank n + std::vector& getRank() { return rank; } ///< get a reference to this channel's ranks + const std::vector& getRank() const { return rank; } ///< get a const reference to this channel's ranks + tick getTime() const { return time; } ///< get the time that this channel is at + unsigned getLastRankID() const { return lastCommand ? lastCommand->getAddress().getRank() : systemConfig.getRankCount() - 1; }///< get the last rank id a command was issued to + bool isEmpty() const; + + + unsigned getTransactionQueueCount() const { return transactionQueue.size(); } ///< determine how many items are in the transaction completion queue + unsigned getTransactionQueueDepth() const { return transactionQueue.depth(); } ///< determine how large the transaction completion queue is + Rank& operator[](unsigned rank_num) { return rank[rank_num]; } + + // mutators + void setTime(tick value) { time = value; } ///< update the time for this channel + void setChannelID(const unsigned value); + Transaction::TransactionType setReadWriteType(const int) const; + + // overloads + Channel& operator =(const Channel& rs); + bool operator==(const Channel& right) const; + friend std::ostream& operator<<(std::ostream& , const Channel&); + + private: + bool sendPower(double PsysRD, double PsysWR, std::vector rankArray, std::vector PsysACTSTBYArray, std::vector PsysACTArray, const tick currentTime) const; + + // serialization + explicit Channel(const Settings& settings, const SystemConfiguration& sysConf, Statistics& stats, const PowerConfig& power,const std::vector& rank, const TimingSpecification& timing); + explicit Channel(); + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Channel.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Channel.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,3447 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Channel.hh" +#include "base/trace.hh" + +using std::endl; +using std::setw; +using std::cerr; +using std::hex; +using std::dec; +using std::min; +using std::max; +using std::vector; + +using namespace DRAMsimII; + +using namespace std; + +////////////////////////////////////////////////////////////////////////// +/// @brief constructs the dramChannel using this _settings reference, also makes a reference to the dramSystemConfiguration object +/// @param _settings the _settings file that defines the number of ranks, refresh policy, etc. +/// @param _systemConfig a const reference is made to this for some functions to grab parameters from +/// @param _stats a reference to the _stats object that will be collecting data +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Channel::Channel(const Settings& _settings, + const SystemConfiguration& _systemConfig, Statistics& _stats) : + time(0ll), lastCommandIssueTime(-1ll * _settings.tCMD), lastCommand(NULL), + timingSpecification(_settings), transactionQueue( + _settings.transactionQueueDepth), refreshCounter( + _settings.rankCount), systemConfig(_systemConfig), + statistics(_stats), powerModel(_settings), channelID(UINT_MAX), + rank(_settings.rankCount * _settings.dimmCount, Rank(_settings, + timingSpecification, _systemConfig, _stats)), + finishedTransactions(), lastCprhLocation(0) +{ + setupCprhValues(); +#if 0 + // assign an id to each channel (normally done with commands) + for (unsigned i = 0; i < _settings.rankCount; ++i) + { + rank[i].setRankID(i); + } +#endif + +#if 0 + for (unsigned i = 0; i < rank.size() * rank[0].bank.size() * 2; i++) + { + pair a = getNextCPRHValues(i); + cerr << a.first << " " << a.second; + if ((i % 2) == 1) + cerr << endl; + else + cerr << " "; + } +#endif + + // initialize the refresh counters per rank + + if (_settings.refreshPolicy != NO_REFRESH) + { + // stagger the times that each rank will be refreshed so they don't all arrive incomingTransaction a burst + unsigned step = _settings.tREFI / _settings.rankCount; + Address addr(0, 0, 0, 0, 0); + + for (unsigned j = 0; j < refreshCounter.size(); ++j) + { + addr.setRank(j); + + refreshCounter[j] = new Transaction( + Transaction::AUTO_REFRESH_TRANSACTION, j * step + 1, 8, + addr, 0, 0); + + assert(refreshCounter[j]->isRefresh()); + + //refreshCounter[j] = j * (step + 1); + + } + } +} + +////////////////////////////////////////////////////////////////////////// +/// normal copy constructor +/// @brief the copy constructor for building unitialized copies of a channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Channel::Channel(const Channel& rhs, const SystemConfiguration& systemConfig, + Statistics& stats) : + time(rhs.time), + lastCommandIssueTime(rhs.lastCommandIssueTime), + lastCommand(rhs.lastCommand ? new Command(*rhs.lastCommand) : NULL), + timingSpecification(rhs.timingSpecification), transactionQueue( + rhs.transactionQueue), refreshCounter( + rhs.refreshCounter.size()), systemConfig(systemConfig), + statistics(stats), powerModel(rhs.powerModel), + channelID(rhs.channelID), + // to initialize the references + rank((unsigned) systemConfig.getRankCount() + * systemConfig.getDimmCount(), Rank(rhs.rank[0], + timingSpecification, systemConfig, stats)), + finishedTransactions(), cprhSequence(rhs.cprhSequence), + lastCprhLocation(rhs.lastCprhLocation) +{ + // to fill incomingTransaction the values + rank = rhs.rank; + + for (vector::size_type i = 0; i < refreshCounter.size(); ++i) + { + refreshCounter[i] = new Transaction(*rhs.refreshCounter[i]); + } +} + +////////////////////////////////////////////////////////////////////////// +/// deserialization constructor +/// @brief the constructor to build copies of a channel once it's been deserialized, needs further initialization before it's ready +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Channel::Channel(const Settings& settings, const SystemConfiguration& sysConf, + Statistics &stats, const PowerConfig &power, + const std::vector &newRank, const TimingSpecification &timing) : + time(0), lastCommandIssueTime(-1ll * settings.tCMD), lastCommand(NULL), + timingSpecification(timing), transactionQueue(0), + refreshCounter(0), systemConfig(sysConf), statistics(stats), + powerModel(power), channelID(UINT_MAX), rank(newRank), + finishedTransactions(), lastCprhLocation(0) +{ +} + +////////////////////////////////////////////////////////////////////////// +/// @brief copy constructor, reassigns the ordinal to each rank as they are duplicated +/// @param rhs the dramChannel object to be copied +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Channel::Channel(const Channel &rhs) : + time(rhs.time), lastCommandIssueTime(rhs.lastCommandIssueTime), + lastCommand(rhs.lastCommand), timingSpecification( + rhs.timingSpecification), transactionQueue( + rhs.transactionQueue), refreshCounter( + rhs.refreshCounter.size()), systemConfig(rhs.systemConfig), + statistics(rhs.statistics), powerModel(rhs.powerModel), channelID( + rhs.channelID), + rank((unsigned) rhs.rank.size(), Rank(rhs.rank[0], + timingSpecification, systemConfig, statistics)), + finishedTransactions(), cprhSequence(rhs.cprhSequence), + lastCprhLocation(rhs.lastCprhLocation) +{ + // TODO: copy over values incomingTransaction ranks now that reference members are init + // assign an id to each channel (normally done with commands) + //dimm = rhs.dimm; + rank = rhs.rank; + + for (vector::size_type i = 0; i < refreshCounter.size(); ++i) + { + refreshCounter[i] = new Transaction(*rhs.refreshCounter[i]); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief channel destructor +/// @details need to remove all the commands in the queues before destructing the channel +/// because some refresh commands are simultaneously in two or more queues and will be +/// duplicated in the command pool if they are not removed properly +////////////////////////////////////////////////////////////////////////// +Channel::~Channel() +{ +#if 1 + // must remove commands this way to prevent queues from being automatically deleted, thus creating double frees on refresh commands + while (Command *cmd = getNextCommand()) + { + Transaction *hostTransaction = cmd->removeHost(); + if (hostTransaction != NULL) + delete hostTransaction; + + delete lastCommand; + + lastCommand = cmd; + } +#endif + + delete lastCommand; + lastCommand = NULL; + +#if 1 + for (vector::iterator i = refreshCounter.begin(), end = + refreshCounter.end(); i != end; ++i) + { + delete *i; + *i = NULL; + } + + while (Transaction *trans = transactionQueue.pop()) + { + delete trans; + } +#endif +} + +void Channel::setChannelID(const unsigned value) +{ + channelID = value; + unsigned currentId = 0; + for (vector::iterator i = rank.begin(); i != rank.end(); ++i) + { + i->setRankID(value, currentId++); + } + + currentId = 0; + // for (vector::iterator i = dimm.begin(), end = dimm.end(); + // i != end; ++i) + // { + // i->setDimmId(value, currentId++); + // } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief Moves the specified channel to at least the time given +/// @param currentTime issue all events up to and including this time +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +void Channel::moveToTime(const tick currentTime) +{ + assert(finishedTransactions.empty()); + + /// @todo continue until no events are processed, no commands issued, no transactions decoded + while (time < currentTime) + { + // move time to either when the next command executes or the next transaction decodes, whichever is earlier + // otherwise just go to the end +#ifndef NDEBUG + tick oldTime = time; +#endif + /// @todo verify that this is right + //time = max(min(currentTime,min(nextTransactionDecodeTime(),min(nextCommandExecuteTime(),nextRefreshTime()))),time); + time = max(min(currentTime, min(nextTransactionDecodeTime(), + nextCommandExecuteTime())), time); + assert(time <= currentTime); + assert(time >= oldTime); + + // has room to decode an available transaction, as many as are ready + // unsigned decodedCount = 0; + // unsigned decodedRefreshCount = 0; + + while (Transaction *nextTransaction = getTransaction()) + { + // actually remove it from the queue now + //Transaction *decodedTransaction = getTransaction(); + assert(nextTransaction); + + // if (nextTransaction->isRefresh()) + // decodedRefreshCount++; + // else + // decodedCount++; + // then break into commands and insert into per bank command queues + assert(checkForAvailableCommandSlots(nextTransaction)); + +#ifndef NDEBUG + bool t2cResult = +#endif + transaction2commands(nextTransaction); + + assert(t2cResult); + + nextTransaction->setDecodeTime(time); + // checkForAvailablecommandSlots() should not have returned true if there was not enough space + + DPRINTF( + MemoryAccess, + "T->C [%ld] Q[%d/%d]->[%d/%d] %s", + time, + getTransactionQueueCount(), + transactionQueue.depth(), + rank[nextTransaction->getAddress().getRank()].bank[nextTransaction->getAddress().getBank()].size(), + rank[nextTransaction->getAddress().getRank()].bank[nextTransaction->getAddress().getBank()].depth(), + *nextTransaction); + + //nextToDecode = readAvailableTransaction(); + //nextTransaction = readTransaction(true); + } +#ifndef NDEBUG + //if (decodedCount > 3 || decodedRefreshCount > 1) + //cerr << "decoded " << decodedCount << "/" << decodedRefreshCount << endl; +#endif + + // execute commands for this time, reevaluate what the next command is since this may have changed after decoding the transaction + const Command *nextCommand = readNextCommand(); + + while (nextCommand && (earliestExecuteTime(nextCommand) <= time)) + { + Command *executingCommand = getNextCommand(nextCommand); + + assert(executingCommand == nextCommand); + + assert(earliestExecuteTimeLog(nextCommand) <= time); + + executeCommand(executingCommand); + + nextCommand = readNextCommand(); + } + } + + //transFinishTime = currentTime; + //M5_TIMING_LOG("ch[" << channelID << "] @ " << dec << time); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief determines when the next transaction is decoded, command ready to be executed or next refresh command arrives +/// @return the time when the next event happens +/// @sa readTransactionSimple() readNextCommand() earliestExecuteTime() checkForAvailableCommandSlots() nextRefreshTime() +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +tick Channel::nextTick() const +{ + return max(min(min(nextTransactionDecodeTime(), nextCommandExecuteTime()), + nextRefreshTime()), time + 1); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief determine when the next transaction incomingTransaction the queue will be decoded +/// @return the time when the decoding will be complete +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +tick Channel::nextTransactionDecodeTime() const +{ + if (const Transaction *nextTrans = readTransaction(false)) + { + if (nextTrans) + { + if (nextTrans->isRefresh()) + return nextTrans->getArrivalTime(); + else + return nextTrans->getEnqueueTime() + + timingSpecification.tBufferDelay(); + } + } + + return TICK_MAX; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief return any transactions that finished when moveToTime() was called +/// @details moves results from the internal queue to the given queue +/// @returns a queue that has the results in transactionID, finished time pairs +////////////////////////////////////////////////////////////////////////// +void Channel::getPendingTransactions( + std::queue > &outputQueue) +{ + while (!finishedTransactions.empty()) + { + outputQueue.push(finishedTransactions.front()); + finishedTransactions.pop(); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief determines the next time available for a command to issue +/// @return the next time an event occurs on this channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +tick Channel::nextCommandExecuteTime() const +{ + // then check to see when the next command occurs + if (const Command *tempCommand = readNextCommand()) + { + tick tempCommandExecuteTime = earliestExecuteTime(tempCommand); +#ifndef NDEBUG + tick tempGap = minProtocolGap(tempCommand); + + if (time + tempGap != tempCommandExecuteTime) + cerr << time << " " << tempGap << " " << tempCommandExecuteTime + << " " << tempCommand->getCommandType() << " " + << tempCommand->getAddress() << endl; + ; + assert(time + tempGap == tempCommandExecuteTime); +#endif + return tempCommandExecuteTime; + } + else + return TICK_MAX; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief get the next refresh time +/// @return the time at which the next refresh should be issued for this channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +tick Channel::nextRefreshTime() const +{ + assert(rank.size() >= 1); + + if (systemConfig.getRefreshPolicy() != NO_REFRESH) + { + return readNextRefresh()->getArrivalTime(); + //return *(std::min_element(refreshCounter.begin(), refreshCounter.end())); + } + else + return TICK_MAX; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief adds this command to the history queue +/// @details this allows other groups to view a recent history of commands that were issued to decide what to execute next +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +void Channel::retireCommand(Command *newestCommand, const bool isHit) +{ + statistics.collectCommandStats(newestCommand); + + assert(((newestCommand->isReadOrWrite() || newestCommand->isRefresh()) + && newestCommand->getHost()) || (!(newestCommand->isReadOrWrite() + || newestCommand->isRefresh()) && !newestCommand->getHost())); + + // transaction complete? if so, put incomingTransaction completion queue + // note that the host transaction should only be pointed to by a CAS command + // since this is when a transaction is done from the standpoint of the requester + if (Transaction *completedTransaction = newestCommand->removeHost()) + { + DPRINTF(MemoryAccess, "-T %s", *completedTransaction); + + if (!newestCommand->isRefresh()) + { + statistics.collectTransactionStats(completedTransaction); + + assert(newestCommand->getEnqueueTime() + >= completedTransaction->getEnqueueTime() + && newestCommand->getCompletionTime() + <= completedTransaction->getCompletionTime()); + + const unsigned origTrans = + completedTransaction->getOriginalTransaction(); + + M5_DEBUG(assert(origTrans < UINT_MAX)); + + if (origTrans < UINT_MAX) + finishedTransactions.push(std::pair(origTrans, + completedTransaction->getCompletionTime())); + } + else + { + assert(systemConfig.getRefreshPolicy() != NO_REFRESH); + } + + delete completedTransaction; + + } + assert(!newestCommand->getHost()); + + if (!isHit) + { + delete lastCommand; + + lastCommand = newestCommand; + } + else + { + delete newestCommand; + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief enqueue the transaction into the transactionQueue +/// @param incomingTransaction the transaction to be put into the queue +/// @return true if there was room incomingTransaction the queue for this command and the algorithm allowed it, false otherwise +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +bool Channel::enqueue(Transaction *incomingTransaction) +{ + if (transactionQueue.isFull()) + return false; + + incomingTransaction->setEnqueueTime(time); + + assert(!incomingTransaction->isRefresh()); + + assert(incomingTransaction->getAddress().getChannel() == channelID); + + bool result; + + switch (systemConfig.getTransactionOrderingAlgorithm()) + { + case STRICT: + result = transactionQueue.push(incomingTransaction); + break; + case RIFF: + // search from back to front + // insert right after a conflict, any transaction over the seniority limit or any read + if (incomingTransaction->isRead()) + { + for (int currentIndex = transactionQueue.size() - 1; currentIndex + >= 0; --currentIndex) + { + // prevent against starvation and RAW errors, reads do not switch their ordering + if (transactionQueue[currentIndex]->isRead() || (time + - transactionQueue[currentIndex]->getEnqueueTime() + > systemConfig.getSeniorityAgeLimit()) + || transactionQueue[currentIndex]->getAddress() + == incomingTransaction->getAddress()) + { + result = transactionQueue.insert(incomingTransaction, + currentIndex + 1); + assert(result); + return result; + } + } + // if there were no conditions to force it to choose another location, insert at the head + result = transactionQueue.push_front(incomingTransaction); + } + else + { + result = transactionQueue.push(incomingTransaction); + } + break; + default: + cerr << "Unknown transaction ordering algorithm." << endl; + exit(-1); + break; + } + + return result; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief counts the number of reads and writes so far and returns whichever had more +/// @param rankID which rank to look at when determining which transaction type to choose +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Transaction::TransactionType Channel::setReadWriteType(const int rankID) const +{ + unsigned readCount = 0; + unsigned writeCount = 0; + unsigned emptyCount = 0; + + vector::const_iterator currentBank = rank[rankID].bank.begin(); + vector::const_iterator bankEnd = rank[rankID].bank.end(); + + for (; currentBank != bankEnd; ++currentBank) + { + if (const Command *currentCommand = currentBank->front()) + { + if (currentCommand->isActivate()) + { + currentCommand = currentBank->read(1); + assert(currentCommand && currentCommand->isReadOrWrite()); + } + + if (currentCommand->isRead()) + { + readCount++; + } + else + { + writeCount++; + } + } + else + { + emptyCount++; + } + } + + DEBUG_LOG("Rank[" << rankID << "] Read[" << readCount << "] Write[" + << writeCount << "] Empty[" << emptyCount << "]"); + + if (readCount >= writeCount) + return Transaction::READ_TRANSACTION; + else + return Transaction::WRITE_TRANSACTION; +} + +////////////////////////////////////////////////////////////////////// +/// @brief performs power calculations for this epoch and cumulative +/// @details calculates the power according to Micron technical note TN-47-04\n +/// also does breakdowns of power consumed per channel and per epoch as well as averaged over time +/// @author Joe Gross +////////////////////////////////////////////////////////////////////// +ostream &Channel::doPowerCalculation(ostream& os) +{ + double PsysRD = 0.0; + double PsysWR = 0.0; + + double PsysACT_STBY = 0.0; + double PsysPRE_STBY = 0.0; + double PsysPRE_PDN = 0.0; + double PsysACT_PDN = 0.0; + double PsysACT = 0.0; + //double PsysACTAdjusted = 0.0; + + os << "+ch[" << channelID << "]"; + + for (vector::iterator k = rank.begin(); k != rank.end(); ++k) + { + unsigned thisRankRasCount = 1; + + //rankArray.push_back(k->getRankId()); + + for (vector::iterator l = k->bank.begin(); l != k->bank.end(); ++l) + { + thisRankRasCount += l->getRASCount(); + l->accumulateAndResetCounts(); + } + + // FIXME: assumes CKE is always high, so (1 - CKE_LOW_PRE%) = 1 + double percentActive = 1.0 - (k->getPrechargeTime(time) / max( + (double) (time - powerModel.getLastCalculation()), 0.00000001)); + + assert(percentActive >= 0.0F && percentActive <= 1.0F); + assert(k->getPrechargeTime(time) <= time + - powerModel.getLastCalculation()); + + /// @todo actually simulate CKE, per rank + double CKE_LO_PRE = 0.95F; + double CKE_LO_ACT = 0.01F; + + // calculate background power + // calculate PsysACT-STBY + double PschACT_STBY = powerModel.getPdsACT_STBY() * percentActive * (1 + - CKE_LO_ACT); + PsysACT_STBY += powerModel.getDevicesPerRank() + * powerModel.getVoltageScaleFactor() + * powerModel.getFrequencyScaleFactor() * PschACT_STBY; + + // calculate PsysPRE-STBY + double PschPRE_STBY = powerModel.getPdsPRE_STBY() * (1.0 + - percentActive) * (1 - CKE_LO_PRE); + PsysPRE_STBY += powerModel.getDevicesPerRank() + * powerModel.getFrequencyScaleFactor() + * powerModel.getVoltageScaleFactor() * PschPRE_STBY; + + // calculate PsysPRE-PDN + double PschPRE_PDN = powerModel.getPdsPRE_PDN() * (1.0 - percentActive) + * (CKE_LO_PRE); + PsysPRE_PDN += powerModel.getDevicesPerRank() + * powerModel.getFrequencyScaleFactor() + * powerModel.getVoltageScaleFactor() * PschPRE_PDN; + + // calculate PsysACT-PDN + double PschACT_PDN = powerModel.getPdsACT_PDN() * percentActive + * CKE_LO_ACT; + PsysACT_PDN += powerModel.getDevicesPerRank() + * powerModel.getFrequencyScaleFactor() + * powerModel.getVoltageScaleFactor() * PschACT_PDN; + + // calculate PsysACT + double tRRDsch = ((double) (time - powerModel.getLastCalculation())) + / (thisRankRasCount > 0 ? thisRankRasCount : 0.00000001); +#if 0 +#ifndef NDEBUG + cerr << "rrd " << tRRDsch << " " << powerModel.gettRC() << endl; +#endif +#endif + double PschACT = powerModel.getPdsACT() * powerModel.gettRC() / tRRDsch; + +#if 0 + if (tRRDsch > 200.0F) + cerr << "t=" << time << ", last t=" << powerModel.getLastCalculation() << ", #RAS=" << perRankRASCount << endl; +#endif + PsysACT += powerModel.getDevicesPerRank() + * powerModel.getVoltageScaleFactor() * PschACT; + + //PsysACTArray.push_back(PsysACT); + + double RDschPct = k->getReadCycles() / (double) (time + - powerModel.getLastCalculation()); + + PsysRD += powerModel.getDevicesPerRank() + * powerModel.getVoltageScaleFactor() + * powerModel.getFrequencyScaleFactor() * powerModel.getPdsRD() + * RDschPct; + + double WRschPct = k->getWriteCycles() / (double) (time + - powerModel.getLastCalculation()); + + PsysWR += powerModel.getDevicesPerRank() + * powerModel.getVoltageScaleFactor() + * powerModel.getFrequencyScaleFactor() * powerModel.getPdsWR() + * WRschPct; + + os << " rk[" << k->getRankId() << "] prechargeTime{" + << k->getPrechargeTime(time) << "} rasCount{" + << thisRankRasCount << "} duration{" << time + - powerModel.getLastCalculation() << "} read{" + << k->getReadCycles() << "} readHits{" << k->getReadHits() + << "} write{" << k->getWriteCycles() << "}"; + + k->resetPrechargeTime(time); + k->resetCycleCounts(); + } + + os << "-Psys(ACT_STBY) ch[" << channelID << "] {" << setprecision(5) + << PsysACT_STBY << "} mW " << endl; + + os << "-Psys(ACT) ch[" << channelID << "] {" << setprecision(5) << PsysACT + << "} mW" << endl; + + os << "-Psys(PRE_STBY) ch[" << channelID << "] {" << setprecision(5) + << PsysPRE_STBY << "} mW" << endl; + + os << "-Psys(RD) ch[" << channelID << "] {" << setprecision(5) << PsysRD + << "} mW" << endl; + + os << "-Psys(WR) ch[" << channelID << "] {" << setprecision(5) << PsysWR + << "} mW" << endl; + + powerModel.setLastCalculation(time); + + return os; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns a pointer to the next transaction to issue to this channel without removing it +/// @details read the next available transaction for this channel without actually removing it from the queue \n +/// if bufferDelay is set, then only transactions that have been incomingTransaction the queue long enough to decode are considered +/// @return the next transaction that should be issued to this channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +const Transaction *Channel::readTransaction(const bool bufferDelay) const +{ + const unsigned delay = bufferDelay ? timingSpecification.tBufferDelay() : 0; + + unsigned val = readAvailableTransaction(bufferDelay); + + const Transaction *nextTransaction = + (val < UINT_MAX) ? transactionQueue[val] : NULL; + + if (systemConfig.getRefreshPolicy() == NO_REFRESH) + { + if ((nextTransaction) && (time >= nextTransaction->getEnqueueTime() + + delay)) + { + return nextTransaction; + } + } + else + { + const tick nextRefresh = nextRefreshTime(); + + // give an advantage to normal transactions, but prevent starvation for refresh operations + // if there is a normal transaction ready to go, it's ready to go and the refresh command isn't starving + if (nextTransaction && ((time < nextRefresh + + systemConfig.getSeniorityAgeLimit()) && (time + >= nextTransaction->getEnqueueTime() + delay))) + { + return nextTransaction; + } + // either there is no transaction or the refresh command will starve + else if (((time >= nextRefresh) || !bufferDelay) + && (checkForAvailableCommandSlots(readNextRefresh()))) + { + return readNextRefresh(); + } + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief read a transaction that is ready to go, out of order possibly +/// @details searches from the head to the end or the decode window to find +/// a transaction that is able to be decoded at the current time +/// @returns a pointer to the next transaction that can currently be decoded +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +unsigned Channel::readAvailableTransaction(const bool bufferDelay) const +{ + const unsigned delay = bufferDelay ? timingSpecification.tBufferDelay() : 0; + + unsigned limit = min(systemConfig.getDecodeWindow(), + transactionQueue.size()); + + for (unsigned i = 0; i < limit; ++i) + { + const Transaction *currentTrans = transactionQueue[i]; + tick enqueueTime = currentTrans->getEnqueueTime(); + + // if it's ready to decode + if ((enqueueTime + delay <= time) && checkForAvailableCommandSlots( + currentTrans)) + { + bool conflict = false; + // make sure not to create a RAW, WAR, WAW problem + for (unsigned j = 0; j < i; ++j) + { + if (currentTrans->getAddress() + == transactionQueue[j]->getAddress()) + { + conflict = true; + break; + } + } + if (!conflict) + return i; + } + else if (time - enqueueTime > systemConfig.getSeniorityAgeLimit()) + break; + } + return UINT_MAX; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief removes and returns the next decodable transaction +/// @sa readAvailableTransaction() +/// @details returns a transaction that can be decoded right now in the same +/// way as readAvailableTransaction(), but actually removes it +////////////////////////////////////////////////////////////////////////// +Transaction *Channel::getAvailableTransaction(unsigned useThis) +{ + if (useThis < UINT_MAX) + return transactionQueue.remove(useThis); + else + { + unsigned val = readAvailableTransaction(true); + if (val < UINT_MAX) + return transactionQueue.remove(val); + else + return NULL; + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief get the next transaction, whether a refresh transaction or a normal R/W transaction +/// @details gets the next transaction for this channel and removes it, always returns a transaction that is able to decode +/// @return the next transaction for this channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Transaction *Channel::getTransaction() +{ + unsigned val = readAvailableTransaction(true); + + const Transaction *nextTransaction = + (val < UINT_MAX) ? transactionQueue[val] : NULL; + + // no refresh transactions, just see if normal transactions are decoded + if (systemConfig.getRefreshPolicy() == NO_REFRESH) + { + if ((nextTransaction) && (time >= nextTransaction->getEnqueueTime() + + timingSpecification.tBufferDelay())) + { + return getAvailableTransaction(val); + } + } + else + { + const tick nextRefresh = nextRefreshTime(); + + // give an advantage to normal transactions, but prevent starvation for refresh operations + // if there is a normal transaction ready to go, it's ready to go and the refresh command isn't starving + if (nextTransaction && ((time < nextRefresh + + systemConfig.getSeniorityAgeLimit()) && (time + >= nextTransaction->getEnqueueTime() + + timingSpecification.tBufferDelay()))) + { + return getAvailableTransaction(val); + } + else if ((time >= nextRefresh) && (checkForAvailableCommandSlots( + readNextRefresh()))) + { + return createNextRefresh(); + } + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief get the next refresh command and remove it from the queue +/// @details returns a pointer to a refresh transaction that represents what the next refresh \n +/// transaction would be. this should not be enqueued as it has not been removed yet +/// @return the next possible refresh transaction +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Transaction *Channel::createNextRefresh() +{ + Transaction *newRefreshTransaction = + refreshCounter[readNextRefresh()->getAddress().getRank()]; + assert(refreshCounter[newRefreshTransaction->getAddress().getRank()] + == newRefreshTransaction); + + unsigned rank = newRefreshTransaction->getAddress().getRank(); + + refreshCounter[rank] = new Transaction( + Transaction::AUTO_REFRESH_TRANSACTION, + newRefreshTransaction->getArrivalTime() + + timingSpecification.tREFI(), 8, + newRefreshTransaction->getAddress(), 0, 0); + + //refreshCounter[rank] = refreshCounter[rank] + timingSpecification.tREFI(); + + //static Address address; + + //address.setAddress(channelID,earliestRank,0,0,0); + + //::new(&newRefreshTransaction)Transaction(Transaction::AUTO_REFRESH_TRANSACTION, earliestTime, 8, address, 0, 0, UINT_MAX); + + assert(refreshCounter[rank]->isRefresh()); + assert(newRefreshTransaction->isRefresh()); + + return newRefreshTransaction; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns a pointer to the next refresh transaction that's going to be issued to this channel +/// @details returns a pointer to a representative object for the next refresh that this channel will see +/// @return a pointer to a representative copy of the next refresh transaction +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +const Transaction *Channel::readNextRefresh() const +{ + assert(rank.size() >= 1); + + vector::const_iterator i = refreshCounter.begin(); + Transaction *earliestRefresh = *i; + ++i; + + for (vector::const_iterator end = refreshCounter.end(); i + != end; ++i) + { + if ((*i)->getArrivalTime() < earliestRefresh->getArrivalTime()) + { + earliestRefresh = *i; + } + } + + assert(earliestRefresh->isRefresh()); + + return earliestRefresh; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief reset some _stats to account for the fact that fast-forwarding has moved time forward significantly +/// @param time the time at which the timing model begins +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +void Channel::resetToTime(const tick time) +{ + lastCommandIssueTime = time - timingSpecification.tCMD(); + this->time = time; + powerModel.resetToTime(time); + // adjust the start time of the refreshes to match the new time + for (vector::iterator i = refreshCounter.begin(); i + != refreshCounter.end(); ++i) + { + (*i)->setArrivalTime((*i)->getArrivalTime() + time); + //*i = *i + time; + } + + for (vector::iterator i = rank.begin(); i != rank.end(); ++i) + { + i->resetToTime(time); + } + + // for (vector::iterator i = dimm.begin(), end = dimm.end(); + // i != end; ++i) + // { + // i->resetToTime(time); + // } +} + +////////////////////////////////////////////////////////////////////// +/// @brief determines if there are enough command slots for the transaction to be decoded +/// @details this will ensure that a given transaction can be broken into and inserted as commands in this channel +/// if there is not enough room according to a given algorithm, then it will indicate that this is not possible +/// @author Joe Gross +/// @param incomingTransaction trans the transaction to be considered +/// @return true if there is enough room, false otherwise +////////////////////////////////////////////////////////////////////// +bool Channel::checkForAvailableCommandSlots( + const Transaction *incomingTransaction) const +{ + if (incomingTransaction == NULL) + { + return false; + } + // ensure that this transaction belongs on this channel + assert(incomingTransaction->getAddress().getChannel() == channelID + || incomingTransaction->isRefresh()); + + /// @todo switch to iterator arithmetic + const Bank + &destinationBank = + rank[incomingTransaction->getAddress().getRank()].bank[incomingTransaction->getAddress().getBank()]; + + unsigned + availableCommandSlots = + (incomingTransaction->isRefresh()) ? 0 + : rank[incomingTransaction->getAddress().getRank()].bank[incomingTransaction->getAddress().getBank()].freeCommandSlots(); + + // with closed page, all transactions convert into one of the following: + // RAS, CAS, Precharge + // RAS, CAS+Precharge + switch (systemConfig.getRowBufferManagementPolicy()) + { + case CLOSE_PAGE_AGGRESSIVE: + case CLOSE_PAGE: + // refresh transactions become only one command and are handled differently + if (incomingTransaction->isRefresh()) + { + const Rank &destinationRank = + rank[incomingTransaction->getAddress().getRank()]; + // make sure that there is room in all the queues for one command + // refresh commands refresh a row, but kill everything currently in the sense amps + // therefore, we need to make sure that the refresh commands happen when all banks + // are available + for (vector::const_iterator currentBank = + destinationRank.bank.begin(); currentBank + != destinationRank.bank.end(); ++currentBank) + { + if (currentBank->isFull()) + return false; + } + } + // must know that there is >0 slots open or the result may not be accurate + else if (systemConfig.getRowBufferManagementPolicy() + == CLOSE_PAGE_AGGRESSIVE + && destinationBank.closePageAggressiveInsertCheck( + incomingTransaction, time)) + { + return true; + } + // every transaction translates into at least two commands + else if (availableCommandSlots < 2) + { + return false; + } + // or three commands if the CAS+Precharge command is not available + else if (!systemConfig.isAutoPrecharge() && (availableCommandSlots < 3)) + { + return false; + } + break; + + // open page systems may, in the best case, add a CAS command to an already open row + // closing the row and precharging may be delayed + + // all break down into PRE,RAS,CAS + // or CAS + case OPEN_PAGE: + case OPEN_PAGE_AGGRESSIVE: + + // refresh transactions become only one command and are handled differently + if (incomingTransaction->isRefresh()) + { + const Rank ¤tRank = + rank[incomingTransaction->getAddress().getRank()]; + // make sure that there is room in all the queues for one command + // refresh commands refresh a row, but kill everything currently in the sense amps + // therefore, we need to make sure that the refresh commands happen when all banks + // are available + for (vector::const_iterator i = currentRank.bank.begin(); i + != currentRank.bank.end(); ++i) + { + if (i->freeCommandSlots() < 2) + return false; + } + return true; + } + else if (!destinationBank.isFull()) + { + // try to do a normal open page insert on this transaction + if ((systemConfig.getRowBufferManagementPolicy() + == OPEN_PAGE_AGGRESSIVE) + && (destinationBank.openPageAggressiveInsertCheck( + incomingTransaction, time))) + { + return true; + } + else + { + // first, the precharge command, if necessary + if (((destinationBank.isEmpty() + && destinationBank.isActivated()) + || (!destinationBank.isEmpty() + && !destinationBank.back()->isRefresh()))) + { + if (destinationBank.freeCommandSlots() < 3) + { + return false; + } + assert(!destinationBank.back() + || destinationBank.back()->getCommandType() + != Command::REFRESH_ALL); + assert(!destinationBank.back() + || destinationBank.back()->getCommandType() + != Command::PRECHARGE); + } + else if (destinationBank.freeCommandSlots() < 2) + { + return false; + } + + return true; + } + } + else + { + return false; + } + + break; + + default: + + cerr << "Unhandled row buffer management policy" << endl; + return false; + break; + } + return true; +} + +////////////////////////////////////////////////////////////////////// +/// @brief converts a transaction into corresponding commands +/// @details takes a transaction and divides it into a number of commands, depending which row buffer management policy is chosen\n +/// currently will divide it into RAS, CAS, Pre or RAS, CAS+P and insert these commands into the per bank queues\n +/// the CAS command will contain a pointer to the host transaction to indicate that a read transaction has available data +/// @author Joe Gross +/// @param incomingTransaction the transaction which is divided up +/// @return true if the transaction was able to be divided up and put into per bank queues +////////////////////////////////////////////////////////////////////// +bool Channel::transaction2commands(Transaction *incomingTransaction) +{ + if (incomingTransaction == NULL) + { + return false; + } + // ensure that this transaction belongs on this channel + assert(incomingTransaction->getAddress().getChannel() == channelID + || incomingTransaction->isRefresh()); + assert(incomingTransaction->getAddress().getChannel() + < systemConfig.getChannelCount()); + assert(incomingTransaction->getAddress().getRank() + < (systemConfig.getRankCount() * systemConfig.getDimmCount())); + + vector::iterator destinationRank = rank.begin() + + incomingTransaction->getAddress().getRank(); + + vector::iterator destinationBank = destinationRank->bank.begin() + + incomingTransaction->getAddress().getBank(); + + assert(incomingTransaction->getAddress().getBank() + < systemConfig.getBankCount()); + assert(incomingTransaction->getAddress().getRow() + < systemConfig.getRowCount()); + assert(incomingTransaction->getAddress().getColumn() + < systemConfig.getColumnCount()); + + // with closed page, all transactions convert into one of the following: + // RAS, CAS, Precharge + // RAS, CAS+Precharge + switch (systemConfig.getRowBufferManagementPolicy()) + { + // will either convert a CAS+P into CAS, CAS+P by appending a new command or will add a CAS before a PRE (when autoprecharge is not available) + case CLOSE_PAGE: + case CLOSE_PAGE_AGGRESSIVE: + + // refresh transactions become only one command and are handled differently + if (incomingTransaction->isRefresh()) + { + // check to see if every per bank command queue has room for one command + // make sure that there is room in all the queues for one command + // refresh commands refresh a row, but kill everything currently in the sense amps + // therefore, we need to make sure that the refresh commands happen when all banks + // are available + for (vector::const_iterator currentBank = + destinationRank->bank.begin(); currentBank + != destinationRank->bank.end(); ++currentBank) + { + if (currentBank->isFull()) + return false; + } + // then add the command to all queues + Command *refreshCommand = new Command(incomingTransaction, time, + systemConfig.isAutoPrecharge(), + timingSpecification.tBurst()); + + for (vector::iterator currentBank = + destinationRank->bank.begin(); currentBank + != destinationRank->bank.end(); ++currentBank) + { +#ifndef NDEBUG + bool result = +#endif // NDEBUG + currentBank->push(refreshCommand); + assert(result); + assert(currentBank->back() == refreshCommand); + } + } + // need at least one free command slot + // or three commands if the CAS+Precharge command is not available + else if (systemConfig.getRowBufferManagementPolicy() + == CLOSE_PAGE_AGGRESSIVE && destinationBank->aggressiveInsert( + incomingTransaction, time)) + { + //statistics.reportHit(); + } + // every transaction translates into at least two commands + // or three commands if the CAS+Precharge command is not available + else if ((destinationBank->freeCommandSlots() < 2) + || (!systemConfig.isAutoPrecharge() + && (destinationBank->freeCommandSlots() < 3))) + { + return false; + } + // then it can be piggybacked on an existing R, C, P or R, C+P chain + // also make sure not to starve + // R C1 P => R C1 C2 P + // R C1+P => R C1 C2+P + // TODO: look for the last non-refresh command in the per-bank queue + else + { + // didn't find place to issue command + //statistics.reportMiss(); + + // command one, the RAS command to activate the row +#ifndef NDEBUG + bool result = +#endif + destinationBank->push(new Command(incomingTransaction, + time, false, timingSpecification.tBurst(), + Command::ACTIVATE)); + assert(result); + assert(destinationBank->back()->getAddress() + == incomingTransaction->getAddress()); + + // command two, CAS or CAS+Precharge +#ifndef NDEBUG + result = +#endif + destinationBank->push(new Command(incomingTransaction, + time, systemConfig.isAutoPrecharge(), + timingSpecification.tBurst())); + assert(result); + assert(destinationBank->back()->getAddress() + == incomingTransaction->getAddress()); + + // possible command three, Precharge + if (!systemConfig.isAutoPrecharge()) + { +#ifndef NDEBUG + result = +#endif + destinationBank->push(new Command(incomingTransaction, + time, false, timingSpecification.tBurst(), + Command::PRECHARGE)); + assert(result); + assert(destinationBank->back()->getAddress() + == incomingTransaction->getAddress()); + } + } + break; + + // open page systems may, in the best case, add a CAS command to an already open row + // closing the row and precharging may be pushed back one slot + case OPEN_PAGE_AGGRESSIVE: + // look to see if this queue or queues are getting too full and collapse CAS(W), Pre into + // CAS+P commands to relieve congestion + if (incomingTransaction->isRefresh()) + { + vector::iterator bankEnd = destinationRank->bank.end(); + // evaluate every per bank queue in this rank and collapse + for (vector::iterator i = destinationRank->bank.begin(); i + != bankEnd; ++i) + { + if (i->isHighUtilization()) + { + i->collapse(); + } + } + } + else + { + if (destinationBank->isHighUtilization()) + { + destinationBank->collapse(); + } + } + + // lack of break it intentional + case OPEN_PAGE: + + // refresh transactions become only one command and are handled differently + if (incomingTransaction->isRefresh()) + { + // make sure that there is room in all the queues for one command + // refresh commands refresh a row, but kill everything currently in the sense amps + // therefore, we need to make sure that the refresh commands happen when all banks + // are available + vector::const_iterator bankEnd = destinationRank->bank.end(); + for (vector::const_iterator i = destinationRank->bank.begin(); i + != bankEnd; ++i) + { + if (i->back()) + assert(i->back()->isRefresh() || i->back()->isReadOrWrite()); + + // either cannot fit a single REF command or cannot fit Pre + REF + if (i->isFull() || (i->freeCommandSlots() < 2 + && !i->back()->isPrecharge())) + return false; + } + // then add the command to all queues + Command *refreshCommand = new Command(incomingTransaction, time, + false, timingSpecification.tBurst()); + + Address tempAddr(incomingTransaction->getAddress()); + unsigned bankNumber = 0; + + for (vector::iterator i = destinationRank->bank.begin(); i + != bankEnd; ++i) + { + // can only refresh banks that are in the precharged state + if (i->back() && i->back()->isReadOrWrite()) + { + i->back()->setAutoPrecharge(true); + } + // add a Pre command before the REF to flush written data back to the banks before executing a refresh + else if (i->isEmpty() && i->isActivated()) + { + // then need to precharge before + tempAddr.setBank(bankNumber); + + assert(i->freeCommandSlots() >= 2); +#ifndef NDEBUG + bool result = +#endif // NDEBUG + i->push(new Command(incomingTransaction, tempAddr, + time, false, timingSpecification.tBurst(), + Command::PRECHARGE)); + assert(result); + assert(&(rank[tempAddr.getRank()].bank[bankNumber]) == &*i); + } + else + { + if (i->isEmpty()) + assert(!i->isActivated()); + else + assert(i->back()->isRefresh()); + } + +#ifndef NDEBUG + bool result = +#endif // NDEBUG + i->push(refreshCommand); + assert(result); + bankNumber++; + } + + for (vector::const_iterator + i = + rank[incomingTransaction->getAddress().getRank()].bank.begin(); i + != rank[incomingTransaction->getAddress().getRank()].bank.end(); ++i) + { + assert(i->back() == refreshCommand); + } + + return true; + } + else if (!destinationBank->isFull()) + { + // try to do a normal open page insert on this transaction + if (destinationBank->aggressiveInsert(incomingTransaction, time)) + { + // found place to insert, hit + //statistics.reportHit(); + } + else + { + // first, the precharge command, if necessary + if (((destinationBank->isEmpty() + && destinationBank->isActivated()) + || (!destinationBank->isEmpty() + && !destinationBank->back()->isRefresh()))) + { + assert(!destinationBank->back() + || !destinationBank->back()->isPrecharge()); + + if (destinationBank->freeCommandSlots() < 3) + { + // for aggressive mode, set CAS(W) to CAS(W)+P when there are only two slots left + if (systemConfig.getRowBufferManagementPolicy() + == OPEN_PAGE_AGGRESSIVE + && destinationBank->freeCommandSlots() == 2 + && destinationBank->back()->isReadOrWrite()) + { + assert(!destinationBank->back()->isPrecharge()); + assert(destinationBank->back()->isReadOrWrite()); + destinationBank->back()->setAutoPrecharge(true); + } + // not enough slots left + else + { + return false; + } + } + else + { + assert(!destinationBank->back() + || !destinationBank->back()->isRefresh()); + assert(!destinationBank->isFull()); +#ifndef NDEBUG + bool result = +#endif // NDEBUG + destinationBank->push(new Command( + incomingTransaction, time, false, + timingSpecification.tBurst(), + Command::PRECHARGE)); + assert(result); + } + } + else if (destinationBank->freeCommandSlots() < 2) + { + return false; + } + + // did not find place to insert + //statistics.reportMiss(); + + // RAS command + assert(!destinationBank->isFull()); +#ifndef NDEBUG + bool result = +#endif // NDEBUG + destinationBank->push(new Command(incomingTransaction, + time, false, timingSpecification.tBurst(), + Command::ACTIVATE)); + assert(result); + + // CAS/CASW command + assert(!destinationBank->isFull()); +#ifndef NDEBUG + result = +#endif // NDEBUG + destinationBank->push(new Command(incomingTransaction, + time, false, timingSpecification.tBurst())); + assert(result); + } + } + else + { + return false; + } + + break; + + default: + + cerr << "Unhandled row buffer management policy" << endl; + return false; + + } + + incomingTransaction->setDecodeTime(time); + + return true; +} + +////////////////////////////////////////////////////////////////////// +/// @brief chooses and dequeues the next command to execute +/// @details Chooses the command which should be executed next from the given channel +/// Choice is made based on command_ordering_algorithm from system config +/// Command returned has already been removed from the per_bank_command_queue +/// from which it was selected +/// @author Joe Gross +/// @return a pointer to the next command +////////////////////////////////////////////////////////////////////// +Command *Channel::getNextCommand(const Command *useThisCommand) +{ + // populate the cache if need be + if (useThisCommand == NULL) + useThisCommand = readNextCommand(); + + if (useThisCommand) + { + vector::iterator currentRank = rank.begin() + + useThisCommand->getAddress().getRank(); + + if (rank[useThisCommand->getAddress().getRank()].bank[useThisCommand->getAddress().getBank()].front() + != useThisCommand) + assert( + rank[useThisCommand->getAddress().getRank()].bank[useThisCommand->getAddress().getBank()].front() + == useThisCommand); + + // if it was a refresh all command, then dequeue all n banks worth of commands + if (useThisCommand->isRefresh()) + { + if (!currentRank->refreshAllReady()) + assert(currentRank->refreshAllReady()); + + vector::iterator bankEnd = currentRank->bank.end(); + + vector::iterator currentBank = currentRank->bank.begin(); + + assert(currentBank->front() == useThisCommand); + + //Command *tempCommand = const_cast(currentBank->front()); + + for (; currentBank != bankEnd; ++currentBank) + { + assert(currentBank->front() != NULL); + if (!currentBank->front()->isRefresh()) + assert(currentBank->front()->isRefresh()); + + currentBank->pop(); + } + + return const_cast (useThisCommand); + } + else + { + assert( + (useThisCommand->isPrecharge() + && systemConfig.getRowBufferManagementPolicy() + == OPEN_PAGE) + || (currentRank->bank[useThisCommand->getAddress().getBank()].front() + == useThisCommand)); + + vector::iterator currentBank = currentRank->bank.begin() + + useThisCommand->getAddress().getBank(); + + assert(currentBank->front() == useThisCommand); + + Command *tempCommand = currentBank->pop(); + + assert(tempCommand && tempCommand == useThisCommand); + + if ((systemConfig.getRowBufferManagementPolicy() + == OPEN_PAGE_AGGRESSIVE) && useThisCommand->isReadOrWrite() + && !currentBank->isEmpty() + && currentBank->isHighUtilization() + && currentBank->front()->isBasicPrecharge()) + { + assert(!tempCommand->isPrecharge()); + tempCommand->setAutoPrecharge(true); + assert(currentBank->front()->isBasicPrecharge()); + delete currentBank->pop(); + } + + return tempCommand; + } + } + else + { + return NULL; + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief returns a pointer to the command which would be chosen to be executed next +/// @details chooses a command according to the command ordering algorithm, tries to choose a command which can execute +/// the command returned may not be able to be executed yet, so it is important to check this +/// command is not actually removed from the per bank queues +/// @author Joe Gross +/// @return a const pointer to the next available command +////////////////////////////////////////////////////////////////////// +const Command *Channel::readNextCommand() const +{ + switch (systemConfig.getCommandOrderingAlgorithm()) + { + case FIRST_AVAILABLE_AGE: + { + const Command *candidateCommand = NULL; + + tick candidateExecuteTime = TICK_MAX; + + vector::const_iterator rankEnd = rank.end(); + + for (vector::const_iterator currentRank = rank.begin(); currentRank + != rankEnd; ++currentRank) + { + bool isRefreshCommand = true; + + vector::const_iterator bankEnd = currentRank->bank.end(); + + for (vector::const_iterator currentBank = + currentRank->bank.begin(); currentBank != bankEnd; ++currentBank) + { + if (!currentBank->isEmpty()) + { + const Command *challengerCommand = currentBank->front(); + + assert( + !challengerCommand + || challengerCommand->isRefresh() + || rank[challengerCommand->getAddress().getRank()].bank[challengerCommand->getAddress().getBank()].front() + == challengerCommand); + + // see if it is a refresh command + if (isRefreshCommand && challengerCommand->isRefresh() + && currentRank->refreshAllReady()) + { + tick challengerExecuteTime = earliestExecuteTime( + challengerCommand); +#ifndef NDEBUG + tick minGap = minProtocolGap(challengerCommand); + + if (time + minGap != challengerExecuteTime) + { + cerr << "cet " << challengerExecuteTime + << ", mingap " << time + minGap << endl; + cerr << challengerCommand << endl; + assert(time + minGap == challengerExecuteTime); + } +#endif + if (challengerExecuteTime < candidateExecuteTime + || (candidateExecuteTime + == challengerExecuteTime + && challengerCommand->getEnqueueTime() + < candidateCommand->getEnqueueTime())) + { + candidateCommand = challengerCommand; + // stop searching since all the queues are proved to have refresh commands at the front + break; + } + } + // can ignore refresh commands since it's known that not all the queues have a ref command at the front + else if (!challengerCommand->isRefresh()) + { + tick challengerExecuteTime = earliestExecuteTime( + challengerCommand); +#ifndef NDEBUG + tick minGap = minProtocolGap(challengerCommand); + + if (time + minGap != challengerExecuteTime) + { + cerr << time << " " << minGap << " " + << challengerExecuteTime << " " + << challengerCommand->getCommandType() + << " " << challengerCommand->getAddress() + << endl; + + if (challengerCommand && (time + minGap + != challengerExecuteTime)) + { + minGap = minProtocolGap(challengerCommand); + assert(challengerCommand && (time + minGap + == challengerExecuteTime)); + } + } +#endif + // set a new candidate if the challenger can be executed sooner or execution times are the same but the challenger is older + if ((challengerExecuteTime < candidateExecuteTime) + || (candidateExecuteTime + == challengerExecuteTime + && challengerCommand->getEnqueueTime() + < candidateCommand->getEnqueueTime())) + { + candidateExecuteTime = challengerExecuteTime; + candidateCommand = challengerCommand; + } + } + } + + // if it was a refresh command was chosen then it wouldn't make it this far, so it's not a refresh command + // if a refresh command wasn't chosen then there one can't be found later + isRefreshCommand = false; + } + } + + if (candidateCommand) + { + assert( + candidateCommand->isRefresh() + || rank[candidateCommand->getAddress().getRank()].bank[candidateCommand->getAddress().getBank()].front() + == candidateCommand); + +#ifdef DEBUG_GREEDY + timingOutStream << "rk[" << candidateCommand->getAddress().rank << "] rk[" << candidateCommand->getAddress().bank << "]\tWinner: " << *candidateCommand << "gap[" << candidateGap << "] now[" << time << "]" << endl; +#endif + } + + return candidateCommand; + } + break; + + case FIRST_AVAILABLE_RIFF: + { + const Command *candidateCommand = NULL; + + tick candidateExecuteTime = TICK_MAX; + + vector::const_iterator rankEnd = rank.end(); + + for (vector::const_iterator currentRank = rank.begin(); currentRank + != rankEnd; ++currentRank) + { + bool isRefreshCommand = true; + + vector::const_iterator bankEnd = currentRank->bank.end(); + + for (vector::const_iterator currentBank = + currentRank->bank.begin(); currentBank != bankEnd; ++currentBank) + { + if (!currentBank->isEmpty()) + { + const Command *challengerCommand = currentBank->front(); + + assert( + challengerCommand == NULL + || challengerCommand->isRefresh() + || rank[challengerCommand->getAddress().getRank()].bank[challengerCommand->getAddress().getBank()].front() + == challengerCommand); + + // see if it is a refresh command + if (isRefreshCommand && challengerCommand->isRefresh() + && currentRank->refreshAllReady()) + { + tick challengerExecuteTime = earliestExecuteTime( + challengerCommand); +#ifndef NDEBUG + tick minGap = minProtocolGap(challengerCommand); + + if (time + minGap != challengerExecuteTime) + assert(time + minGap == challengerExecuteTime); +#endif + if ((challengerExecuteTime < candidateExecuteTime) + || (candidateExecuteTime + == challengerExecuteTime + && ((challengerCommand->isRead() + && candidateCommand->isWrite()) + || (challengerCommand->isRead() + && candidateCommand->isRead() + && challengerCommand->getEnqueueTime() + < candidateCommand->getEnqueueTime()))) + || (time - challengerCommand->getEnqueueTime() + > 12 + * systemConfig.getSeniorityAgeLimit())) + { + candidateCommand = challengerCommand; + // stop searching since all the queues are proved to have refresh commands at the front + break; + } + } + // can ignore refresh commands since it's known that not all the queues have a ref command at the front + else if (!challengerCommand->isRefresh()) + { + tick challengerExecuteTime = earliestExecuteTime( + challengerCommand); +#ifndef NDEBUG + tick minGap = minProtocolGap(challengerCommand); + + if (time + minGap != challengerExecuteTime) + { + cerr << time << " " << minGap << " " + << challengerExecuteTime; + + assert(time + minGap == challengerExecuteTime); + } +#endif + // set a new candidate if the challenger can be executed sooner or execution times are the same but the challenger is older + if ((challengerExecuteTime < candidateExecuteTime) + || (candidateExecuteTime + == challengerExecuteTime + && ((challengerCommand->isRead() + && candidateCommand->isWrite()) + || (challengerCommand->isRead() + && candidateCommand->isRead() + && challengerCommand->getEnqueueTime() + < candidateCommand->getEnqueueTime()))) + || (time - challengerCommand->getEnqueueTime() + > 12 + * systemConfig.getSeniorityAgeLimit())) + { + candidateExecuteTime = challengerExecuteTime; + candidateCommand = challengerCommand; + } + } + } + + // if it was a refresh command was chosen then it wouldn't make it this far, so it's not a refresh command + // if a refresh command wasn't chosen then there one can't be found later + isRefreshCommand = false; + } + } + + if (candidateCommand) + { + assert( + candidateCommand->isRefresh() + || rank[candidateCommand->getAddress().getRank()].bank[candidateCommand->getAddress().getBank()].front() + == candidateCommand); + +#ifdef DEBUG_GREEDY + timingOutStream << "rk[" << candidateCommand->getAddress().rank << "] rk[" << candidateCommand->getAddress().bank << "]\tWinner: " << *candidateCommand << "gap[" << candidateGap << "] now[" << time << "]" << endl; +#endif + } + + return candidateCommand; + } + break; + + case FIRST_AVAILABLE_QUEUE: + { + const Command *candidateCommand = NULL; + + tick candidateExecuteTime = TICK_MAX; + + vector::const_iterator rankEnd = rank.end(); + + for (vector::const_iterator currentRank = rank.begin(); currentRank + != rankEnd; ++currentRank) + { + bool isRefreshCommand = true; + + vector::const_iterator bankEnd = currentRank->bank.end(); + + for (vector::const_iterator currentBank = + currentRank->bank.begin(); currentBank != bankEnd; ++currentBank) + { + if (!currentBank->isEmpty()) + { + const Command *challengerCommand = currentBank->front(); + + assert( + challengerCommand == NULL + || challengerCommand->isRefresh() + || rank[challengerCommand->getAddress().getRank()].bank[challengerCommand->getAddress().getBank()].front() + == challengerCommand); + + // see if it is a refresh command + if (isRefreshCommand && challengerCommand->isRefresh() + && currentRank->refreshAllReady()) + { + tick challengerExecuteTime = earliestExecuteTime( + challengerCommand); +#ifndef NDEBUG + tick minGap = minProtocolGap(challengerCommand); + + if (time + minGap != max(challengerExecuteTime, time)) + assert(time + minGap == challengerExecuteTime); +#endif + // if it can execute earlier, at the same time and has greater queue pressure or it is starving + if ((challengerExecuteTime < candidateExecuteTime) + || (candidateExecuteTime + == challengerExecuteTime + && currentBank->size() + > rank[candidateCommand->getAddress().getRank()].bank[candidateCommand->getAddress().getBank()].size()) + || (time - challengerCommand->getEnqueueTime() + > systemConfig.getSeniorityAgeLimit())) + { + candidateCommand = challengerCommand; + // stop searching since all the queues are proved to have refresh commands at the front + break; + } + } + // can ignore refresh commands since it's known that not all the queues have a ref command at the front + else if (!challengerCommand->isRefresh()) + { + tick challengerExecuteTime = earliestExecuteTime( + challengerCommand); +#ifndef NDEBUG + tick minGap = minProtocolGap(challengerCommand); + + if (time + minGap != challengerExecuteTime) + { + cerr << time << " " << minGap << " " + << challengerExecuteTime; + + assert(time + minGap == challengerExecuteTime); + } +#endif + // if it can execute earlier, at the same time and has greater queue pressure or it is starving + if ((challengerExecuteTime < candidateExecuteTime) + || (candidateExecuteTime + == challengerExecuteTime + && currentBank->size() + > rank[candidateCommand->getAddress().getRank()].bank[candidateCommand->getAddress().getBank()].size()) + || (time - challengerCommand->getEnqueueTime() + > systemConfig.getSeniorityAgeLimit())) + { + candidateExecuteTime = challengerExecuteTime; + candidateCommand = challengerCommand; + } + } + } + + // if it was a refresh command was chosen then it wouldn't make it this far, so it's not a refresh command + // if a refresh command wasn't chosen then there one can't be found later + isRefreshCommand = false; + } + } + + if (candidateCommand) + { + assert( + candidateCommand->isRefresh() + || rank[candidateCommand->getAddress().getRank()].bank[candidateCommand->getAddress().getBank()].front() + == candidateCommand); + +#ifdef DEBUG_GREEDY + timingOutStream << "rk[" << candidateCommand->getAddress().rank << "] rk[" << candidateCommand->getAddress().bank << "]\tWinner: " << *candidateCommand << "gap[" << candidateGap << "] now[" << time << "]" << endl; +#endif + } + + return candidateCommand; + } + break; + + // this strategy executes all commands in the order they were entered + case STRICT_ORDER: + { + tick oldestCommandTime = TICK_MAX; + const Command *oldestCommand = NULL; + + vector::const_iterator rankEnd = rank.end(); + + for (vector::const_iterator currentRank = rank.begin(); currentRank + != rankEnd; ++currentRank) + { + bool notAllRefresh = false; + + vector::const_iterator bankEnd = currentRank->bank.end(); + + for (vector::const_iterator currentBank = + currentRank->bank.begin(); currentBank != bankEnd; ++currentBank) + { + if (const Command *challengerCommand = currentBank->front()) + { +#ifndef NDEBUG + { + const tick executeTime = earliestExecuteTime( + challengerCommand); + if (executeTime != time + minProtocolGap( + challengerCommand)) + { + assert(executeTime == time + minProtocolGap( + challengerCommand)); + } + } +#endif + // choose the oldest command that can be executed + if (challengerCommand->getEnqueueTime() < oldestCommandTime) + { + // if it's a refresh command and + // we haven't proved that all the queues aren't refresh_all commands, search + if (challengerCommand->isRefresh()) + { + if (!notAllRefresh) + { + // if all are known now to be refresh commands + if (currentRank->refreshAllReady()) + { + oldestCommandTime + = challengerCommand->getEnqueueTime(); + oldestCommand = challengerCommand; + // don't need to check other banks again + break; + } + } + } + else + { + oldestCommandTime + = challengerCommand->getEnqueueTime(); + oldestCommand = challengerCommand; + } + } + } + + notAllRefresh = true; + } + } + + // if any executable command was found, prioritize it over those which must wait + + return oldestCommand; + } + break; + + // alternate ranks as we go down banks + case RANK_ROUND_ROBIN: + { + // the command type to look for first + bool readSweep = true; + + // look at the most recently retired command in this channel's history + //const unsigned lastBankOffset = lastCommand ? lastCommand->getAddress().getBank() : 0; + //const vector::const_iterator lastRank = rank.begin() + (lastCommand ? lastCommand->getAddress().getRank() : 0); + const Command::CommandType lastCommandType = + lastCommand ? (lastCommand->getCommandType()) : Command::READ; + + // attempt to group RAS/CAS pairs together + switch (lastCommandType) + { + // if it was RAS before and you want to finish doing the read/write + case Command::ACTIVATE: + { + // look at the command just after the RAS, it should be some sort of CAS + + const Command *nextCommand = ((rank.begin() + + lastCommand->getAddress().getRank())->bank.begin() + + lastCommand->getAddress().getBank())->front(); + + if (nextCommand && nextCommand->isReadOrWrite()) + { + return nextCommand; + } + else + { + cerr + << "error: Found a row activate not followed by a column command." + << endl; + exit(-2); + } + } + break; + + case Command::READ: + // try to reuse open rows + if (lastCommand) + { + const Command *nextCommand = ((rank.begin() + + lastCommand->getAddress().getRank())->bank.begin() + + lastCommand->getAddress().getBank())->front(); + + if (nextCommand && (nextCommand->isReadOrWrite() + || nextCommand->isBasicPrecharge())) + { + return nextCommand; + } + assert(!nextCommand || !nextCommand->isBasicPrecharge()); + } + case Command::READ_AND_PRECHARGE: + case Command::PRECHARGE: + case Command::REFRESH_ALL: + readSweep = true; + break; + + case Command::WRITE: + // try to reuse open rows + if (lastCommand) + { + const Command *nextCommand = ((rank.begin() + + lastCommand->getAddress().getRank())->bank.begin() + + lastCommand->getAddress().getBank())->front(); + + if (nextCommand && (nextCommand->isReadOrWrite() + || nextCommand->isBasicPrecharge())) + { + return nextCommand; + } + assert(!nextCommand || !nextCommand->isBasicPrecharge()); + } + case Command::WRITE_AND_PRECHARGE: + + readSweep = false; + break; + + default: + readSweep = true; + cerr << "warn: Unhandled command type." << endl; + break; + } + + unsigned currentBankOffset = + lastCommand ? lastCommand->getAddress().getBank() : 0; + + vector::const_iterator currentRank = rank.begin() + + (lastCommand ? lastCommand->getAddress().getRank() : 0) + 1; + if (currentRank == rank.end()) + { + currentBankOffset = (currentBankOffset + 1) + % systemConfig.getBankCount(); + currentRank = rank.begin(); + } + + // set original values to know when a full sweep is finished + const vector::const_iterator rankEnd = rank.end(); + const unsigned startingBankOffset = currentBankOffset; + const vector::const_iterator startingRank = currentRank; + const bool originalReadSweep = readSweep; + + while (true) + { + const Command *potentialCommand = (currentRank->bank.begin() + + currentBankOffset)->front(); + + // refresh commands are considered elsewhere + if (potentialCommand && !potentialCommand->isRefresh()) + { + // group reads and writes with each other + if (systemConfig.isReadWriteGrouping()) + { + if (potentialCommand->isActivate()) + assert( + (currentRank->bank.begin() + currentBankOffset)->read( + 1)); + + const Command + *secondCommand = + potentialCommand->isActivate() ? (currentRank->bank.begin() + + currentBankOffset)->read(1) + : potentialCommand; + assert(secondCommand->isReadOrWrite() + || secondCommand->isBasicPrecharge()); + + if ((secondCommand->isRead() && readSweep) + || (secondCommand->isWrite() && !readSweep) + || secondCommand->isBasicPrecharge()) + { + assert( + (currentRank->bank.begin() + currentBankOffset)->front() + == potentialCommand); + return potentialCommand; + } + } + else // don't have to follow read_write grouping considerations + { + return potentialCommand; + } + } + + // before switching to the next rank, see if all the queues are refreshes in any rank + if (currentRank->refreshAllReady()) + { + return currentRank->bank.begin()->front(); + } + + // move on to the next rank + currentRank++; + + if (currentRank == rank.end()) + { + currentRank = rank.begin(); + + // select the next bank + currentBankOffset = (currentBankOffset + 1) + % systemConfig.getBankCount(); + } + + // swap R/W for W/R when doing read/write grouping + if (currentBankOffset == startingBankOffset && currentRank + == startingRank) + { + if (systemConfig.isReadWriteGrouping()) + { + // try other types + readSweep = !readSweep; + + if (readSweep == originalReadSweep) + { +#ifndef NDEBUG + for (vector::const_iterator i = rank.begin(); i + != rankEnd; ++i) + { + for (vector::const_iterator j = + i->bank.begin(); j != i->bank.end(); ++j) + { + assert(j->isEmpty()); + } + } +#endif + return NULL; + } + } + else + { + return NULL; + } + } + } + } + break; + + // keep rank id as long as possible, go round robin down a given rank + case BANK_ROUND_ROBIN: + { + bool readSweep = true; + + // look at the most recently retired command in this channel's history + const Command::CommandType lastCommandType = + lastCommand ? (lastCommand->getCommandType()) : Command::READ; + + // attempt to issue RAS and CAS together + switch (lastCommandType) + { + case Command::ACTIVATE: + { + // look at the command just after the RAS, it should be some sort of CAS + + const Command *nextCommand = ((rank.begin() + + lastCommand->getAddress().getRank())->bank.begin() + + lastCommand->getAddress().getBank())->front(); + + if (nextCommand && nextCommand->isReadOrWrite()) + { + return nextCommand; + } + else + { + cerr + << "error: row activate command not followed by a column command." + << endl; + exit(-2); + } + } + break; + // doing read sweeping + case Command::READ: + // try to reuse open rows + if (lastCommand) + { + const Command *nextCommand = ((rank.begin() + + lastCommand->getAddress().getRank())->bank.begin() + + lastCommand->getAddress().getBank())->front(); + + if (nextCommand && (nextCommand->isReadOrWrite() + || nextCommand->isBasicPrecharge())) + { + return nextCommand; + } + assert(!nextCommand || !nextCommand->isBasicPrecharge()); + } + case Command::REFRESH_ALL: + case Command::READ_AND_PRECHARGE: + case Command::PRECHARGE: + readSweep = true; + break; + + // doing write sweeping + case Command::WRITE: + // try to reuse open rows + if (lastCommand) + { + const Command *nextCommand = ((rank.begin() + + lastCommand->getAddress().getRank())->bank.begin() + + lastCommand->getAddress().getBank())->front(); + + if (nextCommand && (nextCommand->isReadOrWrite() + || nextCommand->isBasicPrecharge())) + { + return nextCommand; + } + assert(!nextCommand || !nextCommand->isBasicPrecharge()); + } + case Command::WRITE_AND_PRECHARGE: + readSweep = false; + break; + + default: + readSweep = true; // FIXME: added this to ensure no uninit vars + cerr << "warn: unhandled command type" << endl; + break; + } + + vector::const_iterator currentRank = rank.begin() + + (lastCommand ? lastCommand->getAddress().getRank() : 0); + vector::const_iterator currentBank = currentRank->bank.begin() + + (lastCommand ? lastCommand->getAddress().getBank() : 0) + 1; + if (currentBank == currentRank->bank.end()) + { + currentRank++; + if (currentRank == rank.end()) + currentRank = rank.begin(); + currentBank = currentRank->bank.begin(); + } + + // set original values to know when a full sweep is finished + const vector::const_iterator rankEnd = rank.end(); + const vector::const_iterator startingBank = currentBank; + const vector::const_iterator startingRank = currentRank; + const bool originalReadSweep = readSweep; + + while (true) + { + const Command *potentialCommand = currentBank->front(); + + // see if this command could be used + if (potentialCommand && !potentialCommand->isRefresh()) + { + if (systemConfig.isReadWriteGrouping()) + { + if (potentialCommand->isActivate()) + assert(currentBank->read(1)); + + const Command + *secondCommand = + (potentialCommand->isActivate() + && currentBank->read(1)) ? currentBank->read( + 1) + : potentialCommand; + assert(secondCommand->isReadOrWrite() + || secondCommand->isBasicPrecharge()); + + if ((secondCommand->isRead() && readSweep) + || (secondCommand->isWrite() && !readSweep) + || secondCommand->isBasicPrecharge()) + { + assert(currentBank->front()->getAddress().getRank() + == currentRank->getRankId()); + assert(currentBank->front() == potentialCommand); + return potentialCommand; + } + } + else // don't have to follow read_write grouping considerations + { + return potentialCommand; + } + } + + // then switch to the next bank + currentBank++; + if (currentBank == currentRank->bank.end()) + { + // before switching to the next rank, see if all the queues are refreshes in any rank + if (currentRank->refreshAllReady()) + { + return currentRank->bank.begin()->front(); + } + + currentRank++; + if (currentRank == rankEnd) + currentRank = rank.begin(); + currentBank = currentRank->bank.begin(); + } + + // back to the beginning, either no result or look for the opposite type + // n.b. must compare rank iterators first, otherwise comparing bank iterators based on unequal rank iterators is a runtime error + if (currentRank == startingRank && currentBank == startingBank) + { + if (systemConfig.isReadWriteGrouping()) + { + // try other types + readSweep = !readSweep; + + if (readSweep == originalReadSweep) + { +#ifndef NDEBUG + for (vector::const_iterator i = rank.begin(); i + != rankEnd; ++i) + { + for (vector::const_iterator j = + i->bank.begin(); j != i->bank.end(); ++j) + { + assert(j->isEmpty()); + } + } +#endif + return NULL; + } + } + else + { + + return NULL; + } + } + } + } + break; + + case COMMAND_PAIR_RANK_HOPPING: + { + // determine where to start + unsigned location = (lastCprhLocation + 1) % (2 * cprhSequence.size()); + bool isActivate = (location % 2) == 0; + pair memLocation = getNextCPRHValues(location); + + while (true) + { + const Command *potentialCommand = + ((rank.begin() + memLocation.first)->bank.begin() + + memLocation.second)->front(); + + // see if this command could be used + if (potentialCommand) + { + if (!potentialCommand->isRefresh()) + { + if (potentialCommand->isActivate() == isActivate) + { + //cerr << "choose " << location; + return potentialCommand; + } + } + else + { + // look for refreshes + if ((rank.begin() + memLocation.first)->refreshAllReady()) + { + //cerr << "choose " << location; + return potentialCommand; + } + } + } + + // quit if already checked every rank/bank combination + if (location == lastCprhLocation) + { + return NULL; + } + + // then switch command + location = (location + 1) % (2 * cprhSequence.size()); + isActivate = (location % 2) == 0; + memLocation = getNextCPRHValues(location); + } + } + break; + + default: + { + cerr << "This configuration and algorithm combination is not supported" + << endl; + exit(-2); + } + break; + } + return NULL; +} + +void Channel::setupCprhValues() +{ + const unsigned rankCount = systemConfig.getDimmCount() + * systemConfig.getRankCount(); + const unsigned bankCount = systemConfig.getBankCount(); + cprhSequence.resize(rankCount * bankCount); + + cprhSequence[0] + = pair , pair > (pair< + unsigned, unsigned> (0, bankCount / 2), pair (0, 0)); + + for (unsigned i = 1; i < rankCount * bankCount; i++) + { + unsigned lastCasBank = cprhSequence[i - 1].second.second; + unsigned lastCasRank = cprhSequence[i - 1].second.first; + + lastCasBank = (lastCasBank + 1) % bankCount; + lastCasRank = (lastCasBank == 0) ? (lastCasRank + 1) % rankCount + : lastCasRank; + cprhSequence[i].second.first = lastCasRank; + cprhSequence[i].second.second = lastCasBank; + + unsigned lastRasBank = cprhSequence[i - 1].first.second; + unsigned lastRasRank = cprhSequence[i - 1].first.first; + lastRasRank = (lastCasBank == 0) ? lastRasRank : (lastRasRank + 1) + % rankCount; + lastRasBank = (lastCasBank == 0) ? bankCount / 2 : lastRasBank + >= bankCount / 2 ? (lastRasBank + bankCount / 2) % bankCount + : lastRasBank + bankCount / 2 + 1; + cprhSequence[i].first.first = lastRasRank; + cprhSequence[i].first.second = lastRasBank; + } +} + +void Channel::setLastCprhLocation(unsigned rank, unsigned bank, bool isActivate) +{ + unsigned location = 0; + + for (; location < cprhSequence.size(); location++) + { + pair < pair , pair > memValue + = cprhSequence[location]; + unsigned currentRank = isActivate ? memValue.first.first + : memValue.second.first; + unsigned currentBank = isActivate ? memValue.first.second + : memValue.second.second; + if (currentRank == rank && currentBank == bank) + { + lastCprhLocation = 2 * location + (isActivate ? 0 : 1); + //cerr << "set to " << lastCprhLocation << endl; + return; + } + } + + cerr << "did not find " << endl; + exit(-6); +} + +pair Channel::getNextCPRHValues(const unsigned location) const +{ +#if 0 + unsigned oldBank = nextBank; + unsigned oldRank = nextRank; + + if (isActivate) + { + // set the rank of the next CAS + nextBank = 2 * (oldBank % (systemConfig.getBankCount() / 2)) + !(oldBank / (systemConfig.getBankCount() / 2)); + nextRank = (systemConfig.getRankCount() - ((2 * (oldBank % (systemConfig.getBankCount() / 2)) + !(oldBank / (systemConfig.getBankCount() / 2))) % systemConfig.getRankCount()) + oldRank) % systemConfig.getRankCount(); + } + else + { + if (oldBank == systemConfig.getBankCount() - 1) + { + nextRank = (oldRank + 1) % systemConfig.getRankCount(); + nextBank = systemConfig.getBankCount() / 2; + } + else + { + nextBank = (oldBank % 2) * (systemConfig.getBankCount() / 2) + ((oldBank + 1) / 2); + nextRank = (oldRank + oldBank + 1) % systemConfig.getRankCount(); + } + } +#endif + pair < pair , pair > loc + = cprhSequence[location / 2]; + return (location % 2) == 0 ? loc.first : loc.second; + +} + +////////////////////////////////////////////////////////////////////////// +/// @brief Updates the channel time to what it would be had this command been executed +/// @details Updates the rank and bank records of the most recent RAS, CAS, etc. times +/// Enqueues RAS times to allow t_faw to be determined later +/// Updates rank and bank records of CAS, RAS lengths for later calculations in +/// min_protocol_gap() +/// @param thisCommand the command to execute at this time +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +void Channel::executeCommand(Command *thisCommand) +{ + DPRINTF(MemoryAccess, "C %s", *thisCommand); + + vector commandsExecuted; + + vector::iterator currentRank = rank.begin() + + thisCommand->getAddress().getRank(); + + vector::iterator currentBank = currentRank->bank.begin() + + thisCommand->getAddress().getBank(); + + currentRank->setLastBankID(thisCommand->getAddress().getBank()); + + thisCommand->setStartTime(time); + + bool commandHit = false; + + assert(canIssue(thisCommand)); + + bool wasActivated = currentBank->isActivated(); + + lastCommandIssueTime = time; + + if (systemConfig.getCommandOrderingAlgorithm() == COMMAND_PAIR_RANK_HOPPING) + { + setLastCprhLocation(thisCommand->getAddress().getRank(), + thisCommand->getAddress().getBank(), thisCommand->isActivate()); + } + + switch (thisCommand->getCommandType()) + { + case Command::ACTIVATE: + { + assert(!thisCommand->getHost()); + + currentRank->issueRAS(time, thisCommand); + + // specific for RAS command + thisCommand->setCompletionTime(thisCommand->getStartTime() + + timingSpecification.tCMD() + timingSpecification.tRAS()); + } + break; + + case Command::READ_AND_PRECHARGE: + + wasActivated = currentBank->isActivated(); + // precharge may be issued first because timings are based on time, not the last time at which a read command was issued + currentRank->issuePRE(time, thisCommand); + + // lack of break is intentional + case Command::READ: + { + // specific for CAS command + // should account for tAL buffering the CAS command until the right moment + //thisCommand->setCompletionTime(max(currentBank.getLastRasTime() + timingSpecification.tRCD() + timingSpecification.tCAS() + timingSpecification.tBurst(), time + timingSpecification.tCMD() + timingSpecification.tCAS() + timingSpecification.tBurst())); + assert(wasActivated); + + thisCommand->setCompletionTime(max(currentBank->getLastRasTime() + + timingSpecification.tRCD() + timingSpecification.tCAS() + + timingSpecification.tBurst(), time + + timingSpecification.tAL() + timingSpecification.tCAS() + + timingSpecification.tBurst())); + thisCommand->getHost()->setCompletionTime( + thisCommand->getCompletionTime()); + + for (vector::iterator i = rank.begin(); i != rank.end(); ++i) + { + i->issueCAS(time, thisCommand); + } + } + break; + + case Command::WRITE_AND_PRECHARGE: + + wasActivated = currentBank->isActivated(); + // precharge may be issued first because timings are based on time, not the last time at which a read command was issued + currentRank->issuePRE(time, thisCommand); + + // missing break is intentional + case Command::WRITE: + + // for the CAS write command + //thisCommand->setCompletionTime(time + timingSpecification.tCMD() + timingSpecification.tCWD() + timingSpecification.tBurst() + timingSpecification.tWR()); + assert(wasActivated); + { + thisCommand->setCompletionTime(time + timingSpecification.tCMD() + + timingSpecification.tCWD() + timingSpecification.tBurst()); + + thisCommand->getHost()->setCompletionTime( + thisCommand->getCompletionTime()); + + for (vector::iterator i = rank.begin(); i != rank.end(); ++i) + { + i->issueCASW(time, thisCommand); + } + } + break; + + case Command::PRECHARGE: + + // issued to the rank which issues to banks + currentRank->issuePRE(time, thisCommand); + + thisCommand->setCompletionTime(thisCommand->getStartTime() + + timingSpecification.tCMD() + timingSpecification.tRP()); + + break; + + case Command::REFRESH_ALL: + + currentRank->issueREF(time); + + thisCommand->setCompletionTime(time + timingSpecification.tCMD() + + timingSpecification.tRFC()); + thisCommand->getHost()->setCompletionTime( + thisCommand->getCompletionTime()); + break; + + case Command::RETIRE_COMMAND: + cerr << "Unimplemented command type" << endl; + break; + + case Command::PRECHARGE_ALL: + cerr << "Unimplemented command type" << endl; + break; + + case Command::ACTIVATE_ALL: + cerr << "Unimplemented command type" << endl; + break; + + case Command::DRIVE_COMMAND: + cerr << "Unimplemented command type" << endl; + break; + + case Command::DATA_COMMAND: + cerr << "Unimplemented command type" << endl; + break; + + case Command::CAS_WITH_DRIVE_COMMAND: + cerr << "Unimplemented command type" << endl; + break; + + case Command::SELF_REFRESH: + cerr << "Unimplemented command type" << endl; + break; + + case Command::DESELECT: + cerr << "Unimplemented command type" << endl; + break; + + case Command::NOOP: + cerr << "Unimplemented command type" << endl; + break; + + case Command::INVALID_COMMAND: + cerr << "Unimplemented command type" << endl; + break; + + default: + cerr << "Unknown command type" << endl; + break; + } + + // inserts into a queue which dequeues into the command pool + retireCommand(thisCommand, commandHit); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief find the protocol gap between a command and current system state +/// @details old version of the function to check the next available command +/// time, now used to check newer functions and ensure changes don't break +/// timing requirements +////////////////////////////////////////////////////////////////////////// +tick Channel::minProtocolGap(const Command *currentCommand) const +{ + tick min_gap = 0; + + const unsigned currentRankID = currentCommand->getAddress().getRank(); + + const Rank ¤tRank = rank[currentRankID]; + + const Bank ¤tBank = + currentRank.bank[currentCommand->getAddress().getBank()]; + + switch (currentCommand->getCommandType()) + { + case Command::ACTIVATE: + { + // refer to Table 11.4 in Memory Systems: Cache, DRAM, Disk + + // respect the row cycle time limitation + tick tRCGap = (tick)(currentBank.getLastRasTime() - time) + + timingSpecification.tRC(); + + // respect tRRD and tRC of all other banks of same rank + tick tRRDGap = (tick)(currentRank.lastActivateTimes.front() - time) + + timingSpecification.tRRD(); + + // respect tRP of same bank + tick tRPGap = (tick)(currentBank.getLastPrechargeTime() - time) + + timingSpecification.tRP(); + + // respect the t_faw value for DDR2 and beyond + tick tFAWGap = (tick)(currentRank.lastActivateTimes.back() - time) + + timingSpecification.tFAW(); + + // respect tRFC + tick tRFCGap = (tick)(currentRank.getLastRefreshTime() - time) + + timingSpecification.tRFC(); + + min_gap = max(max(max(tRFCGap, tRCGap), tRPGap), max(tRRDGap, tFAWGap)); + } + break; + + case Command::READ_AND_PRECHARGE: + // Auto precharge will be issued as part of command, + // but DRAM devices are intelligent enough to delay the prec command + // until tRAS timing is met (thanks to tAL), so no need to check tRAS timing requirement here. + + case Command::READ: + { + //respect last ras of same rank + tick tRCDGap = ((currentBank.getLastRasTime() - time) + + timingSpecification.tRCD() - timingSpecification.tAL()); + + // ensure that if no other rank has issued a CAS command that it will treat + // this as if a CAS command was issued long ago + tick otherRankLastCASTime = time - 10000000; + int otherRankLastCASLength = timingSpecification.tBurst(); + tick otherRankLastCASWTime = time - 10000000; + int otherRankLastCASWLength = timingSpecification.tBurst(); + + // find the most recent cas(w) time and length + for (vector::const_iterator thisRank = rank.begin(); thisRank + != rank.end(); ++thisRank) + { + if (thisRank->getRankId() != currentRank.getRankId()) + { + if (thisRank->getLastCasTime() > otherRankLastCASTime) + { + otherRankLastCASTime = thisRank->getLastCasTime(); + otherRankLastCASLength = thisRank->getLastCasLength(); + } + if (thisRank->getLastCaswTime() > otherRankLastCASWTime) + { + otherRankLastCASWTime = thisRank->getLastCaswTime(); + otherRankLastCASWLength = thisRank->getLastCaswLength(); + } + } + } + + //respect last cas of same rank + // DW 3/9/2006 add these two lines + //cas_length = max(timing_specification.t_int_burst,this_r.last_cas_length); + //casw_length = max(timing_specification.t_int_burst,this_r.last_casw_length); + // DW 3/9/2006 replace the line after next with the next line + //t_cas_gap = max(0,(int)(this_r.last_cas_time + cas_length - now)); + tick t_cas_gap = ((currentRank.getLastCasTime() - time) + + timingSpecification.tBurst()); + + //respect last cas write of same rank + // DW 3/9/2006 replace the line after next with the next line + //t_cas_gap = max(t_cas_gap,(int)(this_r.last_casw_time + timing_specification.t_cwd + casw_length + timing_specification.t_wtr - now)); + t_cas_gap = max((tick) t_cas_gap, ((currentRank.getLastCaswTime() + - time) + timingSpecification.tCWD() + + timingSpecification.tBurst() + timingSpecification.tWTR())); + + if (rank.size() > 1) + { + //respect most recent cas of different rank + t_cas_gap = max((tick) t_cas_gap, (otherRankLastCASTime - time) + + otherRankLastCASLength + timingSpecification.tRTRS()); + //respect timing of READ follow WRITE, different ranks + t_cas_gap = max((tick) t_cas_gap, (otherRankLastCASWTime - time) + + timingSpecification.tCWD() + otherRankLastCASWLength + + timingSpecification.tRTRS() - timingSpecification.tCAS()); + } + min_gap = max(tRCDGap, t_cas_gap); + + //fprintf(stderr," [%8d] [%8d] [%8d] [%8d] [%8d] [%2d]\n",(int)now,(int)this_r_last_cas_time,(int)this_r_last_casw_time,(int)other_r_last_cas_time,(int)other_r_last_casw_time,min_gap); + } + break; + + case Command::WRITE_AND_PRECHARGE: + // Auto precharge will be issued as part of command, so + // Since commodity DRAM devices are write-cycle limited, we don't have to worry if + // the precharge will met tRAS timing or not. So WRITE_AND_PRECHARGE + // has the exact same timing requirements as a simple CAS COMMAND. + + case Command::WRITE: + { + //respect last ras of same rank + tick t_ras_gap = ((currentBank.getLastRasTime() - time) + + timingSpecification.tRCD() - timingSpecification.tAL()); + + tick otherRankLastCASTime = time - 10000000; + int otherRankLastCASLength = timingSpecification.tBurst(); + tick otherRankLastCASWTime = time - 10000000; + int otherRankLastCASWLength = timingSpecification.tBurst(); + + // find the most recent CAS/CASW time and length + // FIXME: change to use iterators + for (unsigned rank_id = 0; rank_id < rank.size(); ++rank_id) + { + if (rank_id != currentRankID) + { + if (rank[rank_id].getLastCasTime() > otherRankLastCASTime) + { + otherRankLastCASTime = rank[rank_id].getLastCasTime(); + otherRankLastCASLength = rank[rank_id].getLastCasLength(); + } + if (rank[rank_id].getLastCaswTime() > otherRankLastCASWTime) + { + otherRankLastCASWTime = rank[rank_id].getLastCaswTime(); + otherRankLastCASWLength = rank[rank_id].getLastCaswLength(); + } + } + } + // DW 3/9/2006 add these two lines + //cas_length = max(timing_specification.t_int_burst,this_r.last_cas_length); + //casw_length = max(timing_specification.t_int_burst,this_r.last_casw_length); + + // respect last cas to same rank + // DW 3/9/2006 replace the line after next with the next line + // t_cas_gap = max(0,(int)(this_r.last_cas_time + timing_specification.t_cas + cas_length + timing_specification.t_rtrs - timing_specification.t_cwd - now)); + tick t_cas_gap = (tick)(currentRank.getLastCasTime() - time) + + timingSpecification.tCAS() + timingSpecification.tBurst() + + timingSpecification.tRTRS() - timingSpecification.tCWD(); + + // respect last cas to different ranks + t_cas_gap = max((tick) t_cas_gap, (otherRankLastCASTime - time) + + timingSpecification.tCAS() + otherRankLastCASLength + + timingSpecification.tRTRS() - timingSpecification.tCWD()); + + // respect last cas write to same rank + // DW 3/9/2006 replace the line after next with the next line + // t_cas_gap = max(t_cas_gap,(int)(this_r.last_casw_time + casw_length - now)); + t_cas_gap = max((tick) t_cas_gap, + (currentRank.getLastCaswTime() - time) + + currentRank.getLastCaswLength()); + + // respect last cas write to different ranks + t_cas_gap = max((tick) t_cas_gap, (otherRankLastCASWTime - time) + + otherRankLastCASWLength + timingSpecification.tOST()); + + min_gap = max((tick) t_ras_gap, (tick) t_cas_gap); + } + break; + + case Command::RETIRE_COMMAND: + break; + + case Command::PRECHARGE: + { + // respect t_ras of same bank + tick t_ras_gap = (currentBank.getLastRasTime() - time) + + timingSpecification.tRAS(); + + // respect t_cas of same bank + tick t_cas_gap = ((tick)(currentBank.getLastCasTime() - time) + + timingSpecification.tAL() + timingSpecification.tCAS() + + timingSpecification.tBurst() + max(0, + timingSpecification.tRTP() - timingSpecification.tCMD())); + + // respect t_casw of same bank + t_cas_gap = max((tick) t_cas_gap, ((currentBank.getLastCaswTime() + - time) + timingSpecification.tAL() + + timingSpecification.tCWD() + timingSpecification.tBurst() + + timingSpecification.tWR())); + + min_gap = max(t_ras_gap, t_cas_gap); + } + break; + + case Command::PRECHARGE_ALL: + break; + + case Command::ACTIVATE_ALL: + break; + + case Command::DRIVE_COMMAND: + break; + + case Command::DATA_COMMAND: + break; + + case Command::CAS_WITH_DRIVE_COMMAND: + break; + + case Command::REFRESH_ALL: + // respect tRFC and tRP + min_gap + = max((currentRank.getLastRefreshTime() + + timingSpecification.tRFC()), + (currentRank.getLastPrechargeTime() + + timingSpecification.tRP())) - time; + break; + + case Command::INVALID_COMMAND: + break; + + default: + break; + } + + return max(min_gap, lastCommandIssueTime + (tick)( + timingSpecification.tCMD()) - time); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief Returns the soonest time that this command may execute +/// @details refer to Table 11.4 in Memory Systems: Cache, DRAM, Disk by Jacob/Wang +/// @details Looks at all of the timing parameters and decides when the this command may soonest execute +////////////////////////////////////////////////////////////////////////// +tick Channel::earliestExecuteTime(const Command *currentCommand) const +{ + const vector::const_iterator currentRank = rank.begin() + + currentCommand->getAddress().getRank(); + + const vector::const_iterator currentBank = currentRank->bank.begin() + + currentCommand->getAddress().getBank(); + +#ifndef NDEBUG + tick nextTime = 0; + + switch (currentCommand->getCommandType()) + { + case Command::ACTIVATE: + { + // refer to Table 11.4 in Memory Systems: Cache, DRAM, Disk + + // respect the row cycle time limitation + tick tRCLimit = currentBank->getLastRasTime() + + timingSpecification.tRC(); + + // respect the row-to-row activation delay for different banks within a rank + tick tRRDLimit = currentRank->lastActivateTimes.front() + + timingSpecification.tRRD(); + + // respect tRP of same bank + tick tRPLimit = currentBank->getLastPrechargeTime() + + timingSpecification.tRP(); + + // respect the t_faw value for DDR2 and beyond, look at the fourth activate ago + tick tFAWLimit = currentRank->lastActivateTimes.back() + + timingSpecification.tFAW(); + + // respect tRFC, refresh cycle time + tick tRFCLimit = currentRank->getLastRefreshTime() + + timingSpecification.tRFC(); + + nextTime = max(max(max(tRFCLimit, tRCLimit), tRPLimit), max(tRRDLimit, + tFAWLimit)); + + assert(nextTime >= currentBank->getLastPrechargeTime() + + timingSpecification.tRP()); + //DEBUG_TIMING_LOG(currentCommand->getCommandType() << " ras[" << setw(2) << t_ras_gap << "] rrd[" << setw(2) << t_rrd_gap << "] faw[" << setw(2) << t_faw_gap << "] cas[" << setw(2) << t_cas_gap << "] rrd[" << setw(2) << t_rrd_gap << "] rp[" << setw(2) << t_rp_gap << "] min[" << setw(2) << min_gap << "]"); + } + break; + + case Command::READ_AND_PRECHARGE: + // Auto precharge will be issued as part of command, + // but DRAM devices are intelligent enough to delay the prec command + // until tRAS timing is met (thanks to tAL), so no need to check tRAS timing requirement here. + + case Command::READ: + { + //respect last RAS of same rank + tick tRCDLimit = currentBank->getLastRasTime() + + (timingSpecification.tRCD() - timingSpecification.tAL()); + + // ensure that if no other rank has issued a CAS command that it will treat + // this as if a CAS command was issued long ago + + // respect last CAS of same rank + // DW 3/9/2006 add these two lines + //cas_length = max(timing_specification.t_int_burst,this_r.last_cas_length); + //casw_length = max(timing_specification.t_int_burst,this_r.last_casw_length); + // DW 3/9/2006 replace the line after next with the next line + //t_cas_gap = max(0,(int)(this_r.last_cas_time + cas_length - now)); + tick tCASLimit = currentRank->getLastCasTime() + + timingSpecification.tBurst(); + + // respect last CASW of same rank + // DW 3/9/2006 replace the line after next with the next line + //t_cas_gap = max(t_cas_gap,(int)(this_r.last_casw_time + timing_specification.t_cwd + casw_length + timing_specification.t_wtr - now)); + tCASLimit = max(tCASLimit, currentRank->getLastCaswTime() + + timingSpecification.tCWD() + timingSpecification.tBurst() + + timingSpecification.tWTR()); + + //if (rank->size() > 1) + { + //respect most recent CAS of different rank + tCASLimit = max(tCASLimit, currentRank->getOtherLastCasTime() + + currentRank->getOtherLastCasLength() + + timingSpecification.tRTRS()); + //respect timing of READ follow WRITE, different ranks + tCASLimit = max(tCASLimit, currentRank->getOtherLastCaswTime() + + timingSpecification.tCWD() + + currentRank->getOtherLastCaswLength() + + timingSpecification.tRTRS() - timingSpecification.tCAS()); + } + + nextTime = max(tRCDLimit, tCASLimit); + + //fprintf(stderr," [%8d] [%8d] [%8d] [%8d] [%8d] [%2d]\n",(int)now,(int)this_r_last_cas_time,(int)this_r_last_casw_time,(int)other_r_last_cas_time,(int)other_r_last_casw_time,min_gap); + } + break; + + case Command::WRITE_AND_PRECHARGE: + // Auto precharge will be issued as part of command, so + // Since commodity DRAM devices are write-cycle limited, we don't have to worry if + // the precharge will meet tRAS timing or not. So WRITE_AND_PRECHARGE + // has the exact same timing requirements as a simple WRITE. + + case Command::WRITE: + { + //respect last RAS of same rank + tick tRASLimit = currentBank->getLastRasTime() + + timingSpecification.tRCD() - timingSpecification.tAL(); + + // DW 3/9/2006 add these two lines + //cas_length = max(timing_specification.t_int_burst,this_r.last_cas_length); + //casw_length = max(timing_specification.t_int_burst,this_r.last_casw_length); + + // respect last cas to same rank + // DW 3/9/2006 replace the line after next with the next line + // t_cas_gap = max(0,(int)(this_r.last_cas_time + timing_specification.t_cas + cas_length + timing_specification.t_rtrs - timing_specification.t_cwd - now)); + tick tCASLimit = currentRank->getLastCasTime() + + timingSpecification.tCAS() + timingSpecification.tBurst() + + timingSpecification.tRTRS() - timingSpecification.tCWD(); + + // respect last cas to different ranks + tCASLimit = max(tCASLimit, currentRank->getOtherLastCasTime() + + timingSpecification.tCAS() + + currentRank->getOtherLastCasLength() + + timingSpecification.tRTRS() - timingSpecification.tCWD()); + + // respect last cas write to same rank + // DW 3/9/2006 replace the line after next with the next line + // t_cas_gap = max(t_cas_gap,(int)(this_r.last_casw_time + casw_length - now)); + tCASLimit = max(tCASLimit, currentRank->getLastCaswTime() + + currentRank->getLastCaswLength()); + + // respect last CASW to different ranks + // TODO: should this not also be -tAL? + tCASLimit = max(tCASLimit, currentRank->getOtherLastCaswTime() + + currentRank->getOtherLastCaswLength() + + timingSpecification.tOST()); + + nextTime = max(tRASLimit, tCASLimit); + } + break; + + case Command::PRECHARGE: + { + // respect t_ras of same bank + tick tRASLimit = currentBank->getLastRasTime() + + timingSpecification.tRAS(); + + // respect t_cas of same bank + //tick tCASLimit = max(time,currentBank->getLastCasTime() + timingSpecification.tAL() + timingSpecification.tCAS() + timingSpecification.tBurst() + max(0,timingSpecification.tRTP() - timingSpecification.tCMD())); + // tAL is accounted for by measuring the execution time internal to the DRAM + tick tCASLimit = currentBank->getLastCasTime() + + timingSpecification.tAL() + timingSpecification.tCAS() + + timingSpecification.tBurst() + max(0, + timingSpecification.tRTP() - timingSpecification.tCMD()); + + // respect t_casw of same bank + //tCASLimit = max(tCASLimit,currentBank->getLastCaswTime() + timingSpecification.tAL() + timingSpecification.tCWD() + timingSpecification.tBurst() + timingSpecification.tWR()); + // tAL is accounted for by measuring the execution time internal to the DRAM + tCASLimit = max(tCASLimit, currentBank->getLastCaswTime() + + timingSpecification.tAL() + timingSpecification.tCWD() + + timingSpecification.tBurst() + timingSpecification.tWR()); + + nextTime = max(tRASLimit, tCASLimit); + } + break; + + case Command::REFRESH_ALL: + // respect tRFC and tRP + nextTime + = max(currentRank->getLastRefreshTime() + + timingSpecification.tRFC(), + currentRank->getLastPrechargeTime() + + timingSpecification.tRP()); + break; + + case Command::RETIRE_COMMAND: + case Command::PRECHARGE_ALL: + case Command::ACTIVATE_ALL: + case Command::DRIVE_COMMAND: + case Command::DATA_COMMAND: + case Command::CAS_WITH_DRIVE_COMMAND: + case Command::SELF_REFRESH: + case Command::DESELECT: + case Command::NOOP: + case Command::INVALID_COMMAND: + default: + cerr << "Unsupported command encountered." << endl; + nextTime = 0; + break; + } + + tick actualNext = max(nextTime, lastCommandIssueTime + + timingSpecification.tCMD()); + tick predictedNext = max( + currentRank->next(currentCommand->getCommandType()), max( + currentBank->next(currentCommand->getCommandType()), + lastCommandIssueTime + timingSpecification.tCMD())); + if (actualNext != predictedNext) + assert(actualNext == predictedNext); +#endif + + return max(currentRank->next(currentCommand->getCommandType()), max( + currentBank->next(currentCommand->getCommandType()), + lastCommandIssueTime + timingSpecification.tCMD())); +} + +bool Channel::isEmpty() const +{ + for (vector::const_iterator i = rank.begin(); i != rank.end(); ++i) + { + if (!i->isEmpty()) + return false; + } + return transactionQueue.isEmpty(); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief Returns the soonest time that this command may execute, tracks the limiting factor +/// @details refer to Table 11.4 in Memory Systems: Cache, DRAM, Disk by Jacob/Wang +/// @details Looks at all of the timing parameters and decides when the this command may execute soonest +////////////////////////////////////////////////////////////////////////// +tick Channel::earliestExecuteTimeLog(const Command *currentCommand) const +{ + static unsigned tRCcount, tRRDcount, tRPcount, tFAWcount, tRFCcount; + static unsigned tRCDcount, tCAScount, tCASWcount, tCASotherCount, + tCASWotherCount; + static unsigned tRAScount; + tick nextTime; + + const Rank ¤tRank = rank[currentCommand->getAddress().getRank()]; + + const Bank ¤tBank = + currentRank.bank[currentCommand->getAddress().getBank()]; + + switch (currentCommand->getCommandType()) + { + case Command::ACTIVATE: + { + // refer to Table 11.4 in Memory Systems: Cache, DRAM, Disk + + // respect the row cycle time limitation + tick tRCLimit = currentBank.getLastRasTime() + + timingSpecification.tRC(); + + const tick lastRASTime = currentRank.lastActivateTimes.front(); + + // respect the row-to-row activation delay for different banks within a rank + tick tRRDLimit = lastRASTime + timingSpecification.tRRD(); + + // respect tRP of same bank + tick tRPLimit = currentBank.getLastPrechargeTime() + + timingSpecification.tRP(); + + // respect the t_faw value for DDR2 and beyond, look at the fourth activate ago + tick tFAWLimit = currentRank.lastActivateTimes.back() + + timingSpecification.tFAW(); + + // respect tRFC, refresh cycle time + tick tRFCLimit = currentRank.getLastRefreshTime() + + timingSpecification.tRFC(); + + nextTime = max(max(max(tRFCLimit, tRCLimit), tRPLimit), max(tRRDLimit, + tFAWLimit)); + + if (nextTime == tRCLimit) + tRCcount++; + if (nextTime == tRRDLimit) + tRRDcount++; + if (nextTime == tRPLimit) + tRPcount++; + if (nextTime == tFAWLimit) + tFAWcount++; + if (nextTime == tRFCLimit) + tRFCcount++; + + assert(nextTime >= currentBank.getLastPrechargeTime() + + timingSpecification.tRP()); + //DEBUG_TIMING_LOG(currentCommand->getCommandType() << " ras[" << setw(2) << t_ras_gap << "] rrd[" << setw(2) << t_rrd_gap << "] faw[" << setw(2) << t_faw_gap << "] cas[" << setw(2) << t_cas_gap << "] rrd[" << setw(2) << t_rrd_gap << "] rp[" << setw(2) << t_rp_gap << "] min[" << setw(2) << min_gap << "]"); + } + break; + + case Command::READ_AND_PRECHARGE: + // Auto precharge will be issued as part of command, + // but DRAM devices are intelligent enough to delay the prec command + // until tRAS timing is met (thanks to tAL), so no need to check tRAS timing requirement here. + + case Command::READ: + { + //respect last RAS of same rank + tick tRCDLimit = currentBank.getLastRasTime() + + (timingSpecification.tRCD() - timingSpecification.tAL()); + + // ensure that if no other rank has issued a CAS command that it will treat + // this as if a CAS command was issued long ago + + // respect last CAS of same rank + // DW 3/9/2006 add these two lines + //cas_length = max(timing_specification.t_int_burst,this_r.last_cas_length); + //casw_length = max(timing_specification.t_int_burst,this_r.last_casw_length); + // DW 3/9/2006 replace the line after next with the next line + //t_cas_gap = max(0,(int)(this_r.last_cas_time + cas_length - now)); + tick tCASLimit = currentRank.getLastCasTime() + + timingSpecification.tBurst(); + + // respect last CASW of same rank + // DW 3/9/2006 replace the line after next with the next line + //t_cas_gap = max(t_cas_gap,(int)(this_r.last_casw_time + timing_specification.t_cwd + casw_length + timing_specification.t_wtr - now)); + tick tCASWLimit = currentRank.getLastCaswTime() + + timingSpecification.tCWD() + timingSpecification.tBurst() + + timingSpecification.tWTR(); + + //respect most recent CAS of different rank + tick tCASOtherLimit = currentRank.getOtherLastCasTime() + + currentRank.getOtherLastCasLength() + + timingSpecification.tRTRS(); + //respect timing of READ follow WRITE, different ranks + tick tCASWOtherLimit = currentRank.getOtherLastCaswTime() + + timingSpecification.tCWD() + + currentRank.getOtherLastCaswLength() + + timingSpecification.tRTRS() - timingSpecification.tCAS(); + + nextTime = max(max(tRCDLimit, tCASLimit), max(max(tCASWLimit, + tCASOtherLimit), tCASWOtherLimit)); + + if (nextTime == tRCDLimit) + tRCDcount++; + if (nextTime == tCASLimit) + tCAScount++; + if (nextTime == tCASWLimit) + tCASWcount++; + if (nextTime == tCASOtherLimit) + tCASotherCount++; + if (nextTime == tCASWOtherLimit) + tCASWotherCount++; + + //fprintf(stderr," [%8d] [%8d] [%8d] [%8d] [%8d] [%2d]\n",(int)now,(int)this_r_last_cas_time,(int)this_r_last_casw_time,(int)other_r_last_cas_time,(int)other_r_last_casw_time,min_gap); + } + break; + + case Command::WRITE_AND_PRECHARGE: + // Auto precharge will be issued as part of command, so + // Since commodity DRAM devices are write-cycle limited, we don't have to worry if + // the precharge will meet tRAS timing or not. So WRITE_AND_PRECHARGE + // has the exact same timing requirements as a simple WRITE. + + case Command::WRITE: + { + //respect last RAS of same rank + tick tRASLimit = currentBank.getLastRasTime() + + timingSpecification.tRCD() - timingSpecification.tAL(); + + // DW 3/9/2006 add these two lines + //cas_length = max(timing_specification.t_int_burst,this_r.last_cas_length); + //casw_length = max(timing_specification.t_int_burst,this_r.last_casw_length); + + // respect last cas to same rank + // DW 3/9/2006 replace the line after next with the next line + // t_cas_gap = max(0,(int)(this_r.last_cas_time + timing_specification.t_cas + cas_length + timing_specification.t_rtrs - timing_specification.t_cwd - now)); + tick tCASLimit = max(time, currentRank.getLastCasTime() + + timingSpecification.tCAS() + timingSpecification.tBurst() + + timingSpecification.tRTRS() - timingSpecification.tCWD()); + + // respect last cas to different ranks + tick tCASOtherLimit = currentRank.getOtherLastCasTime() + + timingSpecification.tCAS() + + currentRank.getOtherLastCasLength() + + timingSpecification.tRTRS() - timingSpecification.tCWD(); + + // respect last cas write to same rank + // DW 3/9/2006 replace the line after next with the next line + // t_cas_gap = max(t_cas_gap,(int)(this_r.last_casw_time + casw_length - now)); + tick tCASWLimit = currentRank.getLastCaswTime() + + currentRank.getLastCaswLength(); + + // respect last CASW to different ranks + // TODO: should this not also be -tAL? + tick tCASWOtherLimit = currentRank.getOtherLastCaswTime() + + currentRank.getOtherLastCaswLength() + + timingSpecification.tOST(); + + nextTime = max(max(tRASLimit, tCASLimit), max(max(tCASOtherLimit, + tCASWOtherLimit), tCASWLimit)); + + if (nextTime == tRASLimit) + tRAScount++; + if (nextTime == tCASLimit) + tCAScount++; + if (nextTime == tCASWLimit) + tCASWcount++; + if (nextTime == tCASOtherLimit) + tCASotherCount++; + if (nextTime == tCASWOtherLimit) + tCASWotherCount++; + } + break; + + case Command::PRECHARGE: + { + // respect t_ras of same bank + tick tRASLimit = currentBank.getLastRasTime() + + timingSpecification.tRAS(); + + // respect t_cas of same bank + // TODO: do not need tAL for these + //tick tCASLimit = max(time,currentBank.getLastCasTime() + timingSpecification.tAL() + timingSpecification.tCAS() + timingSpecification.tBurst() + max(0,timingSpecification.tRTP() - timingSpecification.tCMD())); + // tAL is accounted for by measuring the execution time internal to the DRAM + tick tCASLimit = max(time, currentBank.getLastCasTime() + + timingSpecification.tCAS() + timingSpecification.tBurst() + + max(0, timingSpecification.tRTP() + - timingSpecification.tCMD())); + + // respect t_casw of same bank + //tCASLimit = max(tCASLimit,currentBank.getLastCaswTime() + timingSpecification.tAL() + timingSpecification.tCWD() + timingSpecification.tBurst() + timingSpecification.tWR()); + // tAL is accounted for by measuring the execution time internal to the DRAM + tCASLimit = max(tCASLimit, currentBank.getLastCaswTime() + + timingSpecification.tCWD() + timingSpecification.tBurst() + + timingSpecification.tWR()); + + nextTime = max(tRASLimit, tCASLimit); + } + break; + + case Command::REFRESH_ALL: + // respect tRFC and tRP + nextTime = max(currentRank.getLastRefreshTime() + + timingSpecification.tRFC(), + currentRank.getLastPrechargeTime() + timingSpecification.tRP()); + break; + + case Command::RETIRE_COMMAND: + case Command::PRECHARGE_ALL: + case Command::ACTIVATE_ALL: + case Command::DRIVE_COMMAND: + case Command::DATA_COMMAND: + case Command::CAS_WITH_DRIVE_COMMAND: + case Command::SELF_REFRESH: + case Command::DESELECT: + case Command::NOOP: + case Command::INVALID_COMMAND: + default: + cerr << "Unsupported command encountered." << endl; + nextTime = 0; + break; + } + + return max(nextTime, max(time, lastCommandIssueTime + + timingSpecification.tCMD())); +} + +void Channel::resetStats() +{ +} + +////////////////////////////////////////////////////////////////////////// +/// @brief the assignment operator, will copy non-key items to this channel +/// @details copies the non-reference items over, should be used for deserialization +/// @return a reference to this channel, for chaining +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +Channel& Channel::operator =(const Channel &rhs) +{ + time = rhs.time; + lastCommandIssueTime = rhs.lastCommandIssueTime; + lastCommand = rhs.lastCommand ? new Command(*(rhs.lastCommand)) : NULL; + transactionQueue = rhs.transactionQueue; + refreshCounter = rhs.refreshCounter; + channelID = rhs.channelID; + rank = rhs.rank; + //dimm = rhs.dimm; + powerModel = rhs.powerModel; + timingSpecification = rhs.timingSpecification; + + return *this; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief the equality operator, to determine if the channels are equal incomingTransaction value +/// @return true if the channels are equal +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +bool Channel::operator ==(const Channel& rhs) const +{ + return (time == rhs.time && lastCommandIssueTime + == rhs.lastCommandIssueTime && timingSpecification + == rhs.timingSpecification && transactionQueue + == rhs.transactionQueue && ((lastCommand == NULL && rhs.lastCommand + == NULL) || (*lastCommand == *(rhs.lastCommand))) && systemConfig + == rhs.systemConfig && statistics == rhs.statistics && powerModel + == rhs.powerModel && channelID == rhs.channelID && rank == rhs.rank + && refreshCounter == rhs.refreshCounter); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief the insertion operator, adds a string to the given stream with _stats about this channel +/// @return the input stream but with a string representing the channel state appended +/// @author Joe Gross +////////////////////////////////////////////////////////////////////////// +std::ostream& DRAMsimII::operator<<(std::ostream& os, + const DRAMsimII::Channel& r) +{ + os << "T[" << r.time << "] ch[" << r.channelID << endl; + os << r.timingSpecification << endl; + os << r.powerModel << endl; + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/M5dramSystem.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/M5dramSystem.py Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,93 @@ +# Copyright (C) 2008 University of Maryland. +# This file is part of DRAMsimII. +# +# DRAMsimII is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# DRAMsimII is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with DRAMsimII. If not, see . + +from m5.params import * +from m5.proxy import * +from MemObject import * +from PhysicalMemory import * + + +class M5dramSystem(PhysicalMemory): + type = 'M5dramSystem' + dramType = Param.String("ddr3","dram type") + datarate = Param.Int(800000000,""); + clockGranularity = Param.Int(2,"the number of beats per cycle") + channels = Param.Int(2,"the number of channels per dram system") + dimms = Param.Int(2,"the number of dimms in each channel") + ranks = Param.Int(2,"the number of ranks in each dimm") + banks = Param.Int(8,"the number of banks per rank") + rows = Param.Int(16384,"") + columns = Param.Int(1024,"") + channelWidth = Param.Int(8, "") + physicalAddressMappingPolicy = Param.String("closePageBaseline", "address mapping policy, physical to logical") + rowBufferPolicy = Param.String("closePageAggressive","") + rowSize = Param.Int(16,"the size of each row") + columnSize = Param.Int(16,"the size of the column") + postedCas = Param.Bool(True,"") + autoRefreshPolicy = Param.String("refreshOneChanAllRankAllBank","") + commandOrderingAlgorithm = Param.String("firstAvailableAge","") + transactionOrderingAlgorithm = Param.String("RIFF","") + perBankQueueDepth = Param.Int(8,"") + transactionQueueDepth = Param.Int(16,"") + decodeWindow = Param.Int(16,"") + readWriteGrouping = Param.Bool(True,"") + autoPrecharge = Param.Bool(True,"") + + # timing parameters + tBufferDelay = Param.Int(2,"delay from Transaction to Commands") + tBurst = Param.Int(8,"burst length, DDR2=8, DDR3=16") + tCAS = Param.Int(10,"column address strobe latency") + tCMD = Param.Int(2,"1T timing, 2 beats per command") + tCWD = Param.Int(8,"write delay") + tFAW = Param.Int(32,"four activation window") + tRAS = Param.Int(28,"minimum activate to precharge time") + tRC = Param.Int(38, "row cycle") + tRCD = Param.Int(10,"row to column delay") + tRFC = Param.Int(128, "refresh to refresh time") + tRRD = Param.Int(6,"activate to activate different ranks") + tRP = Param.Int(10,"row precharge time") + tRTP = Param.Int(6,"read to precharge time") + tRTRS = Param.Int(2,"rank to rank switching time") + tWR = Param.Int(12,"write recovery time") + tWTR = Param.Int(6,"write to read time") + tAL = Param.Int(8,"additive latency") + refreshTime = Param.Int(64000,"") + tREFI = Param.Int(6240,"refresh interval") + seniorityAgeLimit = Param.Int(1024,"how long a command can be deferred") + + # power settings + PdqRD = Param.Float(1.1, "read power") + PdqWR = Param.Float(8.2,"") + PdqRDoth = Param.Float(0,"") + PdqWRoth = Param.Float(0,"") + DQperDRAM = Param.Int(8,"") + DQSperDRAM = Param.Int(4,"") + DMperDRAM = Param.Int(2,"") + frequencySpec = Param.Int(800000000,"") + maxVCC = Param.Float(1.9,"") + systemVDD = Param.Float(1.8,"") + IDD0 = Param.Float(90,"") + IDD2P = Param.Float(7,"") + IDD2N = Param.Float(60,"") + IDD3N = Param.Float(60,"") + IDD3P = Param.Float(50,"") + IDD4R = Param.Float(145,"") + IDD4W = Param.Float(145,"") + IDD5A = Param.Float(235,"") + + cpuRatio = Param.Int(5,"ratio of CPU speed to DRAM data bus speed") + cachelinesPerRow = Param.String("-1","") + epoch = Param.Int(1000000, "cycles (memory) between stats reporting") diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Rank.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Rank.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,273 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef RANK_HH +#define RANK_HH +#pragma once + +#include "globals.hh" +#include "Bank.hh" +#include "Settings.hh" +#include "TimingSpecification.hh" + +#include + +namespace DRAMsimII +{ +/// @brief represents a logical rank +class Rank +{ +private: + class CircularBuffer + { + protected: + std::vector buffer; + + std::vector::iterator _back, _front; + //const std::vector::iterator begin, end; + public: + void reset(const tick value) + { + for (std::vector::iterator i = buffer.begin(), end = + buffer.end(); i < end; i++) + *i = value; + } + + tick back() const + { + return *_back; + } + + tick front() const + { + return *_front; + } + + void push_front(const tick value) + { + _front++; + + if (_front == buffer.end()) + _front = buffer.begin(); + + *_front = value; + + _back++; + + if (_back == buffer.end()) + _back = buffer.begin(); + } + + CircularBuffer() : + buffer(4, -250), _back(buffer.begin()), _front(buffer.begin()) + { + while (_front + 1 != buffer.end()) + _front++; + } + + tick operator[](const unsigned i) const + { + return buffer[i]; + } + + CircularBuffer &operator=(const CircularBuffer &rhs) + { + buffer = rhs.buffer; + + //begin = buffer.begin(); + //end = buffer.end(); + _front = buffer.begin(); + while (_front + 1 != buffer.end()) + _front++; + _back = buffer.begin(); + return *this; + } + + CircularBuffer(const CircularBuffer &rhs) : + buffer(rhs.buffer), _back(buffer.begin()), _front(buffer.begin()) + { + while (_front + 1 != buffer.end()) + _front++; + } + + bool operator==(const CircularBuffer &rhs) const + { + for (unsigned i = 0; i < 4; i++) + if (buffer[i] != rhs[i]) + return false; + + if (*_front != rhs.front() || *_back != rhs.back()) + return false; + + return true; + } + }; + + const TimingSpecification& timing; ///< reference to the timing information, used in calculations + const SystemConfiguration& systemConfig; ///< reference to system configuration information + Statistics& statistics; ///< reference for collecting statistics + +protected: + + tick lastRefreshTime; ///< the time of the last refresh + tick lastPrechargeAnyBankTime; ///< the time of the last precharge + tick lastCASTime; ///< the time of the last CAS + tick lastCASWTime; ///< the time of the last CASW + + tick otherLastCASTime; ///< the time of the most recent CAS from any other rank on this channel + tick otherLastCASWTime; ///< the time of the most recent CASW from any other rank on this channel + + tick prechargeTime; ///< total time that all banks in this rank are precharged in this epoch + tick totalPrechargeTime; ///< total time that all banks are precharged, all time + + tick nextActivateTime; ///< the time at which an ACT may be sent to this rank + tick nextReadTime; ///< the time at which a CAS may be sent to this rank + tick nextWriteTime; ///< the time at which a CASW may be sent to this rank + tick nextRefreshTime; ///< the time at which a Ref may be sent to this rank + + tick lastCalculationTime; ///< the time at which the last power calculation was done + + unsigned lastCASLength; ///< the length of the last CAS + unsigned lastCASWLength; ///< the length of the last CASW + unsigned otherLastCASLength; ///< the length of the last CAS on any other rank + unsigned otherLastCASWLength; ///< the length of the last CASW on any other rank + unsigned CASLength; ///< total cycles the bus spent sending data + unsigned CASWLength; ///< the total cycles the bus spent receiving data + unsigned rankID; ///< the ordinal number of this rank + unsigned lastBankID; ///< id of the last accessed bank of this rank + unsigned banksPrecharged; ///< the number of banks in the precharge state + + std::pair hits; ///< the number of read and write hits to this rank + +public: + + CircularBuffer lastActivateTimes; + std::vector bank; ///< the banks within this rank + + // functions + bool refreshAllReady() const; + Command *getCommand(const unsigned bank); + void issueRAS(const tick currentTime, const Command *currentCommand); + void issuePRE(const tick currentTime, const Command *currentCommand); + void issueCAS(const tick currentTime, const Command *currentCommand); + void issueCASW(const tick currentTime, const Command *currentCommand); + void issueREF(const tick currentTime); + void resetToTime(const tick time); + tick next(Command::CommandType nextCommandType) const; + + // constructors + explicit Rank(const Rank &, const TimingSpecification &, + const SystemConfiguration &, Statistics& stats); + explicit Rank(const Settings& settings, + const TimingSpecification &timingVal, + const SystemConfiguration &systemConfigVal, Statistics& stats); + Rank(const Rank &); + + // accessors + unsigned getRankId() const + { + return rankID; + } + tick getTotalPrechargeTime(const tick currentTime) const; + tick getPrechargeTime(const tick currentTime) const; + tick getLastRefreshTime() const + { + return lastRefreshTime; + } + tick getLastCasTime() const + { + return lastCASTime; + } + tick getLastCaswTime() const + { + return lastCASWTime; + } + tick getOtherLastCasTime() const + { + return otherLastCASTime; + } + tick getOtherLastCaswTime() const + { + return otherLastCASWTime; + } + tick getLastPrechargeTime() const + { + return lastPrechargeAnyBankTime; + } + unsigned getLastBankID() const + { + return lastBankID; + } + unsigned getLastCasLength() const + { + return lastCASLength; + } + unsigned getLastCaswLength() const + { + return lastCASWLength; + } + unsigned getOtherLastCasLength() const + { + return otherLastCASLength; + } + unsigned getOtherLastCaswLength() const + { + return otherLastCASWLength; + } + unsigned getReadCycles() const + { + return CASLength; + } + unsigned getWriteCycles() const + { + return CASWLength; + } + unsigned getReadHits() const + { + return hits.first; + } + unsigned getWriteHits() const + { + return hits.second; + } + bool isEmpty() const; + + // mutators + void setRankID(const unsigned channelID, const unsigned rankID); + void setLastBankID(const unsigned value) + { + lastBankID = value; + } + void resetPrechargeTime(const tick time); + void resetCycleCounts() + { + hits.first = hits.second = CASLength = CASWLength = 0; + } + + // overloads + Rank& operator=(const Rank &rs); + bool operator==(const Rank& right) const; + friend std::ostream& operator<<(std::ostream& os, const Rank& r); + +private: + //serialization + explicit Rank(const TimingSpecification &timing, + const std::vector &newBank, Statistics &stats, + SystemConfiguration &sysConfig); + explicit Rank(); +}; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Rank.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Rank.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,537 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include "Rank.hh" + +using std::vector; +using std::max; +using std::endl; +using std::cerr; +using namespace DRAMsimII; + +Rank::Rank(const Settings& settings, const TimingSpecification &timing, const SystemConfiguration &sysConfig, Statistics& stats): +timing(timing), +systemConfig(sysConfig), +statistics(stats), +lastRefreshTime(-1ll * settings.tRFC), +lastPrechargeAnyBankTime(-100), +lastCASTime(-100), +lastCASWTime(-100), +otherLastCASTime(-100), +otherLastCASWTime(-100), +prechargeTime(0), +totalPrechargeTime(0), +nextActivateTime(0), +nextReadTime(0), +nextWriteTime(0), +nextRefreshTime(0), +lastCalculationTime(0), +lastCASLength(0), +lastCASWLength(0), +otherLastCASLength(0), +otherLastCASWLength(0), +CASLength(0), +CASWLength(0), +rankID(UINT_MAX), +lastBankID(settings.bankCount - 1), +banksPrecharged(/*settings.rowBufferManagementPolicy == OPEN_PAGE ? 0 : settings.bankCount */ 0), +lastActivateTimes(), +bank(sysConfig.getBankCount(),Bank(settings, timing, sysConfig, stats)) +{} + +Rank::Rank(const Rank &rhs): +timing(rhs.timing), +systemConfig(rhs.systemConfig), +statistics(rhs.statistics), +lastRefreshTime(rhs.lastRefreshTime), +lastPrechargeAnyBankTime(rhs.lastPrechargeAnyBankTime), +lastCASTime(rhs.lastCASTime), +lastCASWTime(rhs.lastCASWTime), +otherLastCASTime(rhs.otherLastCASTime), +otherLastCASWTime(rhs.otherLastCASWTime), +prechargeTime(rhs.prechargeTime), +totalPrechargeTime(rhs.totalPrechargeTime), +nextActivateTime(rhs.nextActivateTime), +nextReadTime(rhs.nextReadTime), +nextWriteTime(rhs.nextWriteTime), +nextRefreshTime(rhs.nextRefreshTime), +lastCalculationTime(0), +lastCASLength(rhs.lastCASLength), +lastCASWLength(rhs.lastCASWLength), +otherLastCASLength(rhs.otherLastCASLength), +otherLastCASWLength(rhs.otherLastCASWLength), +CASLength(rhs.CASLength), +CASWLength(rhs.CASWLength), +rankID(rhs.rankID), +lastBankID(rhs.lastBankID), +banksPrecharged(rhs.banksPrecharged), +lastActivateTimes(rhs.lastActivateTimes), +bank(rhs.bank) +{} + +Rank::Rank(const Rank &rhs, const TimingSpecification &timing, const SystemConfiguration &sysConfig, Statistics& stats): +timing(timing), +systemConfig(sysConfig), +statistics(rhs.statistics), +lastRefreshTime(rhs.lastRefreshTime), +lastPrechargeAnyBankTime(rhs.lastPrechargeAnyBankTime), +lastCASTime(rhs.lastCASTime), +lastCASWTime(rhs.lastCASWTime), +otherLastCASTime(rhs.otherLastCASTime), +otherLastCASWTime(rhs.otherLastCASWTime), +prechargeTime(rhs.prechargeTime), +totalPrechargeTime(rhs.totalPrechargeTime), +nextActivateTime(rhs.nextActivateTime), +nextReadTime(rhs.nextReadTime), +nextWriteTime(rhs.nextWriteTime), +nextRefreshTime(rhs.nextRefreshTime), +lastCalculationTime(0), +lastCASLength(rhs.lastCASLength), +lastCASWLength(rhs.lastCASWLength), +otherLastCASLength(rhs.otherLastCASLength), +otherLastCASWLength(rhs.otherLastCASWLength), +CASLength(rhs.CASLength), +CASWLength(rhs.CASWLength), +rankID(rhs.rankID), +lastBankID(rhs.lastBankID), +banksPrecharged(rhs.banksPrecharged), +lastActivateTimes(rhs.lastActivateTimes), +bank((unsigned)sysConfig.getBankCount(), Bank(rhs.bank[0], timing, sysConfig, stats)) +{ + // TODO: copy over values in banks now that reference members are init + //for (unsigned i = 0; i < systemConfig.getBankCount(); i++) + //{ + // bank[i] = rhs.bank[i]; + //} + bank = rhs.bank; +} + +Rank::Rank(const TimingSpecification &timingSpec, const std::vector& newBank, Statistics& stats, SystemConfiguration& sysConfig): +timing(timingSpec), +systemConfig(sysConfig), +statistics(stats), +lastRefreshTime(-1ll * timingSpec.tRFC()), +lastPrechargeAnyBankTime(-100), +lastCASTime(-100), +lastCASWTime(-100), +otherLastCASTime(-100), +otherLastCASWTime(-100), +prechargeTime(0), +totalPrechargeTime(0), +nextActivateTime(0), +nextReadTime(0), +nextWriteTime(0), +nextRefreshTime(0), +lastCalculationTime(0), +lastCASLength(0), +lastCASWLength(0), +otherLastCASLength(0), +otherLastCASWLength(0), +CASLength(0), +CASWLength(0), +rankID(UINT_MAX), +lastBankID(0), +banksPrecharged(0), +lastActivateTimes(), // make the queue hold four (tFAW) +bank(newBank) +{} + +void Rank::setRankID(const unsigned channelID, const unsigned rankID) +{ + this->rankID = rankID; + + if (systemConfig.getRowBufferManagementPolicy() == CLOSE_PAGE || systemConfig.getRowBufferManagementPolicy() == CLOSE_PAGE_AGGRESSIVE) + { + unsigned bankID = 0; + for (vector::iterator i = bank.begin(); i != bank.end(); ++i) + { + Transaction t(Transaction::AUTO_PRECHARGE_TRANSACTION, 0, timing.tBurst(), Address(channelID, rankID, bankID++, 0, 0)); + i->push(new Command(&t, 0, false, timing.tBurst(), Command::PRECHARGE)); + } + } +} + + +////////////////////////////////////////////////////////////////////////// +/// @brief this logically issues a RAS command and updates all variables to reflect this +////////////////////////////////////////////////////////////////////////// +void Rank::issueRAS(const tick currentTime, const Command *currentCommand) +{ + // RAS time history queue, per rank + const tick thisRASTime = currentTime; + // record these for tFAW calculations + lastActivateTimes.push_front(thisRASTime); + + lastBankID = currentCommand->getAddress().getBank(); + + // for power modeling, if all banks were precharged and now one is being activated, record the interval that one was precharged + if (banksPrecharged == bank.size()) + { + prechargeTime += max(currentTime - max(lastCalculationTime, lastPrechargeAnyBankTime),(tick)0); + totalPrechargeTime += max(currentTime - max(lastCalculationTime, lastPrechargeAnyBankTime), (tick)0); + for (vector::const_iterator curBnk = bank.begin(); curBnk != bank.end(); ++curBnk) + assert(!curBnk->isActivated()); + } + banksPrecharged--; + assert(banksPrecharged < bank.size()); + // update the bank to reflect this change also + bank[currentCommand->getAddress().getBank()].issueRAS(currentTime,currentCommand); + + // calculate when the next few commands can happen + nextActivateTime = max(currentTime + timing.tRRD(), max(lastActivateTimes.back() + timing.tFAW() , nextActivateTime)); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief issue a precharge command to this rank +////////////////////////////////////////////////////////////////////////// +void Rank::issuePRE(const tick currentTime, const Command *currentCommand) +{ + // update the bank to reflect this change also + Bank ¤tBank = bank[currentCommand->getAddress().getBank()]; + currentBank.issuePRE(currentTime, currentCommand); + + switch (currentCommand->getCommandType()) + { + case Command::READ_AND_PRECHARGE: + case Command::WRITE_AND_PRECHARGE: + lastPrechargeAnyBankTime = max(lastPrechargeAnyBankTime, currentBank.getLastPrechargeTime()); + break; + case Command::PRECHARGE: + // choose the latest time since there may be +Pre commands that have queued a Pre internally + lastPrechargeAnyBankTime = max(lastPrechargeAnyBankTime, currentTime); + break; + default: + cerr << "Unhandled CAS variant" << endl; + break; + } + + banksPrecharged++; + assert(banksPrecharged > 0); + assert(banksPrecharged <= bank.size()); + + // calculate when the next few commands can happen + nextRefreshTime = max(nextRefreshTime, lastPrechargeAnyBankTime + timing.tRP()); + assert (nextRefreshTime == lastPrechargeAnyBankTime + timing.tRP() || nextRefreshTime == lastRefreshTime + timing.tRFC()); + +} + +////////////////////////////////////////////////////////////////////////// +// @brief issue a CAS command to this rank +////////////////////////////////////////////////////////////////////////// +void Rank::issueCAS(const tick currentTime, const Command *currentCommand) +{ + if (currentCommand->getAddress().getRank() == rankID) + { + + // update the bank to reflect this change also + bank[currentCommand->getAddress().getBank()].issueCAS(currentTime, currentCommand); + + lastCASTime = currentTime; + + lastCASLength = currentCommand->getLength(); + + CASLength += currentCommand->getLength(); + + assert(currentCommand->getAddress().getBank() == lastBankID); + + // calculate when the next few commands can happen + nextReadTime = max(nextReadTime, currentTime + timing.tBurst()); + nextWriteTime = max(nextWriteTime, currentTime + timing.tCAS() + timing.tBurst() + timing.tRTRS() - timing.tCWD()); + } + // was to another bank + else + { + assert(currentTime + timing.tAL() > otherLastCASTime); + otherLastCASTime = currentTime; + otherLastCASLength = currentCommand->getLength(); + + // calculate when the next few commands can happen + nextReadTime = max(nextReadTime, currentTime + timing.tBurst() + timing.tRTRS()); + nextWriteTime = max(nextWriteTime, currentTime + timing.tCAS() + timing.tBurst() + timing.tRTRS() - timing.tCWD()); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief issue a CASW command to this rank +////////////////////////////////////////////////////////////////////////// +void Rank::issueCASW(const tick currentTime, const Command *currentCommand) +{ + if (currentCommand->getAddress().getRank() == rankID) + { + + // update the bank to reflect this change also + bank[currentCommand->getAddress().getBank()].issueCASW(currentTime, currentCommand); + + lastCASWTime = currentTime; + + lastCASWLength = currentCommand->getLength(); + + CASWLength += currentCommand->getLength(); + + assert(currentCommand->getAddress().getBank() == lastBankID); + + // calculate when the next few commands can happen + // ensure that the next read does not happen until the write is done with the I/O drivers + nextReadTime = max(nextReadTime, currentTime + timing.tCWD() + timing.tBurst() + timing.tWTR()); + + nextWriteTime = max(nextWriteTime, currentTime + timing.tBurst()); + } + else + { + assert(currentTime + timing.tAL() > otherLastCASWTime); + otherLastCASWTime = currentTime; + otherLastCASWLength = currentCommand->getLength(); + + // calculate when the next few commands can happen + nextReadTime = max(nextReadTime, currentTime + timing.tCWD() + timing.tBurst() + timing.tRTRS() - timing.tCAS()); + nextWriteTime = max(nextWriteTime, currentTime + timing.tOST() + timing.tBurst()); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief issue a refresh command to this rank +////////////////////////////////////////////////////////////////////////// +void Rank::issueREF(const tick currentTime) +{ + lastRefreshTime = currentTime; + + // FIXME: should this not count as a RAS + PRE command to all banks? + + for (vector::iterator i = bank.begin(), end = bank.end(); i < end; i++) + { + i->issueREF(); + } + + // calculate when the next few commands can happen + nextRefreshTime = max(nextRefreshTime, currentTime + timing.tRFC()); + assert (nextRefreshTime == lastPrechargeAnyBankTime + timing.tRP() || nextRefreshTime == lastRefreshTime + timing.tRFC() || currentTime < 250); + nextActivateTime = max(nextActivateTime, currentTime + timing.tRFC()); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief reset the accumulated precharge time for this rank +////////////////////////////////////////////////////////////////////////// +void Rank::resetPrechargeTime(const tick time) +{ + prechargeTime = 0; + lastCalculationTime = time; + assert (nextRefreshTime == lastPrechargeAnyBankTime + timing.tRP() || nextRefreshTime == lastRefreshTime + timing.tRFC()); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns the next time this command type may be issued +////////////////////////////////////////////////////////////////////////// +tick Rank::next(Command::CommandType nextCommandType) const +{ + switch (nextCommandType) + { + case Command::READ: + case Command::READ_AND_PRECHARGE: + return nextReadTime; + break; + case Command::ACTIVATE: + return nextActivateTime; + break; + case Command::WRITE: + case Command::WRITE_AND_PRECHARGE: + return nextWriteTime; + break; + case Command::PRECHARGE: + return 0; + break; + case Command::REFRESH_ALL: + return nextRefreshTime; + break; + default: + return TICK_MAX; + break; + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief get the next command in the queue for this bank +/// @details simply return the command for this bank if it is not a refresh all command +/// otherwise remove the refresh all commands from all the other queues, assuming there is +/// a refresh all command at the head of each, else return null +/// @author Joe Gross +/// @param thisBank the ordinal of the bank to get the next command for (0..n) +/// @return the next command to be issued for this bank +////////////////////////////////////////////////////////////////////// +Command *Rank::getCommand(const unsigned thisBank) +{ + if (bank[thisBank].nextCommandType() == Command::REFRESH_ALL) + { + if (refreshAllReady()) + { + Command *tempCommand = NULL; + + for (vector::iterator currentBank = bank.begin(); currentBank != bank.end(); ++currentBank) + { + delete tempCommand; + + tempCommand = currentBank->pop(); + + assert(tempCommand->isRefresh()); + } + + return tempCommand; + } + else + { + return NULL; + } + } + else + { + return bank[thisBank].pop(); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief update this rank to seem like time started at a nonzero time +/// @details used when the simulator has fast forwarded to a certain time and then +/// begun detailed simulation. this function will avoid giving too large/small values +/// after a simple->detailed switch +////////////////////////////////////////////////////////////////////////// +void Rank::resetToTime(const tick time) +{ + lastCASTime = time - 1000; + lastCASWTime = time - 1000; + lastPrechargeAnyBankTime = time; + lastRefreshTime = time - timing.tRFC(); + lastCalculationTime = time; + prechargeTime = 0; + + nextActivateTime = time; + nextRefreshTime = time + timing.tRP(); + lastActivateTimes.reset(time - timing.tFAW()); + //for (boost::circular_buffer::iterator i = lastActivateTimes.begin(); i != lastActivateTimes.end(); ++i) + // *i = time - timing.tFAW(); + for (vector::iterator i = bank.begin(); i != bank.end(); ++i) + i->resetToTime(time); + +} + +////////////////////////////////////////////////////////////////////////// +/// @brief get the total length of time that this rank had all banks precharged +/// @returns cycles all banks are precharged +////////////////////////////////////////////////////////////////////////// +tick Rank::getTotalPrechargeTime(const tick currentTime) const +{ + return totalPrechargeTime + ((banksPrecharged == bank.size()) ? max(currentTime - max(lastPrechargeAnyBankTime, lastCalculationTime), (tick)0) : 0); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief get the total length of time that this rank had all banks precharged since the last reset +/// @returns cycles all banks are precharged +////////////////////////////////////////////////////////////////////////// +tick Rank::getPrechargeTime(const tick currentTime) const +{ + return prechargeTime + ((banksPrecharged == bank.size()) ? max(currentTime - max(lastPrechargeAnyBankTime, lastCalculationTime), (tick)0) : 0); +} + +////////////////////////////////////////////////////////////////////// +/// @brief is there a refresh command ready at each per bank queue +/// @details if there is a refresh all command at the head of each per +/// bank queue, then the next command for this rank is a refresh all banks +/// command\n +/// this is signified by inserting a refresh all command into the tail of each +/// queue and removing them when they all reach the front\n +/// this is done to ensure that a refresh command will never disturb an open +/// row that has a waiting CAS, as the refresh command will ruin the row +/// @author Joe Gross +/// @return true if all queue heads have refresh all commands +////////////////////////////////////////////////////////////////////// +bool Rank::refreshAllReady() const +{ + for (vector::const_iterator currentBank = bank.begin(); currentBank != bank.end(); ++currentBank) + { + // if any queue is empty or the head of any queue isn't a refresh command, then the rank isn't ready for a refresh all command + if (!currentBank->front() || !currentBank->front()->isRefresh()) + { + return false; + } + } + return true; +} + +bool Rank::isEmpty() const +{ + for (vector::const_iterator i = bank.begin(); i != bank.end(); ++i) + { + if (!i->hasNoReadWrite()) + return false; + } + return true; +} + +Rank& Rank::operator =(const Rank& rhs) +{ + lastRefreshTime = rhs.lastRefreshTime; + lastPrechargeAnyBankTime = rhs.lastPrechargeAnyBankTime; + lastCASTime = rhs.lastCASTime; + lastCASWTime = rhs.lastCASWTime; + prechargeTime = rhs.prechargeTime; + totalPrechargeTime = rhs.totalPrechargeTime; + lastCASLength = rhs.lastCASLength; + lastCASWLength = rhs.lastCASWLength; + rankID = rhs.rankID; + lastBankID = rhs.lastBankID; + banksPrecharged = rhs.banksPrecharged; + lastActivateTimes = rhs.lastActivateTimes; + bank = rhs.bank; + CASLength = rhs.CASLength; + CASWLength = rhs.CASWLength; + otherLastCASTime = rhs.otherLastCASTime; + otherLastCASWTime = rhs.otherLastCASWTime; + otherLastCASLength = rhs.otherLastCASLength; + otherLastCASWLength = rhs.otherLastCASWLength; + lastCalculationTime = rhs.lastCalculationTime; + nextRefreshTime = rhs.nextRefreshTime; + nextWriteTime = rhs.nextWriteTime; + nextReadTime = rhs.nextReadTime; + nextActivateTime = rhs.nextActivateTime; + + return *this; +} + +bool Rank::operator==(const Rank& right) const +{ + return (timing == right.timing && lastRefreshTime == right.lastRefreshTime && lastPrechargeAnyBankTime == right.lastPrechargeAnyBankTime && + lastCASTime == right.lastCASTime && lastCASWTime == right.lastCASWTime && prechargeTime == right.prechargeTime && totalPrechargeTime == right.totalPrechargeTime && + lastCASLength == right.lastCASLength && lastCASWLength == right.lastCASWLength && rankID == right.rankID && lastBankID == right.lastBankID && + banksPrecharged == right.banksPrecharged && lastActivateTimes == right.lastActivateTimes && bank == right.bank && CASLength == right.CASLength && + CASWLength == right.CASWLength && otherLastCASTime == right.otherLastCASTime && otherLastCASWTime == right.otherLastCASWTime && + otherLastCASLength == right.otherLastCASLength && otherLastCASWLength == right.otherLastCASWLength && systemConfig == right.systemConfig); +} + +std::ostream& DRAMsimII::operator<<(std::ostream &os, const Rank &r) +{ + os << r.lastRefreshTime << endl; + os << r.lastPrechargeAnyBankTime << endl; + os << r.lastCASTime << endl; + os << r.lastCASWTime << endl; + os << r.prechargeTime << endl; + os << r.totalPrechargeTime << endl; + os << r.lastCASLength << endl; + os << r.lastCASWLength << endl; + os << r.rankID << endl; + os << r.lastBankID << endl; + os << r.banksPrecharged << endl; + + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/SConscript --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/SConscript Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,47 @@ +Import('*') +import shutil +import re + +conf = Configure(env) + +#try: +# env.Replace(CCFLAGS = env._dict['CCFLAGS'].remove('-Werror')) +#except ValueError: +# pass + +#env.Append(CCFLAGS = ['-Wunused-macros']) + +try: + if 'fast' in re.split('[/.]',COMMAND_LINE_TARGETS[0]): + env.Append(CCFLAGS = ['-fprefetch-loop-arrays','-ffast-math', '-funroll-all-loops', '-fomit-frame-pointer', '-Wuninitialized', '-Wno-conversion', + '-finline-functions', '-Wno-unused-variable'],CPPDEFINES = ['M5', '__STDC_LIMIT_MACROS']) + + else: + raise IndexError +except IndexError: + # then this must be a debug build + pass + + +env.Append(CPPDEFINES = ['__STDC_LIMIT_MACROS']) + + +SimObject('M5dramSystem.py') + +Source('Address.cc') +Source('Bank.cc') +Source('command.cc') +Source('Channel.cc') +Source('event.cc') +Source('m5-dramSystem.cc') +Source('powerConfig.cc') +Source('Rank.cc') +Source('Settings.cc') +Source('Statistics.cc') +Source('System.cc') +Source('SystemConfiguration.cc') +Source('TimingSpecification.cc') +Source('transaction.cc') + +env = conf.Finish() + diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Settings.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Settings.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,363 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef DRAMSETTINGS +#define DRAMSETTINGS + +#include "Address.hh" +#include "enumTypes.hh" + +#include +#include +#include +#include +#include +#include +#include + +namespace DRAMsimII +{ + /// @brief stores the settings to be used to initialize a dramSystem object + class Settings + { + private: + static std::map tokenizeMap; + static std::map lookupMap; + public: + ////////////////////////////////////////////////////////////////////////// + // command data + unsigned epoch; + RefreshPolicy refreshPolicy; + DRAMType dramType; + unsigned dataRate; // frequency + CommandOrderingAlgorithm commandOrderingAlgorithm; + TransactionOrderingAlgorithm transactionOrderingAlgorithm; + unsigned perBankQueueDepth; + unsigned columnSize; + unsigned rowSize; + unsigned channelWidth; + unsigned columnCount; + unsigned rowCount; + //unsigned historyQueueDepth; + //unsigned completionQueueDepth; + unsigned transactionQueueDepth; + //unsigned eventQueueDepth; + //unsigned refreshQueueDepth; + //unsigned refreshTime; + unsigned seniorityAgeLimit; + unsigned decodeWindow; + RowBufferPolicy rowBufferManagementPolicy; + Address::AddressMappingScheme addressMappingScheme; + bool postedCAS; + bool readWriteGrouping; + bool autoPrecharge; + unsigned clockGranularity; + unsigned channelCount; + unsigned dimmCount; + unsigned rankCount; + unsigned bankCount; + ////////////////////////////////////////////////////////////////////////// + // timing data + unsigned tRTRS; + unsigned tAL; + unsigned tBurst; + unsigned tCAS; + unsigned tCWD; + unsigned tFAW; + unsigned tRAS; + unsigned tRC; + unsigned tRCD; + unsigned tREFI; + unsigned tRFC; + unsigned tRP; + unsigned tRRD; + unsigned tRTP; + unsigned tWR; + unsigned tWTR; + unsigned tCMD; + unsigned tInternalBurst; + unsigned tBufferDelay; + float cpuToMemoryClockRatio; + ////////////////////////////////////////////////////////////////////////// + // power data + float PdqRD; + float PdqWR; + float PdqRDoth; + float PdqWRoth; + unsigned DQperDRAM; + unsigned DQSperDRAM; + unsigned DMperDRAM; + unsigned frequencySpec; + float maxVCC; + float VDD; + unsigned IDD0; + unsigned IDD1; + unsigned IDD2P; + unsigned IDD2N; + unsigned IDD3P; + unsigned IDD3N; + unsigned IDD4W; + unsigned IDD4R; + unsigned IDD5; + + // converts a string to a file_io_token + static FileIOToken dramTokenizer(const std::string & value) + { + std::string lowerValue; + + for (std::string::const_iterator i = value.begin(), end = value.end(); i < end; i++) + { + lowerValue += tolower(*i); + } + + FileIOToken first = unknown_token; + + if (!tokenize(lowerValue,first)) + std::cerr << "warn: unknown token: " << std::endl; + + return first; + } + + bool setKeyValue(const std::string &nodeName, const std::string &nodeValue); + bool setKeyValue(const char* nodeName, const std::string &nodeValue) { std::string name(nodeName); return setKeyValue(name, nodeValue); } + + static std::map createTokenizer() + { + std::map theMap; + + // should all be lower case + theMap["type"]=dram_type_token; + theMap["datarate"]=datarate_token; + theMap["dramspec"]=dram_type_token; + theMap["dramtype"]=dram_type_token; + theMap["tbufferdelay"]=t_buffer_delay_token; + theMap["inputtype"]=input_type_token; + theMap["infileformat"] = input_type_token; + theMap["infiletype"]=input_type_token; + theMap["inputfiletype"]=input_type_token; + theMap["epoch"]=epoch_token; + theMap["clock_granularity"] = clock_granularity_token; + theMap["clockgranularity"] = clock_granularity_token; + theMap["row_buffer_policy"] = row_buffer_management_policy_token; + theMap["rowbufferpolicy"] = row_buffer_management_policy_token; + theMap["auto_precharge"] = auto_precharge_token; + theMap["autoprecharge"] = auto_precharge_token; + theMap["pa_mapping_policy"] = addr_mapping_scheme_token; + theMap["physicaladdressmappingpolicy"] = addr_mapping_scheme_token; + theMap["addr_mapping_scheme"] = addr_mapping_scheme_token; + theMap["addressmappingscheme"] = addr_mapping_scheme_token; + theMap["addressmappingpolicy"] = addr_mapping_scheme_token; + theMap["physicaladdressmappingpolicy"] = addr_mapping_scheme_token; + theMap["transaction_ordering_policy"] = transaction_ordering_policy_token; + theMap["transactionorderingpolicy"] = transaction_ordering_policy_token; + theMap["command_ordering_algorithm"] = command_ordering_algorithm_token; + theMap["commandorderingalgorithm"] = command_ordering_algorithm_token; + theMap["transactionorderingalgorithm"] = transaction_ordering_policy_token; + theMap["command_ordering_policy"] = command_ordering_algorithm_token; + theMap["commandorderingpolicy"] = command_ordering_algorithm_token; + theMap["inputfile"] = input_file_token; + theMap["infile"] = input_file_token; + theMap["averageinterarrivalcyclecount"] = average_interarrival_cycle_count; + theMap["interarrivalcyclecount"] = average_interarrival_cycle_count; + theMap["auto_refresh_policy"] = refresh_policy_token; + theMap["autorefreshpolicy"] = refresh_policy_token; + theMap["cputomemoryclockratio"] = cpu_to_memory_clock_ratio; + theMap["refresh_policy"] = refresh_policy_token; + theMap["refreshpolicy"] = refresh_policy_token; + theMap["riff"] = riff_token; + theMap["posted_cas"] = posted_cas_token; + theMap["postedcas"] = posted_cas_token; + theMap["channel_count"] = channel_count_token; + theMap["channelcount"] = channel_count_token; + theMap["channels"] = channel_count_token; + theMap["dimms"] = dimm_count_token; + theMap["channel_width" ] = channel_width_token; + theMap["channelwidth"] = channel_width_token; + theMap["rank_count"] = rank_count_token; + theMap["rankcount"] = rank_count_token; + theMap["ranks"] = rank_count_token; + theMap["bank_count"] = bank_count_token; + theMap["bankcount"] = bank_count_token; + theMap["banks"] = bank_count_token; + theMap["row_count" ] = row_count_token; + theMap["rowcount" ] = row_count_token; + theMap["rows"] = row_count_token; + theMap["col_count" ] = col_count_token; + theMap["columncount"] = col_count_token; + theMap["columns"] = col_count_token; + theMap["col_size" ] = col_size_token; + theMap["columnsize"] = col_size_token; + theMap["row_size" ] = row_size_token; + theMap["rowsize"] = row_size_token; + theMap["per_bank_queue_depth" ] = per_bank_queue_depth_token; + theMap["perbankqueuedepth"] = per_bank_queue_depth_token; + theMap["t_cmd" ] = t_cmd_token; + theMap["tcmd"] = t_cmd_token; + theMap["t_faw"] = t_faw_token; + theMap["tfaw"] = t_faw_token; + theMap["t_rfc" ] = t_rfc_token; + theMap["trfc"] = t_rfc_token; + theMap["t_rrd" ] = t_rrd_token; + theMap["trrd"] = t_rrd_token; + theMap["t_rtp" ] = t_rtp_token; + theMap["trtp"] = t_rtp_token; + theMap["t_wr" ] = t_wr_token; + theMap["twr"] = t_wr_token; + theMap["t_wtr" ] = t_wtr_token; + theMap["twtr"] = t_wtr_token; + theMap["t_ras" ] = t_ras_token; + theMap["tras"] = t_ras_token; + theMap["t_rcd" ] = t_rcd_token; + theMap["trcd"] = t_rcd_token; + theMap["t_cas" ] = t_cas_token; + theMap["tcas"] = t_cas_token; + theMap["t_rp" ] = t_rp_token; + theMap["trp"] = t_rp_token; + theMap["t_rcd" ] = t_rcd_token; + theMap["trcd"] = t_rcd_token; + theMap["t_rc"] = t_rc_token; + theMap["trc"] = t_rc_token; + theMap["t_cwd" ] = t_cwd_token; + theMap["tcwd"] = t_cwd_token; + theMap["t_al" ] = t_al_token; + theMap["tal"] = t_al_token; + theMap["t_dqs"] = t_dqs_token; + theMap["tdqs"] = t_dqs_token; + theMap["t_rtrs"] = t_rtrs_token; + theMap["trtrs"] = t_rtrs_token; + theMap["t_burst" ] = t_burst_token; + theMap["tburst"] = t_burst_token; + theMap["trefi"] = t_refi_token; + theMap["read_write_grouping" ] = read_write_grouping_token; + theMap["readwritegrouping"] = read_write_grouping_token; + theMap["seniority_age_limit" ] = seniority_age_limit_token; + theMap["seniorityagelimit"] = seniority_age_limit_token; + theMap["decodewindow"] = decode_window_token; + theMap["transaction_queue_depth"] = transaction_queue_depth_token; + theMap["transactionqueuedepth"] = transaction_queue_depth_token; + theMap["idd0"] = idd0_token; + theMap["idd1"] = idd1_token; + theMap["idd2p"] = idd2p_token; + theMap["idd2n"] = idd2n_token; + theMap["idd3p"] = idd3p_token; + theMap["idd3n"] = idd3n_token; + theMap["idd4r"] = idd4r_token; + theMap["idd4w"] = idd4w_token; + theMap["idd5" ] = idd5_token; + theMap["idd5a"] = idd5_token; + theMap["maxvcc"] = max_vcc_token; + theMap["systemvdd"] = vdd_token; + theMap["frequencyspec"] = frequency_spec_token; + theMap["pdqrd"] = p_dq_rd_token; + theMap["pdqwr"] = p_dq_wr_token; + theMap["pdqrdoth"] = p_dq_rd_oth_token; + theMap["pdqwroth"] = p_dq_wr_oth_token; + theMap["dqperdram"] = dq_per_dram_token; + theMap["dqsperdram"] = dqs_per_dram_token; + theMap["dmperdram"] = dm_per_dram_token; + theMap["fetch"] = FETCH; + theMap["ifetch"] = FETCH; + theMap["p_fetch"] = FETCH; + theMap["p_lock_rd"] = LOCK_RD; + theMap["p_lock_wr"] = LOCK_WR; + theMap["lock_rd"] = LOCK_RD; + theMap["r"] = MEM_RD; + theMap["w"] = MEM_WR; + theMap["lock_wr"] = LOCK_WR; + theMap["mem_rd"] = MEM_RD; + theMap["write"] = MEM_WR; + theMap["mem_wr"] = MEM_WR; + theMap["read"] = MEM_RD; + theMap["p_mem_rd"] = MEM_RD; + theMap["p_mem_wr"] = MEM_WR; + theMap["p_i/o_rd"] = IO_RD; + theMap["p_i/o_wr"] = IO_WR; + theMap["io_rd"] = IO_RD; + theMap["i/o_rd"] = IO_RD; + theMap["io_wr"] = IO_WR; + theMap["i/o_wr"] = IO_WR; + theMap["p_int_ack"] = INT_ACK; + theMap["int_ack"] = INT_ACK; + theMap["boff"] = BOFF; + theMap["ps"] = PICOSECOND; + theMap["ns"] = NANOSECOND; + theMap["us"] = MICROSECOND; + theMap["ms"] = MILLISECOND; + theMap["s"] = SECOND; + + return theMap; + } + + + static FileIOToken fileIOToken(const unsigned char *input) + { + const std::string inputS((const char *)input); + return dramTokenizer(inputS); + } + + static bool tokenize(const std::string &nodeName, FileIOToken &token) + { + if (nodeName.length() == 0) + { + token = unknown_token; + return true; + } + else if (nodeName.length() > 1 && nodeName.at(0) == '/' && nodeName.at(1) == '/') + { + token = comment_token; + return true; + } + else + { + std::string lowerNodeName; + + for (std::string::const_iterator i = nodeName.begin(), end = nodeName.end(); i < end; i++) + { + lowerNodeName += tolower(*i); + } + + std::map::iterator result = tokenizeMap.find(lowerNodeName); + + if (result != tokenizeMap.end()) + { + token = result->second; + return true; + } + else + std::cerr << lowerNodeName << " failed" << std::endl; + return false; + } + } + + static bool detokenize(const FileIOToken token, std::string &value) + { + std::map::iterator result = lookupMap.find(token); + + if (result != lookupMap.end()) + { + value = result->second; + return true; + } + else + return false; + } + + // create a dramSettings from command line arguments + explicit Settings(); + + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Settings.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Settings.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,299 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include +#include +#include + +#include "globals.hh" +#include "Settings.hh" + +using std::map; +using std::string; +using std::cerr; +using std::endl; +using std::ostream; + +using namespace DRAMsimII; + +namespace DRAMsimII +{ + map Settings::tokenizeMap = Settings::createTokenizer(); +} + + +////////////////////////////////////////////////////////////////////////// +/// @brief blank settings constructor +////////////////////////////////////////////////////////////////////////// +Settings::Settings(): +epoch(UINT_MAX), + refreshPolicy(NO_REFRESH), + dramType(DDR), + dataRate(800000000), + commandOrderingAlgorithm(STRICT_ORDER), + transactionOrderingAlgorithm((TransactionOrderingAlgorithm)STRICT), + perBankQueueDepth(), + columnSize(0), + rowSize(0), + channelWidth(0), + columnCount(0), + rowCount(0), + //historyQueueDepth(0), + //completionQueueDepth(0), + transactionQueueDepth(0), + //eventQueueDepth(0), + //refreshQueueDepth(0), + //refreshTime(0), + seniorityAgeLimit(0), + decodeWindow(UINT_MAX), + rowBufferManagementPolicy(OPEN_PAGE), + addressMappingScheme(Address::BURGER_BASE_MAP), + postedCAS(false), + readWriteGrouping(true), + autoPrecharge(false), + clockGranularity(0), + channelCount(0U), + dimmCount(0U), + rankCount(0U), + bankCount(0U), + tRTRS(UINT_MAX), + tAL(UINT_MAX), + tBurst(UINT_MAX), + tCAS(UINT_MAX), + tCWD(UINT_MAX), + tFAW(UINT_MAX), + tRAS(UINT_MAX), + tRC(UINT_MAX), + tRCD(UINT_MAX), + tREFI(UINT_MAX), + tRFC(UINT_MAX), + tRP(UINT_MAX), + tRRD(UINT_MAX), + tRTP(UINT_MAX), + tWR(UINT_MAX), + tWTR(UINT_MAX), + tCMD(UINT_MAX), + tInternalBurst(UINT_MAX), + tBufferDelay(UINT_MAX), + cpuToMemoryClockRatio(-1.0F), + PdqRD(-1.0F), + PdqWR(-1.0F), + PdqRDoth(-1.0F), + PdqWRoth(-1.0F), + DQperDRAM(UINT_MAX), + DQSperDRAM(UINT_MAX), + DMperDRAM(UINT_MAX), + frequencySpec(UINT_MAX), + maxVCC(-1.0F), + VDD(-1.0F), + IDD0(UINT_MAX), + IDD1(UINT_MAX), + IDD2P(UINT_MAX), + IDD2N(UINT_MAX), + IDD3P(UINT_MAX), + IDD3N(UINT_MAX), + IDD4W(UINT_MAX), + IDD4R(UINT_MAX), + IDD5(UINT_MAX) +{} + + +////////////////////////////////////////////////////////////////////////// +/// @brief sets a parameter based on a name and value +/// @details looks for and attempts to parse a parameter name and value +/// using the name and value passed in +/// @return true if the parameter was recognized and the value converted +/// false otherwise +////////////////////////////////////////////////////////////////////////// +bool Settings::setKeyValue(const string &nodeName, const string &value) +{ + string nodeValue; + + for (std::string::const_iterator i = value.begin(), end = value.end(); i < end; i++) + { + nodeValue += tolower(*i); + } + + const FileIOToken token = dramTokenizer(nodeName); + + switch (token) + { + + case refresh_policy_token: + if (nodeValue == "none" || nodeValue == "no refresh") + refreshPolicy = NO_REFRESH; + else if (nodeValue == "bankconcurrent") + refreshPolicy = BANK_CONCURRENT; + else if (nodeValue == "bankstaggeredhidden") + refreshPolicy = BANK_STAGGERED_HIDDEN; + else if (nodeValue == "refreshonechanallrankallbank") + refreshPolicy = ONE_CHANNEL_ALL_RANK_ALL_BANK; + else + return false; + break; + case transaction_ordering_policy_token: + if (nodeValue == "strict") + transactionOrderingAlgorithm = (TransactionOrderingAlgorithm)STRICT; + else if (nodeValue == "riff") + transactionOrderingAlgorithm = (TransactionOrderingAlgorithm)RIFF; + else + transactionOrderingAlgorithm = (TransactionOrderingAlgorithm)STRICT; + break; + case command_ordering_algorithm_token: + if (nodeValue == "strict") + commandOrderingAlgorithm = STRICT_ORDER; + else if (nodeValue == "bankroundrobin" || nodeValue == "brr") + commandOrderingAlgorithm = BANK_ROUND_ROBIN; + else if (nodeValue == "rankroundrobin" || nodeValue == "rrr") + commandOrderingAlgorithm = RANK_ROUND_ROBIN; + else if (nodeValue == "cprh" || nodeValue == "commandpairrankhop" || nodeValue == "command_pair_rank_hop" || nodeValue == "commandpairrankhopping") + commandOrderingAlgorithm = COMMAND_PAIR_RANK_HOPPING; + else if (nodeValue == "firstavailableage" || nodeValue == "firstavailable" || nodeValue == "frsta") + commandOrderingAlgorithm = FIRST_AVAILABLE_AGE; + else if (nodeValue == "firstavailableriff" || nodeValue == "frstr") + commandOrderingAlgorithm = FIRST_AVAILABLE_RIFF; + else if (nodeValue == "firstavailablequeue" || nodeValue == "frstq") + commandOrderingAlgorithm = FIRST_AVAILABLE_QUEUE; + else + { + cerr << "Unrecognized ordering algorithm: " << nodeValue << endl; + commandOrderingAlgorithm = FIRST_AVAILABLE_AGE; + } + break; + case addr_mapping_scheme_token: + if (nodeValue == "burgerbase") + addressMappingScheme = Address::BURGER_BASE_MAP; + else if (nodeValue == "closepagebaseline") + addressMappingScheme = Address::CLOSE_PAGE_BASELINE; + else if (nodeValue == "intel845g") + { + if (channelCount > 1) + { + cerr << "error: Intel 845G doesn't support multiple channels, resetting to SDRAM Base Map" << endl; + addressMappingScheme = Address::SDRAM_BASE_MAP; + } + else + { + addressMappingScheme = Address::INTEL845G_MAP; + } + } + else if (nodeValue == "sdrambase" || nodeValue == "sdbas") + addressMappingScheme = Address::SDRAM_BASE_MAP; + else if (nodeValue == "sdramhiperf" || nodeValue == "sdhipf") + addressMappingScheme = Address::SDRAM_HIPERF_MAP; + else if (nodeValue == "closepagehighlocality" || nodeValue == "highlocality" || nodeValue == "hiloc") + addressMappingScheme = Address::CLOSE_PAGE_HIGH_LOCALITY; + else if (nodeValue == "closepagelowlocality" || nodeValue == "lowlocality" || nodeValue == "loloc") + addressMappingScheme = Address::CLOSE_PAGE_LOW_LOCALITY; + else if (nodeValue == "closepagebaselineopt" || nodeValue == "cpbopt") + addressMappingScheme = Address::CLOSE_PAGE_BASELINE_OPT; + else + addressMappingScheme = Address::SDRAM_HIPERF_MAP; + break; + case row_buffer_management_policy_token: + if (nodeValue == "openpage" || nodeValue == "open") + rowBufferManagementPolicy = OPEN_PAGE; + else if (nodeValue == "closepage" || nodeValue == "clos") + rowBufferManagementPolicy = CLOSE_PAGE; + else if (nodeValue == "closepageaggressive" || nodeValue == "closepageoptimized" || nodeValue == "cpa") + rowBufferManagementPolicy = CLOSE_PAGE_AGGRESSIVE; + else if (nodeValue == "openpageaggressive" || nodeValue == "opa") + rowBufferManagementPolicy = OPEN_PAGE_AGGRESSIVE; + else + return false; + break; + case dram_type_token: + if (nodeValue == "ddr2") + dramType = DDR2; + else if (nodeValue == "ddr") + dramType = DDR; + else if (nodeValue == "ddr3") + dramType = DDR3; + else if (nodeValue == "drdram") + dramType = DRDRAM; + else + dramType = DDR3; + break; + default: + cerr << nodeName << " was not recognized" << endl; + return false; + break; + //result = false; + break; + } + + + return true; +} + +ostream &DRAMsimII::operator<<(ostream &os, const CommandOrderingAlgorithm coa) +{ + switch (coa) + { + case STRICT_ORDER: + os << "STR"; + break; + case RANK_ROUND_ROBIN: + os << "RRR"; + break; + case BANK_ROUND_ROBIN: + os << "BRR"; + break; + case FIRST_AVAILABLE_AGE: + os << "FRSTA"; + break; + case FIRST_AVAILABLE_RIFF: + os << "FRSTR"; + break; + case FIRST_AVAILABLE_QUEUE: + os << "FRSTQ"; + break; + case COMMAND_PAIR_RANK_HOPPING: + os << "CPRH"; + break; + } + + return os; +} + +ostream &DRAMsimII::operator<<(ostream &os, const RowBufferPolicy rbp) +{ + switch (rbp) + { + case AUTO_PAGE: + os << "AUTO"; + break; + case OPEN_PAGE: + os << "OPEN"; + break; + case OPEN_PAGE_AGGRESSIVE: + os << "OPA"; + break; + case CLOSE_PAGE: + os << "CLOS"; + break; + case CLOSE_PAGE_AGGRESSIVE: + os << "CPA"; + break; + default: + os << "UNKN"; + break; + } + + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Statistics.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Statistics.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,191 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef STATISTICS_HH +#define STATISTICS_HH +#pragma once + +#include "globals.hh" +#include "transaction.hh" +#include "command.hh" +#include "Settings.hh" + +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif + +namespace DRAMsimII +{ + template + bool operator==(const std::tr1::unordered_map &first, const std::tr1::unordered_map &second) + { + if (first.size() != second.size()) return false; + + typename std::tr1::unordered_map::const_iterator firstEnd = first.end(); + typename std::tr1::unordered_map::const_iterator secondEnd = second.end(); + for (typename std::tr1::unordered_map::const_iterator it1 = first.begin();it1 != firstEnd; it1++) + { + typename std::tr1::unordered_map::const_iterator it2 = second.find(it1->first); + + if(it2 == secondEnd || (it1->second != it2->second)) + return false; + } + return true; + } + + + /// @brief stores statistics about this memory system, primarily relating to counts of transactions/commands + class Statistics + { + + public: + + template + class WeightedAverage + { + uint64_t count; + T total; + + public: + WeightedAverage():count(0), total(0) + {} + + void add(T _value, uint64_t _count) + { + total += _value * (T)_count; + count += _count; + } + + void clear() + { + total = 0; + count = 0; + } + + T average() const + { + return total / ((count > 0) ? (T)count : (T)1); + } + }; + + class DelayCounter + { + private: + tick accumulatedLatency; ///< the total latency for this address + unsigned count; ///< the total number of times this address has been seen + public: + DelayCounter(): + accumulatedLatency(0), + count(0) {} + + void countUp() + { + count++; + } + + void delay(tick value) + { + accumulatedLatency += value; + } + + tick getAccumulatedLatency() const { return accumulatedLatency; } + unsigned getCount() const { return count; } + + bool operator==(const DelayCounter &right) const + { + return accumulatedLatency == right.accumulatedLatency && + count == right.count; + } + + }; + + protected: + + const std::vector &channel; + + const unsigned channels; + const unsigned ranks; + const unsigned banks; + unsigned validTransactionCount; + unsigned startNumber; + unsigned endNumber; + unsigned burstOf8Count; + unsigned burstOf4Count; + unsigned columnDepth; + unsigned readCount; + unsigned writeCount; + std::vector > bandwidthData; ///< per channel count of bytes read and written + float timePerEpoch; ///< the number of seconds that have elapsed per epoch + + public: + + // constructors + explicit Statistics(const Settings& settings, const std::vector &); + + // functions + std::pair getReadWriteBytes() const { return std::pair(getReadBytesTransferred(),getWriteBytesTransferred()); } + void clear(); + void collectTransactionStats(const Transaction*); + void collectCommandStats(const Command*); + inline void setValidTransactionCount(int vtc) {validTransactionCount = vtc;} + + // accessors + const std::vector >& getBandwidthData() const { return bandwidthData;} + + unsigned getReadBytesTransferred() const + { + unsigned value = 0; + + for (std::vector >::const_iterator i = bandwidthData.begin(), end = bandwidthData.end(); + i != end; ++i) + { + value += i->first; + } + + return value; + } + + unsigned getWriteBytesTransferred() const + { + unsigned value = 0; + + for (std::vector >::const_iterator i = bandwidthData.begin(), end = bandwidthData.end(); + i != end; ++i) + { + value += i->second; + } + + return value; + } + + //const std::vector, std::pair > > > &getHitRate() const { return hitRate; } + friend std::ostream &operator<<(std::ostream &, const Statistics &); + + // overloads + bool operator==(const Statistics& right) const; + + private: + + explicit Statistics(const std::vector &); + + }; +} + +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/Statistics.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/Statistics.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,254 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include "Statistics.hh" +#include "Channel.hh" +#include "globals.hh" + +#ifdef M5 +#include "base/statistics.hh" +#include "base/stats/types.hh" +#include "sim/async.hh" +#include "base/stats/text.hh" +#endif + +#include +#include +#include + +using std::ostream; +using std::endl; +using std::map; +using std::ios; +using std::tr1::unordered_map; +using std::setprecision; +using std::setiosflags; +using std::string; +using std::pair; +using std::vector; + +using namespace DRAMsimII; + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor based on a given set of Settings +////////////////////////////////////////////////////////////////////////// +Statistics::Statistics(const Settings& settings, const vector &_cache) : +channel(_cache), channels(settings.channelCount), ranks(settings.rankCount * settings.dimmCount), banks(settings.bankCount), +validTransactionCount(0), startNumber(0), endNumber(0), burstOf8Count(0), burstOf4Count(0), +columnDepth(log2(settings.columnSize)), +readCount(0), writeCount(0), bandwidthData(settings.channelCount), +timePerEpoch((float) settings.epoch / settings.dataRate) +{ +} + +////////////////////////////////////////////////////////////////////////// +/// @brief no arg constructor for deserialization, should not be called otherwise +////////////////////////////////////////////////////////////////////////// +Statistics::Statistics(const std::vector &channel) : + channel(channel), channels(0), ranks(0), banks(0), validTransactionCount(UINT_MAX), startNumber(UINT_MAX), + endNumber(UINT_MAX), burstOf8Count(UINT_MAX), burstOf4Count(UINT_MAX), columnDepth(UINT_MAX), readCount(0), + writeCount(0), bandwidthData(0), timePerEpoch(0) +{ +} + +////////////////////////////////////////////////////////////////////////// +/// @brief collects transaction statistics once a transaction has finished +////////////////////////////////////////////////////////////////////////// +void Statistics::collectTransactionStats(const Transaction *currentTransaction) +{ + //#pragma omp critical + { + if (currentTransaction->isRead() || currentTransaction->isWrite()) + { + if (currentTransaction->getLength() == 8) + { + ++burstOf8Count; + } + else + { + ++burstOf4Count; + } + + if (currentTransaction->isRead()) + { + + bandwidthData[currentTransaction->getAddress().getChannel()].first += currentTransaction->getLength() * 8; + + assert(currentTransaction->getLatency() > 4); + readCount++; + } + else if (currentTransaction->isWrite()) + { + bandwidthData[currentTransaction->getAddress().getChannel()].second += currentTransaction->getLength() * 8; + + // 64bit bus for most DDRx architectures + /// @todo use #DQ * length to calculate bytes Tx, Rx + writeCount++; + } + + } + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief collects commands stats once a command has executed +////////////////////////////////////////////////////////////////////////// +void Statistics::collectCommandStats(const Command *currentCommand) +{ + //#pragma omp critical + { + if (!currentCommand->isRefresh()) + { + assert(currentCommand->getLatency() < 2147483648 || (currentCommand->isPrecharge() + && currentCommand->getEnqueueTime() == 0)); + } + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief insertion operator overload to dump statistics +/// @details prints info about the statistics since the last reset +////////////////////////////////////////////////////////////////////////// +ostream &DRAMsimII::operator<<(ostream &os, const Statistics &statsLog) +{ + using std::vector; +#if 0 + os << "RR[" << setw(6) << setprecision(6) << (double)statsLog.end_time/max(1,statsLog.bo4_count + statsLog.bo8_count) << "] "; + os << "BWE[" << setw(6) << setprecision(6) << ((double)statsLog.bo8_count * 8.0 + statsLog.bo4_count * 4.0) * 100.0 / max(statsLog.end_time,(tick)1) << "]" << endl; + + os << "----R W Total----" << endl; + os << statsLog.readCount << " " << statsLog.writeCount << " " << statsLog.readCount + statsLog.writeCount << endl; +#endif + + Statistics::WeightedAverage averageLatency; + + os << "----Average Transaction Latency {" << averageLatency.average() << "}" << endl; +#if 0 + averageLatency.clear(); + + os << "----Average Adjusted Transaction Latency {" << averageLatency.average() << "}" << endl; +#endif +#if 0 + averageLatency.clear(); + + os << "----Average Cumulative Transaction Latency {" << averageLatency.average() << "}" << endl; +#endif + averageLatency.clear(); + + os << "----Bandwidth {" << setprecision(10) << (float) statsLog.getReadBytesTransferred() / statsLog.timePerEpoch << "} {" + << (float) statsLog.getWriteBytesTransferred() / statsLog.timePerEpoch << "}" << endl; + + os << "----Per Channel Bandwidth "; + + unsigned currentChannel = 0; + for (vector >::const_iterator i = statsLog.getBandwidthData().begin(); i + != statsLog.getBandwidthData().end(); ++i) + { + os << "ch[" << currentChannel++ << "] R{" << i->first << "} W{" << i->second << "} "; + } + os << endl; + +#ifdef M5 + + using Stats::Info; + std::list::const_iterator i = Stats::statsList().begin(); + std::list::const_iterator end = Stats::statsList().end(); + + for (;i != end;++i) + { + Info *info = *i; + if (info->name.find("ipc_total") != string::npos) + { + os << "----IPC"; + std::vector::const_iterator start = ((Stats::FormulaInfoProxy *)info)->result().begin(); + std::vector::const_iterator end = ((Stats::FormulaInfoProxy *)info)->result().end(); + while (start != end) + { + os << " {" << *start << "}"; + start++; + // only considering single-threaded for now + //break; + } + os << endl; + } + if ((info->name.find("dcache.overall_hits") != string::npos) || + (info->name.find("dcache.overall_misses") != string::npos) || + (info->name.find("dcache.overall_miss_latency") != string::npos) || + (info->name.find("icache.overall_hits") != string::npos) || + (info->name.find("icache.overall_misses") != string::npos) || + (info->name.find("icache.overall_miss_latency") != string::npos) || + (info->name.find("l2.overall_hits") != string::npos) || + (info->name.find("l2.overall_misses") != string::npos) || + (info->name.find("l2.overall_mshr_hits") != string::npos) || + (info->name.find("l2.overall_mshr_misses") != string::npos) || + (info->name.find("l2.overall_mshr_miss_latency") != string::npos) || + (info->name.find("l2.overall_miss_latency") != string::npos) || + (info->name.find("l3cache.overall_hits") != string::npos) || + (info->name.find("l3cache.overall_misses") != string::npos) || + (info->name.find("l3cache.overall_miss_latency") != string::npos) || + (info->name.find("l3cache.overall_mshr_miss_latency") != string::npos)) + { + { + os << "----M5 Stat: {" << info->name << "}"; + + std::vector::const_iterator start = ((Stats::FormulaInfoProxy *)info)->result().begin(); + std::vector::const_iterator end = ((Stats::FormulaInfoProxy *)info)->result().end(); + while (start != end) + { + os << " {" << *start << "}"; + start++; + } + os << endl; + } + } + } +#endif + + return os; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief reset collected statistics up to this point +////////////////////////////////////////////////////////////////////////// +void Statistics::clear() +{ + using std::vector; + + readCount = writeCount = 0; + + for (vector >::iterator i = bandwidthData.begin(); i != bandwidthData.end(); ++i) + { + i->first = i->second = 0; + } + +#ifdef M5 + //async_statdump = + async_event = async_statreset = true; +#endif // M5DEBUG +} + +////////////////////////////////////////////////////////////////////////// +/// @brief equality operator to test if two sets of statistics are equal +////////////////////////////////////////////////////////////////////////// +bool Statistics::operator==(const Statistics& rhs) const +{ + return (validTransactionCount == rhs.validTransactionCount && startNumber == rhs.startNumber && endNumber == rhs.endNumber + && burstOf8Count == rhs.burstOf8Count && burstOf4Count == rhs.burstOf4Count && columnDepth == rhs.columnDepth && + /// @todo restore comparisons once tr1 implementations support this + channels == rhs.channels && ranks == rhs.ranks && banks == rhs.banks && readCount == rhs.readCount && writeCount + == rhs.writeCount && bandwidthData == rhs.bandwidthData); +} + diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/System.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/System.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,91 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef SYSTEM_HH +#define SYSTEM_HH + +#include "globals.hh" +#include "SystemConfiguration.hh" +#include "TimingSpecification.hh" +#include "Address.hh" +#include "command.hh" +#include "Statistics.hh" +#include "event.hh" +#include "Channel.hh" +#include "Rank.hh" +#include "Settings.hh" +#include "powerConfig.hh" +#include "SystemConfiguration.hh" + +#include +#include +#include + +namespace DRAMsimII +{ + /// @brief represents a DRAM system, the memory controller(s) and associated channels + /// @details contains a representation for a DRAM system, with the memory controller(s), channels, ranks, banks + /// statistics, ability to read input streams, handle asynchronous requests, return requests at certain times + /// @author Joe Gross + class System + { + protected: + // members + const SystemConfiguration systemConfig; ///< stores the parameters for the DRAM system, including channel/rank/bank/row counts + Statistics statistics; ///< keeps running statistics about the simulation + std::vector channel; ///< represents the independent channels + + tick time; ///< master clock, usually set to the oldest channel's time + tick lastStatsTime; ///< the time at which stats were last printed + tick nextStats; ///< the next time at which stats should be collected + + //functions + unsigned findOldestChannel() const; + void updateSystemTime(); + + void checkStats(); + void printStats(); + virtual void doPowerCalculation(); + virtual void printStatistics(); + + public: + + // functions + bool moveToTime(const tick endTime); + bool enqueue(Transaction* trans); + virtual tick nextTick() const; + unsigned pendingTransactionCount() const; + void getPendingTransactions(std::queue > &); + + // accessors + bool isFull(const unsigned channelNumber) const { return channel[channelNumber].isFull(); } ///< returns true if this channel has no more room + double Frequency() const { return systemConfig.Frequency(); } ///< accessor to get the frequency of the DRAM system + tick getTime() const { return time; } + void resetToTime(const tick time); + bool isEmpty() const; + + // constructors + explicit System(const Settings& settings); + explicit System(const System& rhs); + ~System(); + + // friends + friend std::ostream &operator<<(std::ostream &, const System &); + bool operator==(const System &rhs) const; + + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/System.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/System.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,424 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "System.hh" +#include "base/trace.hh" + +using std::setprecision; +using std::string; +using std::cerr; +using std::for_each; +using std::max; +using std::bind2nd; +using std::mem_fun_ref; +using std::vector; +using std::endl; +using std::ostream; +using std::min; +using std::stringstream; +using namespace DRAMsimII; + +////////////////////////////////////////////////////////////////////// +/// @brief constructor for a dramSystem, based on dramSettings +/// @author Joe Gross +/// @param settings the settings that define what the system should look like +////////////////////////////////////////////////////////////////////// +System::System(const Settings &settings) : + systemConfig(settings), statistics(settings, channel), channel( + systemConfig.getChannelCount(), Channel(settings, systemConfig, + statistics)), time(0), nextStats(settings.epoch) +{ + // set the channelID so that each channel may know its ordinal value + for (unsigned i = 0; i < settings.channelCount; i++) + { + channel[i].setChannelID(i); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief copy constructor +/// @details will copy channel 0 into all the other channels via copy constructor +/// and then use the assignment operator to copy the contents over +////////////////////////////////////////////////////////////////////////// +System::System(const System &rhs) : + systemConfig(rhs.systemConfig), statistics(rhs.statistics), channel( + systemConfig.getChannelCount(), Channel(rhs.channel[0], + systemConfig, statistics)), time(0), nextStats( + rhs.nextStats) +{ + Address::initialize( systemConfig); + channel = rhs.channel; +} + +System::~System() +{ + printStats(); + STATS_LOG("----Runtime: {" << time / systemConfig.getDatarate() + << "} duration{" << time - lastStatsTime << "}"); +} + +////////////////////////////////////////////////////////////////////// +/// @brief returns the time at which the next event happens +/// @details returns the time when the memory system next has an event\n +/// the event may either be a conversion of a transaction into commands or it may be the the +/// next time a command may be issued +/// @author Joe Gross +/// @return the time of the next event, or TICK_MAX if there was no next event found +/// @todo should always be a next event due to perpetual stats collection, could throw an exception when there are no stats being collected +////////////////////////////////////////////////////////////////////// +tick System::nextTick() const +{ + tick nextEvent = nextStats; + + // find the next time to wake from among all the channels + for (vector::const_iterator currentChan = channel.begin(), end = + channel.end(); currentChan != end; ++currentChan) + { + tick channelNextWake = currentChan->nextTick(); + assert(channelNextWake > currentChan->getTime()); + + if (channelNextWake < nextEvent) + { + nextEvent = channelNextWake; + } + } + assert(nextEvent < TICK_MAX); + assert(nextEvent > time); + return nextEvent; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief decides if enough time has passed to do a new power calculation +/// @brief or stats calculation, if so, aggregate and report results +////////////////////////////////////////////////////////////////////////// +void System::checkStats() +{ + if (time >= nextStats) + { + printStats(); + lastStatsTime = time; + } + + while (time >= nextStats) + nextStats += systemConfig.getEpoch(); +} + +void System::printStats() +{ + DPRINTF(MemoryAccess, "aggregate stats"); + doPowerCalculation(); + + printStatistics(); +} + +////////////////////////////////////////////////////////////////////// +/// @brief updates the system time to be the same as that of the oldest channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////// +void System::updateSystemTime() +{ + vector::const_iterator currentChan = channel.begin(); + time = currentChan->getTime(); + currentChan++; + + for (; currentChan != channel.end(); ++currentChan) + { + if (currentChan->getTime() < time) + time = currentChan->getTime(); + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief enqueue the transaction +/// @details attempts to enqueue the transaction in the correct channel +/// also sets the enqueue time to the current time +/// @author Joe Gross +/// @param currentTransaction the transaction to be added to the per-channel queues +/// @return true if the transaction was able to be enqueued +////////////////////////////////////////////////////////////////////// +bool System::enqueue(Transaction *currentTransaction) +{ + assert(!currentTransaction->isRefresh()); + + // attempt to insert the transaction into the per-channel transaction queue + bool result = + channel[currentTransaction->getAddress().getChannel()].enqueue( + currentTransaction); + + DPRINTF( + MemoryAccess, + "%s+T ch[%d] (%d/%d) %s", + (result ? "" : "!"), + currentTransaction->getAddress().getChannel(), + channel[currentTransaction->getAddress().getChannel()].getTransactionQueueCount(), + channel[currentTransaction->getAddress().getChannel()].getTransactionQueueDepth(), + *currentTransaction); + + return result; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief resets various counters to account for the fact that time starts now +/// @param time the time to reset things to begin at +////////////////////////////////////////////////////////////////////////// +void System::resetToTime(const tick time) +{ + nextStats = time + systemConfig.getEpoch(); + + for (vector::iterator i = channel.begin(); i != channel.end(); ++i) + { + i->resetToTime(time); + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief moves all channels to the specified time +/// @details if a transaction completes before the end time is reached, it is returned and transFinishTime variable is set +/// @author Joe Gross +/// @param endTime the time which the channels should be moved to, finishing and queuing transactions as R/W finish +/// @return a transaction which finished somewhere before the end time +////////////////////////////////////////////////////////////////////// +bool System::moveToTime(const tick endTime) +{ + for (vector::iterator i = channel.begin(), end = channel.end(); i + < end; i++) + { + i->moveToTime(endTime); + } + //#pragma omp parallel for private(i) + // for (i = channel.size() - 1; i >= 0; i--) + // { + // channel[i].moveToTime(endTime); + // } + + updateSystemTime(); + + bool result = true; + + if (time >= nextStats) + { + std::pair rwBytes = statistics.getReadWriteBytes(); + result = rwBytes.first + rwBytes.second > 0; + } + + checkStats(); + + return result; +} + +////////////////////////////////////////////////////////////////////// +/// @brief goes through each channel to find the channel whose time is the least +/// @author Joe Gross +/// @return the ordinal of the oldest channel +////////////////////////////////////////////////////////////////////// +unsigned System::findOldestChannel() const +{ + vector::const_iterator currentChan = channel.begin(); + tick oldestTime = currentChan->getTime(); + unsigned oldestChanID = currentChan->getChannelID(); + for (; currentChan != channel.end(); ++currentChan) + { + if (currentChan->getTime() < oldestTime) + { + oldestChanID = currentChan->getChannelID(); + oldestTime = currentChan->getTime(); + } + } + + return oldestChanID; +} + +////////////////////////////////////////////////////////////////////// +/// @brief prints out the statistics accumulated so far and about the current epoch +/// @author Joe Gross +////////////////////////////////////////////////////////////////////// +void System::printStatistics() +{ + STATS_LOG( statistics); + statistics.clear(); + + for (vector::iterator h = channel.begin(), hEnd = channel.end(); h + != hEnd; ++h) + { + h->resetStats(); + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief calculate and print the power consumption for each channel +/// @author Joe Gross +////////////////////////////////////////////////////////////////////// +void System::doPowerCalculation() +{ + // waiting for OpenMP 3.0 + //#pragma omp parallel + + //#pragma omp for + + //for_each(channel.begin(),channel.end(),bind2nd(mem_fun_ref(&Channel::doPowerCalculation),time, systemConfig.powerOutStream)); + + for (vector::iterator i = channel.begin(), end = channel.end(); i + != end; ++i) + { + stringstream ss; + i->doPowerCalculation(ss); + DPRINTF(MemoryAccess, "%s", ss.str()); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief the number of finished transactions queued up due to moving the channel to a time +/// @returns the number of transactions waiting in the queue +////////////////////////////////////////////////////////////////////////// +unsigned System::pendingTransactionCount() const +{ + unsigned count = 0; + for (vector::const_iterator i = channel.begin(), end = + channel.end(); i != end; ++i) + count += i->pendingTransactionCount(); + return count; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief move all the pending, finished transactions into a new queue +////////////////////////////////////////////////////////////////////////// +void System::getPendingTransactions( + std::queue > &outputQueue) +{ + for (vector::iterator i = channel.begin(), end = channel.end(); i + != end; ++i) + i->getPendingTransactions(outputQueue); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief function to determine if there are any commands or transactions pending in this system +/// @return true if there are any transactions or commands in the queues, false otherwise +////////////////////////////////////////////////////////////////////////// +bool System::isEmpty() const +{ + for (vector::const_iterator i = channel.begin(), end = + channel.end(); i != end; ++i) + { + if (!i->isEmpty()) + return false; + } + return true; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief equality operator for the System object +/// @return true if the systems are equivalent +////////////////////////////////////////////////////////////////////////// +bool System::operator==(const System &rhs) const +{ + return systemConfig == rhs.systemConfig && channel == rhs.channel + && statistics == rhs.statistics && time == rhs.time && nextStats + == rhs.nextStats; +} + +////////////////////////////////////////////////////////////////////// +/// @brief serializes the dramSystem and prints it to the given ostream +/// @author Joe Gross +/// @param os the ostream to print the dramSystem information to +/// @param thisSystem the reference to the dramSystem to be printed +/// @return reference to the ostream passed in with information appended +////////////////////////////////////////////////////////////////////// +ostream &DRAMsimII::operator<<(ostream &os, const System &thisSystem) +{ + os << "RC[" << thisSystem.systemConfig.getRankCount() << "] "; + os << "BC[" << thisSystem.systemConfig.getBankCount() << "] "; + os << "ALG["; + switch (thisSystem.systemConfig.getCommandOrderingAlgorithm()) + { + case STRICT_ORDER: + os << "STR ] "; + break; + case RANK_ROUND_ROBIN: + os << "RRR ] "; + break; + case BANK_ROUND_ROBIN: + os << "BRR ] "; + break; + case COMMAND_PAIR_RANK_HOPPING: + os << "CPRH] "; + break; + case FIRST_AVAILABLE_AGE: + os << "GRDY] "; + break; + default: + os << "UNKN] "; + break; + } + + return os; +} + +ostream& DRAMsimII::operator<<(ostream& os, const DRAMsimII::RefreshPolicy rp) +{ + switch (rp) + { + case NO_REFRESH: + os << "none"; + break; + case BANK_CONCURRENT: + os << "bankConcurrent"; + break; + case BANK_STAGGERED_HIDDEN: + os << "bankStaggeredHidden"; + break; + case ONE_CHANNEL_ALL_RANK_ALL_BANK: + os << "refreshOneChanAllRankAllBank"; + break; + default: + os << "unknown"; + break; + } + + return os; +} + +ostream& DRAMsimII::operator<<(ostream& os, + const DRAMsimII::TransactionOrderingAlgorithm toa) +{ + switch (toa) + { + case RIFF: + os << "RIFF"; + break; + case STRICT: + os << "strict"; + break; + default: + os << "unknown"; + break; + } + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/SystemConfiguration.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/SystemConfiguration.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,97 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef SYSTEMCONFIGURATION_HH +#define SYSTEMCONFIGURATION_HH +#pragma once + +#include "globals.hh" +#include "Settings.hh" +#include "Address.hh" + +#include + +namespace DRAMsimII +{ + /// @brief stores the system configuration options for a dramSystem + class SystemConfiguration + { + protected: + CommandOrderingAlgorithm commandOrderingAlgorithm; ///< describes how to place commands into the per bank command queues + TransactionOrderingAlgorithm transactionOrderingAlgorithm; ///< the algorithm that describes how to place transactions into the queue + unsigned refreshTime; ///< the frequency at which refresh commands are scheduled + RefreshPolicy refreshPolicy; ///< determines how refreshes are handled + unsigned columnSize; ///< the size of each column, in bytes + unsigned rowSize; ///< bytes per row (across one rank) + unsigned seniorityAgeLimit; ///< the oldest a command may be before it takes top priority + DRAMType dramType; + RowBufferPolicy rowBufferManagementPolicy; ///< row buffer management policy? OPEN/CLOSE, etc + Address::AddressMappingScheme addressMappingScheme; ///< addr mapping scheme for physical to DRAM addr + double datarate; ///< the operating frequency of the system + bool postedCAS; ///< TRUE/FALSE, so the CAS command may be stored and run later + bool readWriteGrouping; ///< whether or not reads and writes should be grouped closely + bool autoPrecharge; ///< is CAS+P an available command for close page + int clockGranularity; + unsigned channelCount; ///< How many logical channels are there ? + unsigned dimmCount; + unsigned rankCount; ///< How many ranks are there per channel ? + unsigned bankCount; ///< How many banks per device? + unsigned rowCount; ///< rows per bank + unsigned columnCount; ///< columns per row + unsigned decodeWindow; ///< how many transactions to consider when decoding to commands + const unsigned epoch; ///< the amount of time between stats aggregation and reporting + + + public: + // constructors + explicit SystemConfiguration(const Settings& settings); + explicit SystemConfiguration(const SystemConfiguration &rhs); + + // accessors + RowBufferPolicy getRowBufferManagementPolicy() const { return rowBufferManagementPolicy; } + Address::AddressMappingScheme getAddressMappingScheme() const { return addressMappingScheme; } + CommandOrderingAlgorithm getCommandOrderingAlgorithm() const { return commandOrderingAlgorithm; } + TransactionOrderingAlgorithm getTransactionOrderingAlgorithm() const { return transactionOrderingAlgorithm; } + unsigned getRankCount() const { return rankCount; } + unsigned getBankCount() const { return bankCount; } + unsigned getChannelCount() const { return channelCount; } + unsigned getDimmCount() const { return dimmCount; } + unsigned getRowCount() const { return rowCount; } + unsigned getColumnCount() const { return columnCount; } + unsigned getColumnSize() const { return columnSize; } + unsigned getRefreshTime() const { return refreshTime; } + unsigned getSeniorityAgeLimit() const { return seniorityAgeLimit; } + unsigned getEpoch() const { return epoch; } + double getDatarate() const { return datarate; } + RefreshPolicy getRefreshPolicy() const { return refreshPolicy; } + DRAMType getDRAMType() const { return dramType; } + bool isAutoPrecharge() const { return autoPrecharge; } + bool isReadWriteGrouping() const { return readWriteGrouping; } + bool isPostedCAS() const { return postedCAS; } + double Frequency() const { return datarate; } + unsigned getDecodeWindow() const { return decodeWindow; } + + // operator overloads + SystemConfiguration& operator =(const SystemConfiguration &rs); + bool operator ==(const SystemConfiguration &) const; + + // friends + friend std::ostream &operator<<(std::ostream &, const System &); + friend std::ostream &operator<<(std::ostream &, const SystemConfiguration &); + + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/SystemConfiguration.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/SystemConfiguration.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,173 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include +#include "SystemConfiguration.hh" + +#ifdef WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +using std::ostream; +using namespace DRAMsimII; +using std::stringstream; +using std::cout; +using std::ios; +using std::setw; +using std::string; +using std::cerr; +using std::ifstream; +using std::setfill; +using std::setprecision; +using std::endl; + + +SystemConfiguration::SystemConfiguration(const Settings& settings): +commandOrderingAlgorithm(settings.commandOrderingAlgorithm), +transactionOrderingAlgorithm(settings.transactionOrderingAlgorithm), +//refreshTime(settings.dataRate * settings.refreshTime), +refreshPolicy(settings.refreshPolicy), +columnSize(settings.columnSize), +rowSize(settings.rowSize), +seniorityAgeLimit(settings.seniorityAgeLimit), +dramType(settings.dramType), +rowBufferManagementPolicy(settings.rowBufferManagementPolicy), +addressMappingScheme(settings.addressMappingScheme), +datarate(settings.dataRate), +postedCAS(settings.postedCAS), +readWriteGrouping(settings.readWriteGrouping), +autoPrecharge(settings.autoPrecharge), +clockGranularity(settings.clockGranularity), +channelCount(settings.channelCount), +dimmCount(settings.dimmCount), +rankCount(settings.rankCount), +bankCount(settings.bankCount), +rowCount(settings.rowCount), +columnCount(settings.columnCount), +decodeWindow(settings.decodeWindow), +epoch(settings.epoch) +{ + Address::initialize(settings); + + assert(decodeWindow >= 1); +} + + +SystemConfiguration::SystemConfiguration(const SystemConfiguration &rhs): +commandOrderingAlgorithm(rhs.commandOrderingAlgorithm), +transactionOrderingAlgorithm(rhs.transactionOrderingAlgorithm), +refreshTime(rhs.refreshTime), +refreshPolicy(rhs.refreshPolicy), +columnSize(rhs.columnSize), +rowSize(rhs.rowSize), +seniorityAgeLimit(rhs.seniorityAgeLimit), +dramType(rhs.dramType), +rowBufferManagementPolicy(rhs.rowBufferManagementPolicy), +addressMappingScheme(rhs.addressMappingScheme), +datarate(rhs.datarate), +postedCAS(rhs.postedCAS), +readWriteGrouping(rhs.readWriteGrouping), +autoPrecharge(rhs.autoPrecharge), +clockGranularity(rhs.clockGranularity), +channelCount(rhs.channelCount), +dimmCount(rhs.dimmCount), +rankCount(rhs.rankCount), +bankCount(rhs.bankCount), +rowCount(rhs.rowCount), +columnCount(rhs.columnCount), +decodeWindow(rhs.decodeWindow), +epoch(rhs.epoch) +{} + +SystemConfiguration& SystemConfiguration::operator =(const DRAMsimII::SystemConfiguration &rhs) +{ + if (this == &rhs) + { + return *this; + } + commandOrderingAlgorithm = rhs.commandOrderingAlgorithm; + transactionOrderingAlgorithm = rhs.transactionOrderingAlgorithm; + refreshTime = rhs.refreshTime; + refreshPolicy = rhs.refreshPolicy; + columnSize = rhs.columnSize; + rowSize = rhs.rowSize; + rowCount = rhs.rowCount; + columnCount = rhs.columnCount; + seniorityAgeLimit = rhs.seniorityAgeLimit; + dramType = rhs.dramType; + rowBufferManagementPolicy = rhs.rowBufferManagementPolicy; + addressMappingScheme = rhs.addressMappingScheme; + datarate = rhs.datarate; + postedCAS = rhs.postedCAS; + readWriteGrouping = rhs.readWriteGrouping; + autoPrecharge = rhs.autoPrecharge; + clockGranularity = rhs.clockGranularity; + channelCount = rhs.channelCount; + dimmCount = rhs.dimmCount; + rankCount = rhs.rankCount; + bankCount = rhs.bankCount; + decodeWindow = rhs.decodeWindow; + assert(decodeWindow >= 1); + + return *this; +} + +bool SystemConfiguration::operator ==(const SystemConfiguration& rhs) const +{ + return (commandOrderingAlgorithm == rhs.commandOrderingAlgorithm && + transactionOrderingAlgorithm == rhs.transactionOrderingAlgorithm && + refreshTime == rhs.refreshTime && + refreshPolicy == rhs.refreshPolicy && + columnSize == rhs.columnSize && + rowSize == rhs.rowSize && + seniorityAgeLimit == rhs.seniorityAgeLimit && + dramType == rhs.dramType && + rowBufferManagementPolicy == rhs.rowBufferManagementPolicy && + addressMappingScheme == rhs.addressMappingScheme && + AlmostEqual(datarate,rhs.datarate) && + postedCAS == rhs.postedCAS && + readWriteGrouping == rhs.readWriteGrouping && + autoPrecharge == rhs.autoPrecharge && + clockGranularity == rhs.clockGranularity && + channelCount == rhs.channelCount && + dimmCount == rhs.dimmCount && + rankCount == rhs.rankCount && + bankCount == rhs.bankCount && + rowCount == rhs.rowCount && + columnCount == rhs.columnCount && + decodeWindow == rhs.decodeWindow && + epoch == rhs.epoch); +} + +ostream &DRAMsimII::operator<<(ostream &os, const SystemConfiguration &this_a) +{ + os << "CH[" << this_a.channelCount << "] "; + os << "RK[" << this_a.rankCount << "] "; + os << "BK[" << this_a.bankCount << "] "; + + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/TimingSpecification.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/TimingSpecification.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,93 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef TIMINGSPECIFICATION_HH +#define TIMINGSPECIFICATION_HH + +#include "globals.hh" +#include "Settings.hh" + +namespace DRAMsimII +{ + // t_pp (min prec to prec of any bank) ignored + /// @brief contains all the specs for this channel's DIMMs + class TimingSpecification + { + protected: + + int t_al; ///< additive latency, used with posted cas + int t_burst; ///< number of cycles utilized per cacheline burst + int t_cas; ///< delay between start of CAS and start of burst + int t_ccd; ///< column-to-column delay, the minimum column command timing, determined by internal burst (prefetch) length. + int t_cmd; ///< command bus duration... + int t_cwd; ///< delay between end of CASW and start of burst + int t_faw; ///< four bank activation + int t_ras; ///< interval between ACT and PRECHARGE to same bank + int t_rc; ///< t_rc is simply t_ras + t_rp + int t_rcd; ///< RAS to CAS delay of same bank + int t_rfc; ///< refresh cycle time + int t_rp; ///< interval between PRECHARGE and ACT to same bank + int t_rrd; ///< row to row activation delay + int t_rtp; ///< read to precharge delay + int t_rtrs; ///< rank hand off penalty, also t_dqs + int t_wr; ///< write recovery time , time to restore data + int t_wtr; ///< write to read turnaround time + int t_ost; ///< on-die termination switching time + int t_int_burst; ///< internal prefetch length of DRAM devices, 4 for DDR2, 8 for DDR3 + int t_buffer_delay; ///< the delay a transaction experiences before it can be converted to a series of commands + int t_refi; ///< refresh interval, should send one refresh every n ticks to a rank + + public: + // constructors + explicit TimingSpecification(const Settings& settings); + + // accessors + int tAL() const { return t_al; } + int tCAS() const { return t_cas; } + int tCCD() const { return t_ccd; } + int tBurst() const { return t_burst; } + int tRTP() const { return t_rtp; } + int tRAS() const { return t_ras; } + int tCWD() const { return t_cwd; } + int tWR() const { return t_wr; } + int tBufferDelay() const { return t_buffer_delay; } + int tCMD() const { return t_cmd; } + int tREFI() const { return t_refi; } + int tRCD() const { return t_rcd; } + int tRP() const { return t_rp; } + int tRRD() const { return t_rrd; } + int tFAW() const { return t_faw; } + int tRFC() const { return t_rfc; } + int tWTR() const { return t_wtr; }; + int tRTRS() const { return t_rtrs; } + int tRC() const { return t_rc; } + int tOST() const { return t_ost; } + + // friends + friend std::ostream &operator<<( std::ostream&, const TimingSpecification&); + + // overloads + bool operator==(const TimingSpecification& right) const; + + private: + friend void unitTests(const Settings &settings); + + TimingSpecification(); + + + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/TimingSpecification.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/TimingSpecification.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,203 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include + +#include "TimingSpecification.hh" + +using std::ostream; +using std::cerr; +using std::endl; +using namespace DRAMsimII; + +// no arg constructor for deserialization and unit testing +TimingSpecification::TimingSpecification(): +t_al(-1), +t_burst(-1), +t_cas(-1), +t_ccd(-1), +t_cmd(-1), +t_cwd(-1), +t_faw(-1), +t_ras(-1), +t_rc(-1), +t_rcd(-1), +t_rfc(-1), +t_rp(-1), +t_rrd(-1), +t_rtp(-1), +t_rtrs(-1), +t_wr(-1), +t_wtr(-1), +t_ost(0), +t_int_burst(-1), +t_buffer_delay(-1), +t_refi(-1) +{} + + +TimingSpecification::TimingSpecification(const Settings& settings): +t_buffer_delay(settings.tBufferDelay), +t_refi(settings.tREFI) +{ + switch(settings.dramType) + { + case DDR: + + t_ccd = 2; // internal fetch is 1 cycle, 2 beats for DDR + t_al = 0; // no such thing in DDR + t_burst = settings.tBurst; // depending on system config! can be 2, 4, or 8 + t_cas = settings.tCAS; + t_cmd = 2; // protocol specific, cannot be changed + t_cwd = 2; // protocol specific, cannot be changed + t_int_burst = 2; // protocol specific, cannot be changed + t_faw = 0; // no such thing in DDR + t_ras = settings.tRAS; // 40 ns @ 2.5 ns per beat == 16 beats + t_rc = settings.tRC; // 55 ns t_rc + t_rcd = settings.tRCD; + t_rfc = settings.tRFC; // 70 ns @ 2.5 ns per beat == 28 beats + t_rp = settings.tRP; // 15 ns @ 2.5ns per beat = 6 beats + t_rrd = settings.tRRD; + t_rtp = settings.tRTP; + t_rtrs = settings.tRTRS; + t_wr = settings.tWR; // 15 ns @ 2.5 ns per beat = 6 beats + t_wtr = settings.tWTR; + t_rtrs = settings.tRTRS; + t_ost = 0; // does not exist for DDR + assert(t_rcd + t_cwd + t_burst + t_wr >= t_ras); + break; + + case DDR2: + + t_ccd = 4; // two cycles, 4 beats in DDR2 + t_al = settings.postedCAS ? settings.tAL : 0; // if posted CAS is disabled, tAL should be zero + t_rcd = settings.tRCD; + t_burst = settings.tBurst; // can be 4 or 8 + t_cas = settings.tCAS; + t_cmd = 2; // protocol specific, cannot be changed + t_rtp = settings.tRTP; + t_rc = settings.tRC; + t_ras = settings.tRAS; + //assert(t_rcd + t_burst + t_rtp - t_ccd == t_rc); + assert(settings.tCWD + 2 == settings.tCAS); + t_cwd = t_cas - 2; // protocol specific, cannot be changed + t_int_burst = 4; // protocol specific, cannot be changed + t_faw = settings.tFAW; + t_rp = settings.tRP; + t_rfc = settings.tRFC; + t_rrd = settings.tRRD; + t_rtrs = settings.tRTRS; + t_wr = settings.tWR; + t_wtr = settings.tWTR; + t_ost = 5; // 2.5 cycles to turn off, 2 to turn on + + // DRAM will delay internally if tRAS is not met + // this MHC will account for any issues + //assert(t_rcd + t_rtp + t_burst - t_ccd >= t_ras); + assert(t_rcd + t_cwd + t_burst + t_wr >= t_ras); + + if (t_al > t_rcd) + { + cerr << "tAL must be <= tRCD to ensure proper operation" << endl; + exit(-20); + } + assert(t_al >= 0 && t_al <= 8); // must be 0..4 cycles, or 0..8 beats + assert(t_al + t_cmd == t_rcd); + + + break; + + case DDR3: + + t_ccd = 8; // four cycles, eight beats in DDR3 + t_al = settings.postedCAS ? settings.tAL : 0; // if posted CAS is disabled, tAL should be zero + t_burst = 8; // protocol specific, cannot be changed + t_cas = settings.tCAS; + t_cmd = 2; // protocol specific, cannot be changed + assert(settings.tCWD + 2 == settings.tCAS); + t_cwd = t_cas - 2; // fixed + t_int_burst = 8; // protocol specific, cannot be changed + t_faw = settings.tFAW; + t_ras = settings.tRAS; // 27 ns @ 0.75ns per beat = 36 beats + t_rc = settings.tRC; // 36 ns @ 0.75ns per beat = 48 beats + t_rcd = settings.tRCD; + t_rfc = settings.tRFC; + t_rp = settings.tRP; // 9 ns @ 0.75ns per beat = 12 beats + t_rrd = settings.tRRD; + t_rtrs = settings.tRTRS; + t_rtp = settings.tRTP; + t_wr = settings.tWR; + t_wtr = settings.tWTR; + t_ost = 5; // 2.5 cycles to turn off, 2 to turn on + + // DRAM will delay internally if tRAS is not met + // this MHC will account for any issues + //assert(t_rcd + t_rtp + t_burst - t_ccd >= t_ras); + assert(t_rcd + t_cwd + t_burst + t_wr >= t_ras); + assert(t_al == t_cas - 2 || t_al == t_cas - 4 || t_al == 0); + + break; + + case SDRAM: + + t_ccd = 1; // one cycle, one beat in SDR + t_al = 0; // no such thing as posted CAS in SDRAM + t_burst = settings.tBurst; // depending on system config, can be 1, 2, 4, or 8 + t_cas = settings.tCAS; + t_cmd = 1; // protocol specific, cannot be changed + t_cwd = 0; //no such thing in SDRAM + t_int_burst = 1; // prefetch length is 1 + t_faw = 0; // no such thing in SDRAM + t_ras = settings.tRAS; + t_rc = settings.tRC; + t_rcd = settings.tRCD; + t_rfc = settings.tRC; // same as t_rc + t_rp = settings.tRP; // 12 ns @ 1.25ns per cycle = 9.6 cycles + t_rrd = 0; // no such thing in SDRAM + t_rtp = settings.tRTP; + t_rtrs = settings.tRTRS; // no such thing in SDRAM + t_wr = settings.tWR; + t_ost = 0; // does not exist in SDRAM + break; + + case DRDRAM: + cerr << "DRDRAM not yet supported." << endl; + exit(-12); + break; + + default: + break; + } +} + +bool TimingSpecification::operator==(const TimingSpecification &right) const +{ + return (t_al == right.t_al && t_burst == right.t_burst && t_cas == right.t_cas && t_ccd == right.t_ccd && t_cmd == right.t_cmd && + t_cwd == right.t_cwd && t_faw == right.t_faw && t_ras == right.t_ras && t_rc == right.t_rc && t_rcd == right.t_rcd && + t_rfc == right.t_rfc && t_rp == right.t_rp && t_rrd == right.t_rrd && t_rtp == right.t_rtp && t_rtrs == right.t_rtrs && + t_wr == right.t_wr && t_wtr == right.t_wtr && t_int_burst == right.t_int_burst && t_buffer_delay == right.t_buffer_delay && + t_refi == right.t_refi && t_ost == right.t_ost); + +} +ostream &DRAMsimII::operator<<(ostream &os, const TimingSpecification &this_a) +{ + os << "rtrs[" << this_a.t_rtrs << "] "; + return os; +} + + diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/command.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/command.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,100 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef COMMAND_HH +#define COMMAND_HH + +#include "globals.hh" +#include "Address.hh" +#include "queue.hh" +#include "transaction.hh" +#include "event.hh" +#include "base/fast_alloc.hh" + +namespace DRAMsimII +{ + /// @brief represents a DRAM command from the memory controller to the DRAMs + class Command: public Event, public FastAlloc + { + public: + /// @brief available command types to send to DRAMs + /// @details a basic DRAM command may be any of the following + enum CommandType + { + ACTIVATE, ///< open this row + READ, ///< read from the open row + READ_AND_PRECHARGE, ///< read from the open row and then close it + WRITE, ///< write this value to the open row + WRITE_AND_PRECHARGE, ///< write this value and then close the row + RETIRE_COMMAND, ///< ? + PRECHARGE, ///< close this open row + PRECHARGE_ALL, ///< precharge each bank in the rank, end of a refresh + ACTIVATE_ALL, ///< activate a row in each bank in the rank, half of a refresh + DRIVE_COMMAND, ///< ? + DATA_COMMAND, ///< for FBD, holds data instead of a command + CAS_WITH_DRIVE_COMMAND, ///< ? + REFRESH_ALL, ///< refresh all banks in the rank + SELF_REFRESH, ///< put the rank into self refresh mode + DESELECT, ///< command inhibit, does not allow new commands to be executed + NOOP, ///< the no operation command + INVALID_COMMAND ///< no command, or not a valid command at this time + }; + + protected: + + mutable CommandType commandType;///< what type of command this is + Transaction *hostTransaction; ///< backward pointer to the original transaction + unsigned length; ///< the burst length + + // assignment operator + Command &operator=(const Command &rhs); + + public: + + // constructors + explicit Command(const Command&); + explicit Command(); + explicit Command(Transaction *hostTransaction, const tick enqueueTime, const bool autoPrecharge, const unsigned commandLength, const CommandType commandType = READ); + explicit Command(Transaction *hostTransaction, const Address &addr, const tick enqueueTime, const bool autoPrecharge, const unsigned commandLength, const CommandType commandType = READ); + ~Command(); + + // accessors + CommandType getCommandType() const { return commandType; } + Transaction *getHost() const { return hostTransaction; } + unsigned getLength() const { return length; } + bool isActivate() const { return ((commandType == ACTIVATE) || (commandType == ACTIVATE_ALL)); } + bool isRead() const { return ((commandType == READ) || (commandType == READ_AND_PRECHARGE)); } + bool isWrite() const { return ((commandType == WRITE) || (commandType == WRITE_AND_PRECHARGE)); } + bool isPrecharge() const { return ((commandType == READ_AND_PRECHARGE) || (commandType == WRITE_AND_PRECHARGE) || (commandType == PRECHARGE)); } + bool isBasicPrecharge() const { return commandType == PRECHARGE; } + bool isRefresh() const { return (commandType == REFRESH_ALL); } + bool isReadOrWrite() const { return isRead() || isWrite(); } + + // mutators + Transaction *removeHost() { Transaction* host = hostTransaction; hostTransaction = NULL; return host; } + void setAutoPrecharge(const bool autoPrecharge) const; + + // friends + friend std::ostream &DRAMsimII::operator<<(std::ostream &,const Command &); + + // overloads + bool operator==(const Command& right) const; + bool operator!=(const Command& right) const; + }; + + std::ostream& operator<<(std::ostream&, const DRAMsimII::Command::CommandType&); +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/command.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/command.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,296 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include "command.hh" + +using std::cerr; +using std::endl; +using std::ostream; +using namespace DRAMsimII; + +////////////////////////////////////////////////////////////////////////// +/// @brief blank constructor for NULL commands +////////////////////////////////////////////////////////////////////////// +Command::Command(): +Event(), +commandType(RETIRE_COMMAND), +hostTransaction(NULL), +length(0) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief copy constructor +////////////////////////////////////////////////////////////////////////// +Command::Command(const Command &rhs): +Event(rhs), +commandType(rhs.commandType), +hostTransaction(rhs.hostTransaction ? new Transaction(*rhs.hostTransaction) : NULL), +length(rhs.length) +{ + assert(!hostTransaction || + (commandType == WRITE_AND_PRECHARGE && hostTransaction->isWrite()) || + (commandType == READ_AND_PRECHARGE && hostTransaction->isRead()) || + (commandType == READ && hostTransaction->isRead()) || + (commandType == WRITE && hostTransaction->isWrite()) || + (commandType == REFRESH_ALL && hostTransaction->isRefresh()) || + (commandType == ACTIVATE) || (commandType == PRECHARGE) + ); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor when an explicit address is given +////////////////////////////////////////////////////////////////////////// +Command::Command(Transaction *hostTransaction, const Address &addr, const tick enqueueTime, const bool autoPrecharge, const unsigned commandLength, const CommandType type): +Event(addr,enqueueTime), +hostTransaction((type == READ) ? hostTransaction : 0), +length(commandLength) +{ + if (type == READ) + { + switch (hostTransaction->getType()) + { + case Transaction::AUTO_REFRESH_TRANSACTION: + commandType = REFRESH_ALL; + break; + case Transaction::WRITE_TRANSACTION: + commandType = autoPrecharge ? WRITE_AND_PRECHARGE : WRITE; + break; + case Transaction::READ_TRANSACTION: + case Transaction::IFETCH_TRANSACTION: + commandType = autoPrecharge ? READ_AND_PRECHARGE : READ; + break; + default: + cerr << "Unknown transaction type, quitting." << endl; + exit(-21); + break; + } + } + else + { + assert(type == PRECHARGE || type == ACTIVATE); + commandType = type; + } + + assert((isWrite() && hostTransaction->isWrite()) || + (isRead() && hostTransaction->isRead()) || + (isActivate()) || (isPrecharge()) || + (isRefresh() && hostTransaction->isRefresh()) + ); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor when the hostTransaction's address should be used +////////////////////////////////////////////////////////////////////////// +Command::Command(Transaction *hostTransaction, const tick enqueueTime, const bool autoPrecharge, const unsigned commandLength, const CommandType type): +Event(hostTransaction->getAddress(),enqueueTime), +hostTransaction((type == READ) ? hostTransaction : NULL), +length(commandLength) +{ + if (type == READ) + { + switch (hostTransaction->getType()) + { + case Transaction::AUTO_REFRESH_TRANSACTION: + commandType = REFRESH_ALL; + break; + case Transaction::WRITE_TRANSACTION: + commandType = autoPrecharge ? WRITE_AND_PRECHARGE : WRITE; + break; + case Transaction::READ_TRANSACTION: + case Transaction::IFETCH_TRANSACTION: + commandType = autoPrecharge ? READ_AND_PRECHARGE : READ; + break; + default: + cerr << "Unknown transaction type, quitting." << endl; + exit(-21); + break; + } + } + else + { + assert(type == PRECHARGE || type == ACTIVATE); + commandType = type; + } + + assert((commandType == WRITE_AND_PRECHARGE && hostTransaction->isWrite()) || + (commandType == READ_AND_PRECHARGE && hostTransaction->isRead()) || + (commandType == READ && hostTransaction->isRead()) || + (commandType == WRITE && hostTransaction->isWrite()) || + (commandType == ACTIVATE) || (commandType == PRECHARGE) || + (commandType == REFRESH_ALL && hostTransaction->isRefresh()) + ); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief destructor +/// @details deletes the host transaction, thus unlinking the two +////////////////////////////////////////////////////////////////////////// +Command::~Command() +{ + //assert(!hostTransaction); + //if (hostTransaction) + { + delete hostTransaction; + // don't want to checkpoint this + //hostTransaction = NULL; + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief to convert CAS(W)+P <=> CAS(W) +/// @brief only affects CAS commands +////////////////////////////////////////////////////////////////////////// +void Command::setAutoPrecharge(const bool autoPrecharge) const +{ + switch (commandType) + { + case READ_AND_PRECHARGE: + case WRITE_AND_PRECHARGE: + if (!autoPrecharge) + commandType = (commandType == WRITE_AND_PRECHARGE) ? WRITE : READ; + break; + case READ: + case WRITE: + if (autoPrecharge) + commandType = (commandType == WRITE) ? WRITE_AND_PRECHARGE : READ_AND_PRECHARGE; + break; + default: + break; + } + + assert(isReadOrWrite() && hostTransaction); + + assert((isWrite() && hostTransaction->isWrite()) || + (isRead() && hostTransaction->isRead())); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief equality operator +////////////////////////////////////////////////////////////////////////// +bool Command::operator==(const Command& right) const +{ + if (commandType == right.commandType && startTime == right.startTime && + enqueueTime == right.enqueueTime && completionTime == right.completionTime && + length == right.length && this->Event::operator==(right)) + { + if ((hostTransaction && !right.hostTransaction) || + (!hostTransaction && right.hostTransaction)) + return false; + else if (!hostTransaction && !right.hostTransaction) + return true; + else if (*hostTransaction == *right.hostTransaction) + return true; + else + return false; + } + else + return false; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief inequality operator +////////////////////////////////////////////////////////////////////////// +bool Command::operator !=(const Command& right) const +{ + return !(*this == right); +} + +Command &Command::operator =(const Command &rhs) +{ + if (this == &rhs) + { + return *this; + } + length = rhs.length; + hostTransaction = rhs.hostTransaction; + commandType = rhs.commandType; + return *this; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief output stream operator for CommandTypes +////////////////////////////////////////////////////////////////////////// +ostream &DRAMsimII::operator<<(ostream &os, const Command::CommandType &command) +{ + switch(command) + { + case Command::ACTIVATE: + os << "RAS "; + break; + case Command::READ: + os << "CAS "; + break; + case Command::READ_AND_PRECHARGE: + os << "CAS+P "; + break; + case Command::WRITE: + os << "CASW "; + break; + case Command::WRITE_AND_PRECHARGE: + os << "CASW+P "; + break; + case Command::RETIRE_COMMAND: + os << "RETIRE "; + break; + case Command::PRECHARGE: + os << "PREC "; + break; + case Command::PRECHARGE_ALL: + os << "PREC_A "; + break; + case Command::ACTIVATE_ALL: + os << "RAS_A "; + break; + case Command::DRIVE_COMMAND: + os << "DRIVE "; + break; + case Command::DATA_COMMAND: + os << "DATA "; + break; + case Command::CAS_WITH_DRIVE_COMMAND: + os << "CAS+D "; + break; + case Command::REFRESH_ALL: + os << "REF "; + break; + case Command::SELF_REFRESH: + os << "SELREF"; + break; + case Command::DESELECT: + os << "DESLCT"; + break; + case Command::NOOP: + os << "NOOP "; + break; + case Command::INVALID_COMMAND: + os << "INVALD"; + break; + default: + os << "UNKWN"; + break; + } + return os; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief output stream operator +////////////////////////////////////////////////////////////////////////// +ostream &DRAMsimII::operator<<(ostream &os, const Command ¤tCommand) +{ + return os << currentCommand.commandType << (const Event&)(currentCommand); +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/enumTypes.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/enumTypes.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,162 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef ENUMTYPES_HH +#define ENUMTYPES_HH + +namespace DRAMsimII +{ + // This section defines the refresh policy + enum RefreshPolicy + { + NO_REFRESH, // do not simulate refresh operations + BANK_CONCURRENT, // + BANK_STAGGERED_HIDDEN, // + ONE_CHANNEL_ALL_RANK_ALL_BANK // standard refresh, close banks, issue refresh command to activate/precharge a bank based upon the DRAM refresh counter + }; + + enum RowBufferPolicy + { + AUTO_PAGE, // same as OPEN PAGE, but close page after timer expires + OPEN_PAGE, // keep page open indefinitely + OPEN_PAGE_AGGRESSIVE, // improve upon simple open page + CLOSE_PAGE, // close a row after an operation + CLOSE_PAGE_AGGRESSIVE // improve upon regular close page + }; + + + /// we can define various algorithms previously explored by Rixner, McKee et al. here. + enum CommandOrderingAlgorithm + { + STRICT_ORDER, ///< maintains original ordering + RANK_ROUND_ROBIN, ///< alternate ranks + BANK_ROUND_ROBIN, ///< keep same ranks as long as possible, go down banks + FIRST_AVAILABLE_AGE, ///< prioritizes whatever may issue soonest and uses age as a tie-breaker + FIRST_AVAILABLE_RIFF, ///< prioritizes whatever may issue soonest and uses prioritizes reads over writes + FIRST_AVAILABLE_QUEUE, ///< prioritizes whatever may issue soonest and uses queue pressure as the tie-breaker + COMMAND_PAIR_RANK_HOPPING ///< Patented stuff. davewang202@yahoo.com ;) + }; + + enum TransactionOrderingAlgorithm + { + RIFF, ///< read and instruction fetch first + STRICT ///< FIFO + }; + + enum DRAMType + { + DDR, + DDR2, + DDR3, + DRDRAM, + SDRAM + }; + + enum FileIOToken + { + BOFF, + FETCH, + INT_ACK, + IO_RD, + IO_WR, + LOCK_RD, + LOCK_WR, + MEM_RD, + MEM_WR, + MICROSECOND, + MILLISECOND, + NANOSECOND, + PICOSECOND, + SECOND, + addr_mapping_scheme_token, + auto_precharge_token, + average_interarrival_cycle_count, + bank_count_token, + channel_count_token, + channel_width_token, + clock_granularity_token, + col_count_token, + col_size_token, + command_ordering_algorithm_token, + comment_token, + cpu_to_memory_clock_ratio, + datarate_token, + decode_window_token, + dimm_count_token, + dm_per_dram_token, + dq_per_dram_token, + dqs_per_dram_token, + dram_type_token, + epoch_token, + frequency_spec_token, + input_file_token, + input_type_token, + output_file_token, + output_file_dir_token, + output_file_type_token, + p_dq_rd_token, + p_dq_wr_token, + p_dq_rd_oth_token, + p_dq_wr_oth_token, + per_bank_queue_depth_token, + posted_cas_token, + rank_count_token, + read_write_grouping_token, + refresh_policy_token, + riff_token, + row_buffer_management_policy_token, + row_count_token, + row_size_token, + seniority_age_limit_token, + t_al_token, + t_buffer_delay_token, + t_burst_token, + t_cac_token, + t_cas_token, + t_cmd_token, + t_dqs_token, + t_cwd_token, + t_faw_token, + t_ras_token, + t_rc_token, + t_rcd_token, + t_rfc_token, + t_refi_token, + t_rp_token, + t_rrd_token, + t_rtp_token, + t_rtrs_token, + t_wr_token, + t_wtr_token, + transaction_ordering_policy_token, + transaction_queue_depth_token, + unknown_token, + // power config tokens + vdd_token, + max_vcc_token, + idd0_token, + idd1_token, + idd2p_token, + idd2n_token, + idd3p_token, + idd3n_token, + idd4r_token, + idd4w_token, + idd5_token + }; + +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/event.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/event.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,109 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef EVENT_HH +#define EVENT_HH +#pragma once + +#include "Address.hh" + +namespace DRAMsimII +{ + /// @brief pending event queue + class Event + { + protected: + tick arrivalTime; ///< the time that this event was created + tick enqueueTime; ///< the time that this event was put into a queue + tick startTime; ///< when this actually started + tick completionTime; ///< when this finished + + const Address address; ///< the address that this event involves + + // constructors + Event(): + arrivalTime(0), + enqueueTime(0), + startTime(0), + completionTime(0), + address(0x0) + {} + + Event(const Address &add, const tick enqTime): + arrivalTime(0), + enqueueTime(enqTime), + startTime(0), + completionTime(0), + address(add) + {} + + Event(const tick arrTime,const Address &add): + arrivalTime(arrTime), + enqueueTime(0), + startTime(0), + completionTime(0), + address(add) + {} + + Event(const tick arrTime,const PhysicalAddress add): + arrivalTime(arrTime), + enqueueTime(0), + startTime(0), + completionTime(0), + address(add) + {} + + Event(const Event &rhs): + arrivalTime(rhs.arrivalTime), + enqueueTime(rhs.enqueueTime), + startTime(rhs.startTime), + completionTime(rhs.completionTime), + address(rhs.address) + {} + + public: + // destructors + virtual ~Event() {} + + // accessors + tick getArrivalTime() const { return arrivalTime; } + tick getEnqueueTime() const { return enqueueTime; } + tick getStartTime() const { return startTime; } + tick getCompletionTime() const { return completionTime; } + const Address &getAddress() const { return address; } + + // functions + tick getExecuteTime() const { return completionTime - startTime; } + tick getDelayTime() const { return startTime - enqueueTime; } + tick getLatency() const { return completionTime - enqueueTime; } + + // mutators + void setArrivalTime(const tick at) { arrivalTime = at; } + void setEnqueueTime(const tick et) { enqueueTime = et; } + void setStartTime(const tick st) { startTime = st; } + void setCompletionTime(const tick ct) { completionTime = ct; } + + // friends + friend std::ostream &DRAMsimII::operator<<(std::ostream &, const Event &); + + // overloads + bool operator==(const Event& right) const + { + return (arrivalTime == right.arrivalTime && enqueueTime == right.enqueueTime && startTime == right.startTime && completionTime == right.completionTime && address == right.getAddress()); + } + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/event.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/event.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,31 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include "event.hh" + +using namespace DRAMsimII; + +using std::ostream; + +ostream &DRAMsimII::operator<<(ostream &os, const Event& currentEvent) +{ + return os << currentEvent.address << + " Q[" << std::dec << currentEvent.enqueueTime << + "] S[" << std::dec << currentEvent.startTime << + "] E[" << std::dec << currentEvent.completionTime << + "] EXE[" << std::dec << currentEvent.getExecuteTime() << + "] LAT[" << std::dec << currentEvent.getLatency() << "]"; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/globals.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/globals.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,215 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef GLOBALS_HH +#define GLOBALS_HH +#pragma once +//#define __STDC_LIMIT_MACROS + +#include + +#include +#include +#include + +#include "enumTypes.hh" +#ifdef _MSC_VER +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef unsigned __int8 uint8_t; +#include +#define TICK_MAX _I64_MAX +#define TICK_MIN _I64_MIN +#define PHYSICAL_ADDRESS_MAX _UI64_MAX +#else +#include +#define TICK_MAX INT64_MAX +#define TICK_MIN INT64_MIN +#define PHYSICAL_ADDRESS_MAX UINT64_MAX +#endif + + +// global vars and functions +namespace DRAMsimII +{ + // class forward declarations + class Address; + class Event; + class Command; + class Transaction; + class System; + class Channel; + class SystemConfiguration; + class TimingSpecification; + class Settings; + class PowerConfig; + class Bank; + class Rank; + class Statistics; + + void unitTests(const Settings &settings); + + // overloaded insertion operator functions for printing various aspects of the dram system + std::ostream& operator<<(std::ostream&, const DRAMsimII::Bank&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::Channel&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::Command&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::Event&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::Address&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::Transaction&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::PowerConfig&); + std::ostream& operator<<(std::ostream&, const DRAMsimII::CommandOrderingAlgorithm); + std::ostream& operator<<(std::ostream&, const RowBufferPolicy); + std::ostream& operator<<(std::ostream&, const DRAMsimII::RefreshPolicy); + std::ostream& operator<<(std::ostream&, const DRAMsimII::TransactionOrderingAlgorithm); + + // will compute log2(n)=x for any n, where n=2**x + unsigned inline log2(unsigned input) + { + unsigned l2 = 0; + for (input >>= 1; input > 0; input >>= 1) + { + l2++; + } + return l2; + } + + template + inline T leastSigBit(T n) + { + return n & ~(n - 1); + } + + template + inline bool isPowerOf2(T n) + { + return n != 0 && leastSigBit(n) == n; + } + + inline int floorLog2(unsigned x) + { + assert(x > 0); + + int y = 0; + + if (x & 0xffff0000) { y += 16; x >>= 16; } + if (x & 0x0000ff00) { y += 8; x >>= 8; } + if (x & 0x000000f0) { y += 4; x >>= 4; } + if (x & 0x0000000c) { y += 2; x >>= 2; } + if (x & 0x00000002) { y += 1; } + + return y; + } + +#define EPSILON 1E-5 + + template + inline bool AlmostEqual(T nVal1, T nVal2) + { + return std::abs(nVal1 - nVal2) <= EPSILON * std::fabs(nVal1); + // see Knuth section 4.2.2 pages 217-218 + } + + // converts a string to its corresponding magnitude representation + double ascii2multiplier(const std::string &); + + // debug macros + + //#define DEBUG_FLAG + +#define DEBUG_COMMAND + +#define DEBUG_TRANSACTION + + //#define DEBUG_RAND + +#define DEBUGDRAMSIM + + //#define DEBUG_MIN_PROTOCOL_GAP + + //#define DEBUG_FLAG_2 +//#define NO_STREAMS + +#if !defined(NO_STREAMS) +//#define STATS_LOG(X) systemConfig.statsOutStream << X << std::endl; +#define STATS_LOG(X) +#else +#define STATS_LOG(X) +#endif + +#if !defined(NO_STREAMS) +#define POWER_LOG(X) systemConfig.statsOutStream << X << std::endl; +#else +#define POWER_LOG(X) +#endif + +#if defined(DEBUG) && defined(M5DEBUG) && !defined(NDEBUG) && !defined(NO_STREAMS) // compiler should declare this +#define VERILOG_LOG(X) systemConfig.verilogOutStream << X << std::endl; +#else +#define VERILOG_LOG(X) +#endif + +#if defined(DEBUG) && defined(M5DEBUG) && !defined(NDEBUG) && !defined(NO_STREAMS) // compiler should declare this +#define M5_TIMING(X) ds->getTimingStream() << X << std::endl; +#define M5_TIMING2(X) memory->ds->getTimingStream() << X << std::endl; +#define M5_TIMING3(X) memory->ds->getTimingStream() << X; +#else +#define M5_TIMING(X) +#define M5_TIMING2(X) +#define M5_TIMING3(X) +#endif + +#if defined(DEBUG) && defined(M5DEBUG) && !defined(NDEBUG) // compiler should declare this +#define M5_TIMING_LOG(X) systemConfig.timingOutStream << X << std::endl; +#define M5_DEBUG(X) X; +#else +#define M5_TIMING_LOG(X) +#define M5_DEBUG(X) +#endif + +#if defined(DEBUG) && defined(DEBUG_TRANSACTION) && !defined(NDEBUG) && !defined(NO_STREAMS) // compiler should declare this +#define DEBUG_TRANSACTION_LOG(X) systemConfig.timingOutStream << X << std::endl; +#else +#define DEBUG_TRANSACTION_LOG(X) +#endif + + +#if defined(DEBUG) && defined(DEBUG_COMMAND) && !defined(NDEBUG) && !defined(NO_STREAMS) +#define DEBUG_COMMAND_LOG(X) systemConfig.timingOutStream << X << std::endl; +#else +#define DEBUG_COMMAND_LOG(X) +#endif + +#if defined(DEBUG) && defined(DEBUGDRAMSIM) && !defined(NDEBUG) && !defined(NO_STREAMS) +#define DEBUG_TIMING_LOG(X) systemConfig.timingOutStream << X << std::endl; +#define DEBUG_LOG(X) cerr << X << endl; +#else +#define DEBUG_TIMING_LOG(X) +#define DEBUG_LOG(X) +#endif + +#ifdef _MSC_VER + typedef unsigned __int64 PhysicalAddress; + typedef __int64 tick; +#else + typedef uint64_t PhysicalAddress; + typedef int64_t tick; +#endif + +#define PI 3.1415926535897932384626433832795 + +#define POOL_SIZE 64 +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/m5-dramSystem.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/m5-dramSystem.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,150 @@ +#ifndef M5_DRAMSYSTEM +#define M5_DRAMSYSTEM +#pragma once + +#include "mem/physical.hh" +#include "mem/tport.hh" +#include "base/random.hh" +#include "params/M5dramSystem.hh" // this gets autogenerated and creates the params struct +#include "sim/async.hh" +#include "base/statistics.hh" +#include "base/callback.hh" +#include "base/stats/types.hh" +#include "base/trace.hh" + +#ifdef WIN32 +#include +#else +#include +#endif + +#include + +#include "System.hh" +#include "Settings.hh" +#include "globals.hh" + +using DRAMsimII::tick; + +//#define PROCESS_BEFORE + + +/// @brief wrapper class to allow M5 to work with DRAMsimII +class M5dramSystem: public PhysicalMemory +{ + // taken from m5 interface +private: + + /// allows event-based simulation, scheduling wake ups for the simulator + /// @details derived class that allows the wrapper class to interact with the event model + class TickEvent : public Event + { + + private: + + M5dramSystem *memory; ///< pointer to the wrapper class so static functions may see the single instance + + public: + // constructor + TickEvent(M5dramSystem *c); + + void process(); ///< process to call when a tick event happens + + const char *description(); ///< return a string that describes this event + + void schedule(tick when) { mainEventQueue.schedule(this,when);} + + void deschedule() { mainEventQueue.deschedule(this);} + }; + + /// allows this to receive packets and attach to a bus + class MemoryPort : public SimpleTimingPort + { + private: + + M5dramSystem *memory; ///< pointer to the wrapper class so static functions may see the single instance + + Random randomGen; ///< random number generator to help when simulating delays + + public: + + MemoryPort(const std::string &_name, M5dramSystem *_memory); + + // accessor that was needed to allow the memory system to handle incoming transactions + void doSendTiming(PacketPtr pkt, Tick t) + { + schedSendTiming(pkt,t); + } + + protected: + + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvFunctional(PacketPtr pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop); + + virtual int deviceBlockSize(); + + virtual bool recvTiming(PacketPtr pkt); + }; + + class ExitEvent: public Callback + { + DRAMsimII::System *memory; + + public: + ExitEvent(DRAMsimII::System *val) { memory = val; } + virtual void process() { delete memory; } + }; + + + +protected: + + TickEvent tickEvent; ///< instance of TickEvent to allow the wrapper to receive/send events to the global queue + std::vector ports; ///< ports to send/recv data to other simulator components + std::queue > finishedTransactions; ///< channels will return values as they finish transactions + + int lastPortIndex; ///< the last port accessed + typedef std::vector::iterator PortIterator; + DRAMsimII::System *ds; ///< pointer to the DRAMsimII class + int cpuRatio; ///< the ratio of the cpu frequency to the memory frequency + + std::tr1::unordered_map transactionLookupTable; + unsigned currentTransactionID; + + unsigned int drain(Event *de); + void virtual init(); + +public: + bool movement; + unsigned outstandingPackets; + + typedef M5dramSystemParams Params; ///< the parameters used to initialize the memory system object + + M5dramSystem(const Params *); ///< constructor + + // allows other components to get a port which they can send packets to + virtual Port *getPort(const std::string &if_name, int idx = -1); + + void getAddressRanges(AddrRangeList &resp, bool &snoop); + + int getCPURatio() const { return cpuRatio; } ///< returns the ratio of the cpu frequency to the memory frequency + + //float getInvCPURatio() const { return invCpuRatio; } ///< returns the ratio of the memory frequency to the cpu frequency + + void moveToTime(tick now); + + virtual ~M5dramSystem(); + + virtual void regStats(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/m5-dramSystem.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/m5-dramSystem.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,813 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include +#include +#include +#include +#include "enumTypes.hh" +#include "m5-dramSystem.hh" + +using std::ofstream; +using std::stringstream; +using std::dec; +using std::hex; +using std::endl; +using std::cerr; +using std::string; +using std::ostream; +using std::vector; +using std::pair; +using std::queue; +using DRAMsimII::Settings; +using DRAMsimII::PhysicalAddress; +using DRAMsimII::Transaction; +using DRAMsimII::System; +using DRAMsimII::Address; +using ::Packet; + +//#define TESTNEW + +////////////////////////////////////////////////////////////////////////// +/// @brief stuff taken from PhysicalMemory.cc +////////////////////////////////////////////////////////////////////////// +M5dramSystem *M5dramSystemParams::create() +{ + return new M5dramSystem(this); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns the address range available in this device +////////////////////////////////////////////////////////////////////////// +void M5dramSystem::getAddressRanges(AddrRangeList &resp, bool &snoop) +{ + snoop = false; + resp.clear(); + resp.push_back(RangeSize(start(), params()->range.size())); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief drain all commands from the system in preparation to switch timing modes +////////////////////////////////////////////////////////////////////////// +unsigned int M5dramSystem::drain(::Event *de) +{ + ds->resetToTime((curTick + getCPURatio() - 1) / getCPURatio()); + + // copied from PhysicalMemory::drain(Event *de) + int count = 0; + for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) + { + count += (*pi)->drain(de); + } + + if (count) + changeState( Draining); + else + changeState( Drained); + return count; +} + +////////////////////////////////////////////////////////////////////// +/// @brief move all channels in this system to the specified time +/// @details tells the channels that nothing arrived since the last wakeup and +/// now, so go do whatever would have happened during this time and return finished transactions +/// note that this should probably only process one event per channel at most so that +/// finished transactions can be returned in a timely fashion +/// @author Joe Gross +/// @param now the current time +////////////////////////////////////////////////////////////////////// +void M5dramSystem::moveToTime(const tick now) +{ + // if transactions are returned, then send them back, + // else if time is not brought up to date, then a refresh transaction has finished + movement = ds->moveToTime(now); + + ds->getPendingTransactions(finishedTransactions); + + while (finishedTransactions.size() > 0) + { + pair currentValue = finishedTransactions.front(); + finishedTransactions.pop(); + + assert(currentValue.first < UINT_MAX); + std::tr1::unordered_map::iterator packetIterator = + transactionLookupTable.find(currentValue.first); + assert(packetIterator != transactionLookupTable.end()); + Packet *packet = packetIterator->second; + transactionLookupTable.erase(packetIterator); + outstandingPackets--; + + if (packet) + { + assert(packet->isRead() || packet->isWrite()); +#if 0 + for (std::tr1::unordered_map::const_iterator packetIt = transactionLookupTable.begin(); packetIt != transactionLookupTable.end(); packetIt++) + { + if (packet->getAddr() == packetIt->second->getAddr()) + { + cerr << "match at " << std::hex << packet->getAddr() << endl; + } + } +#endif + + bool needsResponse = +#ifdef PROCESS_BEFORE + true; +#else + packet->needsResponse(); + doAtomicAccess(packet); +#endif + + if (needsResponse) + { + assert(!packet->isWrite()); + assert(curTick < static_cast (currentValue.second + * getCPURatio())); + + DPRINTF( + MemoryAccess, + "<-T [@%d] [+%d]", + static_cast (currentValue.second * getCPURatio()), + static_cast (currentValue.second * getCPURatio() + - curTick)); + + ports[lastPortIndex]->doSendTiming(packet, + static_cast (currentValue.second * getCPURatio())); + assert(lastPortIndex == 0); +#if 0 + static tick returnCount; + + if (++returnCount % 100000 == 0) + { + time_t rawtime; + time(&rawtime); + struct tm *timeinfo = localtime(&rawtime); + //char *timeString = asctime(timeinfo); + //char *pos = strchr(timeString,'\n'); + //*(pos-1) = NULL; + cerr << "\r" << std::dec << returnCount / 100000 << " " + << asctime(timeinfo) << "\r"; + } +#endif + } + else + { + assert(!packet->isRead()); + DPRINTF(MemoryAccess, "xT [%x]", packet->getAddr()); + + delete packet; + } + } + else + { +#ifndef PROCESS_BEFORE + cerr << "warn: no Packet found for corresponding transaction" + << endl; +#endif + } + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief builds a M5dramSystem object +/// @details looks for the settings file and constructs a dramSystem object from that +/// @author Joe Gross +/// @param p the M5 parameters object to extract parameters from +/// @return a new M5dramSystem object +////////////////////////////////////////////////////////////////////// +M5dramSystem::M5dramSystem(const Params *p) : + PhysicalMemory(p), tickEvent(this), ports(1), lastPortIndex(0), ds(NULL), + cpuRatio(0), transactionLookupTable(), currentTransactionID(0), + movement(true), outstandingPackets(0) +{ + Settings settings; + + // initialize the settings according to the autogenerated python interface + settings.setKeyValue("dramtype", p->dramType); + + settings.clockGranularity = p->clockGranularity; + settings.channelCount = p->channels; + settings.dimmCount = p->dimms; + settings.rankCount = p->ranks; + settings.bankCount = p->banks; + settings.rowCount = p->rows; + settings.columnCount = p->columns; + settings.setKeyValue("addressMappingScheme", + p->physicalAddressMappingPolicy); + settings.setKeyValue("rowBufferPolicy", p->rowBufferPolicy); + settings.rowSize = p->rowSize; + settings.columnSize = p->columnSize; + settings.channelWidth = p->channelWidth; + settings.postedCAS = p->postedCas; + settings.setKeyValue("refreshPolicy", p->autoRefreshPolicy); + settings.setKeyValue("commandOrderingAlgorithm", + p->commandOrderingAlgorithm); + settings.setKeyValue("transactionOrderingAlgorithm", + p->transactionOrderingAlgorithm); + settings.perBankQueueDepth = p->perBankQueueDepth; + settings.setKeyValue("transactionOrderingAlgorithm", + p->transactionOrderingAlgorithm); + settings.transactionQueueDepth = p->transactionQueueDepth; + settings.decodeWindow = p->decodeWindow; + settings.readWriteGrouping = p->readWriteGrouping; + settings.autoPrecharge = p->autoPrecharge; + //timing parameters + settings.tBufferDelay = p->tBufferDelay; + settings.tBurst = p->tBurst; + settings.tCAS = p->tCAS; + settings.tCMD = p->tCMD; + settings.tCWD = p->tCWD; + settings.tFAW = p->tFAW; + settings.tRAS = p->tRAS; + settings.tRC = p->tRC; + settings.tRCD = p->tRCD; + settings.tRFC = p->tRFC; + settings.tRRD = p->tRRD; + settings.tRP = p->tRP; + settings.tRTP = p->tRTP; + settings.tRTRS = p->tRTRS; + settings.tWR = p->tWR; + settings.tWTR = p->tWTR; + settings.tAL = p->tAL; + settings.tREFI = p->tREFI; + settings.seniorityAgeLimit = p->seniorityAgeLimit; + // power settings + settings.PdqRD = p->PdqRD; + settings.PdqWR = p->PdqWR; + settings.PdqRDoth = p->PdqRDoth; + settings.PdqWRoth = p->PdqWRoth; + settings.DQperDRAM = p->DQperDRAM; + settings.DQSperDRAM = p->DQSperDRAM; + settings.DMperDRAM = p->DMperDRAM; + settings.frequencySpec = p->frequencySpec; + settings.maxVCC = p->maxVCC; + settings.VDD = p->systemVDD; + settings.IDD0 = p->IDD0; + settings.IDD2P = p->IDD2P; + settings.IDD2N = p->IDD2N; + settings.IDD3N = p->IDD3N; + settings.IDD3P = p->IDD3P; + settings.IDD4R = p->IDD4R; + settings.IDD4W = p->IDD4W; + settings.IDD5 = p->IDD5A; + + settings.epoch = p->epoch; + + ds = new System(settings); + + cpuRatio = (int) round(((float) SimClock::Frequency + / ((float) ds->Frequency()))); + + DPRINTF(MemoryAccess, "%s", *ds); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns a port for other devices to connect to +////////////////////////////////////////////////////////////////////////// +Port *M5dramSystem::getPort(const string &if_name, int idx) +{ + // Accept request for "functional" port for backwards compatibility + // with places where this function is called from C++. I'd prefer + // to move all these into Python someday. + if (if_name == "functional") + { + return new MemoryPort(csprintf("%s-functional", name()), this); + } + + if (if_name != "port") + { + panic("PhysicalMemory::getPort: unknown port %s requested", if_name); + } + + if (idx >= ports.size()) + { + ports.resize(idx + 1); + } + + if (ports[idx] != NULL) + { + panic("PhysicalMemory::getPort: port %d already assigned", idx); + } + + MemoryPort *port = new MemoryPort(csprintf("%s-port%d", name(), idx), this); + + lastPortIndex = idx; + ports[idx] = port; + DPRINTF(MemoryAccess, "called M5dramSystem::getPort"); + return port; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief initializes the ports of this object +////////////////////////////////////////////////////////////////////////// +void M5dramSystem::init() +{ + if (ports.size() == 0) + { + fatal("M5dramSystem object %s is unconnected!", name()); + } + + for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) + { + if (*pi) + (*pi)->sendStatusChange(Port::RangeChange); + } +} + +void M5dramSystem::regStats() +{ + registerExitCallback(new ExitEvent(ds)); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief deletes the DRAMsim object +////////////////////////////////////////////////////////////////////////// +M5dramSystem::~M5dramSystem() +{ + DPRINTF(MemoryAccess, "M5dramSystem destructor"); + + cerr.flush(); + delete ds; +} + +////////////////////////////////////////////////////////////////////////// +/// @brief dumps the memory array to a file as part of a systemwide checkpoint +////////////////////////////////////////////////////////////////////////// +void M5dramSystem::serialize(ostream &os) +{ + gzFile compressedMem; + string filename = name() + ".physmem"; + + SERIALIZE_SCALAR(filename); + + // write memory file + string thefile = Checkpoint::dir() + "/" + filename.c_str(); + + int fd = creat(thefile.c_str(), 0664); + if (fd < 0) + { + perror("creat"); + fatal("Can't open physical memory checkpoint file '%s'\n", filename); + } + + compressedMem = gzdopen(fd, "wb"); + + if (compressedMem == NULL) + { + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + } + + if (gzwrite(compressedMem, pmemAddr, params()->range.size()) + != params()->range.size()) + { + fatal("Write failed on physical memory checkpoint file '%s'\n", + filename); + } + + if (gzclose(compressedMem)) + { + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); + } +} + +////////////////////////////////////////////////////////////////////////// +/// @brief restores the memory array after resuming from a checkpoint +////////////////////////////////////////////////////////////////////////// +void M5dramSystem::unserialize(Checkpoint *cp, const std::string §ion) +{ + gzFile compressedMem; + long *tempPage; + long *pmem_current; + uint64_t curSize; + uint32_t bytesRead; + const int chunkSize = 16384; + + string filename; + + UNSERIALIZE_SCALAR(filename); + + filename = cp->cptDir + "/" + filename; + + // mmap memoryfile + int fd = open(filename.c_str(), O_RDONLY); + + if (fd < 0) + { + perror("open"); + fatal("Can't open physical memory checkpoint file '%s'", filename); + } + + compressedMem = gzdopen(fd, "rb"); + + if (compressedMem == NULL) + { + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + } + + // unmap file that was mmaped in the constructor + // This is done here to make sure that gzip and open don't muck with our + // nice large space of memory before we reallocate it + munmap((char*) pmemAddr, params()->range.size()); + + pmemAddr = (uint8_t *) mmap(NULL, params()->range.size(), PROT_READ + | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + + if (pmemAddr == (void *) MAP_FAILED) + { + perror("mmap"); + fatal("Could not mmap physical memory!\n"); + } + + curSize = 0; + tempPage = (long*) malloc(chunkSize); + if (tempPage == NULL) + fatal("Unable to malloc memory to read file %s\n", filename); + /* Only copy bytes that are non-zero, so we don't give the VM system hell */ + while (curSize < params()->range.size()) + { + bytesRead = gzread(compressedMem, tempPage, chunkSize); + if (bytesRead != chunkSize && bytesRead != params()->range.size() + - curSize) + fatal("Read failed on physical memory checkpoint file '%s'" + " got %d bytes, expected %d or %d bytes\n", filename, + bytesRead, chunkSize, params()->range.size() - curSize); + + assert(bytesRead % sizeof(long) == 0); + + for (int x = 0; x < bytesRead / sizeof(long); x++) + { + if (*(tempPage + x) != 0) + { + pmem_current = (long*) (pmemAddr + curSize + x * sizeof(long)); + *pmem_current = *(tempPage + x); + } + } + curSize += bytesRead; + } + + free(tempPage); + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); +} + +////////////////////////////////////////////////////////////////////// +/// @brief receive a packet and do something with it +/// @details receive a packet, check it to make sure it's valid, then try to enqueue it in DS2 +/// @author Joe Gross +/// @param packet the pointer to the memory transaction packet +/// @return true if the packet is accepted, false otherwise +////////////////////////////////////////////////////////////////////// +bool M5dramSystem::MemoryPort::recvTiming(PacketPtr packet) +{ +#if defined(M5DEBUG) && defined(DEBUG) && !defined(NDEBUG) + using std::setw; + stringstream ss; + ss << "+recvTiming [" << std::dec << curTick << "] "; + // calculate the time elapsed from when the transaction started + ss << setw(2) << (packet->isRead() ? "Rd" : ""); + ss << setw(2) << (packet->isWrite() ? "Wr" : ""); + //M5_TIMING2((packet->isRequest() ? "Rq" : ""); + ss << setw(3) << (packet->isInvalidate() ? "Inv" : ""); + ss << setw(3) << (packet->isResponse() ? "Rsp" : ""); + ss << setw(2) << (packet->isReadWrite() ? "RW" : ""); + ss << setw(2) << (packet->isError() ? "Er" : ""); + ss << setw(2) << (packet->isPrint() ? "Pr" : ""); + ss << setw(2) << (packet->needsExclusive() ? "Ex" : ""); + ss << setw(2) << (packet->needsResponse() ? "NR" : ""); + ss << setw(2) << (packet->isLLSC() ? "LL" : ""); + ss << " 0x" << hex << packet->getAddr() << endl; + ss << " s[0x" << hex << packet->getSize() << "]"; + DPRINTF(MemoryAccess,"%s",ss.str()); +#endif + ////////////////////////////////////////////////////////////////////////// + + // everything that reaches the memory system should be a request of some sort + assert(packet->isRequest()); + + if (packet->memInhibitAsserted()) + { + // snooper will supply based on copy of packet + // still target's responsibility to delete packet + delete packet; + return true; + } + + bool needsResponse = packet->needsResponse(); + + // must look at packets that need to affect the memory system + if (packet->isRead() || packet->isWrite()) + { + assert((packet->isRead() && packet->needsResponse()) + || (!packet->isRead() && !packet->needsResponse())); + assert(!packet->wasNacked()); + + //assert(memory->ds->pendingTransactionCount() == 0); + + // turn packet around to go back to requester if response expected + Address addr(packet->getAddr()); + + // attempt to add the transaction to the memory system + if (memory->ds->isFull(addr.getChannel())) + { +#ifdef M5DEBUG + static tick numberOfDelays = 0; + if (++numberOfDelays % 100000 == 0) + cerr << "\rdelays = " << numberOfDelays; +#endif +#if 0 + // if the packet did not fit, then send a NACK + // tell the sender that the memory system is full until it hears otherwise + // and do not send packets until that time + pkt->result = Packet::Nacked; + short memID = pkt->getDest(); + pkt->makeTimingResponse(); + pkt->setSrc(memID); + doSendTiming(pkt,0); +#endif + + // http://m5.eecs.umich.edu/wiki/index.php/Memory_System + // keep track of the fact that the memory system is waiting to hear that it is ok to send again + // as well as what channel it is likely to retry to (make sure there is room before sending the OK) + //memory->needRetry = true; + //memory->mostRecentChannel = trans->getAddresses().getChannel(); + //memory->mostRecentChannel = addr.getChannel(); + //delete trans; + DPRINTF(MemoryAccess, + "Wait for retry before sending more to ch[%d]", + addr.getChannel()); + return false; + } + else + { + tick currentMemCycle = (curTick + memory->getCPURatio() - 1) + / memory->getCPURatio(); + + // move channels to current time so that calculations based on current channel times work + // should also not start/finish any commands, since this would happen at a scheduled time + // instead of now + memory->moveToTime(currentMemCycle); + + int threadID = + packet->req->hasContextId() ? packet->req->contextId() : 0; + + PhysicalAddress pC = packet->req->hasPC() ? packet->req->getPC() + : 0; + + Transaction::TransactionType + packetType = + packet->req->isPrefetch() ? Transaction::PREFETCH_TRANSACTION + : (packet->req->isInstFetch() ? Transaction::READ_TRANSACTION + : (packet->isRead() ? Transaction::READ_TRANSACTION + : (packet->isWrite() ? Transaction::WRITE_TRANSACTION + : Transaction::READ_TRANSACTION))); + + assert(packet->isRead() ^ (Transaction::WRITE_TRANSACTION + == packetType)); + assert(packet->isWrite() ^ (Transaction::READ_TRANSACTION + == packetType)); + +#ifndef NDEBUG + bool result = +#endif + memory->ds->enqueue(new Transaction(packetType, + currentMemCycle, packet->getSize() / 8, + packet->getAddr(), pC, threadID, + memory->currentTransactionID)); + + (memory->outstandingPackets)++; + + assert(result == true); + + assert(memory->transactionLookupTable.find( + memory->currentTransactionID) + == memory->transactionLookupTable.end()); + +#ifdef PROCESS_BEFORE + bool needsResponse = packet->needsResponse(); + memory->doAtomicAccess(packet); + memory->transactionLookupTable[memory->currentTransactionID] = needsResponse ? packet : NULL; + if (!needsResponse) + delete packet; +#else + memory->transactionLookupTable[memory->currentTransactionID] + = packet; +#endif + + // make sure not to use any that are already being used + while (memory->transactionLookupTable.find( + memory->currentTransactionID) + != memory->transactionLookupTable.end()) + { + memory->currentTransactionID = (memory->currentTransactionID + + 1) % UINT_MAX; + } + + // find out when the next event is + tick next = memory->ds->nextTick(); + assert(next < TICK_MAX); + assert(next > currentMemCycle); + assert(next * memory->getCPURatio() > curTick); + + // deschedule and reschedule yourself to wake at the next event time + if (memory->tickEvent.scheduled()) + memory->tickEvent.deschedule(); + + memory->tickEvent.schedule(next * memory->getCPURatio()); + + DPRINTF(MemoryAccess, "-recvTiming sch[%d]", next); + } + } + else + { + recvAtomic(packet); + if (needsResponse) + { + assert(packet->isResponse()); + schedSendTiming(packet, curTick + 1); + } + else + { + delete packet; + } + } + //upgrade or invalidate + //else if (!packet->isRead() && packet->needsResponse()) +#if 0 + else if (packet->isInvalidate()) + { + assert(packet->cmd != MemCmd::SwapReq); + assert(!packet->isRead() && packet->needsResponse()); + if (packet->needsResponse()) + { + packet->makeAtomicResponse(); + schedSendTiming(packet,curTick + 1); + } + } + else + { + assert(!packet->needsResponse()); + M5_TIMING2("warn: packet not needing response."); + + if (packet->cmd != MemCmd::UpgradeReq) + { + cerr << "warn: deleted packet, not upgradereq, not write, needs no resp" << endl; + delete packet->req; + delete packet; + } + else + { + cerr << "warn: not upgrade request" << endl; + } + } +#endif + + return true; +} + +////////////////////////////////////////////////////////////////////// +/// @brief builds a memory port to interact with other components +/// @param _name the friendly name of this object +/// @param _memory the pointer to the M5dramSystem object that will be backing this object +/// @return a new memoryPort object associated with a dramSystem object +////////////////////////////////////////////////////////////////////// +M5dramSystem::MemoryPort::MemoryPort(const string &_name, M5dramSystem *_memory) : + SimpleTimingPort(_name, _memory), memory(_memory) +{ +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns the block size for this module +////////////////////////////////////////////////////////////////////////// +int M5dramSystem::MemoryPort::deviceBlockSize() +{ + return memory->deviceBlockSize(); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief replies to requests when in functional mode +/// @details simply returns a memory request instantly when running in atomic mode \n +/// does not affect the underlying memory system +////////////////////////////////////////////////////////////////////////// +void M5dramSystem::MemoryPort::recvFunctional(PacketPtr pkt) +{ + if (!checkFunctional(pkt)) + { + // Default implementation of SimpleTimingPort::recvFunctional() + // calls recvAtomic() and throws away the latency; we can save a + // little here by just not calculating the latency. + memory->doFunctionalAccess(pkt); + } +} + +////////////////////////////////////////////////////////////////////// +/// @brief receive a read/write request to be handled without a timing model +/// @author Joe Gross +/// @param pkt a packet containing a transaction +/// @return +////////////////////////////////////////////////////////////////////// +Tick M5dramSystem::MemoryPort::recvAtomic(PacketPtr pkt) +{ + //M5_TIMING_LOG("M5dramSystem recvAtomic()"); + + // because this is simply a read or write, go to the M5 memory object exclusively + // and ignore the timing from DRAMsimII + /// @todo have DS2 also account for this but avoid doing timing calculations + return memory->doAtomicAccess(pkt); +} + +////////////////////////////////////////////////////////////////////// +/// @brief receive a change of status +/// @param status the new status for this port +////////////////////////////////////////////////////////////////////// +void M5dramSystem::MemoryPort::recvStatusChange(Port::Status status) +{ + memory->recvStatusChange(status); +} + +////////////////////////////////////////////////////////////////////// +/// @brief get the range of addresses that this device will accept +/// @param resp the range reference to be completed +/// @param snoop whether this is snooped +////////////////////////////////////////////////////////////////////// +void M5dramSystem::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, + bool &snoop) +{ + memory->getAddressRanges(resp, snoop); +} + +////////////////////////////////////////////////////////////////////// +/// @brief wake up via the global event queue +/// @details wake up and perform some action at this time, then determine when the next wakeup time should be +/// inserts the memory system into the event queue and handles being woken by it +/// @author Joe Gross +////////////////////////////////////////////////////////////////////// +void M5dramSystem::TickEvent::process() +{ + tick currentMemCycle = (curTick + memory->getCPURatio() - 1) + / memory->getCPURatio(); + + DPRINTF(MemoryAccess, "+process [%d]", currentMemCycle); + + // move memory channels to the current time + memory->moveToTime(currentMemCycle); +#if 0 + if (!memory->movement) + { + cerr << "no r/w bytes, outstanding: " << memory->outstandingPackets << ", "; + cerr << (memory->transactionLookupTable.empty() ? "is empty," : "has outstanding transactions,"); + cerr << (memory->ds->isEmpty() ? " reports empty" : " reports not empty") << endl; + } +#endif + + // deschedule yourself + if (memory->tickEvent.scheduled()) + memory->tickEvent.deschedule(); + + // determine the next time to wake up + tick next = memory->ds->nextTick(); + + assert(next > currentMemCycle); + assert(next * memory->getCPURatio() > curTick); + + schedule(next * memory->getCPURatio()); + + DPRINTF(MemoryAccess, "-process sch[%d]", next); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief the TickEvent constructor +/// @details sets a pointer to the underlying DRAMsim memory system +////////////////////////////////////////////////////////////////////////// +M5dramSystem::TickEvent::TickEvent(M5dramSystem *c) : + Event(CPU_Tick_Pri), memory(c) +{ +} + +////////////////////////////////////////////////////////////////////////// +/// @brief returns a description of this component +////////////////////////////////////////////////////////////////////////// +const char *M5dramSystem::TickEvent::description() +{ + return "m5dramSystem tick event"; +} + diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/main.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/main.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,70 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . +//#define _CRTDBG_MAP_ALLOC +#include +#include + +//#include +//#include + +#include "globals.hh" +#include "System.hh" + +using std::cerr; +using std::endl; + +using namespace DRAMsimII; + +int main(int argc,char **argv, char *envp[]) +{ + cerr << "Command line:"; + for (int i = 0; i < argc; ++i) + { + cerr << ' '; + char *hasSpace = strchr(argv[i],' '); + if (hasSpace != NULL) + cerr << '"'; + cerr << argv[i]; + if (hasSpace != NULL) + cerr << '"'; + } + cerr << endl; + std::string b = "ASDFasdfASDfasdf"; + std::string a; + + for (std::string::const_iterator i = b.begin(), end = b.end(); i < end; i++) + { + a += tolower(*i); + } +#if 0 + const Settings settings(argc, argv); +#endif + const Settings settings(); + +#ifdef DEBUG + //cerr << TICK_MAX << endl; + //cerr << PHYSICAL_ADDRESS_MAX << endl; + //DRAMsimII::unitTests(settings); +#endif + { + //System ds(settings); + //ds.runSimulations(); + } + //_CrtDumpMemoryLeaks(); + return 0; +} + + diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/powerConfig.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/powerConfig.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,136 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef POWERCONFIG_H +#define POWERCONFIG_H +#pragma once + +#include "globals.hh" +#include "enumTypes.hh" +#include "Settings.hh" + +#include +#include + +namespace DRAMsimII +{ + /// @brief stores power configuration parameters for this DRAM system necessary to calculate power consumed + /// @author Joe Gross + class PowerConfig + { + protected: + const float VDD; ///< the current voltage + const float VDDmax; ///< the maximum voltage as specified by the manufacturer's datasheets + const int IDD0; ///< Operating Current: One Bank Active-Precharge in mA + const int IDD1; ///< one bank ACT to read to Pre current, in mA + const int IDD2P; ///< Precharge Power-Down Current (CKE=0), in mA + const int IDD2N; ///< Precharge Standby Current (CKE=1), in mA + const int IDD3P; ///< Active Power-Down Current (CKE=0), in mA + const int IDD3N; ///< Active Standby Current (CKE=1), in mA + const int IDD4R; ///< Operating Burst Read Current in mA + const int IDD4W; ///< Operating Burst Write Current in mA + const int IDD5; ///< Burst Refresh Current in mA + + const double PdsACT; ///< power for ACT/PRE commands + const double PdsACT_STBY; ///< background power for active standby + const double PdsPRE_STBY; ///< background power for precharge standby + const double PdsACT_PDN; ///< background power for active powerdown + const double PdsPRE_PDN; ///< background power for precharge powerdown + const double PdsRD; ///< read power + const double PdsWR; ///< write power + + const double voltageScaleFactor; ///< derating based on voltage + const double frequencyScaleFactor; ///< derating based on frequency + + // termination power, based on system design + const double PdstermW; ///< termination power for writes + const double PdqRD; ///< power per DQ, determined by system design + const double PdqWR; ///< power per DQ write + const double PdqRDoth; ///< power per other DQ, read + const double PdqWRoth; ///< power per other DQ, write + + // pins on the DRAM devices + const unsigned DQperDRAM; ///< number of DQ per DRAM + const unsigned DQSperDRAM;///< number of DQS per DRAM + const unsigned DMperDRAM; ///< number of DM per DRAM + const unsigned DQperRank; ///< the number of pins per rank, useful to know how many DRAMs there are per rank + + const unsigned frequency; ///< frequency of the system + const unsigned specFrequency; ///< frequency specified in the data sheets + + const unsigned tBurst; ///< burst length in cycles + const unsigned tRC; ///< tRC according to the data sheet, in cycles + const unsigned tRAS; ///< tRAS according to the data sheet + + tick lastCalculation; ///< the last time at which a power calculation was made + + + public: + // constructors + PowerConfig(const Settings& settings); + ~PowerConfig(); + + // accessors + float getVDD() const { return VDD; } + float getVDDmax() const { return VDDmax; } + unsigned getFrequency() const { return frequency; } + unsigned getSpecFrequency() const { return specFrequency; } + tick getLastCalculation() const { return lastCalculation; } + double getPdsACT_STBY() const { return PdsACT_STBY; } + double getPdsACT_PDN() const { return PdsACT_PDN; } + double getPdsPRE_STBY() const { return PdsPRE_STBY; } + double getPdsPRE_PDN() const { return PdsPRE_PDN; } + double getPdsACT() const { return PdsACT; } + double getPdqRD() const { return PdqRD; } + double getPdqWR() const { return PdqWR; } + double getPdsRD() const { return PdsRD; } + double getPdsWR() const { return PdsWR; } + double getPdqRDoth() const { return PdqRDoth; } + double getPdqWRoth() const { return PdqWRoth; } + unsigned gettRC() const { return tRC; } + unsigned getDQperDRAM() const { return DQperDRAM; } + unsigned getDQSperDRAM() const { return DQSperDRAM; } + unsigned getDMperDRAM() const { return DMperDRAM; } + unsigned getDevicesPerRank() const { return DQperRank; } + int getIDD0() const { return IDD0; } + int getIDD1() const { return IDD1; } + int getIDD2N() const { return IDD2N; } + int getIDD2P() const { return IDD2P; } + int getIDD3N() const { return IDD3N; } + int getIDD3P() const { return IDD3P; } + int getIDD4R() const { return IDD4R; } + int getIDD4W() const { return IDD4W; } + int getIDD5() const { return IDD5; } + unsigned gettBurst() const { return tBurst; } + unsigned gettRAS() const { return tRAS; } + double getVoltageScaleFactor() const { return voltageScaleFactor;} + double getFrequencyScaleFactor() const { return frequencyScaleFactor; } + void resetToTime(const tick newTime) { lastCalculation = newTime; } + + // mutators + void setLastCalculation(const tick lastTime) { lastCalculation = lastTime; } + + // overloads + bool operator==(const PowerConfig& right) const; + PowerConfig &operator=(const PowerConfig& right); + friend std::ostream& operator<<(std::ostream& os, const PowerConfig& pc); + + private: + + PowerConfig(); + }; +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/powerConfig.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/powerConfig.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,182 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include +#include +#include +#include +#include + +#include "powerConfig.hh" + +using namespace DRAMsimII; + +PowerConfig::PowerConfig(const Settings& settings): +VDD(settings.VDD), +VDDmax(settings.maxVCC), +IDD0(settings.IDD0), +IDD1(settings.IDD1), +IDD2P(settings.IDD2P), +IDD2N(settings.IDD2N), +IDD3P(settings.IDD3P), +IDD3N(settings.IDD3N), +IDD4R(settings.IDD4R), +IDD4W(settings.IDD4W), +IDD5(settings.IDD5), +PdsACT((settings.IDD0 - ((settings.IDD3N * settings.tRAS + settings.IDD2N * (settings.tRC - settings.tRAS))/settings.tRC)) * settings.VDD), +PdsACT_STBY(settings.IDD3N * settings.VDD), +PdsPRE_STBY(settings.IDD2N * settings.VDD), +PdsACT_PDN(settings.IDD3P * settings.VDD), +PdsPRE_PDN(settings.IDD2P * settings.VDD), +PdsRD((settings.IDD4R - settings.IDD3N) * settings.VDD), +PdsWR((settings.IDD4W - settings.IDD3N) * settings.VDD), +voltageScaleFactor((settings.VDD / settings.maxVCC) * (settings.VDD / settings.maxVCC)), +frequencyScaleFactor((double)settings.dataRate / (double)settings.frequencySpec), +PdstermW(settings.PdqWR * (settings.DQperDRAM + settings.DQSperDRAM + settings.DMperDRAM)), +PdqRD(settings.PdqRD), +PdqWR(settings.PdqWR), +PdqRDoth(settings.PdqRDoth), +PdqWRoth(settings.PdqWRoth), +DQperDRAM(settings.DQperDRAM), +DQSperDRAM(settings.DQSperDRAM), +DMperDRAM(settings.DMperDRAM), +DQperRank(settings.channelWidth * 8 / DQperDRAM), +frequency(settings.dataRate), +specFrequency(settings.frequencySpec), +tBurst(settings.tBurst), +tRC(settings.tRC), +tRAS(settings.tRAS), +lastCalculation(0) +{} + +PowerConfig::~PowerConfig() +{} + +// no arg constructor for unit testing and deserialization +PowerConfig::PowerConfig(): +VDD(-1.0F), +VDDmax(-1.0F), +IDD0(INT_MAX), +IDD1(INT_MAX), +IDD2P(INT_MAX), +IDD2N(INT_MAX), +IDD3P(INT_MAX), +IDD3N(INT_MAX), +IDD4R(INT_MAX), +IDD4W(INT_MAX), +IDD5(INT_MAX), +PdsACT(-1.0F), +PdsACT_STBY(-1.0F), +PdsPRE_STBY(-1.0F), +PdsACT_PDN(-1.0F), +PdsPRE_PDN(-1.0F), +PdsRD(-1.0F), +PdsWR(-1.0F), +voltageScaleFactor(-1.0), +frequencyScaleFactor(-1.0), +PdstermW(-1.0F), +PdqRD(-1.0F), +PdqWR(-1.0F), +PdqRDoth(-1.0F), +PdqWRoth(-1.0F), +DQperDRAM(UINT_MAX), +DQSperDRAM(UINT_MAX), +DMperDRAM(UINT_MAX), +DQperRank(UINT_MAX), +frequency(UINT_MAX), +specFrequency(UINT_MAX), +tBurst(UINT_MAX), +tRC(UINT_MAX), +tRAS(UINT_MAX), +lastCalculation(TICK_MAX) +{} + +bool PowerConfig::operator==(const PowerConfig& rhs) const +{ + return (AlmostEqual(VDD, rhs.VDD) && AlmostEqual(VDDmax, rhs.VDDmax) && IDD0 == rhs.IDD0 && + IDD2P == rhs.IDD2P && IDD2N == rhs.IDD2N && IDD3P == rhs.IDD3P && IDD1 == rhs.IDD1 && + IDD3N == rhs.IDD3N && IDD4R == rhs.IDD4R && IDD4W == rhs.IDD4W && + IDD5 == rhs.IDD5 && AlmostEqual(PdsACT, rhs.PdsACT) && AlmostEqual(PdsACT_STBY, rhs.PdsACT_STBY) && + AlmostEqual(PdsRD, rhs.PdsRD) && + AlmostEqual(PdsACT_PDN, rhs.PdsACT_PDN) && + AlmostEqual(PdsPRE_STBY, rhs.PdsPRE_STBY) && + AlmostEqual(PdsPRE_PDN, rhs.PdsPRE_PDN) && + AlmostEqual(PdsWR, rhs.PdsWR) && + AlmostEqual(PdstermW, rhs.PdstermW) && + AlmostEqual(PdqRD, rhs.PdqRD) && + AlmostEqual(PdqWR, rhs.PdqWR) && + AlmostEqual(PdqRDoth, rhs.PdqRDoth) && + AlmostEqual(PdqWRoth, rhs.PdqWRoth) && DQperDRAM == rhs.DQperDRAM && DQSperDRAM == rhs.DQSperDRAM && + DMperDRAM == rhs.DMperDRAM && DQperRank == rhs.DQperRank && frequency == rhs.frequency && + specFrequency == rhs.specFrequency && tBurst == rhs.tBurst && tRC == rhs.tRC && + tRAS == rhs.tRAS && lastCalculation==rhs.lastCalculation && + AlmostEqual(voltageScaleFactor, rhs.voltageScaleFactor) && + AlmostEqual(frequencyScaleFactor, rhs.frequencyScaleFactor)); +} + +PowerConfig& PowerConfig::operator =(const PowerConfig &rhs) +{ + const_cast(VDD) = rhs.VDD; + const_cast(VDDmax) = rhs.VDDmax; + const_cast(IDD0) = rhs.IDD0; + const_cast(IDD1) = rhs.IDD1; + const_cast(IDD2P) = rhs.IDD2P; + const_cast(IDD2N) = rhs.IDD2N; + const_cast(IDD3P) = rhs.IDD3P; + const_cast(IDD3N) = rhs.IDD3N; + const_cast(IDD4R) = rhs.IDD4R; + const_cast(IDD4W) = rhs.IDD4W; + const_cast(IDD5) = rhs.IDD5; + const_cast(PdsACT) = rhs.PdsACT; + const_cast(PdsACT_STBY) = rhs.PdsACT_STBY; + const_cast(PdsPRE_STBY) = rhs.PdsPRE_STBY; + const_cast(PdsACT_PDN) = rhs.PdsACT_PDN; + const_cast(PdsPRE_PDN) = rhs.PdsPRE_PDN; + const_cast(PdsRD) = rhs.PdsRD; + const_cast(PdsWR) = rhs.PdsWR; + const_cast(voltageScaleFactor) = rhs.voltageScaleFactor; + const_cast(frequencyScaleFactor) = rhs.frequencyScaleFactor; + const_cast(PdstermW) = rhs.PdstermW; + const_cast(PdqRD) = rhs.PdqRD; + const_cast(PdqWR) = rhs.PdqWR; + const_cast(PdqRDoth) = rhs.PdqRDoth; + const_cast(PdqWRoth) = rhs.PdqWRoth; + + const_cast(DQperDRAM) = rhs.DQperDRAM; + const_cast(DQSperDRAM) = rhs.DQSperDRAM; + const_cast(DMperDRAM) = rhs.DMperDRAM; + const_cast(DQperRank) = rhs.DQperRank; + const_cast(frequency) = rhs.frequency; + const_cast(specFrequency) = rhs.specFrequency; + const_cast(tBurst) = rhs.tBurst; + const_cast(tRC) = rhs.tRC; + const_cast(tRAS) = rhs.tRAS; + lastCalculation = rhs.lastCalculation; + + return *this; +} + +std::ostream& DRAMsimII::operator<<(std::ostream& os, const PowerConfig& pc) +{ + using std::endl; + + os << "PowerConfig" << endl; + os << "VDD" << pc.VDD << endl; + os << "VDDmax" << pc.VDDmax << endl; + os << "IDD0" << pc.IDD0 << endl; + os << "IDD2p" << pc.IDD2P << endl; + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/queue.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/queue.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,447 @@ +// Copyright (C) 2008 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef QUEUE_HH +#define QUEUE_HH + +#include +#include +#include + +namespace DRAMsimII +{ + // forward declaration + template + class Queue; + + template + std::ostream& operator<<(std::ostream&, const Queue&); + + /// @brief the queue template class, rhs circular queue + /// @details push/pop are O(1) operations, while random insertions are O(n) operations + template + class Queue + { + private: + unsigned count; ///< how many elements are in the queue now + unsigned head; ///< the point where items will be inserted + unsigned tail; ///< the point where items will be removed + std::vector entry; ///< the circular queue + const bool pool; ///< whether or not this is a pool + + public: + explicit Queue(): count(0), head(0), tail(0), entry(0), pool(false) + {} + + /// @brief copy constructor + /// @details copy the existing queue, making copies of each element + explicit Queue(const Queue& rhs): + count(rhs.count), + head(rhs.head), + tail(rhs.tail), + entry(rhs.entry.size()), + pool(rhs.pool) + { + entry.reserve(rhs.entry.size()); + + for (unsigned i = 0; i < rhs.count; i++) + { + assert(rhs.at(i) != NULL); + // attempt to copy the contents of this queue + entry[(head + i) % entry.size()] = new T(*rhs.at(i)); + } + + for (unsigned i = 0; i < count; i++) + assert(at(i) && rhs.at(i)); + } + + /// @brief constructor + /// @details create rhs queue of rhs certain size and optionally fill it with empty elements + /// @param size the depth of the circular queue + /// @param preallocate whether or not to fill the queue with blank elements, defaults to false + explicit Queue(const unsigned size, const bool preallocate = false): + count(0), + head(0), + tail(0), + entry(size), + pool(preallocate) + { + entry.reserve(size); + + if (preallocate) + { + while (!isFull()) + { + push(::new T()); + } + } + } + + /// @brief destructor + /// @details remove the elements and delete them before removing the rest of the queue + ~Queue() + { + while (T* value = pop()) + { + if (pool) + ::delete value; + else + delete value; + } + for (typename std::vector::iterator i = entry.begin(); i != entry.end(); ++i) + assert(*i == NULL); + } + + /// @brief change the size of the queue + /// @details remove all existing elements and create rhs new queue of rhs different size + /// @param size the depth to set the queue to + /// @param preallocate whether or not to fill the queue with blank elements, defaults to false + void resize(unsigned size, bool preallocate = false) + { + count = 0; + head = 0; + tail = 0; + entry.resize(size); + pool = preallocate; + + if (preallocate) + { + while (count < entry.size()) + push(::new T); + } + else + { + for (unsigned i = 0 ; i < size; i++) + { + entry[i] = NULL; + } + } + } + + /// @brief add an item to the back of the queue + /// @details issue rhs warning if the element is null + /// return false if the queue is already full add to the tail pointer + /// position and remove from the head + /// @param item the item to be inserted into the queue + bool push(T *item) + { + assert(item != NULL); + if (count == entry.size()) + return false; + else if (item == NULL) + { + std::cerr << "Input pointer is NULL" << std::endl; + return false; + } + else + { + count++; + entry[tail] = item; + tail = (tail + 1) % (unsigned)entry.size(); //advance tail_ptr + return true; + } + } + + /// @brief add an item to the front of the queue efficiently + bool push_front(T *item) + { + assert(item != NULL); + if (count == entry.size()) + return false; + else if (item == NULL) + { + std::cerr << "Input pointer is NULL" << std::endl; + return false; + } + else + { + count++; + head = ((int)head > 0) ? head - 1 : (unsigned)entry.size() - 1; + entry[head] = item; + return true; + } + } + + /// @brief remove the item at the front of the queue + /// @return the item at the head of the queue, NULL if the queue is empty + T *pop() + { + if (count == 0) + return NULL; + else + { + count--; + + T *item = entry[head]; + + entry[head] = NULL; // ensure this item isn't rhs part of the queue anymore + + head = (head + 1) % (unsigned)entry.size(); //advance head_ptr + + return item; + } + } + + /// @brief remove the item from the tail of the queue + /// @return the item formerly at the tail of the queue, or NULL if the queue is empty + /// TODO untested + T* popback() + { + if (count == 0) + return NULL; + else + { + T* theItem = entry[tail]; + entry[tail] = NULL; + count--; + tail = tail - 1 >= 0 ? tail - 1 : (unsigned)entry.size() - 1; // decrease the tail pointer + return theItem; + + } + } + + /// @brief get rhs pointer to the item at the head of the queue + /// @details similar to peek() + /// @return rhs pointer to the item at the front of the queue, or NULL if the queue is empty + const inline T *front() const + { +#ifdef DEBUG + assert(count > 0 ? entry[head] != NULL : entry[head] == NULL); +#endif + return entry[head]; + //return count ? entry[head] : NULL; + } + + /// @brief to get rhs pointer to the item most recently inserted into the queue + const T* back() const + { + return count ? entry[(head + count - 1) % (unsigned)entry.size()] : NULL; + } + + /// @brief get the number of entries currently in this queue + inline unsigned size() const + { + return count; + } + + /// @brief get the number of entries this queue can hold + inline unsigned depth() const + { + return (unsigned)entry.size(); + } + + /// @brief get rhs pointer to the item at this offset without removing it + T *read(const int offset) const + { + if ((offset >= (int)count) || (offset < 0)) + return NULL; + else + return entry[(head + offset) % (unsigned)entry.size()]; + } + + /// @brief release item into pool + /// @details This is useful for when the queue holds preallocated pieces of memory + /// and one would like to store them when they are not in use + void releaseItem(T *item) + { + assert(pool); + //#pragma omp critical + { + +#if 1 + // look around to see if this was already in there, slows things down a lot, so use only when this might be a problem + for (typename std::vector::iterator i = entry.begin(); i != entry.end(); ++i) + { + assert(item != *i); + } +#endif + assert(pool); + if (!push(item)) + { + ::delete item; + item = NULL; + } + } + } + + /// @brief treat this queue like an object pool and retrieve an item + /// @details if there is no available object, then create one + /// @return rhs new item which may or may not be initialized + T *acquireItem() + { + assert(pool); + T* newItem; + //#pragma omp critical + { + if (count == 0) + { + newItem = ::new T; + assert(newItem != NULL); + } + else + newItem = pop(); + } + return newItem; + } + + /// @brief this function makes this queue rhs non-FIFO queue. + /// @details Allows insertion into the middle or at any end + bool insert(T *item, const int offset) + { + assert(offset <= (int)count); + + if (count == entry.size()) + return false; + + else if (item == NULL) + { + std::cerr << "Attempting to insert NULL into queue" << std::endl; + return false; + //_exit(2); + } + else + { + // move everything back by one unit + for (int i = count - 1 ; i >= offset ; --i) + entry[(head + i + 1) % entry.size()] = entry[(head + i) % (unsigned)entry.size()]; + + count++; + + entry[(head + offset) % (unsigned)entry.size()] = item; + + tail = (tail + 1) % (unsigned)entry.size(); // advance tail_ptr + + return true; + } + } + + T *remove(const int offset) + { + assert(offset <= (int)count && offset >= 0); + + // first get the item + T *item = entry[(head + offset) % (unsigned)entry.size()]; + count--; + + tail = (head + count) % (unsigned)entry.size(); + + // then shift the other items up + for (unsigned i = (unsigned)offset; i < count; i++) + { + entry[(head + i) % entry.size()] = entry[(head + i + 1) % (unsigned)entry.size()]; + } + + entry[(head + count) % entry.size()] = NULL; + + return item; + } + + /// @brief the number of entries still available in this queue + unsigned freecount() const + { + assert(entry.size() >= count); + return (unsigned)(entry.size() - count); + } + + /// @brief whether or not there is room for any more entries in this queue + bool isFull() const + { + return (entry.size() == count); + } + + /// @brief whether or not this queue has no entries in it + bool isEmpty() const + { + return (count == 0); + } + + const T* at(const unsigned value) const + { + assert(value < count); + return read(value); + } + + const T* operator[](const unsigned value) const + { + return at(value); + } + + /// @brief do rhs comparison to see if the queues are equal + bool operator==(const Queue& rhs) const + { + if (count == rhs.count && entry.size() == rhs.entry.size() && + head == rhs.head && tail == rhs.tail && pool == rhs.pool) + { + for (unsigned i = 0; i < count; i++) + { + if (at(i) && rhs.at(i)) + { + if (!(*(at(i)) == *(rhs.at(i)))) + return false; + } + else if (at(i) != NULL && rhs.at(i) == NULL) + return false; + else if (at(i) == NULL && rhs.at(i) != NULL) + return false; + } + return true; + } + else + return false; + } + + /// @brief assignment operator overload + /// @details moves all the objects from the rhs object to the lhs object + Queue &operator=(const Queue &rhs) + { + if (&rhs == this) + return *this; + + count = rhs.count; + head = rhs.head; + tail = rhs.tail; + const_cast(pool) = rhs.pool; + + entry.resize(rhs.entry.size()); + + for (unsigned i = 0; i < rhs.count; i++) + { + assert(rhs.at(i)); + + entry[(head + i) % entry.size()] = new T(*(rhs.at(i))); + } + + return *this; + } + + friend std::ostream& operator<< (std::ostream&, const Queue&); + }; + + template + std::ostream& operator<<(std::ostream& in, const Queue& theQueue) + { + in << "Queue S[" << std::dec << theQueue.entry.size() << "] C[" << std::dec << theQueue.count << "] H[" << std::dec << theQueue.head << "] T[" << std::dec << theQueue.tail << "] P[" << theQueue.pool << "]" << std::endl; + if (theQueue.entry.size() > 0) + { + for (unsigned i = 0; i < theQueue.count; i++) + { + in << "\t" << theQueue[i] << std::endl; + } + } + return in; + } +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/transaction.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/transaction.hh Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,90 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#ifndef TRANSACTION_HH +#define TRANSACTION_HH + +#include "globals.hh" +#include "Address.hh" +#include "queue.hh" +#include "event.hh" +#include "base/fast_alloc.hh" // M5 fast allocator class + + +#include + +namespace DRAMsimII +{ + /// @brief a request to read or write some portion of memory, atomically + class Transaction: public Event, public FastAlloc + { + public: + enum TransactionType + { + IFETCH_TRANSACTION, + WRITE_TRANSACTION, + READ_TRANSACTION, + PREFETCH_TRANSACTION, + AUTO_REFRESH_TRANSACTION, + PER_BANK_REFRESH_TRANSACTION, + AUTO_PRECHARGE_TRANSACTION, + CONTROL_TRANSACTION + }; + + protected: + + const TransactionType type; ///< transaction type + const unsigned length; ///< the number of words requested + tick decodeTime; ///< when the transaction was split up into several commands + PhysicalAddress PC; ///< the program counter associated with this transaction + int threadNum; ///< the thread number associated with this transaction + const unsigned originalTransaction; ///< utility counter id in the event that this transaction represents another version of a transaction + + public: + + // accessors + tick getDecodeTime() const { return decodeTime; } ///< get its decode time + tick getDecodeDelay() const { return decodeTime - enqueueTime; } ///< get the time it took before this transaction was decoded + PhysicalAddress getProgramCounter() const { return PC; } ///< get the program counter for this transaction + unsigned getLength() const { return length; } ///< get the number of bytes requested + TransactionType getType() const { return type; } ///< get what type of transaction this is + unsigned getOriginalTransaction() const { return originalTransaction; } ///< get the external transaction that this is a representation for + bool isRead() const { return ((type == IFETCH_TRANSACTION) || (type == READ_TRANSACTION) || (type == PREFETCH_TRANSACTION)); } + bool isWrite() const { return (type == WRITE_TRANSACTION); } + bool isRefresh() const { return (type == AUTO_REFRESH_TRANSACTION); } + + // mutators + void setDecodeTime(const tick value) { decodeTime = value; } + + // constructors + explicit Transaction(const TransactionType transType, const tick arrivalTime, const unsigned burstLength, const Address &address, PhysicalAddress PC, int threadNumber, const unsigned originalTrans = UINT_MAX); + explicit Transaction(const TransactionType transType, const tick arrivalTime, const unsigned burstLength, const Address &address, const unsigned originalTrans = UINT_MAX); + explicit Transaction(const TransactionType transType, const tick arrivalTime, const unsigned burstLength, const PhysicalAddress physicalAddress, PhysicalAddress PC, int threadNumber, const unsigned originalTrans = UINT_MAX); + explicit Transaction(const Transaction &rhs); + explicit Transaction(); + + public: + friend std::ostream &operator<<(std::ostream &, const Transaction &); + + bool operator==(const Transaction& right) const; + bool operator!=(const Transaction& right) const; + }; + + std::ostream& operator<<(std::ostream&, const DRAMsimII::Transaction::TransactionType); + std::ostream& operator<<(std::ostream&, const DRAMsimII::Transaction&); + +} +#endif diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/transaction.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/transaction.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,153 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include "transaction.hh" + +#include + +using std::ostream; +using std::dec; +using std::hex; +using std::setw; +using namespace DRAMsimII; + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor to make a transaction with no values set +////////////////////////////////////////////////////////////////////////// +Transaction::Transaction(): +Event(), +type(CONTROL_TRANSACTION), +length(0), +decodeTime(0), +PC(0), +threadNum(0), +originalTransaction(UINT_MAX) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor to use when creating a transaction based on a request that has a possible program counter and thread ID +////////////////////////////////////////////////////////////////////////// +Transaction::Transaction(const TransactionType transType, const tick arrivalTime,const unsigned burstLength, const Address &address, PhysicalAddress programCounter, int threadNumber, const unsigned originalTrans): +Event(arrivalTime,address), +type(transType), +length(burstLength), +decodeTime(0), +PC(programCounter), +threadNum(threadNumber), +originalTransaction(originalTrans) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor to use when creating a transaction that is linked to a native transaction +////////////////////////////////////////////////////////////////////////// +Transaction::Transaction(const TransactionType transType, const tick arrivalTime, const unsigned burstLength, const Address &address, const unsigned originalTrans): +Event(arrivalTime,address), +type(transType), +length(burstLength), +decodeTime(0), +PC(0), +threadNum(0), +originalTransaction(originalTrans) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief copy constructor to duplicate a transaction +////////////////////////////////////////////////////////////////////////// +Transaction::Transaction(const Transaction &rhs): +Event(rhs), +type(rhs.type), +length(rhs.length), +decodeTime(rhs.decodeTime), +PC(rhs.PC), +threadNum(rhs.threadNum), +originalTransaction(rhs.originalTransaction) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief constructor to create a transaction with a certain size, enqueue time, attributes, and pointer to encapsulated external transaction +////////////////////////////////////////////////////////////////////////// +Transaction::Transaction(const TransactionType transType, const tick arrivalTime, const unsigned burstLength, const PhysicalAddress physicalAddress, PhysicalAddress programCounter, int threadNumber, const unsigned originalTrans): +Event(arrivalTime,physicalAddress), +type(transType), +length(burstLength), +decodeTime(0), +PC(programCounter), +threadNum(threadNumber), +originalTransaction(originalTrans) +{} + +////////////////////////////////////////////////////////////////////////// +/// @brief comparison operator definition +////////////////////////////////////////////////////////////////////////// +bool Transaction::operator==(const Transaction& rhs) const +{ + return (type == rhs.type && length == rhs.length && + decodeTime == rhs.decodeTime && this->Event::operator==(rhs) && originalTransaction == rhs.originalTransaction); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief inequality operator +////////////////////////////////////////////////////////////////////////// +bool Transaction::operator !=(const Transaction& rhs) const +{ + return !(*this == rhs); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief insertion operator overload, prints details of the transaction +////////////////////////////////////////////////////////////////////////// +ostream &DRAMsimII::operator<<(ostream &os, const Transaction& thisTransaction) +{ + return os << thisTransaction.getType() << ((Event&)thisTransaction); +} + +////////////////////////////////////////////////////////////////////////// +/// @brief insertion operator for transactiontype, decodes and prints the transaction type +////////////////////////////////////////////////////////////////////////// +ostream &DRAMsimII::operator<<(ostream &os, const Transaction::TransactionType type) +{ + switch (type) + { + case Transaction::IFETCH_TRANSACTION: + os << "FETCH "; + break; + case Transaction::WRITE_TRANSACTION: + os << "WRITE "; + break; + case Transaction::READ_TRANSACTION: + os << "READ "; + break; + case Transaction::PREFETCH_TRANSACTION: + os << "PREFET "; + break; + case Transaction::AUTO_REFRESH_TRANSACTION: + os << "REFRSH "; + break; + case Transaction::PER_BANK_REFRESH_TRANSACTION: + os << "BNKREF "; + break; + case Transaction::AUTO_PRECHARGE_TRANSACTION: + os << "AUTOPR "; + break; + case Transaction::CONTROL_TRANSACTION: + os << "CTRL "; + break; + default: + os << "UNKWN "; + break; + } + return os; +} diff -r 634d88f0dbd4 -r 846e12a6426c src/mem/dramsimii-m5/src/unitTest.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/dramsimii-m5/src/unitTest.cc Wed Nov 17 18:41:58 2010 -0500 @@ -0,0 +1,948 @@ +// Copyright (C) 2010 University of Maryland. +// This file is part of DRAMsimII. +// +// DRAMsimII is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// DRAMsimII is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with DRAMsimII. If not, see . + +#include + +#include "globals.hh" +#include "transaction.hh" +#include "Address.hh" +#include "queue.hh" +#include "System.hh" +#include "Settings.hh" +#include "SystemConfiguration.hh" + +#include +#include + + +#ifndef WIN32 +// allow dynamic library linking +#define BOOST_TEST_DYN_LINK +#endif + +// undefine these to allow the explicit main +#define BOOST_TEST_MODULE testA +#define BOOST_TEST_MAIN + +#include +#include +#include +#include + +using namespace DRAMsimII; +using namespace boost::serialization; + +//BOOST_CLASS_TRACKING(DRAMsimII::System,boost::serialization::track_never) +//BOOST_CLASS_TRACKING(PowerConfig,track_always) +//BOOST_CLASS_TRACKING(TimingSpecification,track_always) +//BOOST_CLASS_TRACKING(SystemConfiguration,track_always) +//BOOST_CLASS_TRACKING(Bank,track_always) +//BOOST_CLASS_TRACKING(TimingSpecification,track_never) +//BOOST_CLASS_TRACKING(SystemConfiguration,track_never) + +//BOOST_CLASS_TRACKING(DRAMsimII::Queue,boost::serialization::track_never) + +template +void backup(const char *filename,const T& item) +{ + std::ofstream outStream(filename); + boost::archive::text_oarchive oa(outStream); + + oa << item; + outStream.close(); +} + +template +void backup(const char *filename,const T * const item) +{ + std::ofstream outStream(filename); + boost::archive::text_oarchive oa(outStream); + + oa << item; + outStream.close(); +} + +template +void restore(const char *filename, T& item) +{ + std::ifstream ifs(filename,std::ios::binary); + boost::archive::text_iarchive ia(ifs); + ia >> item; + + ifs.close(); +} + +template +void restore(const char *filename, T* &item) +{ + std::ifstream ifs(filename,std::ios::binary); + boost::archive::text_iarchive ia(ifs); + ia >> item; + + ifs.close(); +} + + +using namespace boost::unit_test; +using namespace boost::unit_test::framework; +using std::vector; + +BOOST_AUTO_TEST_CASE( serialize_vector) +{ + + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + Address::initialize(settings); + { + + vector
vecA(18); + + vecA[9] = new Address(0xfaceffee % Address::maxAddress()); + + backup("serializeVectorTest",vecA); + + vector
vecB; + + restore("serializeVectorTest",vecB); + + BOOST_CHECK(vecA == vecB); + } + { + vector vecA(18); + + backup("serializeVectorTest2",vecA); + + vector vecB; + + restore("serializeVectorTest2",vecB); + + BOOST_CHECK(vecA == vecB); + } +} + +BOOST_AUTO_TEST_CASE( rank_copy_test) +{ + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + const TimingSpecification timing(settings); + const SystemConfiguration sysConfig(settings); + + Rank rk1(settings, timing, sysConfig); + Rank rk2(rk1); + + BOOST_CHECK_EQUAL(rk1,rk2); + + std::vector rkV1(1,Rank(settings,timing,sysConfig)); + std::vector rkV2(rkV1); + + BOOST_CHECK(rkV1 == rkV2); + +} + +BOOST_AUTO_TEST_CASE( circular_buffer_test) +{ + std::srand(std::time(0)); + const int size = std::rand() % 500; + const int iterations = (std::rand() % 750) + 500; + boost::circular_buffer cb1(size); + + BOOST_ASSERT(cb1.empty()); + + for (tick i = 0; i <= iterations; i++) + { + BOOST_ASSERT(cb1.size() == std::min(i,static_cast(size))); + cb1.push_front(i*i); + BOOST_CHECK(cb1.front() == static_cast(i*i)); + if (i >= size) + BOOST_CHECK(cb1.back() == (i - size + 1) * (i - size + 1)); + else + BOOST_CHECK(cb1.back() == 0); + } + + BOOST_CHECK(cb1.front() == static_cast((iterations) * (iterations))); + BOOST_CHECK(cb1.back() == static_cast((iterations - size + 1) * (iterations - size + 1))); + + boost::circular_buffer cb2(cb1); + BOOST_CHECK(cb1 == cb2); + boost::circular_buffer cb3 = cb1; + BOOST_CHECK(cb1 == cb3); + + boost::circular_buffer cb4(5); + boost::circular_buffer cb5(cb4); + BOOST_CHECK(cb5 == cb4); + + backup("circularBufferTest",cb1); + boost::circular_buffer cb6(3); + restore("circularBufferTest",cb6); + BOOST_CHECK(cb1 == cb6); +} + +BOOST_AUTO_TEST_CASE( test_transactions) +{ + Settings s(master_test_suite().argc, (char **)master_test_suite().argv); + s.channelCount = 4; + s.rankCount = 4; + s.bankCount = 16; + s.rowCount = 1024; + s.columnCount = 16384; + s.dramType = DDR2; + s.addressMappingScheme = Address::CLOSE_PAGE_BASELINE; + Address::initialize(s); + Address addr(0x00fdbca3); + Address addr2(0x0000f0d0); + + Transaction *t = new Transaction(); + + Transaction *t2 = new Transaction(Transaction::READ_TRANSACTION,1337,64,addr, 0xdeadbeef, 2000, 44); + + BOOST_CHECK(*t != *t2); + + Transaction *t3 = new Transaction(*t2); + + BOOST_CHECK(*t2 == *t3); + + Transaction *t4 = new Transaction(Transaction::WRITE_TRANSACTION,234234223,33, addr2, 33); + + delete t3; + + t3 = new Transaction(*t4); + + //Transaction t5 = *t4; + + BOOST_CHECK(*t3 == *t4); + + //BOOST_CHECK(*t4 == t5); + + t4->setArrivalTime(234230); + t4->setEnqueueTime(234232); + t4->setDecodeTime(234234); + t4->setStartTime(234238); + t4->setCompletionTime(234242); + BOOST_CHECK(t4->getExecuteTime() == 4); + BOOST_CHECK(t4->getDelayTime() == 6); + BOOST_CHECK(t4->getLatency() == 10); + BOOST_CHECK(t4->getDecodeDelay() == 2); + + std::cerr << *t << std::endl; + std::cerr << *t2 << std::endl; + std::cerr << *t3 << std::endl; + std::cerr << *t4 << std::endl; + + +} + +BOOST_AUTO_TEST_CASE( test_commands) +{ + Settings s(master_test_suite().argc, (char **)master_test_suite().argv); + s.channelCount = 4; + s.rankCount = 4; + s.bankCount = 16; + s.rowCount = 1024; + s.columnCount = 16384; + s.dramType = DDR2; + s.addressMappingScheme = Address::CLOSE_PAGE_BASELINE; + Address::initialize(s); + Address addr(0x00fdfbca); + Address addr2(0x0000f0ad0); + + Command *t = new Command(); + + Transaction *trans = new Transaction(Transaction::READ_TRANSACTION,3400,8,addr2,42); + + Command *t2 = new Command(trans,1234,false,4); + + BOOST_CHECK(t2->getAddress() == trans->getAddress()); + + BOOST_CHECK(*t != *t2); + + Command *t3 = new Command(*t2); + + BOOST_CHECK(*t2 == *t3); + + Command *t4 = new Command(trans,1235,false,4); + + delete t3; + + t3 = new Command(*t4); + + //Transaction t5 = *t4; + //delete t3->removeHost(); + //t4->removeHost(); + t3->setEnqueueTime(1234); + + BOOST_CHECK(*t3 != *t4); + + t4->setEnqueueTime(1234); + + BOOST_CHECK(*t3 == *t4); + + //BOOST_CHECK(*t4 == t5); + + t4->setArrivalTime(234230); + t4->setEnqueueTime(234232); + t4->setStartTime(234238); + t4->setCompletionTime(234242); + BOOST_CHECK(t4->getExecuteTime() == 4); + BOOST_CHECK(t4->getDelayTime() == 6); + BOOST_CHECK(t4->getLatency() == 10); + + std::cerr << *t << std::endl; + std::cerr << *t2 << std::endl; + std::cerr << *t3 << std::endl; + std::cerr << *t4 << std::endl; + + +} + +#include +#include + + +BOOST_AUTO_TEST_CASE(addressTest) +{ +#if 0 + boost::mt19937 rng; + boost::uniform_int rngen(0,Address::maxAddress()); + boost::variate_generator> vargen(rng,rngen); + Settings s(master_test_suite().argc, (char **)master_test_suite().argv); + Address::initialize(s); + + Address a; + + for (unsigned i = 0; i < s.channelCount; i++) + for (unsigned j = 0; j < s.rankCount; j++) + for (unsigned k = 0; k < s.bankCount; k++) + for (unsigned l = 0; l < s.columnCount; l++) + for (unsigned m = 0; m < s.rowCount; m++) + a.setAddress(i,j,k,l,m); + for (unsigned i = 0; i < 1500000000; i++) + { + Address *add = new Address(vargen()); + delete add; + } +#endif +} + +BOOST_AUTO_TEST_CASE( serialize_command ) +{ + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + Address::initialize(settings); + Transaction *trans1 = new Transaction(Transaction::IFETCH_TRANSACTION,23423, 8, 0xFACEFACE, 0x1234, 0x4); + // serialize normally + const Command cmd1(trans1, Address(0xBFEAECFE), 123456, true, 8); + backup("abce",cmd1); + Command cmd2; + restore("abce",cmd2); + BOOST_CHECK_EQUAL(cmd1, cmd2); + + // serialize via pointer + const Command *cmd3 = new Command(trans1, Address(0xBFEAECFE), 123456, true, 8); + backup("abce", cmd3); + Command *cmd4; + restore("abce",cmd4); + BOOST_CHECK_EQUAL(*cmd3, *cmd4); + + delete cmd3; + delete cmd4; +} + +BOOST_AUTO_TEST_CASE(testQueue0) +{ + for (int i = 10; i > 0; i--) + { + Queue queueA(16); + + // randomize the head/tail pointers + int numberOfTimes = std::rand() % queueA.depth(); + + for (int j = numberOfTimes; j > 0; j--) + { + if (std::rand() % 2 == 0) + queueA.push(new std::string()); + else + queueA.push_front(new std::string()); + } + while (!queueA.isEmpty()) + delete queueA.pop(); + + + char letter = 'a'; + + for (int i = queueA.depth(); i > 0; --i) + { + std::string *newOne = new std::string(); + *newOne += letter++; + queueA.push(newOne); + } + + BOOST_CHECK(queueA.size() == 16); + + std::string *val = queueA.remove(0); + BOOST_CHECK(queueA.size() == 15); + BOOST_CHECK(*val == "a"); + delete val; + BOOST_CHECK(*(queueA.front()) == "b"); + BOOST_CHECK(*(queueA.back()) == "p"); + + val = queueA.remove(3); + BOOST_CHECK(queueA.size() == 14); + BOOST_CHECK(*val == "e"); + delete val; + BOOST_CHECK(*(queueA.front()) == "b"); + BOOST_CHECK(*(queueA.back()) == "p"); + + val = queueA.remove(13); + BOOST_CHECK(queueA.size() == 13); + BOOST_CHECK(*val == "p"); + delete val; + BOOST_CHECK(*(queueA.front()) == "b"); + BOOST_CHECK(*(queueA.back()) == "o"); + + val = queueA.remove(5); + BOOST_CHECK(queueA.size() == 12); + BOOST_CHECK(*val == "h"); + delete val; + BOOST_CHECK(*(queueA.front()) == "b"); + BOOST_CHECK(*(queueA.back()) == "o"); + + val = queueA.remove(10); + BOOST_CHECK(queueA.size() == 11); + BOOST_CHECK(*val == "n"); + delete val; + BOOST_CHECK(*(queueA.front()) == "b"); + BOOST_CHECK(*(queueA.back()) == "o"); + + val = queueA.remove(0); + BOOST_CHECK(queueA.size() == 10); + BOOST_CHECK(*val == "b"); + delete val; + BOOST_CHECK(*(queueA.front()) == "c"); + BOOST_CHECK(*(queueA.back()) == "o"); + + val = queueA.remove(3); + BOOST_CHECK(queueA.size() == 9); + BOOST_CHECK(*val == "g"); + delete val; + BOOST_CHECK(*(queueA.front()) == "c"); + BOOST_CHECK(*(queueA.back()) == "o"); + + val = queueA.remove(6); + BOOST_CHECK(queueA.size() == 8); + BOOST_CHECK(*val == "l"); + delete val; + BOOST_CHECK(*(queueA.front()) == "c"); + BOOST_CHECK(*(queueA.back()) == "o"); + + val = queueA.remove(7); + BOOST_CHECK(queueA.size() == 7); + BOOST_CHECK(*val == "o"); + delete val; + BOOST_CHECK(*(queueA.front()) == "c"); + BOOST_CHECK(*(queueA.back()) == "m"); + + while (!queueA.isEmpty()) + delete queueA.pop(); + } +} + +BOOST_AUTO_TEST_CASE( test_queue) +{ + // transaction tests + Transaction t(Transaction::READ_TRANSACTION,0xface, 8, Address::maxAddress(), 0, 0, NULL); + Queue queueA(5); + bool result = queueA.push(new std::string("abc")); + BOOST_CHECK(result == true); + result = queueA.push(new std::string("def")); + BOOST_CHECK(result == true); + result = queueA.push(new std::string("ghi")); + BOOST_CHECK(result == true); + result = queueA.push(new std::string("jkl")); + BOOST_CHECK(result == true); + result = queueA.push(new std::string("mno")); + BOOST_CHECK(result == true); + result = queueA.push(new std::string("pqr")); + BOOST_CHECK(result == false); + result = queueA.push(new std::string("stu")); + BOOST_CHECK_EQUAL(result , false); + BOOST_CHECK_EQUAL(queueA.size() , 5); + + + Queue
*q0 = new Queue
(25,true); + delete q0; + + Queue *q3 = new Queue(5); + backup("cmdtest1",q3); + Queue *q2; + restore("cmdtest1",q2); + BOOST_CHECK_EQUAL(*q3,*q2); + + Queue *q4 = new Queue(1); + backup("cmdtest3",q4); + restore("cmdtest3",q4); + + q3->push(new Command(&t,0xfacedeef,true,64,Command::ACTIVATE)); + q3->push(new Command(&t,0xfbcedeef,true,64,Command::ACTIVATE)); + q3->push(new Command(&t,0xfccedeef,true,64,Command::ACTIVATE)); + q3->push(new Command(&t,0xfdcedeef,true,64,Command::ACTIVATE)); + q3->push(new Command(&t,0xfecedeef,true,64,Command::ACTIVATE)); + q3->push(new Command(&t,0xffcedeef,true,64,Command::ACTIVATE)); + backup("cmdtest2",q3); + restore("cmdtest2",q2); + BOOST_CHECK_EQUAL(*q3,*q2); + + delete q2; + delete q3; + + std::srand(std::time(0)); + const int iterations = (std::rand() % 500); + const int size = std::rand() % 500; + + Queue q5(size); + for (int i = iterations; i > 0; --i) + { + q5.push( + new Command( + (new Transaction( + Transaction::READ_TRANSACTION, + std::rand(), + std::rand()%9, + *(new Address(std::rand())), + 0, + 0, + NULL)), + std::rand(), + true,8)); + } + + backup("queueTest",q5); + Queue q6(0); + restore("queueTest",q6); + BOOST_CHECK_EQUAL(q5,q6); + + Queue q7(15); + for (int a = 6; a > 0; --a) + { + for (int i = 5; i > 0; --i) + { + bool result = q7.push(new int(5)); + BOOST_ASSERT(result); + } + q7.insert(new int(4),0); + q7.insert(new int(6),q7.size()); + q7.insert(new int(1),3); + q7.insert(new int(7),0); + q7.insert(new int(8),3); + int *val; + BOOST_CHECK_EQUAL(*q7.front() , 7); + //delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 4); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 5); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 8); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 5); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 1); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 5); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 5); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 5); + delete val; + val = q7.pop(); + BOOST_CHECK_EQUAL(*q7.front() , 6); + delete val; + val = q7.pop(); + delete val; + BOOST_CHECK_EQUAL(q7.size() , 0); + } + + //q7.resize(20); + Queue q8(20); + + for (int a = 5; a > 0; --a) + { + result = q8.push(new int(5)); + BOOST_ASSERT(result); + result = q8.push_front(new int(-5)); + BOOST_ASSERT(result); + result = q8.insert(new int(-1),1); + BOOST_ASSERT(result); + result = q8.insert(new int(-2),q8.size() - 1); + BOOST_ASSERT(result); + + BOOST_CHECK_EQUAL(*q8.front(), -5); + BOOST_CHECK_EQUAL(*q8.back(), 5); + BOOST_CHECK_EQUAL(*q8.at(1), -1); + BOOST_CHECK_EQUAL(*q8.at(q8.size() - 2), -2); + } + BOOST_CHECK_EQUAL(q8.size(), 20); +} + +DRAMsimII::CommandOrderingAlgorithm &operator++(DRAMsimII::CommandOrderingAlgorithm &lhs, int) +{ + lhs = (CommandOrderingAlgorithm)((int)lhs + 1); + return static_cast(lhs); +} + +DRAMsimII::TransactionOrderingAlgorithm &operator++(DRAMsimII::TransactionOrderingAlgorithm &lhs, int) +{ + lhs = (TransactionOrderingAlgorithm)((int)lhs + 1); + return lhs; +} + +DRAMsimII::RowBufferPolicy &operator++(DRAMsimII::RowBufferPolicy &lhs, int) +{ + lhs = (RowBufferPolicy)((int)lhs + 1); + return lhs; +} + +DRAMsimII::Address::AddressMappingScheme &operator++(DRAMsimII::Address::AddressMappingScheme &lhs, int) +{ + lhs = (Address::AddressMappingScheme)((int)lhs + 1); + return lhs; +} + +BOOST_AUTO_TEST_CASE( test_configurations ) +{ + Settings settings0(master_test_suite().argc, (char **)master_test_suite().argv); + + for (settings0.requestCount = 500; settings0.requestCount < 5000; settings0.requestCount += 500) + { + for (settings0.averageInterarrivalCycleCount = 0; settings0.averageInterarrivalCycleCount <= 35; settings0.averageInterarrivalCycleCount += 5) + { + for (settings0.dataRate = 800000000; settings0.dataRate < 3200000000; settings0.dataRate += 200000000) + { + for (settings0.commandOrderingAlgorithm = STRICT_ORDER; settings0.commandOrderingAlgorithm <= COMMAND_PAIR_RANK_HOPPING; settings0.commandOrderingAlgorithm++) + { + for (settings0.transactionOrderingAlgorithm = RIFF; settings0.transactionOrderingAlgorithm <= STRICT; settings0.transactionOrderingAlgorithm++) + { + for (settings0.perBankQueueDepth = 2; settings0.perBankQueueDepth <= 24; settings0.perBankQueueDepth += 2) + { + for (settings0.channelCount = 1; settings0.channelCount <= 4; settings0.channelCount++) + { + for (settings0.rankCount = 1; settings0.rankCount <= 8; settings0.rankCount *= 2) + { + for (settings0.bankCount = 1; settings0.bankCount <= 16; settings0.bankCount *= 2) + { + for (settings0.transactionQueueDepth = 1; settings0.transactionQueueDepth <= 32; settings0.transactionQueueDepth *= 2) + { + for (settings0.seniorityAgeLimit = 256; settings0.seniorityAgeLimit < 16384; settings0.seniorityAgeLimit *= 2) + { + for (settings0.decodeWindow = 1; settings0.decodeWindow <= settings0.transactionQueueDepth; settings0.decodeWindow += 2) + { + for (settings0.rowBufferManagementPolicy = OPEN_PAGE; settings0.rowBufferManagementPolicy <= CLOSE_PAGE_AGGRESSIVE; settings0.rowBufferManagementPolicy++) + { + for (settings0.addressMappingScheme = Address::CLOSE_PAGE_BASELINE; settings0.addressMappingScheme < Address::INTEL845G_MAP; settings0.addressMappingScheme++) + { + System ds2(settings0); + ds2.runSimulations(); + } + + } + } + } + } + } + } + } + } + } + } + } + } + } + +} + + +BOOST_AUTO_TEST_CASE( test_serialization) +{ + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + Settings settings2(master_test_suite().argc, (char **)master_test_suite().argv); + settings2.decodeWindow = 8; + + Queue
t3(5); + t3.push(new Address(0xfeeddeef)); + t3.push(new Address(0xfeeddeed)); + t3.push(new Address(0xfeeddeeb)); + t3.push(new Address(0xfeeddeec)); + t3.push(new Address(0xfeeddeea)); + t3.push(new Address(0xfeeddee0)); + BOOST_CHECK_EQUAL(t3.size() , 5); + + backup("aaaa",&t3); + Queue
*q1; + restore("aaaa",q1); + BOOST_CHECK_EQUAL(t3,*q1); + + const Address t4(0xfedefefd); + + Queue
t5(12); + + // serialize normally + const TimingSpecification ts1(settings); + backup("abcd",ts1); + TimingSpecification ts2(settings2); + restore("abcd",ts2); + BOOST_CHECK_EQUAL(ts1 , ts2); + + + // serialize through a pointer + const TimingSpecification *ts3 = new TimingSpecification(settings); + backup("aaaab",ts3); + TimingSpecification *ts4; + restore("aaaab",ts4); + BOOST_CHECK_EQUAL(*ts3,*ts4); + + // serialize normally + const SystemConfiguration sc1(settings); + backup("abcc",sc1); + SystemConfiguration sc2(settings2); + restore("abcc",sc2); + BOOST_CHECK_EQUAL(sc1 , sc2); + + // serialize via pointer + const SystemConfiguration *sc4 = new SystemConfiguration(settings); + backup("sysconfigbackup", sc4); + SystemConfiguration *sc5; + restore("sysconfigbackup",sc5); + BOOST_CHECK_EQUAL(*sc4,*sc5); + + //TimingSpecification ts3(settings2); + + // serialize normally + Address::initialize(settings); + const Address ad1(0xf5fedef34234234); + backup("abce",ad1); + Address ad2; + restore("abce",ad2); + BOOST_CHECK_EQUAL(ad1 , ad2); + + // serialize via pointer + const Address *ad3 = new Address(0xf5fedef34234234); + backup("abce",ad3); + Address *ad4; + restore("abce",ad4); + BOOST_CHECK_EQUAL(*ad3 , *ad4); + + SystemConfiguration sc3(settings2); + + + const SimulationParameters sp1(settings); + backup("aaad",&sp1); + SimulationParameters *sp2; + restore("aaad",sp2); + BOOST_CHECK_EQUAL(sp1,*sp2); + + //const PowerConfig pc1(settings); + //backup("aaac",&pc1); + const PowerConfig *pc0 = new PowerConfig(settings); + backup("aaac", pc0); + PowerConfig *pc3 = new PowerConfig(settings2); + restore("aaac",pc3); + BOOST_CHECK_EQUAL(*pc0, *pc3); + + // serialize normally + const Statistics st1(settings); + backup("statsReg",&st1); + Statistics *st2 = new Statistics(settings2); + restore("statsReg",st2); + BOOST_CHECK_EQUAL(st1 , *st2); + + // serialize via a pointer + const Statistics *st3 = new Statistics(settings); + backup("statsPtr",st3); + Statistics *st4; + restore("statsPtr",st4); + BOOST_CHECK_EQUAL(*st3,*st4); + + + //BOOST_CHECK_EQUAL(pc1 , pc2); + //BOOST_CHECK_EQUAL(pc1, *pc3); + + const Bank bk1(settings, ts1, sc1); + backup("banktest",&bk1); + //Bank bk2(settings2, *ts3, sc3); + Bank *bk2; + //BOOST_CHECK_EQUAL(bk1 , bk2); + //restore("aaad",bk2); + restore("banktest",bk2); + BOOST_CHECK_EQUAL(bk1 , *bk2); + delete bk2; + Bank *bk3; + restore("banktest",bk3); + BOOST_CHECK_EQUAL(*bk3,bk1); + delete bk3; + + const Bank *bk4 = new Bank(settings, ts1, sc1); + backup("aaae",bk4); + Bank *bk5 = new Bank(settings2, *ts3, sc3); + //BOOST_CHECK_EQUAL(bk1 , bk2); + restore("aaae",bk5); + BOOST_CHECK_EQUAL(*bk5 , *bk4); + + std::vector *bk6 = new std::vector(6,Bank(settings, ts1, sc1)); + + backup("testvector1",bk6); + std::vector *bk7; + restore("testvector1",bk7); + + const Rank rk1(settings,ts1,sc1); + backup("rankTest1",&rk1); + Rank *rk2; + restore("rankTest1",rk2); + BOOST_CHECK_EQUAL(rk1,*rk2); + + // channel tests + Channel ch1(settings, sc1, *st2); + ch1.setChannelID(0); + Transaction *t1 = new Transaction(Transaction::IFETCH_TRANSACTION, 1590, 8, Address(0x14584), 0x20, 0x2); + ch1.moveToTime(150); + ch1.enqueue(t1); + ch1.moveToTime(3523); + backup("chanTest1",&ch1); + Channel *ch2; + restore("chanTest1",ch2); + BOOST_CHECK_EQUAL(ch1, *ch2); + + // system tests + System *ds2 = new System(settings); + backup("ds2",ds2); + System *ds5; + restore("ds2",ds5); + BOOST_CHECK_EQUAL(*ds2,*ds5); + + System *ds3 = new System(settings); + ds3->runSimulations(500); + backup("systemTest",ds3); + + restore("ds2",ds3); + BOOST_CHECK_EQUAL(*ds2,*ds3); + + System *ds4 ; + restore("ds2",ds4); + BOOST_CHECK_EQUAL(*ds3,*ds4); + + delete ds2; + delete ds3; + delete ds4; + //ds.runSimulations(); + //timingOutStream << ds << endl; +} + +BOOST_AUTO_TEST_CASE( serialize_inputstream) +{ + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + const SystemConfiguration sc1(settings); + + Statistics st1(settings); + std::vector ch1(4, Channel(settings,sc1, st1)); + + const InputStream is1(settings, sc1,ch1); + backup("testInputStream",&is1); + InputStream *is2; + restore("testInputStream",is2); + BOOST_CHECK_EQUAL(is1, *is2); +} + + + +#include +using std::stringstream; +using std::string; + +BOOST_AUTO_TEST_CASE( serialize_pattern_test ) +{ + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + + System *ds3 = new System(settings); + + const string name("systemTestRepeat"); + + stringstream fullname; + + unsigned counter = 0; + + for (int i = std::rand() % 16384; i > 0; i--) + { + ds3->runSimulations(500 + (std::rand() % 1024)); + + fullname.str(""); + fullname << name << counter++; + + backup(fullname.str().c_str(),ds3); + + delete ds3; + ds3 = NULL; + + restore(fullname.str().c_str(),ds3); + } +} + + +BOOST_AUTO_TEST_CASE( test_system_serialization) +{ + const Settings settings(master_test_suite().argc, (char **)master_test_suite().argv); + + System *ds3 = new System(settings); + + const string name("systemTest"); + + stringstream fullname; + + unsigned counter = 0; + + for (int i = std::rand() % 16384; i > 0; i--) + { + ds3->runSimulations(500 + (std::rand() % 2*65536)); + + fullname.str(""); + fullname << name << counter++; + + backup(fullname.str().c_str(),ds3); + + System *ds4; + + restore(fullname.str().c_str(),ds4); + + BOOST_CHECK_EQUAL(*ds4,*ds3); + + delete ds3; + + ds4->runSimulations(500 + (std::rand() % 2*65536)); + + fullname.str(""); + fullname << name << counter++; + + backup(fullname.str().c_str(),ds4); + + restore(fullname.str().c_str(),ds3); + + BOOST_CHECK_EQUAL(*ds3,*ds4); + + ds4->runSimulations(); + delete ds4; + } +}