1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-01 05:41:31 +00:00
8bitworkshop/presets/verilog/music.v
2018-02-14 13:38:50 -06:00

165 lines
5.4 KiB
Verilog

`include "hvsync_generator.v"
module sound_psg(clk, reset, out, reg_sel, reg_data, reg_write);
input clk, reset;
input [3:0] reg_sel;
input [7:0] reg_data;
input reg_write;
output [7:0] out;
parameter NVOICES = 4;
reg outputs[NVOICES];
reg [17:0] count[NVOICES];
reg [7:0] register[16];
integer i;
always @(posedge clk) begin
out = 0;
for (i=0; i<NVOICES; i++) begin
if (count[i][17:6] == {register[i*2+1][3:0], register[i*2]}) begin
outputs[i] <= outputs[i] ^ 1;
count[i] <= 0;
end else begin
count[i] <= count[i] + 1;
end
/* verilator lint_off BLKSEQ */
if (register[15][i] && outputs[i]) begin
out = out + 1;
end
end
if (reg_write) begin
register[reg_sel] <= reg_data;
end
end
endmodule
module music_player(clk, reset, advance,
psg_sel, psg_data, psg_write);
parameter NVOICES = 4;
input clk, reset;
input advance;
output [3:0] psg_sel;
output [7:0] psg_data;
output psg_write;
//./mknotes.py -m 12 -f 75898
// Namespace(bias=0, freq=75898.0, length=64, maxbits=12.0, upper=49)
// 434.7 3.23120101673 49
reg [11:0] note_table[64] = '{
2960, 2794, 2637, 2489, 2349, 2217, 2093, 1975,
1864, 1760, 1661, 1568, 1480, 1397, 1318, 1244,
1175, 1109, 1046, 988, 932, 880, 831, 784,
740, 698, 659, 622, 587, 554, 523, 494,
466, 440, 415, 392, 370, 349, 330, 311,
294, 277, 262, 247, 233, 220, 208, 196,
185, 175, 165, 156, 147, 139, 131, 123,
117, 110, 104, 98, 92, 87, 82, 78
};
reg [7:0] music_table[292] = '{
8'h1e,8'h12,8'h8c,8'h23,8'h17,8'h86,8'h2f,8'h86,8'h36,8'h2a,8'h27,8'h86,8'h2f,8'h86,8'h33,8'h1e,8'h23,8'h86,8'h36,8'h2a,8'h86,8'h24,8'h18,8'h86,8'h2e,8'h86,8'h2a,8'h36,8'h25,8'h86,8'h2e,8'h86,8'h31,8'h28,8'h22,8'h86,8'h36,8'h2a,8'h86,8'h1e,8'h22,8'h28,8'h8c,8'h1e,8'h12,8'h8c,8'h23,8'h17,8'h86,8'h2f,8'h86,8'h36,8'h2a,8'h27,8'h86,8'h2f,8'h86,8'h33,8'h1e,8'h23,8'h86,8'h36,8'h2a,8'h86,8'h24,8'h18,8'h86,8'h2e,8'h86,8'h36,8'h2a,8'h25,8'h86,8'h2e,8'h86,8'h31,8'h28,8'h22,8'h86,8'h36,8'h2a,8'h86,8'h28,8'h22,8'h1e,8'h8c,8'h12,8'h1e,8'h86,8'h36,8'h2a,8'h86,8'h1f,8'h13,8'h86,8'h2f,8'h86,8'h32,8'h86,8'h37,8'h2b,8'h86,8'h1e,8'h12,8'h86,8'h36,8'h2a,8'h86,8'h1e,8'h12,8'h86,8'h2a,8'h36,8'h86,8'h1f,8'h13,8'h86,8'h2f,8'h86,8'h32,8'h86,8'h37,8'h2b,8'h86,8'h1e,8'h12,8'h86,8'h36,8'h2a,8'h92,8'h0b,8'h86,8'h17,8'h86,8'h1a,8'h86,8'h23,8'h86,8'h17,8'h86,8'h23,8'h86,8'h26,8'h86,8'h2f,8'h86,8'h23,8'h86,8'h2f,8'h86,8'h32,8'h86,8'h3b,8'h86,8'h2f,8'h86,8'h3b,8'h86,8'h3e,8'h86,8'h86,8'h3b,8'h29,8'h2c,8'h8c,8'h3b,8'h32,8'h2f,8'h8c,8'h3b,8'h32,8'h2f,8'h8c,8'h3b,8'h29,8'h2c,8'h86,8'h3b,8'h86,8'h33,8'h2f,8'h2a,8'h86,8'h86,8'h33,8'h2f,8'h2a,8'h86,8'h3f,8'h86,8'h2a,8'h2f,8'h33,8'h86,8'h3b,8'h86,8'h33,8'h2f,8'h2a,8'h86,8'h37,8'h3b,8'h86,8'h32,8'h2f,8'h2b,8'h86,8'h3d,8'h86,8'h3e,8'h37,8'h2b,8'h86,8'h3b,8'h86,8'h3d,8'h33,8'h2f,8'h86,8'h3f,8'h36,8'h86,8'h33,8'h2f,8'h2a,8'h86,8'h3b,8'h86,8'h3f,8'h36,8'h33,8'h86,8'h3b,8'h86,8'h3d,8'h36,8'h2a,8'h8c,8'h3b,8'h36,8'h33,8'h92,8'h3b,8'h2f,8'h86,8'h26,8'h23,8'h20,8'h8c,8'h3b,8'h2f,8'h1d,8'h8c,8'h3b,8'h2f,8'h26,8'h8c,8'h3b,8'h2f,8'h26,8'h86,8'h3b,8'h2f,8'h86,8'h1e,8'h23,8'h27,8'h86,8'h36,8'h86,8'h38,8'h2f,8'h27,8'h86,8'h33,8'h86,8'h36,8'h27,8'h23,8'h86,8'h38,8'h2f,8'h86,8'h1e,8'h23,8'h27,8'h86,8'h2f,8'h2b,8'h86,8'h26,8'hff
};
reg [15:0] music_ptr = 0;
reg [2:0] freech = 0;
reg [7:0] cur_duration = 0;
reg [3:0] ch_durations[NVOICES];
reg [7:0] psg_regs[16];
reg [3:0] next_reg;
wire [7:0] note = music_table[music_ptr[8:0]];
wire [11:0] period = note_table[note[5:0]];
always @(posedge advance or posedge reset) begin
if (reset) begin
cur_duration <= 0;
music_ptr <= 0;
psg_regs[15] <= 0;
end else if (cur_duration == 0) begin
// TODO: 0xff
music_ptr <= music_ptr + 1;
if (note[7]) begin
cur_duration <= note & 63;
end else begin
psg_regs[freech*2] <= period[7:0];
psg_regs[freech*2+1] <= 8'(period[11:8]);
ch_durations[freech+0] = 4;
psg_regs[15][freech] <= 1;
freech <= (freech == NVOICES-1) ? 0 : freech+1;
end
end else begin
cur_duration <= cur_duration - 1;
for (int i=0; i<NVOICES; i++) begin
if (ch_durations[i] == 0) begin
psg_regs[15][i] <= 0;
end else begin
ch_durations[i] <= ch_durations[i] - 1;
end
end
end
end
always @(posedge clk or posedge reset) begin
psg_sel <= next_reg;
psg_data <= psg_regs[next_reg];
psg_write <= 1;
next_reg <= next_reg + 1;
end
endmodule;
module top(clk, reset, hsync, vsync, rgb, spkr);
input clk, reset;
output hsync, vsync;
output [2:0] rgb;
output [7:0] spkr;
wire display_on;
wire [8:0] hpos;
wire [8:0] vpos;
hvsync_generator hvsync_gen(
.clk(clk),
.reset(reset),
.hsync(hsync),
.vsync(vsync),
.display_on(display_on),
.hpos(hpos),
.vpos(vpos)
);
wire r = display_on && spkr[2];
wire g = display_on && spkr[1];
wire b = display_on && spkr[0];
assign rgb = {b,g,r};
reg [3:0] sel;
reg [7:0] data;
reg write = 0;
sound_psg psg(
.clk(clk),
.reset(reset),
.reg_sel(sel),
.reg_data(data),
.reg_write(write),
.out(spkr));
music_player player(
.clk(hsync),
.reset(reset),
.advance(vsync),
.psg_sel(sel),
.psg_data(data),
.psg_write(write)
);
endmodule