Subversion Repositories ngs

Rev

Rev 61 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.         // for simulation purposes
  130.         initial
  131.         begin
  132.                 bf_wraddr <= 0;
  133.                 bf_datnvol <= 0;
  134.                 bf_data <= 0;
  135.                 do_write <= 0;
  136.                 cur_st <= START;
  137.         end
  138.  
  139.  
  140.  
  141.         // instantiating modules
  142.  
  143.         sound_dac my_dac( .clock(clock),
  144.                           .dac_clock(dac_clock),
  145.                           .dac_leftright(dac_leftright),
  146.                           .dac_data(dac_data),
  147.                           .load(dac_load),
  148.                           .datain(dac_pardata) );
  149.  
  150.         sound_mulacc my_mulacc( .clock(clock),
  151.                                 .vol_in(vol),
  152.                                 .dat_in(mem_do),
  153.                                 .mode_inv7b(int_mode_inv7b),
  154.                                 .load(mulacc_load),
  155.                                 .clr_sum(mulacc_clrsum),
  156.                                 .ready(mulacc_ready),
  157.                                 .sum_out(dac_pardata) );
  158.  
  159.         // DAT-VOL memory block
  160.         mem512b my_mem( .clk(clock),
  161.                         .rdaddr(mem_rdaddr),
  162.                         .dataout(mem_do),
  163.                         .wraddr({5'b0,bf_datnvol,bf_wraddr}),
  164.                         .datain(bf_data),
  165.                         .we(mem_we) );
  166.  
  167.  
  168.  
  169.  
  170.  
  171.         // syncing in asynchronous control signals
  172.         always @(posedge clock)
  173.         begin
  174.                 { int_mode_8chans,sync_mode_8chans } <= { sync_mode_8chans, mode_8chans };
  175.                 { int_mode_pan4ch,sync_mode_pan4ch } <= { sync_mode_pan4ch, mode_pan4ch };
  176.                 { int_mode_inv7b ,sync_mode_inv7b  } <= { sync_mode_inv7b,  mode_inv7b  };
  177.         end
  178.  
  179.  
  180.         // load lrptr (left-right pointer) on dac_load pulse
  181.         always @(posedge clock)
  182.         begin
  183.                 if( dac_load )
  184.                         lrptr <= ~dac_leftright;
  185.         end
  186.  
  187.         // make memory read address from chanptr and lrptr
  188.         always @*
  189.         begin
  190. /*              mem_rdaddr[8:4] <= 5'd0;
  191.                 mem_rdaddr[3]   <= datnvol;
  192.                 mem_rdaddr[2]   <= int_mode_8chans ? chanptr[1] : 1'b0;
  193.                 mem_rdaddr[1]   <= lrptr;
  194.                 mem_rdaddr[0]   <= chanptr[0];*/
  195.  
  196.                 mem_rdaddr[8:4] <= 5'd0;
  197.  
  198.                 if( int_mode_8chans )
  199.                 begin
  200.                         mem_rdaddr[3]   <= datnvol;
  201.                         mem_rdaddr[2]   <= chanptr[1];
  202.                         mem_rdaddr[1]   <= lrptr;
  203.                         mem_rdaddr[0]   <= chanptr[0];
  204.                 end
  205.                 else if( int_mode_pan4ch )
  206.                 begin
  207.                         mem_rdaddr[3] <= datnvol;
  208.  
  209.                         if( datnvol ) // sample data
  210.                         begin
  211.                                 mem_rdaddr[2] <= 1'b0;
  212.                                 mem_rdaddr[1] <= chanptr[1];
  213.                                 mem_rdaddr[0] <= chanptr[0];
  214.                         end
  215.                         else // !datnvol: volumes
  216.                         begin
  217.                                 mem_rdaddr[2]   <= chanptr[1]; // same as in 8 channel
  218.                                 mem_rdaddr[1]   <= lrptr;
  219.                                 mem_rdaddr[0]   <= chanptr[0];
  220.                         end
  221.                 end
  222.                 else //normal 4 channel mode
  223.                 begin
  224.                         mem_rdaddr[3]   <= datnvol;
  225.                         mem_rdaddr[2]   <= 1'b0;
  226.                         mem_rdaddr[1]   <= lrptr;
  227.                         mem_rdaddr[0]   <= chanptr[0];
  228.                 end
  229.         end
  230.  
  231.         // handle mulacc_clrsum signal
  232.         always @(posedge clock)
  233.         begin
  234.                 if( dac_load )
  235.                         mulacc_clrsum <= 1'b1;     // set on dac_load pulse
  236.                 else if( mulacc_load )
  237.                         mulacc_clrsum <= 1'b0;     // clear on mulacc_load pulse, so only first mulacc cycle will read clrsum high
  238.         end
  239.  
  240.  
  241.  
  242.  
  243.  
  244.         localparam START      = 0;
  245.         localparam LOAD_VOL   = 1;
  246.         localparam LOAD_VOL2  = 2;
  247.         localparam LOAD_DAT   = 3;
  248.         localparam LOAD_DAT2  = 4;
  249.         localparam START_MUL  = 5;
  250.         localparam WAIT_STOP  = 6;
  251.         localparam LOOP       = 7;
  252.  
  253.         // FSM!
  254.         always @(posedge clock)
  255.         begin
  256.                 if( dac_load )
  257.                         cur_st <= START;
  258.                 else
  259.                         cur_st <= nxt_st;
  260.         end
  261.  
  262.         always @*
  263.         begin
  264.                 case( cur_st )
  265. /////////////////////////////////////////////////////////////////////
  266.                 START:
  267.                         nxt_st <= LOAD_VOL;
  268. /////////////////////////////////////////////////////////////////////
  269.                 LOAD_VOL:
  270.                         nxt_st <= LOAD_VOL2;
  271. /////////////////////////////////////////////////////////////////////
  272.                 LOAD_VOL2:
  273.                         nxt_st <= LOAD_DAT;
  274. /////////////////////////////////////////////////////////////////////
  275.                 LOAD_DAT:
  276.                         nxt_st <= LOAD_DAT2;
  277. /////////////////////////////////////////////////////////////////////
  278.                 LOAD_DAT2:
  279.                         nxt_st <= START_MUL;
  280. /////////////////////////////////////////////////////////////////////
  281.                 START_MUL:
  282.                         nxt_st <= WAIT_STOP;
  283. /////////////////////////////////////////////////////////////////////
  284.                 WAIT_STOP:
  285.                         if( (!mulacc_ready) || (chanptr == 2'd3) )
  286.                                 nxt_st <= WAIT_STOP;
  287.                         else
  288.                                 nxt_st <= LOOP;
  289. /////////////////////////////////////////////////////////////////////
  290.                 LOOP:
  291.                         nxt_st <= LOAD_VOL;
  292. /////////////////////////////////////////////////////////////////////
  293.                 endcase
  294.         end
  295.  
  296.  
  297.         always @(posedge clock)
  298.         begin
  299.                 case( cur_st )
  300. /////////////////////////////////////////////////////////////////////
  301.                 START:
  302.                 begin
  303.                         chanptr <= 2'd0;
  304.                         mulacc_load <= 1'b0;
  305.                         mem_read <= 1'b0;
  306.                 end
  307. /////////////////////////////////////////////////////////////////////
  308.                 LOAD_VOL:
  309.                 begin
  310.                         mem_read <= 1'b1;
  311.                         datnvol <= 1'b0;
  312.                 end
  313. /////////////////////////////////////////////////////////////////////
  314.                 LOAD_VOL2:
  315.                 begin
  316.                         mem_read <= 1'b0;
  317.                 end
  318. /////////////////////////////////////////////////////////////////////
  319.                 LOAD_DAT:
  320.                 begin
  321.                         vol <= mem_do[5:0];
  322.                         mem_read <= 1'b1;
  323.                         datnvol <= 1'b1;
  324.                 end
  325. /////////////////////////////////////////////////////////////////////
  326.                 LOAD_DAT2:
  327.                 begin
  328.                         mem_read <= 1'b0;
  329.                         mulacc_load <= 1'b1;
  330.                 end
  331. /////////////////////////////////////////////////////////////////////
  332.                 START_MUL:
  333.                 begin
  334.                         mulacc_load <= 1'b0;
  335.                 end
  336. /////////////////////////////////////////////////////////////////////
  337. //              WAIT_STOP:
  338. /////////////////////////////////////////////////////////////////////
  339.                 LOOP:
  340.                 begin
  341.                         chanptr <= chanptr + 2'd1;
  342.                 end
  343. /////////////////////////////////////////////////////////////////////
  344.                 endcase
  345.         end
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355. // controlling writes to memory
  356.  
  357.         // toggles
  358.         always @(negedge clock)
  359.                 wrtgl1 <= in_wrtoggle;
  360.         always @(posedge clock)
  361.                 {wrtgl3,wrtgl2} <= {wrtgl2,wrtgl1};
  362.  
  363.  
  364.         // intermediate buffers and writing
  365.         always @(posedge clock)
  366.         begin
  367.  
  368.                 if( wrtgl3!=wrtgl2 )
  369.                 begin
  370.                         bf_wraddr  <= in_wraddr;
  371.                         bf_data    <= in_data;
  372.                         bf_datnvol <= in_datnvol;
  373.  
  374.                         do_write <= 1'b1;
  375.                 end
  376.  
  377.                 else if( mem_we )
  378.                 begin
  379.                         do_write <= 1'b0;
  380.                 end
  381.  
  382.         end
  383.  
  384.         always @*
  385.         begin
  386.                 mem_we <= do_write & (~mem_read);
  387.         end
  388.  
  389.  
  390. endmodule
  391.  
  392.