verilog work "System.v"
verilog work "LCDC.v"
verilog work "Framebuffer.v"
-verilog work "pixDCM.v"
\ No newline at end of file
+verilog work "pixDCM.v"
+verilog work "Sound1.v"
+verilog work "Sound2.v"
+verilog work "Soundcore.v"
insn_ld_reg_imm8.v insn_ldx_ahl.v insn_push_reg.v insn_vop_intr.v \
Timer.v LCDC.v insn_ldm8_a.v insn_ldm16_a.v Framebuffer.v \
insn_ldbcde_a.v insn_alu_ext.v insn_bit.v insn_two_byte.v \
- insn_incdec_reg8.v
+ insn_incdec_reg8.v Sound1.v Sound2.v Soundcore.v
all: CoreTop_rom.svf CoreTop_diag.svf CoreTop_bootrom.svf CoreTop.twr
--- /dev/null
+`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
--- /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
--- /dev/null
+`define ADDR_NR50 16'hFF24
+`define ADDR_NR51 16'hFF25
+`define ADDR_NR52 16'hFF26
+
+module Soundcore(
+ input core_clk,
+ input wr,
+ input rd,
+ input [15:0] addr,
+ inout [7:0] data,
+ output reg snd_data_l,
+ output reg snd_data_r
+ );
+
+ reg [7:0] nr50,nr51,nr52;
+ reg [3:0] pwmcnt;
+ reg [4:0] cntclk;
+ reg [13:0] lenclk;
+ wire [3:0] sndout1,sndout2,sndout3,sndout4;
+ wire [3:0] right_snd = nr51[0] ? sndout1 : 4'b0;
+ wire [3:0] left_snd = nr51[4] ? sndout1 : 4'b0;
+
+ assign sndout3 = 0;
+ assign sndout4 = 0;
+
+ assign data = rd ?
+ addr == `ADDR_NR50 ? nr50 :
+ addr == `ADDR_NR51 ? nr51 :
+ addr == `ADDR_NR52 ? nr52 : 8'bzzzzzzzz
+ : 8'bzzzzzzzz;
+
+ always @ (negedge core_clk) begin
+ if(wr) begin
+ case(addr)
+ `ADDR_NR50: nr50 <= data;
+ `ADDR_NR51: nr51 <= data;
+ `ADDR_NR52: nr52 <= {data[7],3'b1,data[3:0]};
+ endcase
+ end
+ cntclk <= cntclk + 1;
+ lenclk <= lenclk + 1;
+ pwmcnt <= pwmcnt + 1;
+ snd_data_l <= (pwmcnt <= left_snd) ? 1 : 0;
+ snd_data_r <= (pwmcnt <= right_snd) ? 1 : 0;
+ end
+
+ Sound1(
+ .core_clk(core_clk),
+ .wr(wr),
+ .rd(rd),
+ .addr(addr),
+ .data(data),
+ .cntclk(cntclk[4]),
+ .lenclk(lenclk[13]),
+ .en(nr52[7] & nr52[0]),
+ .snd_data(sndout1)
+ );
+
+ Sound2(
+ .core_clk(core_clk),
+ .wr(wr),
+ .rd(rd),
+ .addr(addr),
+ .data(data),
+ .cntclk(cntclk[4]),
+ .lenclk(lenclk[13]),
+ .en(nr52[7] & nr52[0]),
+ .snd_data(sndout2)
+ );
+
+endmodule