misc: avoid assertion failure when state save fails
[pcsx_rearmed.git] / plugins / dfsound / spu_c64x_dspcode.c
... / ...
CommitLineData
1/*
2 * SPU processing offload to TI C64x DSP using bsp's c64_tools
3 * (C) GraÅžvydas "notaz" Ignotas, 2015
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is furnished to do
10 * so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#define SYSCALLS_C
25#include <libc64_dsp/include/inc_overlay.h>
26#include <stddef.h>
27
28#include "spu.c"
29#include "spu_c64x.h"
30
31/* dummy deps, some bloat but avoids ifdef hell in SPU code.. */
32static void thread_work_start(void) {}
33static void thread_work_wait_sync(struct work_item *work, int force) {}
34static void thread_sync_caches(void) {}
35static int thread_get_i_done(void) { return 0; }
36struct out_driver *out_current;
37void SetupSound(void) {}
38
39
40static void enable_l2_cache(void)
41{
42 volatile uint32_t *L2CFG = (volatile uint32_t *)0x01840000;
43 uint32_t *MARi = (void *)0x01848000;
44 int i;
45
46 // program Memory Attribute Registers
47 // (old c64_tools has the defaults messed up)
48 // 00000000-0fffffff - not configurable
49 // 10000000-7fffffff - system
50 for (i = 0x10; i < 0x80; i++)
51 MARi[i] = 0;
52 // 80000000-9fffffff - RAM
53 for ( ; i < 0xa0; i++)
54 MARi[i] = 1;
55 // 0xa00000-ffffffff - reserved, etc
56 for ( ; i < 0x100; i++)
57 MARi[i] = 0;
58
59 // enable L2 (1 for 32k, 2 for 64k)
60 if (!(*L2CFG & 2)) {
61 *L2CFG = 2;
62 // wait the for the write
63 *L2CFG;
64 }
65}
66
67static void invalidate_cache(struct work_item *work)
68{
69 // see comment in writeout_cache()
70 //syscalls.cache_inv(work, offsetof(typeof(*work), SSumLR), 1);
71 syscalls.cache_inv(spu.s_chan, sizeof(spu.s_chan[0]) * 24, 1);
72 syscalls.cache_inv(work->SSumLR,
73 sizeof(work->SSumLR[0]) * 2 * work->ns_to, 1);
74}
75
76static void writeout_cache(struct work_item *work)
77{
78 int ns_to = work->ns_to;
79
80 syscalls.cache_wb(work->SSumLR, sizeof(work->SSumLR[0]) * 2 * ns_to, 1);
81 // have to invalidate now, otherwise there is a race between
82 // DSP evicting dirty lines and ARM writing new data to this area
83 syscalls.cache_inv(work, offsetof(typeof(*work), SSumLR), 1);
84}
85
86static void do_processing(void)
87{
88 int left, dirty = 0, had_rvb = 0;
89 struct work_item *work;
90
91 while (worker->active)
92 {
93 // i_ready is in first cacheline
94 syscalls.cache_inv(worker, 64, 1);
95
96 left = worker->i_ready - worker->i_done;
97 if (left > 0) {
98 dirty = 1;
99 worker->active = ACTIVE_CNT;
100 syscalls.cache_wb(&worker->active, 4, 1);
101
102 work = &worker->i[worker->i_done & WORK_I_MASK];
103 invalidate_cache(work);
104 had_rvb |= work->rvb_addr;
105 spu.spuCtrl = work->ctrl;
106 do_channel_work(work);
107 writeout_cache(work);
108
109 worker->i_done++;
110 syscalls.cache_wb(&worker->i_done, 4, 1);
111 continue;
112 }
113
114 // nothing to do? Write out non-critical caches
115 if (dirty) {
116 syscalls.cache_wb(spu.spuMemC + 0x800, 0x800, 1);
117 syscalls.cache_wb(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24, 1);
118 if (had_rvb) {
119 left = 0x40000 - spu.rvb->StartAddr;
120 syscalls.cache_wb(spu.spuMem + spu.rvb->StartAddr, left * 2, 1);
121 had_rvb = 0;
122 }
123 dirty = 0;
124 continue;
125 }
126
127 // this ->active loop thing is to avoid a race where we miss
128 // new work and clear ->active just after ARM checks it
129 worker->active--;
130 syscalls.cache_wb(&worker->active, 4, 1);
131 }
132}
133
134static unsigned int exec(dsp_component_cmd_t cmd,
135 unsigned int arg1, unsigned int arg2,
136 unsigned int *ret1, unsigned int *ret2)
137{
138 struct region_mem *mem = (void *)arg1;
139
140 switch (cmd) {
141 case CCMD_INIT:
142 enable_l2_cache();
143 InitADSR();
144
145 spu.spuMemC = mem->spu_ram;
146 spu.SB = mem->SB;
147 spu.s_chan = mem->in.s_chan;
148 spu.rvb = &mem->in.rvb;
149 worker = &mem->worker;
150 memcpy(&spu_config, &mem->in.spu_config, sizeof(spu_config));
151
152 mem->sizeof_region_mem = sizeof(*mem);
153 mem->offsetof_s_chan1 = offsetof(typeof(*mem), in.s_chan[1]);
154 mem->offsetof_spos_3_20 = offsetof(typeof(*mem), worker.i[3].ch[20]);
155 // seems to be unneeded, no write-alloc? but just in case..
156 syscalls.cache_wb(&mem->sizeof_region_mem, 3 * 4, 1);
157 break;
158
159 case CCMD_DOIT:
160 worker->active = ACTIVE_CNT;
161 worker->boot_cnt++;
162 syscalls.cache_inv(worker, 128, 1);
163 syscalls.cache_wb(&worker->i_done, 128, 1);
164 memcpy(&spu_config, &mem->in.spu_config, sizeof(spu_config));
165
166 if (worker->ram_dirty)
167 // it's faster to do it all than just a 512k buffer
168 syscalls.cache_wbInvAll();
169
170 do_processing();
171
172 syscalls.cache_inv(&mem->SB, sizeof(mem->SB), 0);
173 syscalls.cache_inv(&mem->in, sizeof(mem->in), 0);
174 break;
175
176 default:
177 syscalls.printf("bad cmd: %x\n", cmd);
178 break;
179 }
180
181 return 0;
182}
183
184#pragma DATA_SECTION(component_test_dsp, ".sec_com");
185dsp_component_t component_test_dsp = {
186 {
187 NULL, /* init */
188 exec,
189 NULL, /* exec fastcall RPC */
190 NULL, /* exit */
191 },
192
193 COMPONENT_NAME,
194};
195
196DSP_COMPONENT_MAIN
197
198// vim:shiftwidth=1:expandtab