msu1.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #include <string.h>
  2. #include "config.h"
  3. #include "uart.h"
  4. #include "ff.h"
  5. #include "diskio.h"
  6. #include "spi.h"
  7. #include "fpga_spi.h"
  8. #include "cli.h"
  9. #include "fileops.h"
  10. #include "msu1.h"
  11. #include "snes.h"
  12. #include "timer.h"
  13. #include "smc.h"
  14. FIL msufile;
  15. FRESULT msu_res;
  16. DWORD msu_cltbl[CLTBL_SIZE] IN_AHBRAM;
  17. DWORD pcm_cltbl[CLTBL_SIZE] IN_AHBRAM;
  18. UINT msu_audio_bytes_read = 1024;
  19. UINT msu_data_bytes_read = 1;
  20. extern snes_romprops_t romprops;
  21. uint32_t msu_loop_point = 0;
  22. uint32_t msu_page1_start = 0x0000;
  23. uint32_t msu_page2_start = 0x2000;
  24. uint32_t msu_page_size = 0x2000;
  25. uint16_t fpga_status_prev;
  26. uint16_t fpga_status_now;
  27. enum msu_reset_state { MSU_RESET_NONE = 0, MSU_RESET_SHORT, MSU_RESET_LONG };
  28. void prepare_audio_track( uint16_t msu_track )
  29. {
  30. /* open file, fill buffer */
  31. char suffix[11];
  32. f_close( &file_handle );
  33. snprintf( suffix, sizeof( suffix ), "-%d.pcm", msu_track );
  34. strcpy( ( char * )file_buf, ( char * )file_lfn );
  35. strcpy( strrchr( ( char * )file_buf, ( int )'.' ), suffix );
  36. DBG_MSU1 printf( "filename: %s\n", file_buf );
  37. if ( f_open( &file_handle, ( const TCHAR * )file_buf, FA_READ ) == FR_OK )
  38. {
  39. file_handle.cltbl = pcm_cltbl;
  40. pcm_cltbl[0] = CLTBL_SIZE;
  41. f_lseek( &file_handle, CREATE_LINKMAP );
  42. f_lseek( &file_handle, 4L );
  43. f_read( &file_handle, &msu_loop_point, 4, &msu_audio_bytes_read );
  44. DBG_MSU1 printf( "loop point: %ld samples\n", msu_loop_point );
  45. ff_sd_offload = 1;
  46. sd_offload_tgt = 1;
  47. f_lseek( &file_handle, 8L );
  48. set_dac_addr( 0 );
  49. dac_pause();
  50. dac_reset();
  51. ff_sd_offload = 1;
  52. sd_offload_tgt = 1;
  53. f_read( &file_handle, file_buf, MSU_DAC_BUFSIZE, &msu_audio_bytes_read );
  54. /* clear busy bit */
  55. set_msu_status( 0x00, 0x28 ); /* set no bits, reset audio_busy + audio_error */
  56. }
  57. else
  58. {
  59. f_close( &file_handle );
  60. set_msu_status( 0x08, 0x20 ); /* reset audio_busy, set audio_error */
  61. }
  62. }
  63. void prepare_data( uint32_t msu_offset )
  64. {
  65. DBG_MSU1 printf( "Data requested! Offset=%08lx page1=%08lx page2=%08lx\n", msu_offset, msu_page1_start,
  66. msu_page2_start );
  67. if ( ( ( msu_offset < msu_page1_start )
  68. || ( msu_offset >= msu_page1_start + msu_page_size ) )
  69. && ( ( msu_offset < msu_page2_start )
  70. || ( msu_offset >= msu_page2_start + msu_page_size ) ) )
  71. {
  72. DBG_MSU1 printf( "offset %08lx out of range (%08lx-%08lx, %08lx-%08lx), reload\n", msu_offset, msu_page1_start,
  73. msu_page1_start + msu_page_size - 1, msu_page2_start, msu_page2_start + msu_page_size - 1 );
  74. /* "cache miss" */
  75. /* fill buffer */
  76. set_msu_addr( 0x0 );
  77. sd_offload_tgt = 2;
  78. ff_sd_offload = 1;
  79. msu_res = f_lseek( &msufile, msu_offset );
  80. DBG_MSU1 printf( "seek to %08lx, res = %d\n", msu_offset, msu_res );
  81. sd_offload_tgt = 2;
  82. ff_sd_offload = 1;
  83. msu_res = f_read( &msufile, file_buf, 16384, &msu_data_bytes_read );
  84. DBG_MSU1 printf( "read res = %d\n", msu_res );
  85. DBG_MSU1 printf( "read %d bytes\n", msu_data_bytes_read );
  86. msu_reset( 0x0 );
  87. msu_page1_start = msu_offset;
  88. msu_page2_start = msu_offset + msu_page_size;
  89. }
  90. else
  91. {
  92. if ( msu_offset >= msu_page1_start && msu_offset <= msu_page1_start + msu_page_size )
  93. {
  94. msu_reset( 0x0000 + msu_offset - msu_page1_start );
  95. DBG_MSU1 printf( "inside page1, new offset: %08lx\n", 0x0000 + msu_offset - msu_page1_start );
  96. if ( !( msu_page2_start == msu_page1_start + msu_page_size ) )
  97. {
  98. set_msu_addr( 0x2000 );
  99. sd_offload_tgt = 2;
  100. ff_sd_offload = 1;
  101. f_read( &msufile, file_buf, 8192, &msu_data_bytes_read );
  102. DBG_MSU1 printf( "next page dirty (was: %08lx), loaded page2 (start now: ", msu_page2_start );
  103. msu_page2_start = msu_page1_start + msu_page_size;
  104. DBG_MSU1 printf( "%08lx)\n", msu_page2_start );
  105. }
  106. }
  107. else if ( msu_offset >= msu_page2_start && msu_offset <= msu_page2_start + msu_page_size )
  108. {
  109. DBG_MSU1 printf( "inside page2, new offset: %08lx\n", 0x2000 + msu_offset - msu_page2_start );
  110. msu_reset( 0x2000 + msu_offset - msu_page2_start );
  111. if ( !( msu_page1_start == msu_page2_start + msu_page_size ) )
  112. {
  113. set_msu_addr( 0x0 );
  114. sd_offload_tgt = 2;
  115. ff_sd_offload = 1;
  116. f_read( &msufile, file_buf, 8192, &msu_data_bytes_read );
  117. DBG_MSU1 printf( "next page dirty (was: %08lx), loaded page1 (start now: ", msu_page1_start );
  118. msu_page1_start = msu_page2_start + msu_page_size;
  119. DBG_MSU1 printf( "%08lx)\n", msu_page1_start );
  120. }
  121. }
  122. else
  123. {
  124. printf( "!!!WATWATWAT!!!\n" );
  125. }
  126. }
  127. /* clear bank bit to mask bank reset artifact */
  128. fpga_status_now &= ~0x2000;
  129. fpga_status_prev &= ~0x2000;
  130. /* clear busy bit */
  131. set_msu_status( 0x00, 0x10 );
  132. }
  133. int msu1_check_reset( void )
  134. {
  135. static tick_t rising_ticks;
  136. static uint8_t resbutton = 0, resbutton_prev = 0;
  137. int result = MSU_RESET_NONE;
  138. resbutton = get_snes_reset();
  139. if ( resbutton && !resbutton_prev ) /* push */
  140. {
  141. rising_ticks = getticks();
  142. }
  143. else if ( resbutton && resbutton_prev ) /* hold */
  144. {
  145. if ( getticks() > rising_ticks + 99 )
  146. {
  147. result = MSU_RESET_LONG;
  148. }
  149. }
  150. else if ( !resbutton && resbutton_prev ) /* release */
  151. {
  152. if ( getticks() < rising_ticks + 99 )
  153. {
  154. result = MSU_RESET_SHORT;
  155. }
  156. }
  157. else
  158. {
  159. result = MSU_RESET_NONE;
  160. }
  161. resbutton_prev = resbutton;
  162. return result;
  163. }
  164. int msu1_check( uint8_t *filename )
  165. {
  166. /* open MSU file */
  167. strcpy( ( char * )file_buf, ( char * )filename );
  168. strcpy( strrchr( ( char * )file_buf, ( int )'.' ), ".msu" );
  169. printf( "MSU datafile: %s\n", file_buf );
  170. if ( f_open( &msufile, ( const TCHAR * )file_buf, FA_READ ) != FR_OK )
  171. {
  172. printf( "MSU datafile not found\n" );
  173. return 0;
  174. }
  175. msufile.cltbl = msu_cltbl;
  176. msu_cltbl[0] = CLTBL_SIZE;
  177. if ( f_lseek( &msufile, CREATE_LINKMAP ) )
  178. {
  179. printf( "Error creating FF linkmap for MSU file!\n" );
  180. }
  181. romprops.fpga_features |= FEAT_MSU1;
  182. return 1;
  183. }
  184. int msu1_loop()
  185. {
  186. /* it is assumed that the MSU file is already opened by calling msu1_check(). */
  187. while ( fpga_status() & 0x4000 );
  188. uint16_t dac_addr = 0;
  189. uint16_t msu_addr = 0;
  190. uint8_t msu_repeat = 0;
  191. uint16_t msu_track = 0;
  192. uint32_t msu_offset = 0;
  193. fpga_status_prev = fpga_status();
  194. fpga_status_now = fpga_status();
  195. int msu_res;
  196. /* set_msu_addr(0x0);
  197. msu_reset(0x0);
  198. ff_sd_offload=1;
  199. sd_offload_tgt=2;
  200. f_lseek(&msufile, 0L);
  201. ff_sd_offload=1;
  202. sd_offload_tgt=2;
  203. f_read(&msufile, file_buf, 16384, &msu_data_bytes_read);
  204. */
  205. set_dac_addr( dac_addr );
  206. dac_pause();
  207. dac_reset();
  208. set_msu_addr( 0x0 );
  209. msu_reset( 0x0 );
  210. ff_sd_offload = 1;
  211. sd_offload_tgt = 2;
  212. f_lseek( &msufile, 0L );
  213. ff_sd_offload = 1;
  214. sd_offload_tgt = 2;
  215. f_read( &msufile, file_buf, 16384, &msu_data_bytes_read );
  216. prepare_audio_track( 0 );
  217. prepare_data( 0 );
  218. /* audio_start, data_start, 0, audio_ctrl[1:0], ctrl_start */
  219. while ( ( msu_res = msu1_check_reset() ) == MSU_RESET_NONE )
  220. {
  221. cli_entrycheck();
  222. fpga_status_now = fpga_status();
  223. /* Data buffer refill */
  224. if ( ( fpga_status_now & 0x2000 ) != ( fpga_status_prev & 0x2000 ) )
  225. {
  226. DBG_MSU1 printf( "data\n" );
  227. if ( fpga_status_now & 0x2000 )
  228. {
  229. msu_addr = 0x0;
  230. msu_page1_start = msu_page2_start + msu_page_size;
  231. }
  232. else
  233. {
  234. msu_addr = 0x2000;
  235. msu_page2_start = msu_page1_start + msu_page_size;
  236. }
  237. set_msu_addr( msu_addr );
  238. sd_offload_tgt = 2;
  239. ff_sd_offload = 1;
  240. msu_res = f_read( &msufile, file_buf, 8192, &msu_data_bytes_read );
  241. DBG_MSU1 printf( "data buffer refilled. res=%d page1=%08lx page2=%08lx\n", msu_res, msu_page1_start, msu_page2_start );
  242. }
  243. /* Audio buffer refill */
  244. if ( ( fpga_status_now & 0x4000 ) != ( fpga_status_prev & 0x4000 ) )
  245. {
  246. if ( fpga_status_now & 0x4000 )
  247. {
  248. dac_addr = 0;
  249. }
  250. else
  251. {
  252. dac_addr = MSU_DAC_BUFSIZE / 2;
  253. }
  254. set_dac_addr( dac_addr );
  255. sd_offload_tgt = 1;
  256. ff_sd_offload = 1;
  257. f_read( &file_handle, file_buf, MSU_DAC_BUFSIZE / 2, &msu_audio_bytes_read );
  258. }
  259. if ( fpga_status_now & 0x0020 )
  260. {
  261. /* get trackno */
  262. msu_track = get_msu_track();
  263. DBG_MSU1 printf( "Audio requested! Track=%d\n", msu_track );
  264. prepare_audio_track( msu_track );
  265. }
  266. if ( fpga_status_now & 0x0010 )
  267. {
  268. /* get address */
  269. msu_offset = get_msu_offset();
  270. prepare_data( msu_offset );
  271. }
  272. if ( fpga_status_now & 0x0001 )
  273. {
  274. if ( fpga_status_now & 0x0004 )
  275. {
  276. msu_repeat = 1;
  277. set_msu_status( 0x04, 0x01 ); /* set bit 2, reset bit 0 */
  278. DBG_MSU1 printf( "Repeat set!\n" );
  279. }
  280. else
  281. {
  282. msu_repeat = 0;
  283. set_msu_status( 0x00, 0x05 ); /* set no bits, reset bit 0+2 */
  284. DBG_MSU1 printf( "Repeat clear!\n" );
  285. }
  286. if ( fpga_status_now & 0x0002 )
  287. {
  288. DBG_MSU1 printf( "PLAY!\n" );
  289. set_msu_status( 0x02, 0x01 ); /* set bit 0, reset bit 1 */
  290. dac_play();
  291. }
  292. else
  293. {
  294. DBG_MSU1 printf( "PAUSE!\n" );
  295. set_msu_status( 0x00, 0x03 ); /* set no bits, reset bit 1+0 */
  296. dac_pause();
  297. }
  298. }
  299. fpga_status_prev = fpga_status_now;
  300. /* handle loop / end */
  301. if ( msu_audio_bytes_read < MSU_DAC_BUFSIZE / 2 )
  302. {
  303. ff_sd_offload = 0;
  304. sd_offload = 0;
  305. if ( msu_repeat )
  306. {
  307. DBG_MSU1 printf( "loop\n" );
  308. ff_sd_offload = 1;
  309. sd_offload_tgt = 1;
  310. f_lseek( &file_handle, 8L + msu_loop_point * 4 );
  311. ff_sd_offload = 1;
  312. sd_offload_tgt = 1;
  313. f_read( &file_handle, file_buf, ( MSU_DAC_BUFSIZE / 2 ) - msu_audio_bytes_read, &msu_audio_bytes_read );
  314. }
  315. else
  316. {
  317. set_msu_status( 0x00, 0x02 ); /* clear play bit */
  318. dac_pause();
  319. }
  320. msu_audio_bytes_read = MSU_DAC_BUFSIZE;
  321. }
  322. }
  323. f_close( &file_handle );
  324. DBG_MSU1 printf( "Reset " );
  325. if ( msu_res == MSU_RESET_LONG )
  326. {
  327. f_close( &msufile );
  328. DBG_MSU1 printf( "to menu\n" );
  329. return 1;
  330. }
  331. DBG_MSU1 printf( "game\n" );
  332. return 0;
  333. }
  334. /* END OF MSU1 STUFF */