8bitworkshop/presets/verilog/sound_generator.v

113 lines
2.9 KiB
Verilog

`include "hvsync_generator.v"
`include "lfsr.v"
/*
Sound generator module.
This module has a square-wave oscillator (VCO) which can
be modulated by a low-frequency oscillator (LFO) and also
mixed with a LFSR noise source.
*/
module sound_generator(clk, reset, spkr,
lfo_freq,noise_freq, vco_freq,
vco_select, noise_select, lfo_shift, mixer);
input clk, reset;
output reg spkr = 0; // module output
input [9:0] lfo_freq; // LFO frequency (10 bits)
input [11:0] noise_freq; // noise frequency (12 bits)
input [11:0] vco_freq; // VCO frequency (12 bits)
input vco_select; // 1 = LFO modulates VCO
input noise_select; // 1 = LFO modulates Noise
input [2:0] lfo_shift; // LFO modulation depth
input [2:0] mixer; // mix enable {LFO, Noise, VCO}
reg [3:0] div16; // divide-by-16 counter
reg [17:0] lfo_count; // LFO counter (18 bits)
reg lfo_state; // LFO output
reg [12:0] noise_count; // Noise counter (13 bits)
reg noise_state; // Noise output
reg [12:0] vco_count; // VCO counter (12 bits)
reg vco_state; // VCO output
reg [15:0] lfsr; // LFSR output
LFSR #(16'b1000000001011,0) lfsr_gen(
.clk(clk),
.reset(reset),
.enable(div16 == 0 && noise_count == 0),
.lfsr(lfsr)
);
// create triangle waveform from LFO
wire [11:0] lfo_triangle = lfo_count[17] ? ~lfo_count[17:6] : lfo_count[17:6];
wire [11:0] vco_delta = lfo_triangle >> lfo_shift;
always @(posedge clk) begin
// divide clock by 64
div16 <= div16 + 1;
if (div16 == 0) begin
// VCO oscillator
if (reset || vco_count == 0) begin
vco_state <= ~vco_state;
if (vco_select)
vco_count <= vco_freq + vco_delta;
else
vco_count <= vco_freq + 0;
end else
vco_count <= vco_count - 1;
// LFO oscillator
if (reset || lfo_count == 0) begin
lfo_state <= ~lfo_state;
lfo_count <= {lfo_freq, 8'b0};
end else
lfo_count <= lfo_count - 1;
// Noise oscillator
if (reset || noise_count == 0) begin
if (lfsr[0])
noise_state <= ~noise_state;
if (noise_select)
noise_count <= noise_freq + vco_delta;
else
noise_count <= noise_freq + 0;
end else
noise_count <= noise_count - 1;
// Mixer
spkr <= (lfo_state | ~mixer[2])
& (noise_state | ~mixer[1])
& (vco_state | ~mixer[0]);
end
end
endmodule
module test_snchip_top(clk, reset, hsync, vsync, rgb, spkr);
input clk, reset;
output hsync;
output vsync;
output spkr;
output [2:0] rgb;
// don't output a valid sync signal
assign hsync = 0;
assign vsync = 0;
assign rgb = {spkr,1'b0,1'b0};
sound_generator sndgen(
.clk(clk),
.reset(reset),
.spkr(spkr),
.lfo_freq(1000),
.noise_freq(90),
.vco_freq(250),
.vco_select(1),
.noise_select(1),
.lfo_shift(1),
.mixer(3)
);
endmodule