1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - si_controller.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 "si_controller.h"
23
24 #include "../api/m64p_types.h"
25 #include "../api/callbacks.h"
26 #include "../main/main.h"
27 #include "../main/rom.h"
28 #include "../memory/memory.h"
29 #include "../r4300/r4300_core.h"
30 #include "../ri/ri_controller.h"
31
32 #include <string.h>
33
34 enum
35 {
36 SI_STATUS_DMA_BUSY = 0x0001,
37 SI_STATUS_RD_BUSY = 0x0002,
38 SI_STATUS_DMA_ERROR = 0x0008,
39 SI_STATUS_INTERRUPT = 0x1000,
40
41 };
42
dma_si_write(struct si_controller * si)43 static void dma_si_write(struct si_controller* si)
44 {
45 int i;
46
47 if (si->regs[SI_PIF_ADDR_WR64B_REG] != 0x1FC007C0)
48 {
49 DebugMessage(M64MSG_ERROR, "dma_si_write(): unknown SI use");
50 return;
51 }
52
53 for (i = 0; i < PIF_RAM_SIZE; i += 4)
54 *((uint32_t*)(&si->pif.ram[i])) = sl(si->ri->rdram.dram[(si->regs[SI_DRAM_ADDR_REG]+i)/4]);
55
56 update_pif_write(si);
57 cp0_update_count();
58
59 if (g_delay_si)
60 {
61 si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_BUSY;
62 add_interrupt_event(SI_INT, ROM_SETTINGS.sidmaduration);
63 }
64 else
65 {
66 si->regs[SI_STATUS_REG] |= SI_STATUS_INTERRUPT;
67 signal_rcp_interrupt(si->r4300, MI_INTR_SI);
68 }
69 }
70
dma_si_read(struct si_controller * si)71 static void dma_si_read(struct si_controller* si)
72 {
73 int i;
74
75 if (si->regs[SI_PIF_ADDR_RD64B_REG] != 0x1FC007C0)
76 {
77 DebugMessage(M64MSG_ERROR, "dma_si_read(): unknown SI use");
78 return;
79 }
80
81 update_pif_read(si);
82
83 for (i = 0; i < PIF_RAM_SIZE; i += 4)
84 si->ri->rdram.dram[(si->regs[SI_DRAM_ADDR_REG]+i)/4] = sl(*(uint32_t*)(&si->pif.ram[i]));
85 cp0_update_count();
86
87 if (g_delay_si)
88 {
89 si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_BUSY;
90 add_interrupt_event(SI_INT, ROM_SETTINGS.sidmaduration);
91 }
92 else
93 {
94 si->regs[SI_STATUS_REG] |= SI_STATUS_INTERRUPT;
95 signal_rcp_interrupt(si->r4300, MI_INTR_SI);
96 }
97 }
98
init_si(struct si_controller * si,void * eeprom_user_data,void (* eeprom_save)(void *),uint8_t * eeprom_data,size_t eeprom_size,uint16_t eeprom_id,void * af_rtc_user_data,const struct tm * (* af_rtc_get_time)(void *),const uint8_t * ipl3,struct r4300_core * r4300,struct ri_controller * ri)99 void init_si(struct si_controller* si,
100 void* eeprom_user_data,
101 void (*eeprom_save)(void*),
102 uint8_t* eeprom_data,
103 size_t eeprom_size,
104 uint16_t eeprom_id,
105 void* af_rtc_user_data,
106 const struct tm* (*af_rtc_get_time)(void*),
107 const uint8_t* ipl3,
108 struct r4300_core* r4300,
109 struct ri_controller *ri)
110 {
111 si->r4300 = r4300;
112 si->ri = ri;
113
114 init_pif(&si->pif,
115 eeprom_user_data, eeprom_save, eeprom_data, eeprom_size, eeprom_id,
116 af_rtc_user_data, af_rtc_get_time, ipl3
117 );
118 }
119
poweron_si(struct si_controller * si)120 void poweron_si(struct si_controller* si)
121 {
122 memset(si->regs, 0, SI_REGS_COUNT*sizeof(uint32_t));
123
124 poweron_pif(&si->pif);
125 }
126
127
read_si_regs(void * opaque,uint32_t address,uint32_t * value)128 int read_si_regs(void* opaque, uint32_t address, uint32_t* value)
129 {
130 struct si_controller* si = (struct si_controller*)opaque;
131 uint32_t reg = SI_REG(address);
132
133 *value = si->regs[reg];
134
135 return 0;
136 }
137
write_si_regs(void * opaque,uint32_t address,uint32_t value,uint32_t mask)138 int write_si_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
139 {
140 struct si_controller* si = (struct si_controller*)opaque;
141 uint32_t reg = SI_REG(address);
142
143 switch (reg)
144 {
145 case SI_DRAM_ADDR_REG:
146 si->regs[SI_DRAM_ADDR_REG] = MASKED_WRITE(&si->regs[SI_DRAM_ADDR_REG], value, mask);
147 break;
148
149 case SI_PIF_ADDR_RD64B_REG:
150 si->regs[SI_PIF_ADDR_RD64B_REG] = MASKED_WRITE(&si->regs[SI_PIF_ADDR_RD64B_REG], value, mask);
151 dma_si_read(si);
152 break;
153
154 case SI_PIF_ADDR_WR64B_REG:
155 si->regs[SI_PIF_ADDR_WR64B_REG] = MASKED_WRITE(&si->regs[SI_PIF_ADDR_WR64B_REG], value, mask);
156 dma_si_write(si);
157 break;
158
159 case SI_STATUS_REG:
160 si->regs[SI_STATUS_REG] &= ~SI_STATUS_INTERRUPT;
161 clear_rcp_interrupt(si->r4300, MI_INTR_SI);
162 break;
163 }
164
165 return 0;
166 }
167
si_end_of_dma_event(struct si_controller * si)168 void si_end_of_dma_event(struct si_controller* si)
169 {
170 main_check_inputs();
171
172 si->pif.ram[0x3f] = 0x0;
173
174 /* trigger SI interrupt */
175 si->regs[SI_STATUS_REG] &= ~SI_STATUS_DMA_BUSY;
176 si->regs[SI_STATUS_REG] |= SI_STATUS_INTERRUPT;
177 raise_rcp_interrupt(si->r4300, MI_INTR_SI);
178 }
179