diff options
Diffstat (limited to 'include/mips_cpu.h')
-rw-r--r-- | include/mips_cpu.h | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/include/mips_cpu.h b/include/mips_cpu.h new file mode 100644 index 0000000..117d869 --- /dev/null +++ b/include/mips_cpu.h @@ -0,0 +1,177 @@ +/*! \file mips_cpu.h + +*/ +#ifndef mips_cpu_header +#define mips_cpu_header + +#include "mips_mem.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/*! \defgroup mips_cpu CPU API + \addtogroup mips_cpu + @{ +*/ + + +/*! Represents the state of a cpu. + + This another opaque data type, similar to \ref mips_mem_provider. + + \struct mips_cpu_impl +*/ +struct mips_cpu_impl; + +/*! An opaque handle to a mips. + + This represents a handle to a data-type that clients can use, without + knowing how the CPU is implemented. See \ref mips_mem_h for more + commentary. +*/ +typedef struct mips_cpu_impl *mips_cpu_h; + + +/*! Creates and initialises a new CPU instance. + + The CPU should be bound to the given + \ref mips_mem_core "memory space", and have all registers set + to zero. The memory is not owned by the CPU, so it should not + be \ref mips_mem_free "freed" when the CPU is \ref mips_cpu_free "freed". + + \param mem The memory space the processor is connected to; think of it + as the address bus to which the CPU has been wired. +*/ +mips_cpu_h mips_cpu_create(mips_mem_h mem); + +/*! Reset the CPU as if it had just been created, with all registers zerod. + However, it should not modify RAM. Imagine this as asserting the reset + input of the CPU core. +*/ +mips_error mips_cpu_reset(mips_cpu_h state); + +/*! Returns the current value of one of the 32 general purpose MIPS registers */ +mips_error mips_cpu_get_register( + mips_cpu_h state, //!< Valid (non-empty) handle to a CPU + unsigned index, //!< Index from 0 to 31 + uint32_t *value //!< Where to write the value to +); + +/*! Modifies one of the 32 general purpose MIPS registers. */ +mips_error mips_cpu_set_register( + mips_cpu_h state, //!< Valid (non-empty) handle to a CPU + unsigned index, //!< Index from 0 to 31 + uint32_t value //!< New value to write into register file +); + +/*! Sets the program counter for the next instruction to the specified byte address. + + While this sets the value of the PC, it should not cause any kind of + execution to happen. Once you look at branches in detail, you will + see that there is some slight ambiguity about this function. Choose the + only option that makes sense. +*/ +mips_error mips_cpu_set_pc( + mips_cpu_h state, //!< Valid (non-empty) handle to a CPU + uint32_t pc //!< Address of the next instruction to exectute. +); + +/*! Gets the pc for the next instruction. */ +mips_error mips_cpu_get_pc(mips_cpu_h state, uint32_t *pc); + +/*! Advances the processor by one instruction. + + If an exception or error occurs, the CPU and memory state + should be left unchanged. This is so that the user can + inspect what happened and find out what went wrong. So + this should be true: + + uint32_t pc=mips_cpu_get_pc(cpu); + mips_error err=mips_cpu_step(cpu); + if(err!=mips_Success){ + assert(mips_cpu_get_pc(cpu)==pc); + assert(mips_cpu_step(cpu)==err); + } + + Maintaining this property in all cases is actually pretty + difficult, so _try_ to maintain it, but don't worry too + much if under some exceptions it doesn't quite work. +*/ +mips_error mips_cpu_step(mips_cpu_h state); + +/*! Controls printing of diagnostic and debug messages. + + You are encouraged to include diagnostic and debugging + information in your CPU, but you should include a way + to control how much is printed. The default should be + to print nothing, but it is a good idea to have a way + of turning it on and off _without_ recompiling. This function + provides a way for the user to indicate both how much + output they are interested in, and where that output + should go (should it go to stdout, or stderr, or a file?). + + \param state Valid (non-empty) CPU handle. + + \param level What level of output should be printed. There + is no specific format for the output format, the only + requirement is that for level zero there is no output. + + \param dest Where the output should go. This should be + remembered by the CPU simulator, then later passed + to fprintf to provide output. + + \pre It is required that if level>0 then dest!=0, so the + caller will always provide a valid destination if they + have indicated they will require output. + + It is suggested that for level=1 you print out one + line of information per instruction with basic information + like the program counter and the instruction type, and for higher + levels you may want to print the CPU state before each + instruction. Both of these can usually be inserted in + just one place in the processor, and can greatly aid + debugging. + + However, this is completely implementation defined behaviour, + so your simulator does not have to print anything for + any debug level if you don't want to. +*/ +mips_error mips_cpu_set_debug_level(mips_cpu_h state, unsigned level, FILE *dest); + +/*! Free all resources associated with state. + + \param state Either a handle to a valid simulation state, or an empty (NULL) handle. + + It is legal to pass an empty handle to mips_cpu_free. It is illegal + to pass the same non-empty handle to mips_cpu_free twice, and will + result in undefined behaviour (i.e. anything could happen): + + mips_cpu_h cpu=mips_cpu_create(...); + ... + mips_cpu_free(h); // This is fine + ... + mips_cpu_free(h); // BANG! or nothing. Or format the hard disk. + + A better pattern is to always zero the variable after calling free, + in case elsewhere you are not sure if resources have been released yet: + + mips_cpu_h cpu=mips_cpu_create(...); + ... + mips_cpu_free(h); // This is fine + h=0; // Make sure it is now empty + ... + mips_cpu_free(h); // Fine, nothing happens + h=0; // Does nothing here, might could stop other errors +*/ +void mips_cpu_free(mips_cpu_h state); + +/*! + @} +*/ + +#ifdef __cplusplus +}; +#endif + +#endif |