--- /dev/null
+`define ADDR_NR21 16'hFF16
+`define ADDR_NR22 16'hFF17
+`define ADDR_NR23 16'hFF18
+`define ADDR_NR24 16'hFF19
+
+module Sound2(
+ 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] nr21, nr22, nr23, nr24;
+ 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_NR21 ? nr21 :
+ addr == `ADDR_NR22 ? nr22 :
+ addr == `ADDR_NR23 ? nr23 :
+ addr == `ADDR_NR24 ? nr24 : 8'bzzzzzzzz
+ : 8'bzzzzzzzz;
+
+ always @ (negedge core_clk) begin
+ if(en && wr) begin
+ case(addr)
+ `ADDR_NR21: nr21 <= data;
+ `ADDR_NR22: nr22 <= data;
+ `ADDR_NR23: nr23 <= data;
+ `ADDR_NR24: nr24 <= data;
+ endcase
+ end
+ else if(!en) begin
+ nr21 <= 8'h3F;
+ nr22 <= 8'h00;
+ nr23 <= 8'hFF;
+ nr24 <= 8'hBF;
+ end
+ end
+
+ always @ (posedge cntclk) begin
+ if(counter)
+ counter <= counter - 1;
+ else begin
+ counter <= ~{nr24[2:0],nr23} + 1; /* possible A */
+ dutycnt <= dutycnt + 1;
+ end
+
+ case (nr21[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 <= ~nr21[4:0] + 1;
+ end
+
+endmodule