rewrite dma, gxfifo, gxstat, command unpacking; old gxfifo removed; many games fixed, gta and dq4 broken; dma still not finished; your savestates will be broken; have coded 40 hours without checking performance, beware; add dma regs to ioregview, fix cpu selector in < vista;

This commit is contained in:
zeromus 2009-09-21 01:51:42 +00:00
parent 8c6e56e679
commit 523d2713f9
18 changed files with 1608 additions and 1203 deletions

View File

@ -144,6 +144,10 @@ void IPC_FIFOcnt(u8 proc, u16 val)
GFX_PIPE gxPIPE;
GFX_FIFO gxFIFO;
void GFX_PIPEclear()
{
gxPIPE.head = 0;
@ -153,192 +157,122 @@ void GFX_PIPEclear()
void GFX_FIFOclear()
{
u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600);
gxstat &= 0x0000FFFF;
gxFIFO.head = 0;
gxFIFO.tail = 0;
gxFIFO.size = 0;
gxstat |= 0x06000000;
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat);
}
static void GXF_FIFO_handleEvents()
{
if(gxFIFO.size <= 127)
{
//TODO - should this always happen, over and over, until the dma is disabled?
//or only when we change to this state?
if(MMU_new.gxstat.gxfifo_irq == 1)
setIF(0, (1<<21)); //the half gxfifo irq
//might need to trigger a gxfifo dma
triggerDma(EDMAMode_GXFifo);
}
if(gxFIFO.size == 0) {
//we just went to empty
if(MMU_new.gxstat.gxfifo_irq == 2)
setIF(0, (1<<21)); //the empty gxfifo irq
}
}
void GFX_FIFOsend(u8 cmd, u32 param)
{
u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600);
if(cmd==0x41) {
int zzz=9;
}
//INFO("gxFIFO: send 0x%02X = 0x%08X (size %03i/0x%02X) gxstat 0x%08X\n", cmd, param, gxFIFO.size, gxFIFO.size, gxstat);
//printf("fifo recv: %02X: %08X upto:%d\n",cmd,param,gxFIFO.size+1);
gxstat &= 0xF000FFFF;
//TODO - WOAH ! NOT HANDLING A TOO-BIG FIFO RIGHT NOW!
//if (gxFIFO.size > 255)
//{
// GXF_FIFO_handleEvents();
// //NEED TO HANDLE THIS!!!!!!!!!!!!!!!!!!!!!!!!!!
if (gxFIFO.size == 0) // FIFO empty
{
gxstat |= 0x06000000;
if (gxPIPE.size < 4) // pipe not full
{
gxPIPE.cmd[gxPIPE.tail] = cmd;
gxPIPE.param[gxPIPE.tail] = param;
gxPIPE.tail++;
gxPIPE.size++;
if (gxPIPE.tail > 3) gxPIPE.tail = 0;
#ifdef USE_GEOMETRY_FIFO_EMULATION
gxstat |= 0x08000000; // set busy flag
#endif
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat);
NDS_RescheduleGXFIFO();
return;
}
}
// //gxstat |= 0x08000000; // busy
// NDS_RescheduleGXFIFO(1);
// //INFO("ERROR: gxFIFO is full (cmd 0x%02X = 0x%08X) (prev cmd 0x%02X = 0x%08X)\n", cmd, param, gxFIFO.cmd[255], gxFIFO.param[255]);
// return;
//}
if (gxFIFO.size > 255)
{
#ifdef USE_GEOMETRY_FIFO_EMULATION
gxstat |= 0x01000000; // full
gxstat |= 0x08000000; // busy
#else
gxstat |= 0x02000000; // this is hack (must be removed later)
#endif
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat);
NDS_RescheduleGXFIFO();
//INFO("ERROR: gxFIFO is full (cmd 0x%02X = 0x%08X) (prev cmd 0x%02X = 0x%08X)\n", cmd, param, gxFIFO.cmd[255], gxFIFO.param[255]);
return;
}
gxFIFO.cmd[gxFIFO.tail] = cmd;
gxFIFO.param[gxFIFO.tail] = param;
gxFIFO.tail++;
gxFIFO.size++;
if (gxFIFO.tail > 255) gxFIFO.tail = 0;
#ifdef USE_GEOMETRY_FIFO_EMULATION
gxstat |= 0x08000000; // set busy flag
#endif
if (gxFIFO.tail > HACK_GXIFO_SIZE-1) gxFIFO.tail = 0;
gxstat |= ((gxFIFO.size & 0x1FF) << 16);
if (gxFIFO.size < 128) // less half
{
gxstat |= 0x02000000;
if(gxFIFO.size>=HACK_GXIFO_SIZE) {
printf("--FIFO FULL-- : %d\n",gxFIFO.size);
}
#ifndef USE_GEOMETRY_FIFO_EMULATION
gxstat |= 0x02000000; // this is hack (must be removed later)
#endif
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat);
NDS_RescheduleGXFIFO();
//gxstat |= 0x08000000; // set busy flag
GXF_FIFO_handleEvents();
NDS_RescheduleGXFIFO(1);
}
// this function used ONLY in gxFIFO
BOOL GFX_PIPErecv(u8 *cmd, u32 *param)
{
u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600);
gxstat &= 0xF7FFFFFF; // clear busy flag
//gxstat &= 0xF7FFFFFF; // clear busy flag
if (gxPIPE.size > 0)
if (gxFIFO.size == 0)
{
*cmd = gxPIPE.cmd[gxPIPE.head];
*param = gxPIPE.param[gxPIPE.head];
gxPIPE.head++;
gxPIPE.size--;
if (gxPIPE.head > 3) gxPIPE.head = 0;
if (gxPIPE.size < 3)
{
if (gxFIFO.size > 0)
{
gxstat &= 0xF000FFFF;
gxPIPE.cmd[gxPIPE.tail] = gxFIFO.cmd[gxFIFO.head];
gxPIPE.param[gxPIPE.tail] = gxFIFO.param[gxFIFO.head];
gxPIPE.tail++;
gxPIPE.size++;
if (gxPIPE.tail > 3) gxPIPE.tail = 0;
gxFIFO.head++;
gxFIFO.size--;
if (gxFIFO.head > 255) gxFIFO.head = 0;
if (gxFIFO.size > 0)
{
gxPIPE.cmd[gxPIPE.tail] = gxFIFO.cmd[gxFIFO.head];
gxPIPE.param[gxPIPE.tail] = gxFIFO.param[gxFIFO.head];
gxPIPE.tail++;
gxPIPE.size++;
if (gxPIPE.tail > 3) gxPIPE.tail = 0;
gxFIFO.head++;
gxFIFO.size--;
if (gxFIFO.head > 255) gxFIFO.head = 0;
}
gxstat |= ((gxFIFO.size & 0x1FF) << 16);
if (gxFIFO.size < 128)
{
gxstat |= 0x02000000;
if (gxstat & 0x40000000) // IRQ: less half
{
setIF(0, (1<<21));
}
execHardware_doAllDma(EDMAMode_GXFifo);
}
if (gxFIFO.size == 0) // empty
{
gxstat |= 0x04000000;
if (gxstat & 0x80000000) // IRQ: empty
setIF(0, (1<<21));
}
}
else // FIFO empty
{
gxstat &= 0xF000FFFF;
gxstat |= 0x06000000;
if (gxstat & 0x80000000) // IRQ: empty
setIF(0, (1<<21));
}
}
if (gxPIPE.size > 0)
gxstat |= 0x08000000; // set busy flag
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat);
return (TRUE);
GXF_FIFO_handleEvents();
return FALSE;
}
if (gxstat & 0x80000000) // IRQ: empty
setIF(0, (1<<21));
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat);
return FALSE;
*cmd = gxFIFO.cmd[gxFIFO.head];
*param = gxFIFO.param[gxFIFO.head];
gxFIFO.head++;
gxFIFO.size--;
if (gxFIFO.head > HACK_GXIFO_SIZE-1) gxFIFO.head = 0;
GXF_FIFO_handleEvents();
return (TRUE);
}
void GFX_FIFOcnt(u32 val)
{
u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600);
//INFO("gxFIFO: write cnt 0x%08X (prev 0x%08X) FIFO size %03i PIPE size %03i\n", val, gxstat, gxFIFO.size, gxPIPE.size);
//zeromus: i dont like any of this.
if (val & (1<<29)) // clear? (only in homebrew?)
{
GFX_PIPEclear();
GFX_FIFOclear();
return;
}
////INFO("gxFIFO: write cnt 0x%08X (prev 0x%08X) FIFO size %03i PIPE size %03i\n", val, gxstat, gxFIFO.size, gxPIPE.size);
if (val & (1<<15)) // projection stack pointer reset
{
gfx3d_ClearStack();
val &= 0xFFFF5FFF; // clear reset (bit15) & stack level (bit13)
}
//if (val & (1<<29)) // clear? (only in homebrew?)
//{
// GFX_PIPEclear();
// GFX_FIFOclear();
// return;
//}
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, val);
//if (val & (1<<15)) // projection stack pointer reset
//{
// gfx3d_ClearStack();
// val &= 0xFFFF5FFF; // clear reset (bit15) & stack level (bit13)
//}
if (gxFIFO.size == 0) // empty
{
if (val & 0x80000000) // IRQ: empty
setIF(0, (1<<21));
}
//T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, val);
//if (gxFIFO.size == 0) // empty
//{
// if (val & 0x80000000) // IRQ: empty
// setIF(0, (1<<21));
//}
}
// ========================================================= DISP FIFO

