/src/audio.v
module audio(
input wire [5:0] pwm_clock,
input wire [1:0] atick_clock,
input wire [3:0] pattern_clock,
input wire rst_n,
input wire rng,
output wire audio
);
wire [11:0] audio_time0; // per-channel oscillator timer values
wire [11:0] audio_time1;
wire [11:0] audio_time2;
wire [11:0] audio_time3;
wire [1:0] audio_vol0; // per-channel volume values
wire [1:0] audio_vol1;
wire [1:0] audio_vol2;
wire [1:0] audio_vol3;
sequencer seq(
.tick_clock(atick_clock[1:0]),
.pattern_clock(pattern_clock),
.rst_n(rst_n),
.freq0(audio_time0),
.freq1(audio_time1),
.freq2(audio_time2),
.freq3(audio_time3),
.vol0(audio_vol0),
.vol1(audio_vol1),
.vol2(audio_vol2),
.vol3(audio_vol3)
);
audio_psg audio_gen(
.pwm_clock(pwm_clock),
.rst_n(rst_n),
.timer0(audio_time0),
.timer1(audio_time1),
.timer2(audio_time2),
.timer3(audio_time3),
.vol0(audio_vol0),
.vol1(audio_vol1),
.vol2(audio_vol2),
.vol3(audio_vol3),
.rng(rng),
.audio(audio)
);
endmodule
/* PSG with three square wave channels and one noise channel
* 2-bit volume per channel
*/
module audio_psg(
input wire [5:0] pwm_clock,
input wire rst_n,
input wire [11:0] timer0,
input wire [11:0] timer1,
input wire [11:0] timer2,
input wire [11:0] timer3,
input wire [1:0] vol0,
input wire [1:0] vol1,
input wire [1:0] vol2,
input wire [1:0] vol3,
input wire rng,
output wire audio
);
wire [5:0] level;
wire f_clock;
wire ch0_state, ch1_state, ch2_state, ch3_state;
assign f_clock = (pwm_clock == 0);
audio_psg_square_gen chan0(
.clk(f_clock),
.rst_n(rst_n),
.timer(timer0),
.out(ch0_state)
);
audio_psg_square_gen chan1(
.clk(f_clock),
.rst_n(rst_n),
.timer(timer1),
.out(ch1_state)
);
audio_psg_square_gen chan2(
.clk(f_clock),
.rst_n(rst_n),
.timer(timer2),
.out(ch2_state)
);
audio_psg_noise_gen chan3(
.clk(f_clock),
.rst_n(rst_n),
.timer(timer3),
.rng(rng),
.out(ch3_state)
);
// There's probably a better way to do this.
assign level = 31 + {(ch0_state ? {3'b0, vol0} : -{3'b0, vol0}), rng}
+ {(ch1_state ? {3'b0, vol1} : -{3'b0, vol1}), rng}
+ {(ch2_state ? {3'b0, vol2} : -{3'b0, vol2}), rng}
+ {(ch3_state ? {3'b0, vol3} : -{3'b0, vol3}), rng};
assign audio = pwm_clock <= level;
endmodule
/* Signal generator for noise channel */
module audio_psg_noise_gen(
input wire clk, // the audio clock, which is the main clock
// divided by 64.
input wire rst_n,
input wire [11:0] timer, // the timer value
input wire rng, // random bit from lfsr
output wire out // the square wave output
);
reg [11:0] ch_counter;
reg ch_state;
always @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
ch_counter <= 0;
ch_state <= 0;
end
else begin
if (ch_counter == timer) begin
ch_state <= rng;
ch_counter <= 0;
end
else
ch_counter <= ch_counter + 1;
end
end
assign out = ch_state;
endmodule
/* Signal generator for square wave channel */
module audio_psg_square_gen(
input wire clk, // the audio clock, which is the main clock
// divided by 64.
input wire rst_n,
input wire [11:0] timer, // the timer value
output wire out // the square wave output
);
reg [11:0] ch_counter;
reg ch_state;
always @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
ch_counter <= 0;
ch_state <= 0;
end
else begin
if (ch_counter == timer) begin
ch_state <= !ch_state;
ch_counter <= 0;
end
else
ch_counter <= ch_counter + 1;
end
end
assign out = ch_state;
endmodule
parameter T_Fs1 = 12'd2126; // 185 Hz
parameter T_Gs1 = 12'd1894; // 207.65 Hz
parameter T_A1 = 12'd1788; // 220 Hz
parameter T_As1 = 12'd1688; // 233.08 Hz
parameter T_B1 = 12'd1593; // 246.94 Hz
parameter T_C2 = 12'd1503; // 261.63 Hz
parameter T_Fs2 = 12'd1063; // 370 Hz
parameter T_Gs2 = 12'd947; // 415.3 Hz
parameter T_As2 = 12'd844; // 466.16 Hz
parameter T_B2 = 12'd796; // 493.88 Hz
parameter T_C3 = 12'd752; // 523.25 Hz
parameter T_C4 = 12'd376; // 1046.5 Hz
parameter T_B7 = 12'd100; // 3951 Hz
parameter N_Fs1 = 1;
parameter N_Gs1 = 2;
parameter N_A1 = 3;
parameter N_As1 = 4;
parameter N_B1 = 5;
parameter N_C2 = 6;
parameter N_Fs2 = 7;
parameter N_Gs2 = 8;
parameter N_As2 = 9;
parameter N_B2 = 10;
parameter N_C3 = 11;
parameter N_C4 = 12;
parameter N_B7 = 13;
module note_map(
input wire [3:0] select,
output wire [11:0] freq
);
wire [11:0] notes [13:0];
assign notes[0] = 0;
assign notes[N_Fs1] = T_Fs1;
assign notes[N_Gs1] = T_Gs1;
assign notes[N_A1] = T_A1;
assign notes[N_As1] = T_As1;
assign notes[N_B1] = T_B1;
assign notes[N_C2] = T_C2;
assign notes[N_Fs2] = T_Fs2;
assign notes[N_Gs2] = T_Gs2;
assign notes[N_As2] = T_As2;
assign notes[N_B2] = T_B2;
assign notes[N_C3] = T_C3;
assign notes[N_C4] = T_C4;
assign notes[N_B7] = T_B7;
assign freq = notes[select];
endmodule
// Turn this off for the pattern section, since they all have the same
// interface but they're not all using the select lines.
// verilator lint_off UNUSEDSIGNAL
module pattern1_1(
input wire [3:0] select,
output wire [3:0] note
);
wire [3:0] note_sequence [15:0];
assign note_sequence[0] = N_C2;
assign note_sequence[1] = 0;
assign note_sequence[2] = 0;
assign note_sequence[3] = N_C2;
assign note_sequence[4] = 0;
assign note_sequence[5] = 0;
assign note_sequence[6] = N_C2;
assign note_sequence[7] = 0;
assign note_sequence[8] = 0;
assign note_sequence[9] = 0;
assign note_sequence[10] = N_As1;
assign note_sequence[11] = 0;
assign note_sequence[12] = N_As1;
assign note_sequence[13] = 0;
assign note_sequence[14] = N_As1;
assign note_sequence[15] = N_C2;
assign note = note_sequence[select];
endmodule
module pattern1_2(
input wire [3:0] select,
output wire [3:0] note
);
wire [3:0] note_sequence [15:0];
assign note_sequence[0] = N_Gs1;
assign note_sequence[1] = 0;
assign note_sequence[2] = 0;
assign note_sequence[3] = N_Gs1;
assign note_sequence[4] = 0;
assign note_sequence[5] = 0;
assign note_sequence[6] = N_Gs1;
assign note_sequence[7] = 0;
assign note_sequence[8] = 0;
assign note_sequence[9] = 0;
assign note_sequence[10] = N_Fs1;
assign note_sequence[11] = 0;
assign note_sequence[12] = N_Fs1;
assign note_sequence[13] = 0;
assign note_sequence[14] = N_Fs1;
assign note_sequence[15] = N_Gs1;
assign note = note_sequence[select];
endmodule
module pattern1_3(
input wire [3:0] select,
output wire [3:0] note
);
wire [3:0] note_sequence [15:0];
assign note_sequence[0] = N_Gs1;
assign note_sequence[1] = 0;
assign note_sequence[2] = 0;
assign note_sequence[3] = N_Gs1;
assign note_sequence[4] = 0;
assign note_sequence[5] = 0;
assign note_sequence[6] = N_Gs1;
assign note_sequence[7] = 0;
assign note_sequence[8] = N_As1;
assign note_sequence[9] = 0;
assign note_sequence[10] = 0;
assign note_sequence[11] = N_As1;
assign note_sequence[12] = 0;
assign note_sequence[13] = 0;
assign note_sequence[14] = N_B1;
assign note_sequence[15] = 0;
assign note = note_sequence[select];
endmodule
// Where is pattern2? It used to be a lower octave version of pattern1 but that
// is now handled by bit shifting.
module pattern3_1(
input wire [3:0] select,
output wire [3:0] note
);
assign note = N_C2;
endmodule
module pattern3_2(
input wire [3:0] select,
output wire [3:0] note
);
wire [3:0] note_sequence [15:0];
assign note_sequence[0] = N_C2;
assign note_sequence[1] = N_C2;
assign note_sequence[2] = N_C2;
assign note_sequence[3] = N_C2;
assign note_sequence[4] = N_C2;
assign note_sequence[5] = N_C2;
assign note_sequence[6] = N_C2;
assign note_sequence[7] = N_C2;
assign note_sequence[8] = N_C2;
assign note_sequence[9] = N_C2;
assign note_sequence[10] = N_C2;
assign note_sequence[11] = N_As1;
assign note_sequence[12] = N_As1;
assign note_sequence[13] = N_As1;
assign note_sequence[14] = N_A1;
assign note_sequence[15] = N_Gs1;
assign note = note_sequence[select];
endmodule
module pattern3_3(
input wire [3:0] select,
output wire [3:0] note
);
assign note = select <= 10 ? N_Gs1 : N_Fs1;
endmodule
module pattern3_4(
input wire [3:0] select,
output wire [3:0] note
);
wire [3:0] note_sequence [15:0];
assign note_sequence[0] = N_Gs1;
assign note_sequence[1] = N_Gs1;
assign note_sequence[2] = N_Gs1;
assign note_sequence[3] = N_Gs1;
assign note_sequence[4] = N_Gs1;
assign note_sequence[5] = N_Gs1;
assign note_sequence[6] = N_Fs1;
assign note_sequence[7] = N_Fs1;
assign note_sequence[8] = N_Gs1;
assign note_sequence[9] = N_Gs1;
assign note_sequence[10] = N_Gs1;
assign note_sequence[11] = N_Fs1;
assign note_sequence[12] = N_Gs1;
assign note_sequence[13] = N_Gs1;
assign note_sequence[14] = N_As1;
assign note_sequence[15] = N_As1;
assign note = note_sequence[select];
endmodule
module pattern4_1(
input wire [3:0] select,
output wire [3:0] note
);
assign note = select[1:0] == 0 ? N_C4 : 0;
endmodule
module pattern4_2(
input wire [3:0] select,
output wire [3:0] note
);
assign note = select[1:0] == 0 ? N_C4 : (select[1:0] == 2 ? N_B7 : 0);
endmodule
// verilator lint_on UNUSEDSIGNAL
module pattern_selector(
input wire [3:0] pattern,
input wire [3:0] row,
output wire [11:0] freq
);
wire [3:0] pnotes [15:0];
// Pattern 0 is empty
assign pnotes[0] = 0;
pattern1_1 p1(
.select(row),
.note(pnotes[1])
);
pattern1_2 p2(
.select(row),
.note(pnotes[2])
);
pattern1_3 p3(
.select(row),
.note(pnotes[3])
);
pattern3_1 p4(
.select(row),
.note(pnotes[4])
);
pattern3_2 p5(
.select(row),
.note(pnotes[5])
);
pattern3_3 p6(
.select(row),
.note(pnotes[6])
);
pattern3_4 p7(
.select(row),
.note(pnotes[7])
);
pattern4_1 p8(
.select(row),
.note(pnotes[8])
);
pattern4_2 p9(
.select(row),
.note(pnotes[9])
);
// All other patterns are unassigned
assign pnotes[10] = 0;
assign pnotes[11] = 0;
assign pnotes[12] = 0;
assign pnotes[13] = 0;
assign pnotes[14] = 0;
assign pnotes[15] = 0;
note_map nm1(
.select(pnotes[pattern]),
.freq(freq)
);
endmodule
module instrument0(
input wire [1:0] select,
output wire [1:0] vol
);
wire [1:0] vol_sequence [3:0];
assign vol_sequence[0] = 2'b11;
assign vol_sequence[1] = 2'b11;
assign vol_sequence[2] = 2'b11;
assign vol_sequence[3] = 2'b00;
assign vol = vol_sequence[select];
endmodule
module instrument1(
input wire [1:0] select,
output wire [1:0] vol
);
wire [1:0] vol_sequence [3:0];
assign vol_sequence[0] = 2'b10;
assign vol_sequence[1] = 2'b10;
assign vol_sequence[2] = 2'b01;
assign vol_sequence[3] = 2'b00;
assign vol = vol_sequence[select];
endmodule
module instrument2(
input wire [1:0] select,
output wire [1:0] vol
);
wire [1:0] vol_sequence [3:0];
assign vol_sequence[0] = 2'b11;
assign vol_sequence[1] = 2'b01;
assign vol_sequence[2] = 2'b00;
assign vol_sequence[3] = 2'b00;
assign vol = vol_sequence[select];
endmodule
module sequencer(
input wire [1:0] tick_clock,
input wire [3:0] pattern_clock,
input wire rst_n,
output wire [11:0] freq0,
output wire [11:0] freq1,
output wire [11:0] freq2,
output wire [11:0] freq3,
output wire [1:0] vol0,
output wire [1:0] vol1,
output wire [1:0] vol2,
output wire [1:0] vol3
);
wire [11:0] patterns [11:0];
wire [11:0] seq_freq [2:0];
wire [1:0] ivol [2:0];
wire seq_tick = !pattern_clock[3]; //(pattern_clock == 15);
reg [3:0] seq_clock;
assign patterns[0] = 12'h001;
assign patterns[1] = 12'h001;
assign patterns[2] = 12'h002;
assign patterns[3] = 12'h003;
assign patterns[4] = 12'h841;
assign patterns[5] = 12'h851;
assign patterns[6] = 12'h862;
assign patterns[7] = 12'h873;
assign patterns[8] = 12'h941;
assign patterns[9] = 12'h951;
assign patterns[10] = 12'h962;
assign patterns[11] = 12'h973;
// pattern selector 0 drives both channels 0 and 1
pattern_selector ps0(
.pattern(patterns[seq_clock][3:0]),
.row(pattern_clock),
.freq(seq_freq[0])
);
pattern_selector ps1(
.pattern(patterns[seq_clock][7:4]),
.row(pattern_clock),
.freq(seq_freq[1])
);
pattern_selector ps2(
.pattern(patterns[seq_clock][11:8]),
.row(pattern_clock),
.freq(seq_freq[2])
);
instrument0 i0(
.select(tick_clock),
.vol(ivol[0])
);
instrument1 i1(
.select(tick_clock),
.vol(ivol[1])
);
instrument2 i2(
.select(tick_clock),
.vol(ivol[2])
);
always @(posedge seq_tick, negedge rst_n) begin
if (!rst_n)
seq_clock <= 0;
else
if (seq_clock == 4'hB)
seq_clock <= 4'h8;
else
seq_clock <= seq_clock + 1;
end
assign freq0 = seq_freq[0];
assign freq1 = (seq_freq[0] >> 1); // channel 1 is just channel 0 shifted up one octave
assign freq2 = seq_freq[1];
assign freq3 = seq_freq[2];
assign vol0 = seq_freq[0] > 0 ? ivol[0] : 0;
assign vol1 = seq_freq[0] > 0 ? ivol[0] : 0;
assign vol2 = seq_freq[1] > 0 ? ivol[1] : 0;
assign vol3 = seq_freq[2] > 0 ? ivol[2] : 0;
endmodule