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

Subversion Repositories sqmusic

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

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 4 gryzor
module AY_3_8910_capcom
21
#( parameter dump_writes=0, parameter id=0 )
22
(
23 3 gryzor
        input reset_n,
24
  input clk, // CPU clock
25
        input sound_clk, // normally slower than the CPU clock
26
  input  [7:0] din,
27
  input  adr,
28
  input wr_n,  // write
29
        input cs_n, // chip select
30
  output [3:0]A,B,C // channel outputs
31
);
32
 
33
reg [7:0] latches[1:0];
34
reg core_wr;
35
wire sample = clk & ~cs_n & ~wr_n;
36
reg count;
37
 
38
always @(posedge sound_clk or negedge reset_n) begin
39
        if(!reset_n) begin
40
                count=0;
41
        end
42
        else begin
43
                if( !count && core_wr) count=1;
44
                else if( core_wr ) begin
45
                        count=0;
46
                        core_wr=0;
47
                end
48
        end
49
end
50
 
51
always @(posedge sample or negedge reset_n) begin
52
        if(!reset_n) begin
53
                latches[0]=0;
54
                latches[1]=0;
55
        end
56
        else begin
57
                latches[adr] = din;
58
                if(adr) core_wr=1;
59
        end
60
end
61
 
62 4 gryzor
SQMUSIC #(dump_writes, id) core( .reset_n(reset_n), .clk(sound_clk), .data_in(latches[1]),
63 3 gryzor
        .adr( latches[0][3:0] ), .rd(1'b0), .wr(core_wr), .A(A), .B(B), .C(C) );
64
endmodule
65
 
66
/*  The AY core does
67
*/
68 4 gryzor
module SQMUSIC
69
#( parameter dump_writes=0, parameter id=0 ) // set to 1 to dump register writes
70
( // note that input ports are not multiplexed
71 3 gryzor
  input reset_n,
72
  input clk,
73
  input  [7:0] data_in,
74 4 gryzor
  output reg [7:0] data_out,
75 3 gryzor
  input  [3:0] adr,
76
  input rd, // read
77
  input wr,  // write
78
  output [3:0]A,B,C // channel outputs
79
);
80
 
81
reg [7:0] regarray[15:0];
82
reg [3:0] clkdiv16;
83
 
84
wire [3:0] envelope;
85
wire [2:0] sqwave;
86
wire noise, envclk;
87
wire Amix = (noise|regarray[7][3]) ^ (sqwave[0]|regarray[7][0]);
88
wire Bmix = (noise|regarray[7][4]) ^ (sqwave[1]|regarray[7][1]);
89
wire Cmix = (noise|regarray[7][5]) ^ (sqwave[2]|regarray[7][2]);
90
 
91
// internal modules operate at clk/16
92
SQM_CLK_DIVIDER #(12) chA( .clk(clkdiv16[3]), .reset_n(reset_n),
93
  .period({regarray[1][3:0], regarray[0][7:0] }), .div(sqwave[0]) );
94
SQM_CLK_DIVIDER #(12) chB( .clk(clkdiv16[3]), .reset_n(reset_n),
95
  .period({regarray[3][3:0], regarray[2][7:0] }), .div(sqwave[1]) );
96
SQM_CLK_DIVIDER #(12) chC( .clk(clkdiv16[3]), .reset_n(reset_n),
97
  .period({regarray[5][3:0], regarray[4][7:0] }), .div(sqwave[2]) );
98
 
99
// the noise uses a x2 faster clock in order to produce a frequency
100
// of Fclk/16 when period is 1
101
SQM_NOISE    ng( .clk(clkdiv16[3]), .reset_n(reset_n),
102
  .period(regarray[6][4:0]), .noise(noise) );
103
// envelope generator
104
SQM_CLK_DIVIDER #(16) envclkdiv( .clk(clkdiv16[2]), .reset_n(reset_n),
105
  .period({regarray[14],regarray[13]}), .div(envclk) );
106
SQM_ENVELOPE env( .clk(envclk),.ctrl(regarray[15][3:0]),
107
  .gain(envelope), .reset_n(reset_n) );
108
 
109
assign A=regarray[10][4]? envelope&{4{Amix}} : regarray[10][3:0]&{4{Amix}};
110
assign B=regarray[11][4]? envelope&{4{Bmix}} : regarray[10][3:0]&{4{Bmix}};
111
assign C=regarray[12][4]? envelope&{4{Cmix}} : regarray[10][3:0]&{4{Cmix}};
112
 
113
integer aux;
114
 