View File

@ -26,8 +26,6 @@
#ifndef FIFO_H
#define FIFO_H
//#define USE_GEOMETRY_FIFO_EMULATION //enable gxFIFO emulation
#include "types.h"
//=================================================== IPC FIFO
@ -47,14 +45,20 @@ extern u32 IPC_FIFOrecv(u8 proc);
extern void IPC_FIFOcnt(u8 proc, u16 val);
//=================================================== GFX FIFO
//yeah, its oversize for now. thats a simpler solution
//moon seems to overdrive the fifo with immediate dmas
//i think this might be nintendo code too
#define HACK_GXIFO_SIZE 200000
typedef struct
{
u8 cmd[256];
u32 param[256];
u8 cmd[HACK_GXIFO_SIZE];
u32 param[HACK_GXIFO_SIZE];
u16 head; // start position
u16 tail; // tail
u16 size; // size FIFO buffer
u32 head; // start position
u32 tail; // tail
u32 size; // size FIFO buffer
} GFX_FIFO;
typedef struct

File diff suppressed because it is too large Load Diff

View File

@ -27,8 +27,9 @@
#include "FIFO.h"
#include "mem.h"
#include "registers.h"
#include "mc.h"
#include "bits.h"
#define ARMCPU_ARM7 1
#define ARMCPU_ARM9 0
@ -36,6 +37,195 @@
typedef const u8 TWaitState;
enum EDMAMode : u8
{
EDMAMode_Immediate = 0,
EDMAMode_VBlank = 1,
EDMAMode_HBlank = 2,
EDMAMode_HStart = 3,
EDMAMode_MemDisplay = 4,
EDMAMode_Card = 5,
EDMAMode_GBASlot = 6,
EDMAMode_GXFifo = 7,
EDMAMode7_Wifi = 8,
EDMAMode7_GBASlot = 9,
};
enum EDMABitWidth : u8
{
EDMABitWidth_16 = 0,
EDMABitWidth_32 = 1
};
enum EDMASourceUpdate : u8
{
EDMASourceUpdate_Increment = 0,
EDMASourceUpdate_Decrement = 1,
EDMASourceUpdate_Fixed = 2,
EDMASourceUpdate_Invalid = 3,
};
enum EDMADestinationUpdate : u8
{
EDMADestinationUpdate_Increment = 0,
EDMADestinationUpdate_Decrement = 1,
EDMADestinationUpdate_Fixed = 2,
EDMADestinationUpdate_IncrementReload = 3,
};
class TRegister_32
{
public:
virtual u32 read32() = 0;
virtual void write32(const u32 val) = 0;
void write(const int size, const u32 adr, const u32 val) {
if(size==32) write32(val);
else {
const u32 offset = adr&3;
const u32 baseaddr = adr&~offset;
if(size==8) {
printf("WARNING! 8BIT DMA ACCESS\n");
u32 mask = 0xFF<<(offset<<3);
write32((read32()&~mask)|(val<<(offset<<3)));
}
else if(size==16) {
u32 mask = 0xFFFF<<(offset<<3);
write32((read32()&~mask)|(val<<(offset<<3)));
}
}
}
u32 read(const int size, const u32 adr)
{
if(size==32) return read32();
else {
const u32 offset = adr&3;
const u32 baseaddr = adr&~offset;
if(size==8) { printf("WARNING! 8BIT DMA ACCESS\n"); return (read32()>>(offset<<3))&0xFF; }
else return (read32()>>(offset<<3))&0xFFFF;
}
}
};
struct TGXSTAT : public TRegister_32
{
TGXSTAT() {
gxfifo_irq = se = tr = tb = 0;
}
u8 tb; //test busy
u8 tr; //test result
u8 se; //stack error
u8 gxfifo_irq; //irq configuration
virtual u32 read32();
virtual void write32(const u32 val);
void savestate(EMUFILE *f);
bool loadstate(EMUFILE *f);
};
void triggerDma(EDMAMode mode);
class DmaController
{
public:
u8 enable, irq, repeatMode, _startmode;
u8 userEnable;
u32 wordcount;
EDMAMode startmode;
EDMABitWidth bitWidth;
EDMASourceUpdate sar;
EDMADestinationUpdate dar;
u32 saddr, daddr;
//indicates whether the dma needs to be checked for triggering
BOOL check;
//indicates whether the dma right now is logically running
//(though for now we copy all the data when it triggers)
BOOL running;
BOOL paused;
//this flag will sometimes be set when a start condition is triggered
//other conditions may be automatically triggered based on scanning conditions
BOOL triggered;
u64 nextEvent;
int procnum, chan;
void savestate(EMUFILE *f);
bool loadstate(EMUFILE *f);
void exec();
void doCopy();
void doPause();
void doStop();
void doSchedule();
void tryTrigger(EDMAMode mode);
DmaController() :
enable(0), irq(0), bitWidth(EDMABitWidth_16), repeatMode(0), _startmode(0),
sar(EDMASourceUpdate_Increment), dar(EDMADestinationUpdate_Increment),
wordcount(0), startmode(EDMAMode_Immediate),
sad(&saddr),
dad(&daddr),
check(FALSE),
running(FALSE),
paused(FALSE),
triggered(FALSE),
nextEvent(0)
{
sad.controller = this;
dad.controller = this;
ctrl.controller = this;
regs[0] = &sad;
regs[1] = &dad;
regs[2] = &ctrl;
}
class AddressRegister : public TRegister_32 {
public:
//we pass in a pointer to the controller here so we can alert it if anything changes
DmaController* controller;
u32 * const ptr;
AddressRegister(u32* _ptr)
: ptr(_ptr)
{}
virtual u32 read32() {
return *ptr;
}
virtual void write32(const u32 val) {
*ptr = val;
}
};
class ControlRegister : public TRegister_32 {
public:
//we pass in a pointer to the controller here so we can alert it if anything changes
DmaController* controller;
ControlRegister() {}
virtual u32 read32() {
return controller->read32();
}
virtual void write32(const u32 val) {
return controller->write32(val);
}
};
AddressRegister sad, dad;
ControlRegister ctrl;
TRegister_32* regs[3];
void write32(const u32 val);
u32 read32();
};
enum ECardMode
{
CardMode_Normal = 0,
@ -168,9 +358,17 @@ struct MMU_struct
u32 CheckDMAs;
};
//this contains things which can't be memzeroed because they are smarter classes
struct MMU_struct_new
{
MMU_struct_new() ;
BackupDevice backupDevice;
DmaController dma[2][4];
TGXSTAT gxstat;
void write_dma(const int proc, const int size, const u32 adr, const u32 val);
u32 read_dma(const int proc, const int size, const u32 adr);
bool is_dma(const u32 adr) { return adr >= _REG_DMA_CONTROL_MIN && adr <= _REG_DMA_CONTROL_MAX; }
};
extern MMU_struct MMU;
@ -220,7 +418,7 @@ void FASTCALL MMU_write8(u32 proc, u32 adr, u8 val);
void FASTCALL MMU_write16(u32 proc, u32 adr, u16 val);
void FASTCALL MMU_write32(u32 proc, u32 adr, u32 val);
template<int PROCNUM> void FASTCALL MMU_doDMA(u32 num);
//template<int PROCNUM> void FASTCALL MMU_doDMA(u32 num);
//The base ARM memory interfaces
extern struct armcpu_memory_iface arm9_base_memory_iface;
@ -343,20 +541,6 @@ inline void SetupMMU(BOOL debugConsole) {
//T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(adr >> 20) & 0xFF],
// adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr >> 20) & 0xFF]);
enum EDMAMode
{
EDMAMode_Immediate = 0,
EDMAMode_VBlank = 1,
EDMAMode_HBlank = 2,
EDMAMode_HStart = 3,
EDMAMode_MemDisplay = 4,
EDMAMode_Card = 5,
EDMAMode_GBASlot = 6,
EDMAMode_GXFifo = 7,
EDMAMode7_Wifi = 8,
EDMAMode7_GBASlot = 9,
};
FORCEINLINE u8 _MMU_read08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr)
{
//special handling for DMA: read 0 from TCM

View File

@ -1492,22 +1492,6 @@ void NDS_SkipNextFrame() {
#define INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF))
static void execHardware_doDma(int procnum, int chan, EDMAMode modeNum)
{
if(MMU.DMAStartTime[procnum][chan] == modeNum)
{
if(procnum == ARMCPU_ARM9) MMU_doDMA<ARMCPU_ARM9>(chan);
else MMU_doDMA<ARMCPU_ARM7>(chan);
//MMU.DMAStartTime[procnum][chan] = 0; //this was here for main mem dma
}
}
void execHardware_doAllDma(EDMAMode modeNum)
{
for(int i=0;i<2;i++)
for(int j=0;j<4;j++)
execHardware_doDma(i,j,modeNum);
}
enum ESI_DISPCNT
{
@ -1555,22 +1539,15 @@ struct TSequenceItem_GXFIFO : public TSequenceItem
{
FORCEINLINE bool isTriggered()
{
#ifndef USE_GEOMETRY_FIFO_EMULATION
return false;
#else
return enabled && nds_timer >= MMU.gfx3dCycles;
#endif
return enabled && nds_timer >= MMU.gfx3dCycles;
}
FORCEINLINE void exec()
{
#ifdef USE_GEOMETRY_FIFO_EMULATION
enabled = false; //do this first, because gfx3d_execute3D() will cause more scheduled events if necessary
while(isTriggered()) {
enabled = false;
gfx3d_execute3D();
MMU.gfx3dCycles = max(MMU.gfx3dCycles,nds_timer); //uhh i dont entirely understand why this was necessary
//i need to learn more about how the new gxfifo works, but I am leaving that to you for now crazymax ^_^
#endif
}
}
FORCEINLINE u64 next()
@ -1651,30 +1628,57 @@ template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem
template<int procnum, int chan> struct TSequenceItem_DMA : public TSequenceItem
{
DmaController* controller;
FORCEINLINE bool isTriggered()
{
return (MMU.DMAing[procnum][chan])&&nds_timer>=(MMU.DMACycle[procnum][chan]);
return (controller->check && nds_timer>= controller->nextEvent);
}
FORCEINLINE bool isEnabled() { return MMU.DMAing[procnum][chan]!=0; }
FORCEINLINE bool isEnabled() {
return controller->check?TRUE:FALSE;
}
FORCEINLINE u64 next()
{
return MMU.DMACycle[procnum][chan];
return controller->nextEvent;
}
FORCEINLINE void exec()
{
if (MMU.DMACompleted[procnum][chan])
{
u8* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG;
T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF);
if((MMU.DMACrt[procnum][chan])&(1<<30)) {
if(procnum==0) NDS_makeARM9Int(8+chan);
else NDS_makeARM7Int(8+chan);
}
MMU.DMAing[procnum][chan] = FALSE;
}
//printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan);
controller->exec();
// //give gxfifo dmas a chance to re-trigger
// if(MMU.DMAStartTime[procnum][chan] == EDMAMode_GXFifo) {
// MMU.DMAing[procnum][chan] = FALSE;
// if (gxFIFO.size <= 127)
// {
// execHardware_doDma(procnum,chan,EDMAMode_GXFifo);
// if (MMU.DMACompleted[procnum][chan])
// goto docomplete;
// else return;
// }
// }
//
//docomplete:
// if (MMU.DMACompleted[procnum][chan])
// {
// u8* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG;
//
// //disable the channel
// if(MMU.DMAStartTime[procnum][chan] != EDMAMode_GXFifo) {
// T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF);
// MMU.DMACrt[procnum][chan] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory
// }
//
// if((MMU.DMACrt[procnum][chan])&(1<<30)) {
// if(procnum==0) NDS_makeARM9Int(8+chan);
// else NDS_makeARM7Int(8+chan);
// }
//
// MMU.DMAing[procnum][chan] = FALSE;
// }
}
};
@ -1790,12 +1794,14 @@ struct Sequencer
} sequencer;
void NDS_RescheduleGXFIFO()
void NDS_RescheduleGXFIFO(u32 cost)
{
#ifdef USE_GEOMETRY_FIFO_EMULATION
sequencer.gxfifo.enabled = true;
if(!sequencer.gxfifo.enabled) {
MMU.gfx3dCycles = nds_timer;
sequencer.gxfifo.enabled = true;
}
MMU.gfx3dCycles += cost;
NDS_Reschedule();
#endif
}
void NDS_RescheduleTimers()
@ -1812,6 +1818,7 @@ void NDS_RescheduleDMA()
{
//TBD
NDS_Reschedule();
}
static void initSchedule()
@ -1850,6 +1857,15 @@ void Sequencer::init()
gxfifo.enabled = false;
dma_0_0.controller = &MMU_new.dma[0][0];
dma_0_1.controller = &MMU_new.dma[0][1];
dma_0_2.controller = &MMU_new.dma[0][2];
dma_0_3.controller = &MMU_new.dma[0][3];
dma_1_0.controller = &MMU_new.dma[1][0];
dma_1_1.controller = &MMU_new.dma[1][1];
dma_1_2.controller = &MMU_new.dma[1][2];
dma_1_3.controller = &MMU_new.dma[1][3];
#ifdef EXPERIMENTAL_WIFI
wifi.enabled = true;
@ -1891,7 +1907,7 @@ static void execHardware_hblank()
//trigger hblank dmas
//but notice, we do that just after we finished drawing the line
//(values copied by this hdma should not be used until the next scanline)
execHardware_doAllDma(EDMAMode_HBlank);
triggerDma(EDMAMode_HBlank);
}
}
@ -1908,6 +1924,8 @@ static void execHardware_hstart_vblankEnd()
static void execHardware_hstart_vblankStart()
{
//printf("--------VBLANK!!!--------\n");
//turn on vblank status bit
T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1);
T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1);
@ -1927,7 +1945,7 @@ static void execHardware_hstart_vblankStart()
SkipCur2DFrame = false;
//trigger vblank dmas
execHardware_doAllDma(EDMAMode_VBlank);
triggerDma(EDMAMode_VBlank);
}
static void execHardware_hstart_vcount()
@ -1979,7 +1997,7 @@ static void execHardware_hstart()
execHardware_hstart_vcount();
//trigger hstart dmas
execHardware_doAllDma(EDMAMode_HStart);
triggerDma(EDMAMode_HStart);
if(nds.VCount<192)
{
@ -1988,7 +2006,7 @@ static void execHardware_hstart()
//it should be driven by a fifo (and generate just in time as the scanline is displayed)
//but that isnt even possible until we have some sort of sub-scanline timing.
//it may not be necessary.
execHardware_doAllDma(EDMAMode_MemDisplay);
triggerDma(EDMAMode_MemDisplay);
}
//end of 3d vblank
@ -2321,12 +2339,6 @@ void NDS_exec(s32 nb)
void execHardware_interrupts()
{
//THIS IS A HACK but it is necessary until we have gxfifo emulation
#ifndef USE_GEOMETRY_FIFO_EMULATION
if(MMU.reg_IE[ARMCPU_ARM9]&(1<<21))
NDS_makeARM9Int(21); // GX geometry
#endif
if((MMU.reg_IF[0]&MMU.reg_IE[0]) && (MMU.reg_IME[0]))
{
#ifdef GDB_STUB

View File

@ -146,7 +146,7 @@ void emu_halt();
extern u64 nds_timer;
void NDS_Reschedule();
void NDS_RescheduleGXFIFO();
void NDS_RescheduleGXFIFO(u32 cost);
void NDS_RescheduleDMA();
void NDS_RescheduleTimers();

View File

@ -855,12 +855,12 @@ static void OGLRender()
glBegin(GL_TRIANGLES);
VERT *vert0 = &gfx3d.vertlist->list[poly->vertIndexes[0]];
float alpha = poly->getAlpha()/31.0;
float alpha = poly->getAlpha()/31.0f;
if(wireframe) alpha = 1.0;
float color0[4] = {
(vert0->color[0]<<2)/255.0,
(vert0->color[1]<<2)/255.0,
(vert0->color[2]<<2)/255.0,
(vert0->color[0]<<2)/255.0f,
(vert0->color[1]<<2)/255.0f,
(vert0->color[2]<<2)/255.0f,
alpha
};
@ -873,15 +873,15 @@ static void OGLRender()
VERT *vert2 = &gfx3d.vertlist->list[poly->vertIndexes[j+1]];
float color1[4] = {
(vert1->color[0]<<2)/255.0,
(vert1->color[1]<<2)/255.0,
(vert1->color[2]<<2)/255.0,
(vert1->color[0]<<2)/255.0f,
(vert1->color[1]<<2)/255.0f,
(vert1->color[2]<<2)/255.0f,
alpha
};
float color2[4] = {
(vert2->color[0]<<2)/255.0,
(vert2->color[1]<<2)/255.0,
(vert2->color[2]<<2)/255.0,
(vert2->color[0]<<2)/255.0f,
(vert2->color[1]<<2)/255.0f,
(vert2->color[2]<<2)/255.0f,
alpha
};

View File

@ -141,7 +141,7 @@ static void gbaWriteFlash(u32 adr, u8 val)
{
u32 ofs = (adr & 0x0000F000);
//INFO("GBAgame: Flash: erase from 0x%08X to 0x%08X\n", ofs + 0x0A000000, ofs + 0x0A001000);
for (int i = ofs; i < (ofs + 0x1000); i++)
for (u32 i = ofs; i < (ofs + 0x1000); i++)
saveData[i] = 0xFF;
}
gbaFlash.state = 0;
@ -223,7 +223,7 @@ static u8 getSaveTypeGBA(const u8 *data, const u32 size)
u8 type = 0;
u8 *dat = (u8 *)data;
for (int i = 0; i < (size / 4); i++)
for (u32 i = 0; i < (size / 4); i++)
{
u32 tmp = T1ReadLong(dat, i);

View File

@ -24,12 +24,11 @@
#include "MMU.h"
#include "SPU.h"
#include "debug.h"
#include "NDSSystem.h"
#define cpu (&ARMPROC)
#define TEMPLATE template<int PROCNUM>
extern BOOL execute;
static const u16 getsinetbl[] = {
0x0000, 0x0324, 0x0648, 0x096A, 0x0C8C, 0x0FAB, 0x12C8, 0x15E2,
0x18F9, 0x1C0B, 0x1F1A, 0x2223, 0x2528, 0x2826, 0x2B1F, 0x2E11,
@ -198,6 +197,7 @@ TEMPLATE static u32 bios_nop()
TEMPLATE static u32 WaitByLoop()
{
//printf("%lld waitbyloop\n",nds_timer);
//INFO("ARM%c: SWI 0x03 (WaitByLoop)\n", PROCNUM?'7':'9');
if (PROCNUM == ARMCPU_ARM9)
{

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,47 @@
#include "emufile.h"
//geometry engine command numbers
#define GFX3D_NOP 0x00
#define GFX3D_MTX_MODE 0x10
#define GFX3D_MTX_PUSH 0x11
#define GFX3D_MTX_POP 0x12
#define GFX3D_MTX_STORE 0x13
#define GFX3D_MTX_RESTORE 0x14
#define GFX3D_MTX_IDENTITY 0x15
#define GFX3D_MTX_LOAD_4x4 0x16
#define GFX3D_MTX_LOAD_4x3 0x17
#define GFX3D_MTX_MULT_4x4 0x18
#define GFX3D_MTX_MULT_4x3 0x19
#define GFX3D_MTX_MULT_3x3 0x1A
#define GFX3D_MTX_SCALE 0x1B
#define GFX3D_MTX_TRANS 0x1C
#define GFX3D_COLOR 0x20
#define GFX3D_NORMAL 0x21
#define GFX3D_TEXCOORD 0x22
#define GFX3D_VTX_16 0x23
#define GFX3D_VTX_10 0x24
#define GFX3D_XY 0x25
#define GFX3D_XZ 0x26
#define GFX3D_YZ 0x27
#define GFX3D_DIFF 0x28
#define GFX3D_POLYGON_ATTR 0x29
#define GFX3D_TEXIMAGE_PARAM 0x2A
#define GFX3D_PLTT_BASE 0x2B
#define GFX3D_DIF_AMB 0x30
#define GFX3D_SPE_EMI 0x31
#define GFX3D_LIGHT_VECTOR 0x32
#define GFX3D_LIGHT_COLOR 0x33
#define GFX3D_SHININESS 0x34
#define GFX3D_BEGIN_VTXS 0x40
#define GFX3D_END_VTXS 0x41
#define GFX3D_SWAP_BUFFERS 0x50
#define GFX3D_VIEWPORT 0x60
#define GFX3D_BOX_TEST 0x70
#define GFX3D_POS_TEST 0x71
#define GFX3D_VEC_TEST 0x72
#define GFX3D_NOP_NOARG_HACK 0xDD
//produce a 32bpp color from a DS RGB16
#define RGB16TO32(col,alpha) (((alpha)<<24) | ((((col) & 0x7C00)>>7)<<16) | ((((col) & 0x3E0)>>2)<<8) | (((col) & 0x1F)<<3))
@ -274,44 +315,8 @@ extern CACHE_ALIGN const u8 material_3bit_to_8bit[8];
extern CACHE_ALIGN u8 gfx3d_convertedScreen[256*192*4];
extern CACHE_ALIGN u8 gfx3d_convertedAlpha[256*192*2]; //see cpp for explanation of illogical *2
//GE commands:
#ifndef USE_GEOMETRY_FIFO_EMULATION
void gfx3d_glMatrixMode(u32 v);
void gfx3d_glPushMatrix(void);
void gfx3d_glPopMatrix(s32 i);
void gfx3d_glStoreMatrix(u32 v);
void gfx3d_glRestoreMatrix(u32 v);
void gfx3d_glLoadIdentity();
BOOL gfx3d_glLoadMatrix4x4(s32 v);
BOOL gfx3d_glLoadMatrix4x3(s32 v);
BOOL gfx3d_glMultMatrix4x4(s32 v);
BOOL gfx3d_glMultMatrix3x3(s32 v);
BOOL gfx3d_glMultMatrix4x3(s32 v);
BOOL gfx3d_glScale(s32 v);
BOOL gfx3d_glTranslate(s32 v);
void gfx3d_glColor3b(u32 v);
void gfx3d_glNormal(u32 v);
void gfx3d_glTexCoord(u32 val);
BOOL gfx3d_glVertex16b(u32 v);
void gfx3d_glVertex10b(u32 v);
void gfx3d_glVertex3_cord(u32 one, u32 two, u32 v);
void gfx3d_glVertex_rel(u32 v);
void gfx3d_glPolygonAttrib (u32 val);
void gfx3d_glTexImage(u32 val);
void gfx3d_glTexPalette(u32 val);
void gfx3d_glMaterial0(u32 val);
void gfx3d_glMaterial1(u32 val);
void gfx3d_glLightDirection (u32 v);
void gfx3d_glLightColor (u32 v);
BOOL gfx3d_glShininess (u32 val);
void gfx3d_glBegin(u32 v);
void gfx3d_glEnd(void);
// SwapBuffers see follow
void gfx3d_glViewPort(u32 v);
BOOL gfx3d_glBoxTest(u32 v);
BOOL gfx3d_glPosTest(u32 v);
void gfx3d_glVecTest(u32 v);
#endif
extern BOOL isSwapBuffers;
void gfx3d_glFlush(u32 v);
// end GE commands
@ -332,9 +337,7 @@ u16 gfx3d_glGetVecRes(u32 index);
void gfx3d_VBlankSignal();
void gfx3d_VBlankEndSignal(bool skipFrame);
void gfx3d_Control(u32 v);
#ifdef USE_GEOMETRY_FIFO_EMULATION
void gfx3d_execute3D();
#endif
void gfx3d_sendCommandToFIFO(u32 val);
void gfx3d_sendCommand(u32 cmd, u32 param);
@ -352,4 +355,5 @@ void gfx3d_savestate(EMUFILE* os);
bool gfx3d_loadstate(EMUFILE* is, int size);
void gfx3d_ClearStack();
#endif
#endif //_GFX3D_H_

View File

@ -1353,6 +1353,7 @@ static void SoftRastRender()
}
//printf("%d %d %d %d\n",gfx3d.viewport.x,gfx3d.viewport.y,gfx3d.viewport.width,gfx3d.viewport.height);
// printf("%f\n",vert.coord[0]);
//viewport transforms
for(int i=0;i<clippedPolyCounter;i++)

View File

@ -32,6 +32,21 @@ int write16le(u16 b, EMUFILE* os);
int write32le(u32 b, EMUFILE* os);
int write64le(u64 b, EMUFILE* os);
template<typename T>
int readle(T *Bufo, EMUFILE*is)
{
CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8);
switch(sizeof(T)) {
case 1: return read8le((u8*)Bufo,is);
case 2: return read16le((u16*)Bufo,is);
case 4: return read32le((u32*)Bufo,is);
case 8: return read64le((u64*)Bufo,is);
default:
return 0;
}
}
int read8le(u8 *Bufo, EMUFILE*is);
int read16le(u16 *Bufo, EMUFILE*is);
inline int read16le(s16 *Bufo, EMUFILE*is) { return read16le((u16*)Bufo,is); }

View File

@ -78,22 +78,40 @@
#define REG_DISPA_MASTERBRIGHT 0x0400006C
// DMA
#define _REG_DMA_CONTROL_MIN 0x040000B0
#define REG_DMA0SAD 0x040000B0
#define REG_DMA0SADL 0x040000B0
#define REG_DMA0SADH 0x040000B2
#define REG_DMA0DAD 0x040000B4
#define REG_DMA0DADL 0x040000B4
#define REG_DMA0DADH 0x040000B6
#define REG_DMA0CNTL 0x040000B8
#define REG_DMA0CNTH 0x040000BA
#define REG_DMA1SAD 0x040000BC
#define REG_DMA1SADL 0x040000BC
#define REG_DMA1SADH 0x040000BE
#define REG_DMA1DAD 0x040000C0
#define REG_DMA1DADL 0x040000C0
#define REG_DMA1DADH 0x040000C2
#define REG_DMA1CNTL 0x040000C4
#define REG_DMA1CNTH 0x040000C6
#define REG_DMA2SAD 0x040000C8
#define REG_DMA2SADL 0x040000C8
#define REG_DMA2SADH 0x040000CA
#define REG_DMA2DAD 0x040000CC
#define REG_DMA2DADL 0x040000CC
#define REG_DMA2DADH 0x040000CE
#define REG_DMA2CNTL 0x040000D0
#define REG_DMA2CNTH 0x040000D2
#define REG_DMA3SAD 0x040000D4
#define REG_DMA3SADL 0x040000D4
#define REG_DMA3SADH 0x040000D6
#define REG_DMA3DAD 0x040000D8
#define REG_DMA3DADL 0x040000D8
#define REG_DMA3DADH 0x040000DA
#define REG_DMA3CNTL 0x040000DC
#define REG_DMA3CNTH 0x040000DE
#define _REG_DMA_CONTROL_MAX 0x040000DF
#define REG_DMA0FILL 0x040000E0
#define REG_DMA1FILL 0x040000E4
#define REG_DMA2FILL 0x040000E8

View File

@ -24,6 +24,7 @@
#include <zlib.h>
#endif
#include <stack>
#include <set>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
@ -269,8 +270,14 @@ static void mmu_savestate(EMUFILE* os)
u32 version = 3;
write32le(version,os);
//newer savefile system:
//version 2:
MMU_new.backupDevice.save_state(os);
//version 3:
MMU_new.gxstat.savestate(os);
for(int i=0;i<2;i++)
for(int j=0;j<4;j++)
MMU_new.dma[i][j].savestate(os);
MMU_timing.arm9codeFetch.savestate(os, version);
MMU_timing.arm9dataFetch.savestate(os, version);
@ -423,11 +430,16 @@ static bool mmu_loadstate(EMUFILE* is, int size)
if(version < 2)
return true;
//newer savefile system:
bool ok = MMU_new.backupDevice.load_state(is);
if(version < 3)
return ok;
return true;
ok &= MMU_new.gxstat.loadstate(is);
for(int i=0;i<2;i++)
for(int j=0;j<4;j++)
ok &= MMU_new.dma[i][j].loadstate(is);
ok &= MMU_timing.arm9codeFetch.loadstate(is, version);
ok &= MMU_timing.arm9dataFetch.loadstate(is, version);
@ -800,6 +812,10 @@ static int SubWrite(EMUFILE* os, const SFORMAT *sf)
{
uint32 acc=0;
#ifdef DEBUG
std::set<std::string> keyset;
#endif
const SFORMAT* temp = sf;
while(temp->v) {
const SFORMAT* seek = sf;
@ -839,6 +855,16 @@ static int SubWrite(EMUFILE* os, const SFORMAT *sf)
write32le(sf->size,os);
write32le(sf->count,os);
#ifdef DEBUG
//make sure we dont dup any keys
if(keyset.find(sf->desc) != keyset.end())
{
printf("duplicate save key!\n");
assert(false);
}
keyset.insert(sf->desc);
#endif
#ifdef LOCAL_LE
// no need to ever loop one at a time if not flipping byte order
os->fwrite((char *)sf->v,size*count);

View File

@ -186,6 +186,29 @@ IOReg IORegs9[] = {
{"Mtx stack busy",14,1},{"Mtx stack over/under-flow",15,1},{"GX FIFO level",16,9},{"GX FIFO full",24,1},
{"GX FIFO less than half full",25,1},{"GX FIFO empty",26,1},{"GX busy",27,1},{"GX FIFO IRQ condition",30,2}}},
{CatBegin, "DMA registers", 0, 4, 0, {{0}}},
{MMIOReg, "DMA0SAD", REG_DMA0SAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA0DAD", REG_DMA0DAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA0CNT", REG_DMA0CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{MMIOReg, "DMA1SAD", REG_DMA1SAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA1DAD", REG_DMA1DAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA1CNT", REG_DMA1CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{MMIOReg, "DMA2SAD", REG_DMA2SAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA2DAD", REG_DMA2DAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA2CNT", REG_DMA2CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{MMIOReg, "DMA3SAD", REG_DMA3SAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA3DAD", REG_DMA3DAD, 4, 1, {{"Value",0,28}}},
{MMIOReg, "DMA3CNT", REG_DMA3CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
/*{CatBegin, "Video engine B registers", 0, 36, 0, {{0}}},
{MMIOReg, "[B]DISPCNT", 0x04001000, 4, 18, {{"BG mode",0,3},{"Tile OBJ mapping",4,1},{"Bitmap OBJ 2D size",5,1},{"Bitmap OBJ mapping",6,1},
{"Forced blank",7,1},{"Display BG0",8,1},{"Display BG1",9,1},{"Display BG2",10,1},
{"Display BG3",11,1},{"Display OBJ",12,1},{"Display window 0",13,1},{"Display window 1",14,1},
{"Display OBJ window",15,1},{"Display mode",16,2},{"Tile OBJ 1D boundary",20,2},{"Process OBJs during HBlank",23,1},
{"Enable BG ext. palettes",30,1},{"Enable OBJ ext. palettes",31,1}}},
{MMIOReg, "[B]BG0CNT", 0x04001008, 2, 7, {{"Priority",0,2},{"Character base",2,4},{"Mosaic",6,1},{"Palette mode",7,1},
*/
{CatBegin, "IPC registers", 0, 2, 0, {{0}}},
{MMIOReg, "IPCSYNC", 0x04000180, 2, 3, {{"Data input from remote",0,4},{"Data output to remote",8,4},{"Enable IRQ from remote",14,1}}},
@ -234,6 +257,21 @@ IOReg IORegs7[] = {
{"IPC recv FIFO not empty",18,1},{"Gamecard transfer",19,1},{"Gamecard IREQ_MC",20,1},{"Lid opened",22,1},
{"SPI bus",23,1},{"Wifi",24,1}}},
{CatBegin, "DMA registers", 0, 4, 0, {{0}}},
{MMIOReg, "DMA0SAD", REG_DMA0SAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA0DAD", REG_DMA0DAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA0CNT", REG_DMA0CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{MMIOReg, "DMA1SAD", REG_DMA1SAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA1DAD", REG_DMA1DAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA1CNT", REG_DMA1CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{MMIOReg, "DMA2SAD", REG_DMA2SAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA2DAD", REG_DMA2DAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA2CNT", REG_DMA2CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{MMIOReg, "DMA3SAD", REG_DMA3SAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA3DAD", REG_DMA3DAD, 4, 1, {{"Value",0,27}}},
{MMIOReg, "DMA3CNT", REG_DMA3CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}},
{ListEnd, 0, 0, 0, 0, {{0}}}
};
@ -242,6 +280,20 @@ IOReg* IORegs[2] = {IORegs9, IORegs7};
static const int kXMargin = 5;
static const int kYMargin = 1;
typedef std::vector<CIORegView*> TIORegViewList;
static TIORegViewList liveIORegViews;
void RefreshAllIORegViews()
{
//TODO - this is a placeholder for a more robust system for signalling changes to the IORegView for immediate display.
//individual windows should subscribe to this service (so it doesnt always waste time)
for(TIORegViewList::iterator it(liveIORegViews.begin()); it != liveIORegViews.end(); ++it)
{
(*it)->Refresh();
UpdateWindow((*it)->hWnd); //TODO - base class should have this functionality
}
}
/*--------------------------------------------------------------------------*/
CIORegView::CIORegView()
@ -250,12 +302,15 @@ CIORegView::CIORegView()
, Reg(0)
, yoff(0)
{
liveIORegViews.push_back(this);
}
CIORegView::~CIORegView()
{
DestroyWindow(hWnd);
UnregWndClass("DeSmuME_IORegView");
//TODO - is this thread safe? which thread do these calls come from
liveIORegViews.erase(std::find(liveIORegViews.begin(),liveIORegViews.end(),this));
}
/*--------------------------------------------------------------------------*/
@ -609,6 +664,7 @@ LRESULT CALLBACK IORegView_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
rbBand.hwndChild = wnd->hCPUCombo;
rbBand.cxMinChild = 0;
rbBand.cyMinChild = rc.bottom - rc.top;
rbBand.cx = 100;
SendMessage(wnd->hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
GetWindowRect(wnd->hRegCombo, &rc);
@ -642,7 +698,7 @@ LRESULT CALLBACK IORegView_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
SetWindowPos(wnd->hScrollbar, NULL, rc.right-wnd->vsbWidth, wnd->rebarHeight, wnd->vsbWidth, rc.bottom-wnd->rebarHeight, SWP_NOZORDER);
// Keep the first rebar band width to a reasonable value
SendMessage(wnd->hRebar, RB_SETBANDWIDTH, 0, 60);
SendMessage(wnd->hRebar, RB_SETBANDWIDTH, 0, 100);
GetClientRect(hWnd, &rc);
wnd->maxlines = (rc.bottom - wnd->rebarHeight) / wnd->lineheight;

View File

@ -23,9 +23,12 @@
#define IO_REG_H
#include "../common.h"
#include "CWindow.h"
LRESULT CALLBACK IORegView_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
void RefreshAllIORegViews();
class CIORegView : public CToolWindow
{
public:

View File

@ -1267,7 +1267,7 @@ static void StepRunLoop_Paused()
static void StepRunLoop_User()
{
const int kFramesPerToolUpdate = 6;
const int kFramesPerToolUpdate = 1;
Hud.fps = mainLoopData.fps;
Hud.fps3d = mainLoopData.fps3d;