Writing $4203 twice too fast gives erroneous result (not emulated)

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
regiscaelus
Posts: 32
Joined: Thu Jan 24, 2019 1:35 am

Re: Writing $4203 twice too fast gives erroneous result (not emulated)

Post by regiscaelus »

Bingo. I got the multiplication to match the behaviour of real hardware. Writing to WRMPYB will:
- always clear RDMPY
- but only starts a new multiplication if the current multiplication is complete (> 8 cycles)
- update RDDIV with WRMPYB & WRMPYA if the current multiplication is complete or on its last cycle (> 7 cycles).

Consequently, writing at cycle 8 is the special case as the multiplcation is not started and RDDIV only gets updated once with WRMPYB & WRMPYA.
IMG_20220830_145558.jpg
Let's move on to the division now.
regiscaelus
Posts: 32
Joined: Thu Jan 24, 2019 1:35 am

Re: Writing $4203 twice too fast gives erroneous result (not emulated)

Post by regiscaelus »

Division is a bit more straight forward. Writing to WRDIVB:
- always writes WRDIV to RDMPY thus can alter/corrupt results when division is active
- but only starts a new division if division is complete (>16 cycles)
IMG_20220830_154507.jpg
User avatar
FitzRoy
Posts: 144
Joined: Wed Oct 22, 2008 9:27 pm
Contact:

Re: Writing $4203 twice too fast gives erroneous result (not emulated)

Post by FitzRoy »

It would be greatly appreciated from those making test roms to make them colored pass/fail tests. It's just a lot easier than trying to keep track of screenshots when there are so many other test roms to collect and backtest.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Writing $4203 twice too fast gives erroneous result (not emulated)

Post by rainwarrior »

These are exploratory test ROMs, not emulator verification tests. They're for testing a wide variety of inputs to gather information about what was going on.

Once we have better information about the effect and how it works, and how to emulate it, then it makes sense to make an emulator test ROM as well.

We need both of those things.
User avatar
carmiker
Posts: 12
Joined: Wed Sep 16, 2020 4:16 am
Contact:

Re: Writing $4203 twice too fast gives erroneous result (not emulated)

Post by carmiker »

Thanks regiscaelus for that explanation. That made it easy for me to create a draft solution for my fork of bsnes, which I'll commit once I am confident in it and have made it less hacky.

Code: Select all

diff --git a/src/cpu.cpp b/src/cpu.cpp
index ca9fb07..e2e9e62 100644
--- a/src/cpu.cpp
+++ b/src/cpu.cpp
@@ -502,8 +502,11 @@ void CPU::writeCPU(unsigned addr, uint8_t data) {
     io.wrmpyb = data;
     io.rddiv = io.wrmpyb << 8 | io.wrmpya;
 
-    alu.mpyctr = 8;  //perform multiplication over the next eight cycles
-    alu.shift = io.wrmpyb;
+    if (!alu.mpylast) {
+      alu.mpyctr = 8;  //perform multiplication over the next eight cycles
+      alu.shift = io.wrmpyb;
+    }
+
     return;
 
   case 0x4204:  //WRDIVL
@@ -518,10 +521,11 @@ void CPU::writeCPU(unsigned addr, uint8_t data) {
     io.rdmpy = io.wrdiva;
     if(alu.mpyctr || alu.divctr) return;
 
-    io.wrdivb = data;
-
-    alu.divctr = 16;  //perform division over the next sixteen cycles
-    alu.shift = io.wrdivb << 16;
+    if (!alu.divlast) {
+        io.wrdivb = data;
+        alu.divctr = 16;  //perform division over the next sixteen cycles
+        alu.shift = io.wrdivb << 16;
+    }
     return;
 
   case 0x4207:  //HTIMEL
@@ -772,13 +776,19 @@ void CPU::scanline() {
 void CPU::aluEdge() {
   if(alu.mpyctr) {
     --alu.mpyctr;
+    if (!alu.mpyctr)
+        alu.mpylast = 1;
     if(io.rddiv & 1) io.rdmpy += alu.shift;
     io.rddiv >>= 1;
     alu.shift <<= 1;
   }
+  else
+    alu.mpylast = 0;
 
   if(alu.divctr) {
     --alu.divctr;
+    if (!alu.divctr)
+        alu.divlast = 1;
     io.rddiv <<= 1;
     alu.shift >>= 1;
     if(io.rdmpy >= alu.shift) {
@@ -786,6 +796,8 @@ void CPU::aluEdge() {
       io.rddiv |= 1;
     }
   }
+  else
+    alu.divlast = 0;
 }
 
 void CPU::dmaEdge() {
diff --git a/src/cpu.hpp b/src/cpu.hpp
index f48f400..2d0752a 100644
--- a/src/cpu.hpp
+++ b/src/cpu.hpp
@@ -194,7 +194,9 @@ private:
 
   struct ALU {
     unsigned mpyctr = 0;
+    unsigned mpylast = 0;
     unsigned divctr = 0;
+    unsigned divlast = 0;
     unsigned shift = 0;
   } alu;
Myself086: I am occasionally having a blank screen or very wrong colours in both the original bsnes (in accuracy mode) and my fork with your test ROM. I am not sure if this is an issue with the ROM or bsnes.
Last edited by carmiker on Wed Aug 31, 2022 4:27 pm, edited 3 times in total.
Post Reply