/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