Advertisement
Guest User

Untitled

a guest
Feb 26th, 2014
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.27 KB | None | 0 0
  1. struct MSU1 : Coprocessor {
  2. static void Enter();
  3. void enter();
  4. void init();
  5. void load();
  6. void unload();
  7. void power();
  8. void reset();
  9.  
  10. void data_open();
  11. void audio_open();
  12.  
  13. uint8 mmio_read(unsigned addr);
  14. void mmio_write(unsigned addr, uint8 data);
  15.  
  16. void serialize(serializer&);
  17.  
  18. private:
  19. file datafile;
  20. file audiofile;
  21.  
  22. enum Flag : unsigned {
  23. DataBusy = 0x80,
  24. AudioBusy = 0x40,
  25. AudioRepeating = 0x20,
  26. AudioPlaying = 0x10,
  27. AudioError = 0x08,
  28. Revision = 0x01,
  29. };
  30.  
  31. struct MMIO {
  32. uint32 data_seek_offset;
  33. uint32 data_read_offset;
  34.  
  35. uint32 audio_play_offset;
  36. uint32 audio_loop_offset;
  37.  
  38. uint16 audio_track;
  39. uint8 audio_volume;
  40.  
  41. bool data_busy;
  42. bool audio_busy;
  43. bool audio_repeat;
  44. bool audio_play;
  45. bool audio_error;
  46. } mmio;
  47. };
  48.  
  49. extern MSU1 msu1;
  50.  
  51.  
  52. #include <sfc/sfc.hpp>
  53.  
  54. #define MSU1_CPP
  55. namespace SuperFamicom {
  56.  
  57. MSU1 msu1;
  58.  
  59. #include "serialization.cpp"
  60.  
  61. void MSU1::Enter() { msu1.enter(); }
  62.  
  63. void MSU1::enter() {
  64. while(true) {
  65. if(scheduler.sync == Scheduler::SynchronizeMode::All) {
  66. scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
  67. }
  68.  
  69. int16 left = 0, right = 0;
  70.  
  71. if(mmio.audio_play) {
  72. if(audiofile.open()) {
  73. if(audiofile.end()) {
  74. if(!mmio.audio_repeat) {
  75. mmio.audio_play = false;
  76. audiofile.seek(mmio.audio_play_offset = 8);
  77. } else {
  78. audiofile.seek(mmio.audio_play_offset = mmio.audio_loop_offset);
  79. }
  80. } else {
  81. mmio.audio_play_offset += 4;
  82. left = audiofile.readl(2);
  83. right = audiofile.readl(2);
  84. }
  85. } else {
  86. mmio.audio_play = false;
  87. }
  88. }
  89.  
  90. signed lchannel = (double)left * (double)mmio.audio_volume / 255.0;
  91. signed rchannel = (double)right * (double)mmio.audio_volume / 255.0;
  92. left = sclamp<16>(lchannel);
  93. right = sclamp<16>(rchannel);
  94. if(dsp.mute()) left = 0, right = 0;
  95.  
  96. audio.coprocessor_sample(left, right);
  97. step(1);
  98. synchronize_cpu();
  99. }
  100. }
  101.  
  102. void MSU1::init() {
  103. }
  104.  
  105. void MSU1::load() {
  106. }
  107.  
  108. void MSU1::unload() {
  109. if(datafile.open()) datafile.close();
  110. if(audiofile.open()) audiofile.close();
  111. }
  112.  
  113. void MSU1::power() {
  114. audio.coprocessor_enable(true);
  115. audio.coprocessor_frequency(44100.0);
  116. }
  117.  
  118. void MSU1::reset() {
  119. create(MSU1::Enter, 44100);
  120.  
  121. mmio.data_seek_offset = 0;
  122. mmio.data_read_offset = 0;
  123.  
  124. mmio.audio_play_offset = 0;
  125. mmio.audio_loop_offset = 0;
  126.  
  127. mmio.audio_track = 0;
  128. mmio.audio_volume = 0;
  129.  
  130. mmio.data_busy = false;
  131. mmio.audio_busy = false;
  132. mmio.audio_repeat = false;
  133. mmio.audio_play = false;
  134. mmio.audio_error = false;
  135.  
  136. data_open();
  137. audio_open();
  138. }
  139.  
  140. void MSU1::data_open() {
  141. if(datafile.open()) datafile.close();
  142. auto document = Markup::Document(cartridge.information.markup.cartridge);
  143. string name = document["cartridge/msu1/rom/name"].data;
  144. if(name.empty()) name = "msu1.rom";
  145. if(datafile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
  146. datafile.seek(mmio.data_read_offset);
  147. }
  148. }
  149.  
  150. void MSU1::audio_open() {
  151. if(audiofile.open()) audiofile.close();
  152. auto document = Markup::Document(cartridge.information.markup.cartridge);
  153. string name = {"track-", mmio.audio_track, ".pcm"};
  154. for(auto track : document.find("cartridge/msu1/track")) {
  155. if(numeral(track["number"].data) != mmio.audio_track) continue;
  156. name = track["name"].data;
  157. break;
  158. }
  159. if(audiofile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
  160. if(audiofile.size() >= 8) {
  161. uint32 header = audiofile.readm(4);
  162. if(header == 0x4d535531) { //"MSU1"
  163. mmio.audio_loop_offset = 8 + audiofile.readl(4) * 4;
  164. if(mmio.audio_loop_offset > audiofile.size()) mmio.audio_loop_offset = 8;
  165. mmio.audio_error = false;
  166. audiofile.seek(mmio.audio_play_offset);
  167. return;
  168. }
  169. }
  170. audiofile.close();
  171. }
  172. mmio.audio_error = true;
  173. }
  174.  
  175. uint8 MSU1::mmio_read(unsigned addr) {
  176. cpu.synchronize_coprocessors();
  177. addr = 0x2000 | (addr & 7);
  178.  
  179. switch(addr) {
  180. case 0x2000:
  181. return (mmio.data_busy << 7)
  182. | (mmio.audio_busy << 6)
  183. | (mmio.audio_repeat << 5)
  184. | (mmio.audio_play << 4)
  185. | (mmio.audio_error << 3)
  186. | (Revision << 0);
  187. case 0x2001:
  188. if(mmio.data_busy) return 0x00;
  189. if(datafile.end()) return 0x00;
  190. mmio.data_read_offset++;
  191. return datafile.read();
  192. case 0x2002: return 'S';
  193. case 0x2003: return '-';
  194. case 0x2004: return 'M';
  195. case 0x2005: return 'S';
  196. case 0x2006: return 'U';
  197. case 0x2007: return '1';
  198. }
  199. }
  200.  
  201. void MSU1::mmio_write(unsigned addr, uint8 data) {
  202. cpu.synchronize_coprocessors();
  203. addr = 0x2000 | (addr & 7);
  204.  
  205. switch(addr) {
  206. case 0x2000: mmio.data_seek_offset = (mmio.data_seek_offset & 0xffffff00) | (data << 0); break;
  207. case 0x2001: mmio.data_seek_offset = (mmio.data_seek_offset & 0xffff00ff) | (data << 8); break;
  208. case 0x2002: mmio.data_seek_offset = (mmio.data_seek_offset & 0xff00ffff) | (data << 16); break;
  209. case 0x2003: mmio.data_seek_offset = (mmio.data_seek_offset & 0x00ffffff) | (data << 24);
  210. mmio.data_read_offset = mmio.data_seek_offset;
  211. data_open();
  212. break;
  213. case 0x2004: mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0); break;
  214. case 0x2005: mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
  215. mmio.audio_play_offset = 8;
  216. audio_open();
  217. break;
  218. case 0x2006: mmio.audio_volume = data; break;
  219. case 0x2007:
  220. if(mmio.audio_busy) break;
  221. if(mmio.audio_error) break;
  222. mmio.audio_repeat = data & 2;
  223. mmio.audio_play = data & 1;
  224. break;
  225. }
  226. }
  227.  
  228. }
  229.  
  230. #ifdef MSU1_CPP
  231.  
  232. void MSU1::serialize(serializer& s) {
  233. Thread::serialize(s);
  234.  
  235. s.integer(mmio.data_seek_offset);
  236. s.integer(mmio.data_read_offset);
  237.  
  238. s.integer(mmio.audio_play_offset);
  239. s.integer(mmio.audio_loop_offset);
  240.  
  241. s.integer(mmio.audio_track);
  242. s.integer(mmio.audio_volume);
  243.  
  244. s.integer(mmio.data_busy);
  245. s.integer(mmio.audio_busy);
  246. s.integer(mmio.audio_repeat);
  247. s.integer(mmio.audio_play);
  248. s.integer(mmio.audio_error);
  249.  
  250. data_open();
  251. audio_open();
  252. }
  253.  
  254. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement