Subversion Repositories ngs

Rev

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