- Nov 30, 2021
-
-
Geo Ster authored
* So after a week, it's finally here! The initial implementation of the IOP has been added to the emulator. You might wonder why did it take so long? This was mostly because I wanted to make the implementation as complete as possible and also test it to ensure it's bug free. So this is actually based on the MIPS R3000A interpreter I wrote last year for my PS1 emulator. So did I just copy the code and call it a day? Hell no, the code in that ancient project is awful, even if it works. So I completely rewrote the interpreter by using our modern techiniques of storing state. So rewriting the old code allowed me to test if it actually worked in that environment and could boot PSX games. * Due to this, the implementation is a bit more complete than the EE as it includes interrupt support. In addition we have to account for the fact that the IOP runs at 36.864MHz, in constrast to the EE which clocks at 295MHz. This maps approximatly to an 1/8 ratio, which means that 1 IOP instruction will run every 8 EE cycles. The current implementation of this is hacky and a bit inaccurate because some EE instructions can take more than 1 cycle to execute, but it's good enough for now (Play! assumes this as well and can boot 40%+ of games). * Because both the CPU emulators can share a lot of naming conventions, to avoid confusion each processor has been seperated into a namespace so we can always know which CPU we are refering to. Finally, for now reads/writes except for the BIOS and IOP RAM, haven't been implemented but will come soon.
-
- Nov 17, 2021
-
-
Geo Ster authored
* Currently the BIOS only writes to scratchpad and some very few mysterious addresses that don't seem to do anything. However it is important to know when it will try to write to DMAC for example so we can implement it. So instead of writing anything and uncontrollably into a single large buffer let's make an if-else with all the known addresses and how to handle them. When the BIOS tries to write somewhere new we will be notified immediately. * Also rework the disassembly logger to use C FILE* since these are faster then std::ofstream. Normally I wouldn't care about this but in our usecase which is very performance sensitive, it makes a noticeable difference.
-
- Nov 16, 2021
-
-
Geo Ster authored
* Add a few more instructions required to progress further into the BIOS execution * After that the BIOS writes something to 0xb000f410 and then enters a loop at 0x9fc417b0 that only exits when that address contains a value of 0. So unless that address magically changes value on its own, it's either an interrupt (higly unlikely since the INT regs aren't touched) or the IOP doing this (also impossible since the IOP and EE only communicate with DMA and have seperate memory regions). So my guess is that the BIOS expects that address to always be zero no matter the value written to it. Until I am proven wrong let's stick to that to exit that infinite loop and continue...
-
Geo Ster authored
* The BIOS tries to write to 0x1000f430/0x1000f440 which contain the registers MCH_RICM/MCH_DRD. Saldy these registers are quite undocumented. So the writing logic has been taken from PCSX2: https://github.com/PCSX2/pcsx2/blob/master/pcsx2/HwWrite.cpp#L237 Forgive me, for I have sinned.
-
Geo Ster authored
* Since log output is getting very large, it's common to have to wait 5+ minutes before any unknow instruction is encoutered. Printing to the console actually takes a lot of time and slows down interpretation significantly. Right now we don't care, since we just want to boot the BIOS but let's have an option to disable all the log messages if we want. * In addition record all writes to 0xb000f180 which is the BIOS console output address, so we can have some output, which will be very useful
-
- Nov 15, 2021
-
-
Geo Ster authored
* Now the BIOS enters another infinite loop. However that seems to be normal, as it's waiting for COP0_REG[9], the timer which we haven't implemented yet. I think it's also time to add support for interrupts as well since these go hand in hand with timers
-
- 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
* 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.
-
- 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
In addition: * Correct register notation (word refers to a 32bit quantity not 16bit) * Simplify sign extension casing * Add more useful logging
-
- 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
* The ps2tek documentation states the memory map clearly [1]. It seems to have a similar architecture with the PSX, where the main memory map (KUSEG0) is mirrored in multiple regions (KUSEG1/KUSEG2) with different access patterns for each region. For now we don't have to emulate all of them, just the main memory map. * Allocate the entire 512MB memory into an array and make a convenient struct to abstract memory range operations. [1] https://psi-rockin.github.io/ps2tek/#memorymap
-
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!
-