OpenCores
URL https://opencores.org/ocsvn/sqmusic/sqmusic/trunk

Subversion Repositories sqmusic

[/] [sqmusic/] [trunk/] [sqm/] [sqmusic.v] - Diff between revs 4 and 6

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 4 Rev 6
/*
/*
        SQmusic
        SQmusic
  Music synthetiser compatible with AY-3-8910 software compatible
  Music synthetiser compatible with AY-3-8910 software compatible
  Version 0.1, tested on simulation only with Capcom's 1942
  Version 0.1, tested on simulation only with Capcom's 1942
 
 
  (c) Jose Tejada Gomez, 9th May 2013
  (c) Jose Tejada Gomez, 9th May 2013
  You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
  You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
  Read the details of the license in:
  Read the details of the license in:
  http://www.gnu.org/licenses/gpl.txt
  http://www.gnu.org/licenses/gpl.txt
 
 
  Send comments to: jose.tejada@ieee.org
  Send comments to: jose.tejada@ieee.org
 
 
*/
*/
 
 
/* Capcom arcade boards like 1942 use two memory locations to
/* Capcom arcade boards like 1942 use two memory locations to
communicate with the AY-3-8910 (or compatible) chip.  This small code
communicate with the AY-3-8910 (or compatible) chip.  This small code
provides a 2-byte memory map as expected by Capcom games
provides a 2-byte memory map as expected by Capcom games
*/
*/
`timescale 1ns / 1ps
`timescale 1ns / 1ps
module AY_3_8910_capcom
module AY_3_8910_capcom
#( parameter dump_writes=0, parameter id=0 )
#( parameter dump_writes=0, parameter id=0 )
(
(
        input reset_n,
        input reset_n,
  input clk, // CPU clock
  input clk, // CPU clock
        input sound_clk, // normally slower than the CPU clock
        input sound_clk, // normally slower than the CPU clock
  input  [7:0] din,
  input  [7:0] din,
  input  adr,
  input  adr,
  input wr_n,  // write
  input wr_n,  // write
        input cs_n, // chip select
        input cs_n, // chip select
  output [3:0]A,B,C // channel outputs
  output [3:0]A,B,C // channel outputs
);
);
 
 
reg [7:0] latches[1:0];
reg [3:0] adr_latch;
reg core_wr;
wire sample = ~cs_n & ~wr_n;
wire sample = clk & ~cs_n & ~wr_n;
wire core_wr = adr & sample;
reg count;
reg count;
 
 
always @(posedge sound_clk or negedge reset_n) begin
always @(posedge clk or negedge reset_n) begin
        if(!reset_n) begin
        if(!reset_n)
                count=0;
                adr_latch <= 0;
        end
        else
        else begin
        if( sample && adr==0 )
                if( !count && core_wr) count=1;
                adr_latch <= din[3:0];
                else if( core_wr ) begin
 
                        count=0;
 
                        core_wr=0;
 
                end
 
        end
 
end
 
 
 
always @(posedge sample or negedge reset_n) begin
 
        if(!reset_n) begin
 
                latches[0]=0;
 
                latches[1]=0;
 
        end
 
        else begin
 
                latches[adr] = din;
 
                if(adr) core_wr=1;
 
        end
 
end
end
 
 
SQMUSIC #(dump_writes, id) core( .reset_n(reset_n), .clk(sound_clk), .data_in(latches[1]),
SQMUSIC #(dump_writes, id) core( .reset_n(reset_n), .clk(sound_clk), .data_in(din),
        .adr( latches[0][3:0] ), .rd(1'b0), .wr(core_wr), .A(A), .B(B), .C(C) );
        .adr( adr_latch ), .rd(1'b0), .wr(core_wr), .A(A), .B(B), .C(C) );
endmodule
endmodule
 
 
 
//////////////////////////////////////////////////////////////////////////////
/*  The AY core does
/*  The AY core does
*/
*/
module SQMUSIC
module SQMUSIC
#( parameter dump_writes=0, parameter id=0 ) // set to 1 to dump register writes
#( parameter dump_writes=0, parameter id=0 ) // set to 1 to dump register writes
( // note that input ports are not multiplexed
( // note that input ports are not multiplexed
  input reset_n,
  input reset_n,
  input clk,
  input clk,
  input  [7:0] data_in,
  input  [7:0] data_in,
  output reg [7:0] data_out,
  output reg [7:0] data_out,
  input  [3:0] adr,
  input  [3:0] adr,
  input rd, // read
  input rd, // read
  input wr,  // write
  input wr,  // write
  output [3:0]A,B,C // channel outputs
  output [3:0]A,B,C // channel outputs
);
);
 
 
reg [7:0] regarray[15:0];
reg [7:0] regarray[15:0];
reg [3:0] clkdiv16;
reg [3:0] clkdiv16;
 
 
wire [3:0] envelope;
wire [3:0] envelope;
wire [2:0] sqwave;
wire [2:0] sqwave;
wire noise, envclk;
wire noise, envclk;
wire Amix = (noise|regarray[7][3]) ^ (sqwave[0]|regarray[7][0]);
wire Amix = (noise|regarray[7][3]) ^ (sqwave[0]|regarray[7][0]);
wire Bmix = (noise|regarray[7][4]) ^ (sqwave[1]|regarray[7][1]);
wire Bmix = (noise|regarray[7][4]) ^ (sqwave[1]|regarray[7][1]);
wire Cmix = (noise|regarray[7][5]) ^ (sqwave[2]|regarray[7][2]);
wire Cmix = (noise|regarray[7][5]) ^ (sqwave[2]|regarray[7][2]);
 
 
// internal modules operate at clk/16
// internal modules operate at clk/16
SQM_CLK_DIVIDER #(12) chA( .clk(clkdiv16[3]), .reset_n(reset_n),
SQM_CLK_DIVIDER #(12) chA( .clk(clkdiv16[3]), .reset_n(reset_n),
  .period({regarray[1][3:0], regarray[0][7:0] }), .div(sqwave[0]) );
  .period({regarray[1][3:0], regarray[0][7:0] }), .div(sqwave[0]) );
SQM_CLK_DIVIDER #(12) chB( .clk(clkdiv16[3]), .reset_n(reset_n),
SQM_CLK_DIVIDER #(12) chB( .clk(clkdiv16[3]), .reset_n(reset_n),
  .period({regarray[3][3:0], regarray[2][7:0] }), .div(sqwave[1]) );
  .period({regarray[3][3:0], regarray[2][7:0] }), .div(sqwave[1]) );
SQM_CLK_DIVIDER #(12) chC( .clk(clkdiv16[3]), .reset_n(reset_n),
SQM_CLK_DIVIDER #(12) chC( .clk(clkdiv16[3]), .reset_n(reset_n),
  .period({regarray[5][3:0], regarray[4][7:0] }), .div(sqwave[2]) );
  .period({regarray[5][3:0], regarray[4][7:0] }), .div(sqwave[2]) );
 
 
// the noise uses a x2 faster clock in order to produce a frequency
// the noise uses a x2 faster clock in order to produce a frequency
// of Fclk/16 when period is 1
// of Fclk/16 when period is 1
SQM_NOISE    ng( .clk(clkdiv16[3]), .reset_n(reset_n),
SQM_NOISE    ng( .clk(clkdiv16[3]), .reset_n(reset_n),
  .period(regarray[6][4:0]), .noise(noise) );
  .period(regarray[6][4:0]), .noise(noise) );
// envelope generator
// envelope generator
SQM_CLK_DIVIDER #(16) envclkdiv( .clk(clkdiv16[2]), .reset_n(reset_n),
SQM_CLK_DIVIDER #(16) envclkdiv( .clk(clkdiv16[2]), .reset_n(reset_n),
  .period({regarray[14],regarray[13]}), .div(envclk) );
  .period({regarray[14],regarray[13]}), .div(envclk) );
SQM_ENVELOPE env( .clk(envclk),.ctrl(regarray[15][3:0]),
SQM_ENVELOPE env( .clk(envclk),.ctrl(regarray[15][3:0]),
  .gain(envelope), .reset_n(reset_n) );
  .gain(envelope), .reset_n(reset_n) );
 
 
