+`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