0da1c5dcca
First commit of the 4.5 version (latest version available)
159 lines
6.2 KiB
Java
159 lines
6.2 KiB
Java
package mars.simulator;
|
|
|
|
/*
|
|
Copyright (c) 2003-2007, Pete Sanderson and Kenneth Vollmar
|
|
|
|
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
|
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject
|
|
to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
|
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
|
*/
|
|
|
|
/**
|
|
* Represents a (potential) delayed branch. Note it is necessary only when
|
|
* delayed branching is enabled. Here's the protocol for using it:
|
|
*
|
|
* (1) When a runtime decision to branch is made (by either a branch or jump
|
|
* instruction's simulate() method in InstructionSet), then if delayed branching
|
|
* is enabled, the register() method is called with the branch target address but
|
|
* the program counter is NOT set to the branch target address.
|
|
*
|
|
* (2) At the end of that instruction cycle, the simulate() method in Simulator
|
|
* will detect the registered branch, and set its trigger. Don't do anything yet
|
|
* because the next instruction cycle is the delay slot and needs to complete.
|
|
*
|
|
* (3) At the end of the next (delay slot) instruction cycle, the simulate()
|
|
* method in Simulator will detect the triggered branch, set the program
|
|
* counter to its target value and clear the delayed branch.
|
|
*
|
|
* The only interesting situation is when the delay slot itself contains a
|
|
* successful branch! I tried this with SPIM (e.g. beq followed by b)
|
|
* and it treats it as if nothing was there and continues the delay slot
|
|
* into the next cycle. The eventual branch taken is the original one (as one
|
|
* would hope) but in the meantime the first statement following the sequence
|
|
* of successful branches will constitute the delay slot and will be executed!
|
|
*
|
|
* Since only one pending delayed branch can be taken at a time, everything
|
|
* here is done with statics. The class itself represents the potential branch.
|
|
*
|
|
* @author Pete Sanderson
|
|
* @version June 2007
|
|
**/
|
|
|
|
public class DelayedBranch {
|
|
// Class states.
|
|
private static final int CLEARED = 0;
|
|
private static final int REGISTERED = 1;
|
|
private static final int TRIGGERED = 2;
|
|
|
|
// Initially nothing is happening.
|
|
|
|
private static int state = CLEARED;
|
|
private static int branchTargetAddress = 0;
|
|
|
|
/**
|
|
* Register the fact that a successful branch is to occur. This is called in
|
|
* the instruction's simulated execution (its simulate() method in InstructionSet).
|
|
* If a branch is registered but not triggered, this registration will be ignored
|
|
* (cannot happen if class usage protocol is followed). If a branch is currently
|
|
* registered and triggered, reset the state back to registered (but not triggered)
|
|
* in order to carry over the delay slot for another execution cycle. This is the
|
|
* only public member of the class.
|
|
*
|
|
* @param targetAddress The address to branch to after executing the next instruction
|
|
*/
|
|
public static void register(int targetAddress) {
|
|
// About as clean as a switch statement can be!
|
|
switch (state) {
|
|
case CLEARED : branchTargetAddress = targetAddress;
|
|
case REGISTERED :
|
|
case TRIGGERED : state = REGISTERED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger a registered branch. This is called at the end of the MIPS simulator
|
|
* instruction execution cycle (simulate method in Simulator), so a registered
|
|
* branch will be triggered right away. The next execution cycle will be the
|
|
* delay slot and at the end of THAT cycle, the trigger will be detected and the
|
|
* branch carried out. This method has package visibility.
|
|
*
|
|
* Precondition: DelayedBranch.isRegistered()
|
|
*
|
|
* Postcondition: DelayedBranch.isTriggered() && !DelayedBranch.isRegistered()
|
|
*
|
|
*/
|
|
static void trigger() {
|
|
// About as clean as a switch statement can be!
|
|
switch (state) {
|
|
case REGISTERED :
|
|
case TRIGGERED : state = TRIGGERED;
|
|
case CLEARED :
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear the delayed branch. This must be done immediately after setting the
|
|
* program counter to the target address. This method has package visibility.
|
|
*/
|
|
static void clear() {
|
|
state = CLEARED;
|
|
branchTargetAddress = 0;
|
|
}
|
|
|
|
/**
|
|
* Return registration status. Is false initially, true after register() is called
|
|
* but becomes false after trigger() or clear() are called. This method has package
|
|
* visibility.
|
|
*
|
|
* @return true if branch is registered but not triggered, false otherwise.
|
|
*/
|
|
|
|
static boolean isRegistered() {
|
|
return state == REGISTERED;
|
|
}
|
|
|
|
/**
|
|
* Return trigger status. Is false initially, true after trigger() is called
|
|
* but becomes false after clear() is called. This method has package visibility.
|
|
*
|
|
* @return true if branch is registered but not triggered, false otherwise.
|
|
*/
|
|
|
|
static boolean isTriggered() {
|
|
return state == TRIGGERED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return branch target address. This should be retrieved only to set the program
|
|
* counter at the end of the delay slot. This method has package visibility.
|
|
*
|
|
* Precondition: DelayedBranch.isTriggered()
|
|
*
|
|
* @return Target address of the delayed branch.
|
|
*/
|
|
static int getBranchTargetAddress() {
|
|
return branchTargetAddress;
|
|
}
|
|
|
|
} // DelayedBranch |