assign A=regarray[10][4]? envelope&{4{Amix}} : regarray[10][3:0]&{4{Amix}};
assign A=regarray[10][4]? envelope&{4{Amix}} : regarray[10][3:0]&{4{Amix}};
assign B=regarray[11][4]? envelope&{4{Bmix}} : regarray[10][3:0]&{4{Bmix}};
assign B=regarray[11][4]? envelope&{4{Bmix}} : regarray[10][3:0]&{4{Bmix}};
assign C=regarray[12][4]? envelope&{4{Cmix}} : regarray[10][3:0]&{4{Cmix}};
assign C=regarray[12][4]? envelope&{4{Cmix}} : regarray[10][3:0]&{4{Cmix}};
 
 
integer aux;
 
 
 
// 16-count divider
// 16-count divider
always @(posedge clk or reset_n) begin
always @(posedge clk or negedge reset_n) begin
  if( !reset_n)
  if( !reset_n)
    clkdiv16=0;
    clkdiv16<=0;
  else
  else
    clkdiv16<=clkdiv16+1;
    clkdiv16<=clkdiv16+1;
end
end
 
 
always @(posedge clk or reset_n) begin
integer aux;
 
always @(posedge clk or negedge reset_n) begin
  if( !reset_n ) begin
  if( !reset_n ) begin
    data_out=0;
    data_out=0;
    for(aux=0;aux<=15;aux=aux+1) regarray[aux]=0;
    for(aux=0;aux<=15;aux=aux+1) regarray[aux]=0;
  end
  end
  else begin
  else begin
    if( rd )
    if( rd )
      data_out=regarray[ adr ];
      data_out=regarray[ adr ];
    else if( wr ) begin
    else if( wr ) begin
      regarray[adr]=data_in;
      regarray[adr]=data_in;
      if( dump_writes ) begin
      if( dump_writes ) begin
        $display("#%d, %t, %d, %d", id, $realtime, adr, data_in );
        $display("#%d, %t, %d, %d", id, $realtime, adr, data_in );
      end
      end
    end
    end
  end
  end
end
end
 
 
endmodule
endmodule
 
 
module SQM_CLK_DIVIDER(
module SQM_CLK_DIVIDER(
  clk, // this is the divided down clock from the core
  clk, // this is the divided down clock from the core
  reset_n,
  reset_n,
  period,
  period,
        div
        div
);
);
 
 
parameter bw=12;
parameter bw=12;
input clk; // this is the divided down clock from the core
input clk; // this is the divided down clock from the core
input reset_n;
input reset_n;
input [bw-1:0]period;
input [bw-1:0]period;
output div;
output div;
 
 
reg [bw-1:0]count;
reg [bw-1:0]count;
reg clkdiv;
reg clkdiv;
 
 
initial clkdiv=0;
initial clkdiv=0;
 
 
assign div = period==1 ? clk : clkdiv;
assign div = period==1 ? clk : clkdiv;
 
 
always @(posedge clk or reset_n) begin
always @(posedge clk or negedge reset_n) begin
  if( !reset_n) begin
  if( !reset_n) begin
    count=0;
    count<=0;
    clkdiv=0;
    clkdiv<=0;
  end
  end
  else begin
  else begin
    if( period==0 ) begin
    if( period==0 ) begin
      clkdiv<=0;
      clkdiv<=0;
      count<=0;
      count<=0;
    end
    end
    else if( count >= period ) begin
    else if( count >= period ) begin
        count <= 0;
        count <= 0;
        clkdiv = ~clkdiv;
        clkdiv <= ~clkdiv;
      end
      end
      else count <= count+1;
      else count <= count+1;
  end
  end
