`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 = 0, nr22 = 0, nr23 = 0, nr24 = 0; 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; reg rdlatch; reg [15:0] addrlatch; assign data = rdlatch ? addrlatch == `ADDR_NR21 ? nr21 : addrlatch == `ADDR_NR22 ? nr22 : addrlatch == `ADDR_NR23 ? nr23 : addrlatch == `ADDR_NR24 ? nr24 : 8'bzzzzzzzz : 8'bzzzzzzzz; always @ (posedge core_clk) begin rdlatch <= rd; addrlatch <= addr; 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