spu: finish offload code to TI C64x DSP
[pcsx_rearmed.git] / plugins / dfsound / spu_c64x.c
CommitLineData
5514a050 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#include <dlfcn.h>
de4a0279 25#include <stddef.h>
26
5514a050 27#include <inc_libc64_mini.h>
28#include "spu_c64x.h"
29
30static dsp_mem_region_t region;
de4a0279 31static dsp_component_id_t compid;
5514a050 32
33static struct {
34 void *handle;
35 int (*dsp_open)(void);
36 dsp_mem_region_t (*dsp_shm_alloc)(dsp_cache_t _type, sU32 _numBytes);
37 int (*dsp_shm_free)(dsp_mem_region_t _mem);
38 void (*dsp_close)(void);
39 int (*dsp_component_load)(const char *_path, const char *_name, dsp_component_id_t *_id);
40 int (*dsp_cache_inv_virt)(void *_virtAddr, sU32 _size);
41 int (*dsp_rpc_send)(const dsp_msg_t *_msgTo);
42 int (*dsp_rpc_recv)(dsp_msg_t *_msgFrom);
de4a0279 43 int (*dsp_rpc)(const dsp_msg_t *_msgTo, dsp_msg_t *_msgFrom);
5514a050 44 void (*dsp_logbuf_print)(void);
45} f;
46
47static void thread_work_start(void)
48{
de4a0279 49 dsp_msg_t msg;
50 int ret;
51
52 DSP_MSG_INIT(&msg, compid, CCMD_DOIT, 0, 0);
53 ret = f.dsp_rpc_send(&msg);
54 if (ret != 0) {
55 fprintf(stderr, "dsp_rpc_send failed: %d\n", ret);
56 f.dsp_logbuf_print();
57 // maybe stop using the DSP?
58 }
5514a050 59}
60
61static void thread_work_wait_sync(void)
62{
de4a0279 63 dsp_msg_t msg;
64 int ns_to;
65 int ret;
66
67 ns_to = worker->ns_to;
68 f.dsp_cache_inv_virt(spu.sRVBStart, sizeof(spu.sRVBStart[0]) * 2 * ns_to);
69 f.dsp_cache_inv_virt(SSumLR, sizeof(SSumLR[0]) * 2 * ns_to);
70 f.dsp_cache_inv_virt(&worker->r, sizeof(worker->r));
71 worker->stale_cache = 1; // SB, ram
72
73 ret = f.dsp_rpc_recv(&msg);
74 if (ret != 0) {
75 fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret);
76 f.dsp_logbuf_print();
77 }
78 //f.dsp_logbuf_print();
79}
80
81// called before ARM decides to do SPU mixing itself
82static void thread_sync_caches(void)
83{
84 if (worker->stale_cache) {
85 f.dsp_cache_inv_virt(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24);
86 f.dsp_cache_inv_virt(spu.spuMemC + 0x800, 0x800);
87 worker->stale_cache = 0;
88 }
5514a050 89}
90
91static void init_spu_thread(void)
92{
de4a0279 93 dsp_msg_t init_msg, msg_in;
5514a050 94 struct region_mem *mem;
95 int ret;
96
97 if (f.handle == NULL) {
98 const char lib[] = "libc64.so.1";
99 int failed = 0;
100
101 f.handle = dlopen(lib, RTLD_NOW);
102 if (f.handle == NULL) {
103 fprintf(stderr, "can't load %s: %s\n", lib, dlerror());
104 return;
105 }
106 #define LDS(name) \
107 failed |= (f.name = dlsym(f.handle, #name)) == NULL
108 LDS(dsp_open);
109 LDS(dsp_close);
110 LDS(dsp_shm_alloc);
111 LDS(dsp_shm_free);
112 LDS(dsp_cache_inv_virt);
113 LDS(dsp_component_load);
114 LDS(dsp_rpc_send);
115 LDS(dsp_rpc_recv);
de4a0279 116 LDS(dsp_rpc);
5514a050 117 LDS(dsp_logbuf_print);
118 #undef LDS
119 if (failed) {
120 fprintf(stderr, "missing symbol(s) in %s\n", lib);
121 dlclose(f.handle);
122 f.handle = NULL;
123 return;
124 }
125 }
126
127 ret = f.dsp_open();
128 if (ret != 0) {
129 fprintf(stderr, "dsp_open failed: %d\n", ret);
130 return;
131 }
132
de4a0279 133 ret = f.dsp_component_load(NULL, COMPONENT_NAME, &compid);
134 if (ret != 0) {
135 fprintf(stderr, "dsp_component_load failed: %d\n", ret);
136 goto fail_cload;
137 }
138
5514a050 139 region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough
140 if (region.size < sizeof(*mem) || region.virt_addr == 0) {
141 fprintf(stderr, "dsp_shm_alloc failed\n");
142 goto fail_mem;
143 }
144 mem = (void *)region.virt_addr;
145
de4a0279 146 memcpy(&mem->spu_config, &spu_config, sizeof(mem->spu_config));
147
148 DSP_MSG_INIT(&init_msg, compid, CCMD_INIT, region.phys_addr, 0);
149 ret = f.dsp_rpc(&init_msg, &msg_in);
150 if (ret != 0) {
151 fprintf(stderr, "dsp_rpc failed: %d\n", ret);
152 goto fail_init;
153 }
154
155 if (mem->sizeof_region_mem != sizeof(*mem)) {
156 fprintf(stderr, "error: size mismatch 1: %d vs %zd\n",
157 mem->sizeof_region_mem, sizeof(*mem));
158 goto fail_init;
159 }
160 if (mem->offsetof_s_chan1 != offsetof(typeof(*mem), s_chan[1])) {
161 fprintf(stderr, "error: size mismatch 2: %d vs %zd\n",
162 mem->offsetof_s_chan1, offsetof(typeof(*mem), s_chan[1]));
163 goto fail_init;
164 }
165 if (mem->offsetof_worker_ram != offsetof(typeof(*mem), worker.ch[1])) {
166 fprintf(stderr, "error: size mismatch 3: %d vs %zd\n",
167 mem->offsetof_worker_ram, offsetof(typeof(*mem), worker.ch[1]));
168 goto fail_init;
169 }
170
5514a050 171 // override default allocations
172 free(spu.spuMemC);
173 spu.spuMemC = mem->spu_ram;
174 free(spu.sRVBStart);
175 spu.sRVBStart = mem->RVB;
176 free(SSumLR);
177 SSumLR = mem->SSumLR;
de4a0279 178 free(spu.SB);
179 spu.SB = mem->SB;
5514a050 180 free(spu.s_chan);
181 spu.s_chan = mem->s_chan;
182 worker = &mem->worker;
183
de4a0279 184 printf("spu: C64x DSP ready (id=%d).\n", (int)compid);
185 f.dsp_logbuf_print();
186
187pcnt_init();
188 (void)do_channel_work; // used by DSP instead
5514a050 189 return;
190
de4a0279 191fail_init:
192 f.dsp_shm_free(region);
5514a050 193fail_mem:
de4a0279 194 // no component unload func?
195fail_cload:
196 printf("spu: C64x DSP init failed.\n");
197 f.dsp_logbuf_print();
5514a050 198 f.dsp_close();
199 worker = NULL;
200}
201
202static void exit_spu_thread(void)
203{
204 if (worker == NULL)
205 return;
206
207 if (worker->pending)
208 thread_work_wait_sync();
209 f.dsp_shm_free(region);
210 f.dsp_close();
211
212 spu.spuMemC = NULL;
213 spu.sRVBStart = NULL;
214 SSumLR = NULL;
de4a0279 215 spu.SB = NULL;
5514a050 216 spu.s_chan = NULL;
217 worker = NULL;
218}
219
220// vim:shiftwidth=1:expandtab