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

Subversion Repositories sqmusic

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

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

powered by: WebSVN 2.1.0

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