#1  
Old 30th November 2013, 10:39 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default Annoyance in RSP specs

Code:
typedef struct {
    HINSTANCE hInst;
    int MemoryBswaped;    /* If this is set to TRUE, then the memory has been
                              pre-byte-swapped on a DWORD (32 bits) boundary */
    unsigned char *RDRAM;
    unsigned char *DMEM;
    unsigned char *IMEM;

    unsigned long *MI_INTR_REG;

    unsigned long *SP_MEM_ADDR_REG;
    unsigned long *SP_DRAM_ADDR_REG;
    unsigned long *SP_RD_LEN_REG;
    unsigned long *SP_WR_LEN_REG;
    unsigned long *SP_STATUS_REG;
    unsigned long *SP_DMA_FULL_REG;
    unsigned long *SP_DMA_BUSY_REG;
    unsigned long *SP_PC_REG;
    unsigned long *SP_SEMAPHORE_REG;

    unsigned long *DPC_START_REG;
    unsigned long *DPC_END_REG;
    unsigned long *DPC_CURRENT_REG;
    unsigned long *DPC_STATUS_REG;
    unsigned long *DPC_CLOCK_REG;
    unsigned long *DPC_BUFBUSY_REG;
    unsigned long *DPC_PIPEBUSY_REG;
    unsigned long *DPC_TMEM_REG;
....
} RSP_INFO;
While this offset of SP_PC_REG is technically correct on the CPU memory level (within the struct itself), somehow the emulator is contradicting it when I use this formula to emulate MFC0 just on the RSP level.

Code:
const int CR[16] = {
    &RSP.SP_MEM_ADDR_REG  - &RSP.SP_MEM_ADDR_REG, // 0
    &RSP.SP_DRAM_ADDR_REG - &RSP.SP_MEM_ADDR_REG, // 1
    &RSP.SP_RD_LEN_REG    - &RSP.SP_MEM_ADDR_REG, // 2
    &RSP.SP_WR_LEN_REG    - &RSP.SP_MEM_ADDR_REG, // 3
    &RSP.SP_STATUS_REG    - &RSP.SP_MEM_ADDR_REG, // 4
    &RSP.SP_DMA_FULL_REG  - &RSP.SP_MEM_ADDR_REG, // 5
    &RSP.SP_DMA_BUSY_REG  - &RSP.SP_MEM_ADDR_REG, // 6
    &RSP.SP_SEMAPHORE_REG - &RSP.SP_MEM_ADDR_REG, // 8 -> 7
    &RSP.DPC_START_REG    - &RSP.SP_MEM_ADDR_REG, // 10 -> 9
    &RSP.DPC_END_REG      - &RSP.SP_MEM_ADDR_REG,
    &RSP.DPC_CURRENT_REG  - &RSP.SP_MEM_ADDR_REG,
    &RSP.DPC_STATUS_REG   - &RSP.SP_MEM_ADDR_REG,
    &RSP.DPC_CLOCK_REG    - &RSP.SP_MEM_ADDR_REG,
    &RSP.DPC_BUFBUSY_REG  - &RSP.SP_MEM_ADDR_REG,
    &RSP.DPC_PIPEBUSY_REG - &RSP.SP_MEM_ADDR_REG,
    &RSP.DPC_TMEM_REG     - &RSP.SP_MEM_ADDR_REG  // 16 -> 17
};

function MFCO(rd, rt) {
    GPR[rt] = *(DWORD *)(RSP.SP_MEM_ADDR_REG + CR[rd]);
    GPR[0] = 0;
}
??? What the hell is that supposed to mean?

It makes perfect sense enough that starting from SP_SEMAPHORE_REG, where zilmar interposed SP_PC_REG onwards, should offset all the rest of them by 1, but instead it keeps alternating for + 1, + 2, - 1, ??? for some of them.

Confusing as all hell. I guess I need to statically allocate this index within InitiateRSP or something, because I'm sure not using that slow-as-mole-asses, 3+ KB larger switch code in the interpreter code for pj64.
Reply With Quote
  #2  
Old 1st December 2013, 01:58 AM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Right then, I had to make it dynamically buffered for it to tie with the plugin system more forcefully, to this perhaps overly fixated design:

Code:
EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount)
{
...........
    while (RSP.IMEM != RSP.DMEM + 4096)
        message("Virtual host map noncontiguity.", 3);

    RSP = Rsp_Info;
    *RSP.SP_PC_REG = 0x04001000 & 0x00000FFF; /* task init bug on Mupen64 */
    CR[0x0] = RSP.SP_MEM_ADDR_REG;
    CR[0x1] = RSP.SP_DRAM_ADDR_REG;
    CR[0x2] = RSP.SP_RD_LEN_REG;
    CR[0x3] = RSP.SP_WR_LEN_REG;
    CR[0x4] = RSP.SP_STATUS_REG;
    CR[0x5] = RSP.SP_DMA_FULL_REG;
    CR[0x6] = RSP.SP_DMA_BUSY_REG;
    CR[0x7] = RSP.SP_SEMAPHORE_REG;
    CR[0x8] = RSP.DPC_START_REG;
    CR[0x9] = RSP.DPC_END_REG;
    CR[0xA] = RSP.DPC_CURRENT_REG;
    CR[0xB] = RSP.DPC_STATUS_REG;
    CR[0xC] = RSP.DPC_CLOCK_REG;
    CR[0xD] = RSP.DPC_BUFBUSY_REG;
    CR[0xE] = RSP.DPC_PIPEBUSY_REG;
    CR[0xF] = RSP.DPC_TMEM_REG;
    return;
}
Code:
extern unsigned long* CR[16];

static void MFC0(int rt, int rd)
{
    SR[rt] = *(CR[rd]);
    SR[0] = 0x00000000;
    if (rd == 0x7) /* SP_SEMAPHORE_REG */
    {
        if (CFG_MEND_SEMAPHORE_LOCK == 0)
            return;
        *RSP.SP_SEMAPHORE_REG = 0x00000001;
        *RSP.SP_STATUS_REG |= 0x00000001; /* temporary bit to break CPU */
        return;
    }
    if (rd == 0x4) /* SP_STATUS_REG */
    {
        if (CFG_WAIT_FOR_CPU_HOST == 0)
            return;
        ++MFC0_count[rt];
        if (MFC0_count[rt] > 07)
            *RSP.SP_STATUS_REG |= 0x00000001; /* Let OS restart the task. */
    }
    return;
}
Much smaller code and more accurate than the switch() statement in the other interpreter, since moving something over into the destination scalar is an inevitability with MF (but not MT since some CRs are read-only).

I know I said I would have another release done by the end of this month, but maybe a couple other people need time, who seem interested in contributing a thing or two...that and as it turns out I guess I could use a bit more time myself from unexpected encounters like this.

So even though the "relative" placement of SP_PC_REG in the plugin spec is correct, it interferes to an extent, and doesn't necessarily mean that its absolute offset into the RCP memory map is correctly assigned by the emulator. Some other emulation code not released in public indicates the order chosen in the spec was not a necessity, but I'm glad it wasn't a total hindrance, anyway.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT. The time now is 04:38 AM.


Powered by vBulletin® Version 3.7.3
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.