- Nov 14, 2021
-
-
Geo Ster authored
* Seems like branches really do love having bugs in them ;) The bug was noticed when the BEQ instruction was provided 0xffd1 as the offset. Decompiling with ghidra revealed that the offset was -0xbc or -188 as signed but with this bug the value would be 261956 which completely broke the program. Fix this by first casting to int16_t to let the compiler know that we are giving it a 16bit signed int and then convert it to int32_t * In addition make stores/loads bold so I can notice them better, as log output is starting to incrase exponentially
-
Geo Ster authored
* Add more instructions, now the BIOS starts exeuting for longer without interruption yay! * Move some logging messages before the instruction, to avoid printing wrong values in case a register is modified with itself.
-
Geo Ster authored
* Since we have encountered our first FPU register, add the 32 floating point registers to the CPU. * In addition solve a small bug in the JAL instruction related to the return link address. See previous commit for details
-
Geo Ster authored
* As stated in earlier commits we prefetch next instruction before the current one gets executed to guarantee that we have it available in case a branch instruction changes the PC. So a typical fetch cycle for a branch instruction would look like: /* Cycle 1. */ instr = <something> next_instr = read(PC) -> jump PC += 4 (now it points to the branch delay) /* Cycle 2. */ instr = jump next_instr = read(PC) -> branch delay PC += 4 (now it points to the instruction AFTER the delay slot) <execute branch> So if a branch uses offsets instead of hard coding the PC, it will point to the wrong address since it expects to have the PC pointing to the branch delay instruction. To fix this, subtrack 4 from the pc.
-
Geo Ster authored
* Having the header files in a seperate dir is only useful when developing libraries that are meant to be used by other programs. In our case though it makes the file structure more tedious so gather everything in one place.
-
Geo Ster authored
* std::cout is not fit for our usecase, which is format heavy output. This results in a lot of code bloat from switching between std::dec and std::hex. Switching to fmt yields significantly cleaner code.
-
Geo Ster authored
* Currently the way PC was logged was kinda broken, especially on branch delay slots where it would show the jump address instead. This doesn't affect the functionality but makes debugging a bit harder so to fix this, cache the PC together with the instruction being loaded to always have the correct address.
-
Geo Ster authored
* Implement more instructions as usual * Rename instr.doubleword to instr.dword for more compat code * Add the skip branch delay slots feature for beq* instructions
-
- Nov 13, 2021
-
-
Geo Ster authored
* This is only supported on GCC/Clang making compilation fail on MSVC. In addition we don't really need this since accessing the entire 128bit register is very rare and can be emulated by setting each of 64bit parts seperately.
-
Geo Ster authored
* Nothing special really, just adding more instructions and fixes minor bugs to progress further
-
- Nov 04, 2021
-
-
Geo Ster authored
* Currently the BIOS tries to write something to scratchpad and it fails because its address is not our currently supported range. So add a new buffer for the 16KB scratchpad used by the CPU and add a function to use it if the address is in the correct range. * Also shorten some function names and change some array to C-style because we like to work with pointers and STL doesn't like that.
-
Geo Ster authored
* COP0 instructions sadly have way too many encoding to use a single template one them, so rewrite the decoder to manually extract the required bits for each instruction. This fixes a bug where the MTC0 instruction was mistaken for MFC0. * Implement more instructions so we can execute more of the BIOS. In addition fix an oopsie in the ORI instruction which fixes some bugged memory writes. As of now the BIOS tries to write address 0x70003fe0 which maps to the scratchpad memory (assuming no further logic errors are present). Need to investigate why this is and how to emulate it before continuing...
-
- Nov 03, 2021
-
-
Geo Ster authored
* As this very useful document describes [1] the BIOS first checks the prid of COP0 to decide whether to execute the IOP or EE boot sequence. Without this the BIOS doesn't execute the code we want. The code sequence that determines this is added below as suedo assembly MFC0: GPR[26] = COP0_REG[15] /* Load cop0 prid to GPR 26 */ SLTI: GPR[1] = GPR[26] < 89 /* Check if its value is less than 0x59 and store the bool in GPR 1 */ BNE: if GPR[0] != GPR[1] then pc += 20 /* If the comparison is true then jump +20 to IOP */ [1] https://rust-console.github.io/ps2-bios-book/print.html [2] https://psi-rockin.github.io/ps2tek/#biosbootprocess
-
Geo Ster authored
In addition: * Correct register notation (word refers to a 32bit quantity not 16bit) * Simplify sign extension casing * Add more useful logging
-
Geo Ster authored
* MIPS has an architectural feature, where instead of flushing the pipeline when executing a branch instruction, it goes ahead and executes the instruction following the branch as well. Flushing the pipeline is costly and is the cause of those complex branch predictors on modern CPUs that try to guess when a branch will be taken. * To properly emulate this behaviour we must act how the pipeline acts. We will always have 2 instructions loaded the current one and the next one. This way we can load the instruction after the branch even though the pc changes.
-
Geo Ster authored
* The instruction decoding was based on the handy table in ps2tek [1] while the instructions themselves were written based on the document added. * The implementation makes heavy use of bitfields and unions in C++ to make accessing different bits/sections of registers easier and more intuitive. You may also notice the frequent casting (uint32_t)(int16_t) which might seem useless but is there to force the compiler to generate instructions to sign extend the offsets. [1] https://psi-rockin.github.io/ps2tek/#eeinstructiondecoding
-
- Oct 31, 2021
-
-
Geo Ster authored
* Now that the BIOS is loaded we can start executing it! The starting address the EE uses is 0xbfc00000 which maps to KUSEG1. Since all KUSEG regions except KUSEG2 are mirrors of each other we only need to translate the address to the KUSEG appropriate. * The functional differences between KUSEG0/1 are minimal and very niche so I won't bother emulating them now. Address wise we can notice that the only difference between addresses is the most significant half byte. By using that byte as an index in a mask table we can define an appropriate mask for each KUSEG address. Idea taken from a very handy PSX document I discovered last year [1] [1] https://svkt.org/~simias/guide.pdf (43)
-
Geo Ster authored
* This commit adds a most basic CPU class that acts as a template which we will slowly build. * The architecture is pretty simple; the ComponentManager will create all the seperate components (EE, VP, IOP, GS etc) as unique_ptr's since it owns them and only it has access to them. All the other components must pass through the manager to read/write data to memory. To achieve this they are given a pointer to the ComponentManger in their constructor. * For now the CPU directly accesses the bios which shouldn't happen but will be fixed eventually when I implement generic read/writes. The goal is to start implementing the CPU as fast as possible in order to get to the GPU/VPU's and display something!
-