115
// 16-count divider
116
always @(posedge clk or reset_n) begin
117
  if( !reset_n)
118
    clkdiv16=0;
119
  else
120
    clkdiv16<=clkdiv16+1;
121
end
122
 
123
always @(posedge clk or reset_n) begin
124
  if( !reset_n ) begin
125
    data_out=0;
126
    for(aux=0;aux<=15;aux=aux+1) regarray[aux]=0;
127
  end
128
  else begin
129
    if( rd )
130
      data_out=regarray[ adr ];
131 4 gryzor
    else if( wr ) begin
132
      regarray[adr]=data_in;
133
      if( dump_writes ) begin
134
        $display("#%d, %t, %d, %d", id, $realtime, adr, data_in );
135
      end
136
    end
137 3 gryzor
  end
138
end
139
 
140
endmodule
141
 
142
module SQM_CLK_DIVIDER(
143
  clk, // this is the divided down clock from the core
144
  reset_n,
145
  period,
146
        div
147
);
148
 
149
parameter bw=12;
150
input clk; // this is the divided down clock from the core
151
input reset_n;
152
input [bw-1:0]period;
153
output div;
154
 
155
reg [bw-1:0]count;
156
reg clkdiv;
157
 
158
initial clkdiv=0;
159
 
160
assign div = period==1 ? clk : clkdiv;
161
 
162
always @(posedge clk or reset_n) begin
163
  if( !reset_n) begin
164
    count=0;
165
    clkdiv=0;
166
  end
167
  else begin
168
    if( period==0 ) begin
169
      clkdiv<=0;
170
      count<=0;
171
    end
172
    else if( count >= period ) begin
173
        count <= 0;
174
        clkdiv = ~clkdiv;
175
      end
176
      else count <= count+1;
177
  end
178
end
179
endmodule
180
 
181
////////////////////////////////////////////////////////////////
182
module SQM_NOISE(
183
  input clk, // this is the divided down clock from the core
184
  input reset_n,
185
  input [4:0]period,
186
  output noise
187
);
188
 
189
reg [5:0]count;
190
reg [16:0]poly17;
191
wire poly17_zero = poly17==0;
192
assign noise=poly17[16];
193
wire noise_clk;
194
 
195
always @(posedge noise_clk or reset_n) begin
196
  if( !reset_n) begin
197
    poly17=0;
198
  end
199
  else begin
200
     poly17={ poly17[0] ^ poly17[2] ^ poly17_zero, poly17[16:1] };
201
  end
202
end
203
 
204
SQM_CLK_DIVIDER #(5) ndiv( .clk(clk), .reset_n(reset_n),
205
  .period(period), .div(noise_clk) );
206
endmodule
207
 
208
////////////////////////////////////////////////////////////////
209
module SQM_ENVELOPE(
210
  input clk, // this is the divided down clock from the core
211
  input reset_n,
212
  input [3:0]ctrl,
213
  output reg [3:0]gain
214
);
215
 
216
reg dir; // direction
217
reg stop;
218
reg [3:0]prev_ctrl; // last control orders
219
 
220
always @(posedge clk or reset_n) begin
221
  if( !reset_n) begin
222
    gain=4'hF;
223
    dir=0;
224
    prev_ctrl=0;
225
    stop=1;
226
  end
227
  else begin
228
    if (ctrl!=prev_ctrl) begin
229
      prev_ctrl<=ctrl;
230
      if( ctrl[2] ) begin
231
        gain<=0;
232
        dir<=1;
233
        stop<=0;
234
      end
235
      else begin
236
        gain<=4'hF;
237
        dir<=0;
238
        stop<=0;
239
      end
240
    end
241
    else begin
242
      if (!stop) begin
243
        if( !prev_ctrl[3] && ((gain==0&&!dir) || (gain==4'hF&&dir))) begin
244
          stop<=1;
245
          gain<=0;
246
        end
247
        else begin
248
          if( prev_ctrl[0] && ( (gain==0&&!dir) || (gain==4'hF&&dir))) begin // HOLD
249
            stop<=1;
250
            gain <= prev_ctrl[1]? ~gain : gain;
251
          end
252
          else begin
253
            gain <= dir ? gain+1 : gain-1;
254
            if( prev_ctrl[1:0]==2'b10 && ( (gain==1&&!dir) || (gain==4'hE&&dir))) begin // ALTERNATE
255
              dir <= ~dir;
256
            end
257
          end
258
        end
259
      end
260
    end
261
  end
262
end
263
endmodule

powered by: WebSVN 2.1.0

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