spu: start offload code to TI C64x DSP
[pcsx_rearmed.git] / plugins / dfsound / spu_c64x.c
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>
25 #include <inc_libc64_mini.h>
26 #include "spu_c64x.h"
27
28 static dsp_mem_region_t region;
29
30 static struct {
31  void *handle;
32  int  (*dsp_open)(void);
33  dsp_mem_region_t (*dsp_shm_alloc)(dsp_cache_t _type, sU32 _numBytes);
34  int  (*dsp_shm_free)(dsp_mem_region_t _mem);
35  void (*dsp_close)(void);
36  int  (*dsp_component_load)(const char *_path, const char *_name, dsp_component_id_t *_id);
37  int  (*dsp_cache_inv_virt)(void *_virtAddr, sU32 _size);
38  int  (*dsp_rpc_send)(const dsp_msg_t *_msgTo);
39  int  (*dsp_rpc_recv)(dsp_msg_t *_msgFrom);
40  void (*dsp_logbuf_print)(void);
41 } f;
42
43 static void thread_work_start(void)
44 {
45  do_channel_work();
46 }
47
48 static void thread_work_wait_sync(void)
49 {
50 }
51
52 static void init_spu_thread(void)
53 {
54  struct region_mem *mem;
55  int ret;
56
57  if (f.handle == NULL) {
58   const char lib[] = "libc64.so.1";
59   int failed = 0;
60
61   f.handle = dlopen(lib, RTLD_NOW);
62   if (f.handle == NULL) {
63    fprintf(stderr, "can't load %s: %s\n", lib, dlerror());
64    return;
65   }
66   #define LDS(name) \
67     failed |= (f.name = dlsym(f.handle, #name)) == NULL
68   LDS(dsp_open);
69   LDS(dsp_close);
70   LDS(dsp_shm_alloc);
71   LDS(dsp_shm_free);
72   LDS(dsp_cache_inv_virt);
73   LDS(dsp_component_load);
74   LDS(dsp_rpc_send);
75   LDS(dsp_rpc_recv);
76   LDS(dsp_logbuf_print);
77   #undef LDS
78   if (failed) {
79    fprintf(stderr, "missing symbol(s) in %s\n", lib);
80    dlclose(f.handle);
81    f.handle = NULL;
82    return;
83   }
84  }
85
86  ret = f.dsp_open();
87  if (ret != 0) {
88   fprintf(stderr, "dsp_open failed: %d\n", ret);
89   return;
90  }
91
92  region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough
93  if (region.size < sizeof(*mem) || region.virt_addr == 0) {
94   fprintf(stderr, "dsp_shm_alloc failed\n");
95   goto fail_mem;
96  }
97  mem = (void *)region.virt_addr;
98
99  // override default allocations
100  free(spu.spuMemC);
101  spu.spuMemC = mem->spu_ram;
102  free(spu.sRVBStart);
103  spu.sRVBStart = mem->RVB;
104  free(SSumLR);
105  SSumLR = mem->SSumLR;
106  free(spu.s_chan);
107  spu.s_chan = mem->s_chan;
108  worker = &mem->worker;
109
110  printf("C64x DSP ready.\n");
111  return;
112
113 fail_mem:
114  f.dsp_close();
115  worker = NULL;
116 }
117
118 static void exit_spu_thread(void)
119 {
120  if (worker == NULL)
121   return;
122
123  if (worker->pending)
124   thread_work_wait_sync();
125  f.dsp_shm_free(region);
126  f.dsp_close();
127
128  spu.spuMemC = NULL;
129  spu.sRVBStart = NULL;
130  SSumLR = NULL;
131  spu.s_chan = NULL;
132  worker = NULL;
133 }
134
135 // vim:shiftwidth=1:expandtab