end
end
endmodule
endmodule
 
 
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
module SQM_NOISE(
module SQM_NOISE(
  input clk, // this is the divided down clock from the core
  input clk, // this is the divided down clock from the core
  input reset_n,
  input reset_n,
  input [4:0]period,
  input [4:0]period,
  output noise
  output noise
);
);
 
 
reg [5:0]count;
reg [5:0]count;
reg [16:0]poly17;
reg [16:0]poly17;
wire poly17_zero = poly17==0;
wire poly17_zero = poly17==0;
assign noise=poly17[16];
assign noise=poly17[16];
wire noise_clk;
wire noise_clk;
 
 
always @(posedge noise_clk or reset_n) begin
always @(posedge noise_clk or negedge reset_n) begin
  if( !reset_n) begin
  if( !reset_n) begin
    poly17=0;
    poly17<=0;
  end
  end
  else begin
  else begin
     poly17={ poly17[0] ^ poly17[2] ^ poly17_zero, poly17[16:1] };
     poly17<={ poly17[0] ^ poly17[2] ^ poly17_zero, poly17[16:1] };
  end
  end
end
end
 
 
SQM_CLK_DIVIDER #(5) ndiv( .clk(clk), .reset_n(reset_n),
SQM_CLK_DIVIDER #(5) ndiv( .clk(clk), .reset_n(reset_n),
  .period(period), .div(noise_clk) );
  .period(period), .div(noise_clk) );
endmodule
endmodule
 
 
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
module SQM_ENVELOPE(
module SQM_ENVELOPE(
  input clk, // this is the divided down clock from the core
  input clk, // this is the divided down clock from the core
  input reset_n,
  input reset_n,
  input [3:0]ctrl,
  input [3:0]ctrl,
  output reg [3:0]gain
  output reg [3:0]gain
);
);
 
 
reg dir; // direction
reg dir; // direction
reg stop;
reg stop;
reg [3:0]prev_ctrl; // last control orders
reg [3:0]prev_ctrl; // last control orders
 
 
always @(posedge clk or reset_n) begin
always @(posedge clk or negedge reset_n) begin
  if( !reset_n) begin
  if( !reset_n) begin
    gain=4'hF;
    gain<=4'hF;
    dir=0;
    dir<=0;
    prev_ctrl=0;
    prev_ctrl<=0;
    stop=1;
    stop<=1;
  end
  end
  else begin
  else begin
    if (ctrl!=prev_ctrl) begin
    if (ctrl!=prev_ctrl) begin
      prev_ctrl<=ctrl;
      prev_ctrl<=ctrl;
      if( ctrl[2] ) begin
      if( ctrl[2] ) begin
        gain<=0;
        gain<=0;
        dir<=1;
        dir<=1;
        stop<=0;
        stop<=0;
      end
      end
      else begin
      else begin
        gain<=4'hF;
        gain<=4'hF;
        dir<=0;
        dir<=0;
        stop<=0;
        stop<=0;
      end
      end
    end
    end
    else begin
    else begin
      if (!stop) begin
      if (!stop) begin
        if( !prev_ctrl[3] && ((gain==0&&!dir) || (gain==4'hF&&dir))) begin
        if( !prev_ctrl[3] && ((gain==0&&!dir) || (gain==4'hF&&dir))) begin
          stop<=1;
          stop<=1;
          gain<=0;
          gain<=0;
        end
        end
        else begin
        else begin
          if( prev_ctrl[0] && ( (gain==0&&!dir) || (gain==4'hF&&dir))) begin // HOLD
          if( prev_ctrl[0] && ( (gain==0&&!dir) || (gain==4'hF&&dir))) begin // HOLD
            stop<=1;
            stop<=1;
            gain <= prev_ctrl[1]? ~gain : gain;
            gain <= prev_ctrl[1]? ~gain : gain;
          end
          end
          else begin
          else begin
            gain <= dir ? gain+1 : gain-1;
            gain <= dir ? gain+1 : gain-1;
            if( prev_ctrl[1:0]==2'b10 && ( (gain==1&&!dir) || (gain==4'hE&&dir))) begin // ALTERNATE
            if( prev_ctrl[1:0]==2'b10 && ( (gain==1&&!dir) || (gain==4'hE&&dir))) begin // ALTERNATE
              dir <= ~dir;
              dir <= ~dir;
            end
            end
          end
          end
        end
        end
      end
      end
    end
    end
  end
  end
end
end
endmodule
endmodule
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.