Subversion Repositories ngs

Rev

Rev 91 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. // part of NeoGS project (c) 2007-2008 NedoPC
  2. //
  3. // sound_main is the main sound module: it incorporates data storage (512b memory), from which
  4. //  it reads data, prepares it through sound_mulacc and sends to sound_dac. It incorporates in itself
  5. //  sound_dac, so it has outs to the DAC.
  6. // clock is ordinary 24 MHz clock, mode_8chans is asynchronous input signal controlling mode of operation,
  7. //  either 4 or 8 channels.
  8. //
  9. // channels in 4 channel mode (mode_8chans=0,mode_pan4ch=0)
  10. // 1,2 -> left
  11. // 3,4 -> right
  12. // channels in 8 channel mode (mode_8chans=1,mode_pan4ch=0)
  13. // 1,2,5,6 -> left
  14. // 3,4,7,8 -> right
  15. // channels in panning 4 channel mode (mode_8chans=0,mode_pan4ch=1)
  16. // 1,2,3,4 (vols 1,2,5,6) -> left
  17. // 1,2,3,4 (vols 3,4,7,8) -> right
  18. // channels in mem are at addressed 0-7 (corresponding to channels 1-8, respectively).
  19. // mem contains volumes (lower 6 bits, 0-zero volume, 63-max volume) and sound data (signed value with sign inverted:
  20. // -data in mem---+----value--
  21. //          $FF   |     +$7F
  22. //          $81   |     +$01
  23. //          $80   |     +$00
  24. //          $7F   |     -$01 (or $FF)
  25. //          $01   |     -$7F (or $81)
  26. //          $00   |     -$80 (or $80)
  27. // alternatively, it could be treated as unsigned positive samples with middle point of $7F-$80.
  28. //
  29. // inv7b causes 7th bit inversion: samples become signed
  30. //
  31. // clock      ``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__
  32. // mem_read   ______/`````\__________________________________
  33. // mem_wraddr       |  no |     |addr |
  34. // mem_di           |write|     |data |
  35. // mem_***_we ______|here!|_____/`````\______________________
  36. //                                   ^-- data written here!
  37.  
  38. module sound_main(
  39.  
  40.         clock,         // system clock (24 MHz)
  41.  
  42.         mode_8chans,   // =1 - 8 channels, =0 - 4 channels
  43.         mode_pan4ch,   // =1 - 4 channels with panning
  44.         mode_inv7b,    // =1 - invert 7th bit of every sample byte
  45.  
  46.  
  47.         in_wrtoggle,   // from ports.v module (async to clock)
  48.         in_datnvol,    //
  49.         in_wraddr,     //
  50.         in_data,       //
  51.  
  52.  
  53.         dac_clock,     // output to DAC
  54.         dac_leftright, // output to DAC
  55.         dac_data       // output to DAC
  56. );
  57.  
  58.     // input-output description
  59.  
  60.         input clock;
  61.  
  62.         input mode_8chans;
  63.         input mode_pan4ch;
  64.         input mode_inv7b;
  65.  
  66.         input in_wrtoggle;
  67.         input in_datnvol;
  68.         input [2:0] in_wraddr;
  69.         input [7:0] in_data;
  70.  
  71.         output dac_clock;
  72.  
  73.         output dac_leftright;
  74.  
  75.         output dac_data;
  76.  
  77.  
  78.         // internal regs/wires
  79.  
  80.         reg mem_read; // write to mem is forbidden while mem_read=1
  81.  
  82.         reg datnvol;
  83.  
  84.         reg [5:0] vol; // temporary storage for volume
  85.  
  86.         reg mem_we; // write strobe
  87.  
  88.         reg wrtgl1, wrtgl2, wrtgl3; // sync in and edge detect of in_wrtoggle
  89.  
  90.         reg do_write; // indicates that write should be performed
  91.  
  92.         reg [2:0] bf_wraddr;
  93.         reg [7:0] bf_data;
  94.         reg       bf_datnvol;
  95.  
  96.  
  97.  
  98.         wire dac_load; // signal from sound_dac module (when it loads new data)
  99.  
  100.         wire [15:0] dac_pardata; // parallel data from sound_mulacc to sound_dac
  101.  
  102.         reg mulacc_load;   // load to sound_mulacc
  103.         reg mulacc_clrsum; // clr_sum to sound_mulacc
  104.         wire mulacc_ready; // ready from sound_mulacc
  105.  
  106.         wire [7:0] mem_do; // data output of DAT or VOL
  107.  
  108.         reg [8:0] mem_rdaddr;  // read address for both memory blocks
  109.  
  110.         reg int_mode_8chans;  // internal and sync-in mode_8chans signals
  111.         reg sync_mode_8chans; //
  112.  
  113.         reg int_mode_pan4ch,sync_mode_pan4ch; // same for pan4ch signal
  114.         reg int_mode_inv7b, sync_mode_inv7b;  // ...
  115.  
  116.         reg [1:0] chanptr; // pointer to channels (4 channels total: 0,1,4,5 or 2,3,6,7 depending on lrptr state)
  117.         reg lrptr;         // left-right pointer (selects either left (0) or right (1) channels)
  118.  
  119.  
  120.  
  121.  
  122.         reg [2:0] cur_st,nxt_st;
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.         // instantiating modules
  133.  
  134.         sound_dac my_dac( .clock(clock),
  135.                           .dac_clock(dac_clock),
  136.                           .dac_leftright(dac_leftright),
  137.                           .dac_data(dac_data),
  138.                           .load(dac_load),
  139.                           .datain(dac_pardata) );
  140.  
  141.         sound_mulacc my_mulacc( .clock(clock),
  142.                                 .vol_in(vol),
  143.                                 .dat_in(mem_do),
  144.                                 .mode_inv7b(int_mode_inv7b),
  145.                                 .load(mulacc_load),
  146.                                 .clr_sum(mulacc_clrsum),
  147.                                 .ready(mulacc_ready),
  148.                                 .sum_out(dac_pardata) );
  149.  
  150.         // DAT-VOL memory block
  151.         mem512b my_mem( .clk(clock),
  152.                         .re(1'b1),
  153.                         .rdaddr(mem_rdaddr),
  154.                         .dataout(mem_do),
  155.                         .wraddr({5'b0,bf_datnvol,bf_wraddr}),
  156.                         .datain(bf_data),
  157.                         .we(mem_we) );
  158.  
  159.  
  160.  
  161.  
  162.  
  163.         // syncing in asynchronous control signals
  164.         always @(posedge clock)
  165.         begin
  166.                 { int_mode_8chans,sync_mode_8chans } <= { sync_mode_8chans, mode_8chans };
  167.                 { int_mode_pan4ch,sync_mode_pan4ch } <= { sync_mode_pan4ch, mode_pan4ch };
  168.                 { int_mode_inv7b ,sync_mode_inv7b  } <= { sync_mode_inv7b,  mode_inv7b  };
  169.         end
  170.  
  171.  
  172.         // load lrptr (left-right pointer) on dac_load pulse
  173.         always @(posedge clock)
  174.         begin
  175.                 if( dac_load )
  176.                         lrptr <= ~dac_leftright;
  177.         end
  178.  
  179.         // make memory read address from chanptr and lrptr
  180.         always @*
  181.         begin
  182. /*              mem_rdaddr[8:4] <= 5'd0;
  183.                 mem_rdaddr[3]   <= datnvol;
  184.                 mem_rdaddr[2]   <= int_mode_8chans ? chanptr[1] : 1'b0;
  185.                 mem_rdaddr[1]   <= lrptr;
  186.                 mem_rdaddr[0]   <= chanptr[0];*/
  187.  
  188.                 mem_rdaddr[8:4] <= 5'd0;
  189.  
  190.                 if( int_mode_8chans )
  191.                 begin
  192.                         mem_rdaddr[3]   <= datnvol;
  193.                         mem_rdaddr[2]   <= chanptr[1];
  194.                         mem_rdaddr[1]   <= lrptr;
  195.                         mem_rdaddr[0]   <= chanptr[0];
  196.                 end
  197.                 else if( int_mode_pan4ch )
  198.                 begin
  199.                         mem_rdaddr[3] <= datnvol;
  200.  
  201.                         if( datnvol ) // sample data
  202.                         begin
  203.                                 mem_rdaddr[2] <= 1'b0;
  204.                                 mem_rdaddr[1] <= chanptr[1];
  205.                                 mem_rdaddr[0] <= chanptr[0];
  206.                         end
  207.                         else // !datnvol: volumes
  208.                         begin
  209.                                 mem_rdaddr[2]   <= chanptr[1]; // same as in 8 channel
  210.                                 mem_rdaddr[1]   <= lrptr;
  211.                                 mem_rdaddr[0]   <= chanptr[0];
  212.                         end
  213.                 end
  214.                 else //normal 4 channel mode
  215.                 begin
  216.                         mem_rdaddr[3]   <= datnvol;
  217.                         mem_rdaddr[2]   <= 1'b0;
  218.                         mem_rdaddr[1]   <= lrptr;
  219.                         mem_rdaddr[0]   <= chanptr[0];
  220.                 end
  221.         end
  222.  
  223.         // handle mulacc_clrsum signal
  224.         always @(posedge clock)
  225.         begin
  226.                 if( dac_load )
  227.                         mulacc_clrsum <= 1'b1;     // set on dac_load pulse
  228.                 else if( mulacc_load )
  229.                         mulacc_clrsum <= 1'b0;     // clear on mulacc_load pulse, so only first mulacc cycle will read clrsum high
  230.         end
  231.  
  232.  
  233.  
  234.  
  235.  
  236.         localparam START      = 0;
  237.         localparam LOAD_VOL   = 1;
  238.         localparam LOAD_VOL2  = 2;
  239.         localparam LOAD_DAT   = 3;
  240.         localparam LOAD_DAT2  = 4;
  241.         localparam START_MUL  = 5;
  242.         localparam WAIT_STOP  = 6;
  243.         localparam LOOP       = 7;
  244.  
  245.  
  246.  
  247.         // for simulation purposes
  248.         initial
  249.         begin
  250.                 bf_wraddr <= 0;
  251.                 bf_datnvol <= 0;
  252.                 bf_data <= 0;
  253.                 do_write <= 0;
  254.                 cur_st <= START;
  255.         end
  256.  
  257.  
  258.  
  259.         // FSM!
  260.         always @(posedge clock)
  261.         begin
  262.                 if( dac_load )
  263.                         cur_st <= START;
  264.                 else
  265.                         cur_st <= nxt_st;
  266.         end
  267.  
  268.         always @*
  269.         begin
  270.                 case( cur_st )
  271. /////////////////////////////////////////////////////////////////////
  272.                 START:
  273.                         nxt_st <= LOAD_VOL;
  274. /////////////////////////////////////////////////////////////////////
  275.                 LOAD_VOL:
  276.                         nxt_st <= LOAD_VOL2;
  277. /////////////////////////////////////////////////////////////////////
  278.                 LOAD_VOL2:
  279.                         nxt_st <= LOAD_DAT;
  280. /////////////////////////////////////////////////////////////////////
  281.                 LOAD_DAT:
  282.                         nxt_st <= LOAD_DAT2;
  283. /////////////////////////////////////////////////////////////////////
  284.                 LOAD_DAT2:
  285.                         nxt_st <= START_MUL;
  286. /////////////////////////////////////////////////////////////////////
  287.                 START_MUL:
  288.                         nxt_st <= WAIT_STOP;
  289. /////////////////////////////////////////////////////////////////////
  290.                 WAIT_STOP:
  291.                         if( (!mulacc_ready) || (chanptr == 2'd3) )
  292.                                 nxt_st <= WAIT_STOP;
  293.                         else
  294.                                 nxt_st <= LOOP;
  295. /////////////////////////////////////////////////////////////////////
  296.                 LOOP:
  297.                         nxt_st <= LOAD_VOL;
  298. /////////////////////////////////////////////////////////////////////
  299.                 endcase
  300.         end
  301.  
  302.  
  303.         always @(posedge clock)
  304.         begin
  305.                 case( cur_st )
  306. /////////////////////////////////////////////////////////////////////
  307.                 START:
  308.                 begin
  309.                         chanptr <= 2'd0;
  310.                         mulacc_load <= 1'b0;
  311.                         mem_read <= 1'b0;
  312.                 end
  313. /////////////////////////////////////////////////////////////////////
  314.                 LOAD_VOL:
  315.                 begin
  316.                         mem_read <= 1'b1;
  317.                         datnvol <= 1'b0;
  318.                 end
  319. /////////////////////////////////////////////////////////////////////
  320.                 LOAD_VOL2:
  321.                 begin
  322.                         mem_read <= 1'b0;
  323.                 end
  324. /////////////////////////////////////////////////////////////////////
  325.                 LOAD_DAT:
  326.                 begin
  327.                         vol <= mem_do[5:0];
  328.                         mem_read <= 1'b1;
  329.                         datnvol <= 1'b1;
  330.                 end
  331. /////////////////////////////////////////////////////////////////////
  332.                 LOAD_DAT2:
  333.                 begin
  334.                         mem_read <= 1'b0;
  335.                         mulacc_load <= 1'b1;
  336.                 end
  337. /////////////////////////////////////////////////////////////////////
  338.                 START_MUL:
  339.                 begin
  340.                         mulacc_load <= 1'b0;
  341.                 end
  342. /////////////////////////////////////////////////////////////////////
  343. //              WAIT_STOP:
  344. /////////////////////////////////////////////////////////////////////
  345.                 LOOP:
  346.                 begin
  347.                         chanptr <= chanptr + 2'd1;
  348.                 end
  349. /////////////////////////////////////////////////////////////////////
  350.                 endcase
  351.         end
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361. // controlling writes to memory
  362.  
  363.         // toggles
  364.         always @(negedge clock)
  365.                 wrtgl1 <= in_wrtoggle;
  366.         always @(posedge clock)
  367.                 {wrtgl3,wrtgl2} <= {wrtgl2,wrtgl1};
  368.  
  369.  
  370.         // intermediate buffers and writing
  371.         always @(posedge clock)
  372.         begin
  373.  
  374.                 if( wrtgl3!=wrtgl2 )
  375.                 begin
  376.                         bf_wraddr  <= in_wraddr;
  377.                         bf_data    <= in_data;
  378.                         bf_datnvol <= in_datnvol;
  379.  
  380.                         do_write <= 1'b1;
  381.                 end
  382.  
  383.                 else if( mem_we )
  384.                 begin
  385.                         do_write <= 1'b0;
  386.                 end
  387.  
  388.         end
  389.  
  390.         always @*
  391.         begin
  392.                 mem_we <= do_write & (~mem_read);
  393.         end
  394.  
  395.  
  396. endmodule
  397.  
  398.