Subversion Repositories ngs

Rev

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