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

Subversion Repositories sqmusic

[/] [sqmusic/] [trunk/] [sqm/] [sqmusic.v] - Blame information for rev 3

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 gryzor
/*
2
        SQmusic
3
  Music synthetiser compatible with AY-3-8910 software compatible
4
  Version 0.1, tested on simulation only with Capcom's 1942
5
 
6
  (c) Jose Tejada Gomez, 9th May 2013
7
  You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
8
  Read the details of the license in:
9
  http://www.gnu.org/licenses/gpl.txt
10
 
11
  Send comments to: jose.tejada@ieee.org
12
 
13
*/
14
 
15
/* Capcom arcade boards like 1942 use two memory locations to
16
communicate with the AY-3-8910 (or compatible) chip.  This small code
17
provides a 2-byte memory map as expected by Capcom games
18
*/
19
`timescale 1ns / 1ps
20
module AY_3_8910_capcom(
21
        input reset_n,
22
  input clk, // CPU clock
23
        input sound_clk, // normally slower than the CPU clock
24
  input  [7:0] din,
25
  input  adr,
26
  input wr_n,  // write
27
        input cs_n, // chip select
28
  output [3:0]A,B,C // channel outputs
29
);
30
 
31
reg [7:0] latches[1:0];
32
reg core_wr;
33
wire sample = clk & ~cs_n & ~wr_n;
34
reg count;
35
 
36
always @(posedge sound_clk or negedge reset_n) begin
37
        if(!reset_n) begin
38
                count=0;
39
        end
40
        else begin
41
                if( !count && core_wr) count=1;
42
                else if( core_wr ) begin
43
                        count=0;
44
                        core_wr=0;
45
                end
46
        end
47
end
48
 
49
always @(posedge sample or negedge reset_n) begin
50
        if(!reset_n) begin
51
                latches[0]=0;
52
                latches[1]=0;
53
        end
54
        else begin
55
                latches[adr] = din;
56
                if(adr) core_wr=1;
57
        end
58
end
59
 
60
SQMUSIC core( .reset_n(reset_n), .clk(sound_clk), .data_in(latches[1]),
61
        .adr( latches[0][3:0] ), .rd(1'b0), .wr(core_wr), .A(A), .B(B), .C(C) );
62
endmodule
63
 
64
/*  The AY core does
65
*/
66
module SQMUSIC( // pins are not multiplexed
67
  input reset_n,
68
  input clk,
69
  input  [7:0] data_in,
70
  output reg [7:0] data_out, // read functionality not implemented yet
71
  input  [3:0] adr,
72
  input rd, // read
73
  input wr,  // write
74
  output [3:0]A,B,C // channel outputs
75
);
76
 
77
reg [7:0] regarray[15:0];
78
reg [3:0] clkdiv16;
79
 
80
wire [3:0] envelope;
81
wire [2:0] sqwave;
82
wire noise, envclk;
83
wire Amix = (noise|regarray[7][3]) ^ (sqwave[0]|regarray[7][0]);
84
wire Bmix = (noise|regarray[7][4]) ^ (sqwave[1]|regarray[7][1]);
85
wire Cmix = (noise|regarray[7][5]) ^ (sqwave[2]|regarray[7][2]);
86
 
87
// internal modules operate at clk/16
88
SQM_CLK_DIVIDER #(12) chA( .clk(clkdiv16[3]), .reset_n(reset_n),
89
  .period({regarray[1][3:0], regarray[0][7:0] }), .div(sqwave[0]) );
90
SQM_CLK_DIVIDER #(12) chB( .clk(clkdiv16[3]), .reset_n(reset_n),
91
  .period({regarray[3][3:0], regarray[2][7:0] }), .div(sqwave[1]) );
92
SQM_CLK_DIVIDER #(12) chC( .clk(clkdiv16[3]), .reset_n(reset_n),
93
  .period({regarray[5][3:0], regarray[4][7:0] }), .div(sqwave[2]) );
94
 
95
// the noise uses a x2 faster clock in order to produce a frequency
96
// of Fclk/16 when period is 1
97
SQM_NOISE    ng( .clk(clkdiv16[3]), .reset_n(reset_n),
98
  .period(regarray[6][4:0]), .noise(noise) );
99
// envelope generator
100
SQM_CLK_DIVIDER #(16) envclkdiv( .clk(clkdiv16[2]), .reset_n(reset_n),
101
  .period({regarray[14],regarray[13]}), .div(envclk) );
102
SQM_ENVELOPE env( .clk(envclk),.ctrl(regarray[15][3:0]),
103
  .gain(envelope), .reset_n(reset_n) );
104
 
105
assign A=regarray[10][4]? envelope&{4{Amix}} : regarray[10][3:0]&{4{Amix}};
106
assign B=regarray[11][4]? envelope&{4{Bmix}} : regarray[10][3:0]&{4{Bmix}};
107
assign C=regarray[12][4]? envelope&{4{Cmix}} : regarray[10][3:0]&{4{Cmix}};
108
 
109
integer aux;
110
 
111
// 16-count divider
112
always @(posedge clk or reset_n) begin
113
  if( !reset_n)
114
    clkdiv16=0;
115
  else
116
    clkdiv16<=clkdiv16+1;
117
end
118
 
119
always @(posedge clk or reset_n) begin
120
  if( !reset_n ) begin
121
    data_out=0;
122
    for(aux=0;aux<=15;aux=aux+1) regarray[aux]=0;
123
  end
124
  else begin
125
    if( rd )
126
      data_out=regarray[ adr ];
127
    else if( wr ) regarray[adr]=data_in;
128
  end
129
end
130
 
131
endmodule
132
 
133
module SQM_CLK_DIVIDER(
134
  clk, // this is the divided down clock from the core
135
  reset_n,
136
  period,
137
        div
138
);
139
 
140
parameter bw=12;
141
input clk; // this is the divided down clock from the core
142
input reset_n;
143
input [bw-1:0]period;
144
output div;
145
 
146
reg [bw-1:0]count;
147
reg clkdiv;
148
 
149
initial clkdiv=0;
150
 
151
assign div = period==1 ? clk : clkdiv;
152
 
153
always @(posedge clk or reset_n) begin
154
  if( !reset_n) begin
155
    count=0;
156
    clkdiv=0;
157
  end
158
  else begin
159
    if( period==0 ) begin
160
      clkdiv<=0;
161
      count<=0;
162
    end
163
    else if( count >= period ) begin
164
        count <= 0;
165
        clkdiv = ~clkdiv;
166
      end
167
      else count <= count+1;
168
  end
169
end
170
endmodule
171
 
172
////////////////////////////////////////////////////////////////
173
module SQM_NOISE(
174
  input clk, // this is the divided down clock from the core
175
  input reset_n,
176
  input [4:0]period,
177
  output noise
178
);
179
 
180
reg [5:0]count;
181
reg [16:0]poly17;
182
wire poly17_zero = poly17==0;
183
assign noise=poly17[16];
184
wire noise_clk;
185
 
186
always @(posedge noise_clk or reset_n) begin
187
  if( !reset_n) begin
188
    poly17=0;
189
  end
190
  else begin
191
     poly17={ poly17[0] ^ poly17[2] ^ poly17_zero, poly17[16:1] };
192
  end
193
end
194
 
195
SQM_CLK_DIVIDER #(5) ndiv( .clk(clk), .reset_n(reset_n),
196
  .period(period), .div(noise_clk) );
197
endmodule
198
 
199
////////////////////////////////////////////////////////////////
200
module SQM_ENVELOPE(
201
  input clk, // this is the divided down clock from the core
202
  input reset_n,
203
  input [3:0]ctrl,
204
  output reg [3:0]gain
205
);
206
 
207
reg dir; // direction
208
reg stop;
209
reg [3:0]prev_ctrl; // last control orders
210
 
211
always @(posedge clk or reset_n) begin
212
  if( !reset_n) begin
213
    gain=4'hF;
214
    dir=0;
215
    prev_ctrl=0;
216
    stop=1;
217
  end
218
  else begin
219
    if (ctrl!=prev_ctrl) begin
220
      prev_ctrl<=ctrl;
221
      if( ctrl[2] ) begin
222
        gain<=0;
223
        dir<=1;
224
        stop<=0;
225
      end
226
      else begin
227
        gain<=4'hF;
228
        dir<=0;
229
        stop<=0;
230
      end
231
    end
232
    else begin
233
      if (!stop) begin
234
        if( !prev_ctrl[3] && ((gain==0&&!dir) || (gain==4'hF&&dir))) begin
235
          stop<=1;
236
          gain<=0;
237
        end
238
        else begin
239
          if( prev_ctrl[0] && ( (gain==0&&!dir) || (gain==4'hF&&dir))) begin // HOLD
240
            stop<=1;
241
            gain <= prev_ctrl[1]? ~gain : gain;
242
          end
243
          else begin
244
            gain <= dir ? gain+1 : gain-1;
245
            if( prev_ctrl[1:0]==2'b10 && ( (gain==1&&!dir) || (gain==4'hE&&dir))) begin // ALTERNATE
246
              dir <= ~dir;
247
            end
248
          end
249
        end
250
      end
251
    end
252
  end
253
end
254
endmodule

powered by: WebSVN 2.1.0

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