`define ADDR_NR10 16'hFF10 `define ADDR_NR11 16'hFF11 `define ADDR_NR12 16'hFF12 `define ADDR_NR13 16'hFF13 `define ADDR_NR14 16'hFF14 module Sound1( input core_clk, input wr, input rd, input [15:0] addr, inout [7:0] data, input cntclk, input lenclk, input en, output [3:0] snd_data ); /* can be optimized as register file */ reg [7:0] nr10, nr11, nr12, nr13, nr14; reg [10:0] counter = 0; reg [4:0] lencnt = 0; reg [3:0] delta = 4'b1111; reg [2:0] dutycnt; reg [3:0] snd_out = 0; assign snd_data = en ? snd_out : 0; assign data = rd ? addr == `ADDR_NR10 ? nr10 : addr == `ADDR_NR11 ? nr11 : addr == `ADDR_NR12 ? nr12 : addr == `ADDR_NR13 ? nr13 : addr == `ADDR_NR14 ? nr14 : 8'bzzzzzzzz : 8'bzzzzzzzz; always @ (negedge core_clk) begin if(en && wr) begin case(addr) `ADDR_NR10: nr10 <= data; `ADDR_NR11: nr11 <= data; `ADDR_NR12: nr12 <= data; `ADDR_NR13: nr13 <= data; `ADDR_NR14: nr14 <= data; endcase end else if(!en) begin nr10 <= 8'h80; nr11 <= 8'h3F; nr12 <= 8'h00; nr13 <= 8'hFF; nr14 <= 8'hBF; end end always @ (posedge cntclk) begin if(counter) counter <= counter - 1; else begin counter <= ~{nr14[2:0],nr13} + 1; /* possible A */ dutycnt <= dutycnt + 1; end case (nr11[7:6]) 2'b00: snd_out <= dutycnt ? 0 : delta; /* probable A */ 2'b01: snd_out <= (dutycnt[2:1] == 2'b0) ? delta : 0; 2'b10: snd_out <= dutycnt[2] ? delta : 0; 2'b11: snd_out <= (dutycnt[2:1] == 2'b0) ? 0 : delta; endcase end always @ (posedge lenclk) begin if(lencnt) lencnt <= lencnt - 1; /* possible A */ else lencnt <= ~nr11[4:0] + 1; end endmodule