-Replaced subtraction with adding the 2s complement in instructions. That way, the Overflow Flag is calculated properly.
-Made it so that the masking of a result to 0xFFFF comes after calculating the Carry and Overflow Flags but before the Sign and Zero Flags.
-The CMPX instructions now use the aforementioned masking to properly calculate the Sign and Zero Flags even though the result doesn't actually get stored.
Thanks to this commit, IntelliHawk executes 1711 instructions properly. Next, it's supposed to take an Interrupt, which is bizarre because INTRM appears to be true at that point. This doesn't seem possible unless I am once again logging at the wrong time, hiding that the INTRM gets set to false before immediately switching back to true after taking the interrupt. Will look into this later.
-Added and Interrupted flag to make it so that interrupts only trigger once per falling edge.
-For now, interrupts take 28 cycles.
-Made it so that the STIC tracks Pending / Total Executed Cycles just like the CPU.
-Forwarded the cycles executed in the CPU to the STIC's Execute.
-SR1 is now inverted when there are no pending cycles.
--If SR1 is high, 14394 cycles are added to the pending cycles.
--If SR1 is low, 3791 cycles are added to the pending cycles.
--Not sure why the STIC has any connection to the SST, but the docs on the SST are virtually non-existent from what I could find.
--I took advantage of Func and Action instead of passing bool references to both devices. I think this makes sense.
-Added reset functions for both devices.
My comparison log for INTRM is still weird because it says it is true initially (Expected) and remains as such after the first instruction (A bit odd). I think this happens because the STIC is supposed to "tick" and shift SR1 to false immediately, but the STIC tick happens after the CPU tick, and the CPU tick is where the logging happens. I need to find a better place to put this logging, and I need to implement the STIC ticking for IntelliHawk. I'm not positive how to approach the latter issue as I assume a tick means one instruction execution, and my executions happen in a loop on the CPU, which has no reference to the STIC, so I'm not sure where this fits into the equation.
-Foreground / Background | Color Stack Mode
--Actually made a boolean for it (FGBG).
--Reading from a write-only STIC alias of $21 does change the STIC into Color Stack mode, but it doesn't actually read.
--Color stack mode is enabled when $21 or its alias is read and it is disabled (FGBG) when written its written, both having to occur during VBlank Period 1.
---This is what I gathered from the wiki, but I'm confused as to why it says that "The STIC stays in this mode until the program accesses location $21 again." I'm assuming this doesn't mean the mode changes on every access because then I don't understand why a read would change to a different mode than a write.
--FGBG is disabled by default. I don't think it matters.
-I will now assume that 0x7000 is not mapped for the sake of continuing on. I will need to implement a mapper system shortly though.
--Did the same thing for 0x4800.
-AND@, MOVR, CMP enabled.
-Made the logging separator generate before an instruction instead of after the register states. This is quite petty, but I don't like the separator at the end of the file.
I hit an infinite loop, and I'm very very certain it's happening because I don't have an interrupt system yet. Time to stop avoiding that!
-Separated cartridge logic into a separate ICart named Cartridge.cs.
-Made WriteMemory return a bool to match ICart.Write. It currently returns true if either the cart or the core responded.
TODO: Parse the vanilla Intellivision ROM, which will hopefully include the read / writability of the data segments. adelikat seems to think that I just need to send the bytes to $5000, but I'm not convinced.
-Made it so that the indirect ops other than MVO@ decrement R6 when it's the mem address. Indirect write means writing to a register apparently, so maybe the documentation don't contradict itself.
-Fixed my disassembly of branch; I wasn't thinking in hexadecimal. >_<
-Subtracted 1 from the negated offset when branching in reverse. The next op is "BNEQ $FFFC".
-Fixed the branching disassembly; the direction just negates the offset and the second parameter only belongs to BEXT. All of my sources contradict each other, but this seems sensible.
-Applied to the old Gameboy core. Why not? It at least fixes that annoying bug from before if we ever care to use it again.
-Both logs are now written to different files.
--It now just builds a strings and writes on finalization.
-Fixed up format strings.
-As RegisterPC already increments upon reading the third decle, I now just store PC as the return address for jumping instead of PC + 1.
-Retrieved the double bit from the swap / shift / rotate instructions in a more proper way.
TODO: Use more specific variables; most of them suck, and with these docs, I have better names for them.
-Disabled Intellicart hook for ReadMemory, which seemed to be interfering.
-Implemented MVO@.
-Several instructions are now executed in succession until it hits the unimplemented "XORR R5, R5".
I should probably refactor Disassemble and Execute to label registers as source / destination to avoid further confusion at some point. My disassembly might have the source / destination registers flipped as well.
-They both seem to work, but the operands for AND@ are both 0, so this seems fishy.
-I don't know for sure if AND@ executes cycles in the same way that MVI@ as the documentation isn't clear on this, but I assumed it did.
According to my disassembler, the first 5 instructions run on the Executive ROM are:
JSRD R5, $1026
MVI@ R7, R6
ADD@ R6, R1
JSR R5, $1A83
HLT
Considering that I hit a HLT, I figure something is going terribly wrong. Perhaps it has to do with my lack of an interrupt system?
-Added bytesToAdvance assignments to the relevant opcodes I added yesterday.
TODO: Implement more stuff in Execute and use the Executive ROM as a test case.
-Fixed disassembly for JMP:
--Now it uses the parameter pc, not RegisterPC.
--I was loading both the second and third value from the second's address.
--Casting the calculated addresses to bytes when addresses are 16-bit was a bad idea.
--Removed a closing parenthesis I accidentally stuck in the formatting.
It seems that I've gotten far enough to use the Executive ROM as a test case! Now to go instruction by instruction and see if they work as planned and hope this will all eventually make something.
--Afterwards, the data is reconciled, right now by chucking out the core value if the cart responded.
-WriteMemory now writes to both the core and the cart unconditionally.
--Each case now breaks out of the switch statement in case we want to do more complex things at the end of the function later on.
-All default paths in both functions now throw an exception.
-Implemented the final CRC check.
I didn't get around to implementing bank-switched ranges, but I don't think it's worth worrying about that right now considering that the Intellicart is not marked as readable at the initial PC, so something is either wrong or I need to implement more things before this will work. I think I'll put Intellicarts on hold and try to get a .int / .bin to run in the meantime.
--In my test case, only a few segments were set to readable and nothing else was set. 0x1000, which is where the PC is initialized to, certainly isn't in a writable page.
--Although I've read that these memory attributes affect the Intellivision and not the Intellicart, I'm pretty sure this has to be implemented in the Intellicart so that my Read/WriteCart functions can choose to respond / not respond depending on these attributes. I very well could be wrong.
-Hooked Read/WriteCart into Read/WriteMemory.
-Implemented memory attributes into Read/WriteCart.
--TODO: Bank-switching.
TODO: Fine address table and memory attribute / fine address checksums.
--If a future system uses this extension, the condition:
Rom[0] == 0xA8 && Rom[1] == (0xFF ^ Rom[2])
...can verify if the file is in fact an IntelliCart, though I doubt this is a permanent solution to the more underlying problem.
-Initialized the memory devices with a tentative size that ignores the unofficial ranges.
-Masked addresses to match those sizes (That's my understanding of what the memory map needs to do based on other examples).
-Added the ICart interface.
-Started the Intellicart parser; got far enough to know that the files I'm working with are not Intellicarts. ^_^
-Fixed JMP disassembly; I need to return on an invalid opcode because I was breaking out of the inner switch statement, not both that and the outer one.
-Set up the "official" memory map - see http://wiki.intellivision.us/index.php?title=Memory_Map
--Things I didn't do:
---Accessibility.
---Additional Occupied Memory Ranges.
---Addresses Available to Cartridges
---Initialize any of the byte arrays.
--Not sure which of these I need to do, but clearly the byte arrays have to be initialized somewhere to something and there's a lot of gaps in this memory map.
-Made all instructions in the executor, even implemented ones, throw exceptions. I will get rid of the exceptions as I test the instructions.
-Added instructions up to and including 0x57 to disassembly and executor.
-Implemented ADCR.
-Decoded all opcodes up to 0x23F.
TODO: Try vecna's idea of testing the instructions by running a game and implementing instructions as I need them...but first I'll need to implement loading of an Intellivision game.
-Definitions.
--Registers, Flags, TotalExecutedCycles, PendingCycles, ReadMemory, and WriteMemory.
-Execute.
--Implemented opcodes 0x001-0x027 with the exception of 0x004 and 0x005.