1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus - rdp_core.c                                              *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2014 Bobby Smiles                                       *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21 
22 #include "rdp_core.h"
23 
24 #include "../memory/memory.h"
25 #include "../plugin/plugin.h"
26 #include "../r4300/r4300_core.h"
27 #include "../rsp/rsp_core.h"
28 
29 #include <string.h>
30 
update_dpc_status(struct rdp_core * dp,uint32_t w)31 static int update_dpc_status(struct rdp_core* dp, uint32_t w)
32 {
33    /* see do_SP_Task for more info */
34    int do_sp_task_on_unfreeze = 0;
35 
36    /* clear / set xbus_dmem_dma */
37    if (w & DPC_STATUS_CLR_XBUS_DMEM_DMA) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_XBUS_DMEM_DMA;
38    if (w & DPC_STATUS_SET_XBUS_DMEM_DMA) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_XBUS_DMEM_DMA;
39 
40    /* clear / set freeze */
41    if (w & DPC_STATUS_CLR_FREEZE)
42    {
43       dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FREEZE;
44 
45       if (!(dp->sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE)))
46          do_sp_task_on_unfreeze = 1;
47    }
48 
49    if (w & DPC_STATUS_SET_FREEZE) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FREEZE;
50 
51    /* clear / set flush */
52    if (w & DPC_STATUS_CLR_FLUSH) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FLUSH;
53    if (w & DPC_STATUS_SET_FLUSH) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FLUSH;
54 
55    return do_sp_task_on_unfreeze;
56 }
57 
58 
init_rdp(struct rdp_core * dp,struct r4300_core * r4300,struct rsp_core * sp,struct ri_controller * ri)59 void init_rdp(struct rdp_core* dp,
60                  struct r4300_core* r4300,
61                  struct rsp_core* sp,
62                  struct ri_controller *ri)
63 {
64     dp->r4300 = r4300;
65     dp->sp    = sp;
66     dp->ri    = ri;
67 }
68 
poweron_rdp(struct rdp_core * dp)69 void poweron_rdp(struct rdp_core* dp)
70 {
71     memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t));
72     memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t));
73 
74     poweron_fb(&dp->fb);
75 }
76 
77 
read_dpc_regs(void * opaque,uint32_t address,uint32_t * value)78 int read_dpc_regs(void* opaque, uint32_t address, uint32_t* value)
79 {
80     struct rdp_core* dp = (struct rdp_core*)opaque;
81     uint32_t reg        = DPC_REG(address);
82 
83     *value              = dp->dpc_regs[reg];
84 
85     return 0;
86 }
87 
write_dpc_regs(void * opaque,uint32_t address,uint32_t value,uint32_t mask)88 int write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
89 {
90    struct rdp_core* dp = (struct rdp_core*)opaque;
91    uint32_t reg        = DPC_REG(address);
92 
93    switch(reg)
94    {
95       case DPC_STATUS_REG:
96          if (update_dpc_status(dp, value & mask) != 0)
97             do_SP_Task(dp->sp);
98       case DPC_CURRENT_REG:
99       case DPC_CLOCK_REG:
100       case DPC_BUFBUSY_REG:
101       case DPC_PIPEBUSY_REG:
102       case DPC_TMEM_REG:
103          return 0;
104    }
105 
106    dp->dpc_regs[reg] = MASKED_WRITE(&dp->dpc_regs[reg], value, mask);
107 
108    switch(reg)
109    {
110       case DPC_START_REG:
111          dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
112          break;
113       case DPC_END_REG:
114          gfx.processRDPList();
115          signal_rcp_interrupt(dp->r4300, MI_INTR_DP);
116          break;
117    }
118 
119    return 0;
120 }
121 
122 
read_dps_regs(void * opaque,uint32_t address,uint32_t * value)123 int read_dps_regs(void* opaque, uint32_t address, uint32_t* value)
124 {
125     struct rdp_core* dp = (struct rdp_core*)opaque;
126     uint32_t reg        = DPS_REG(address);
127 
128     *value = dp->dps_regs[reg];
129 
130     return 0;
131 }
132 
write_dps_regs(void * opaque,uint32_t address,uint32_t value,uint32_t mask)133 int write_dps_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
134 {
135     struct rdp_core* dp = (struct rdp_core*)opaque;
136     uint32_t reg        = DPS_REG(address);
137 
138     dp->dps_regs[reg] = MASKED_WRITE(&dp->dps_regs[reg], value, mask);
139 
140     return 0;
141 }
142 
rdp_interrupt_event(struct rdp_core * dp)143 void rdp_interrupt_event(struct rdp_core* dp)
144 {
145    raise_rcp_interrupt(dp->r4300, MI_INTR_DP);
146 }
147