dakies/OSS_Verilog huggingface dataset:
module ppfifo_data_sink (
  input               clk,
  input               rst,

  //Ping Pong FIFO Interface
  input               i_rd_rdy,
  output  reg         o_rd_act,
  input       [23:0]  i_rd_size,
  output  reg         o_rd_stb,
  input       [31:0]  i_rd_data
);

//Local Parameters
//Registers/Wires
reg   [23:0]          r_count;
//Submodules
//Asynchronous Logic
//Synchronous Logic
always @ (posedge clk) begin
  if (rst) begin
    o_rd_act          <=  0;
    r_count           <=  0;
    o_rd_stb          <=  0;
  end
  else begin
    //Strobes
    o_rd_stb          <=  0;
    if (i_rd_rdy && !o_rd_act) begin
      r_count         <=  0;
      o_rd_act        <=  1;
    end
    else begin
      if (o_rd_act) begin
        if (r_count < i_rd_size) begin
          o_rd_stb      <=  1;
          r_count       <=  r_count + 1;
        end
        else begin
          o_rd_act      <=  0;
        end
      end
    end
  end
end


endmodule
module sdram_clkgen (

input          clk,
input          rst,

output         locked,
output         out_clk,
output         phy_out_clk
);

wire  clkfbout_buf;
wire  clkfbout;
wire  clkout0;
wire  clkout1;
wire  clkout2;
wire  clkout3;
wire  clkout4;
wire  clkout5;
wire  phy_bufout;


PLL_BASE #(
  .BANDWIDTH            ("OPTIMIZED"          ),
  .CLK_FEEDBACK         ("CLKFBOUT"           ),
  .COMPENSATION         ("SYSTEM_SYNCHRONOUS" ),
  .DIVCLK_DIVIDE        (1                    ),
  .CLKFBOUT_MULT        (18                   ),
  .CLKFBOUT_PHASE       (0.000                ),
  .CLKOUT0_DIVIDE       (9                    ),
//Simulations differ from real world in that the phase must be 0, not 90 degrees
`ifndef SIMULATION
  .CLKOUT0_PHASE        (180.00               ),
`else
  .CLKOUT0_PHASE        (0.00                 ),
`endif
  .CLKOUT0_DUTY_CYCLE   (0.500                ),
  .CLKOUT1_DIVIDE       (9                    ),
  .CLKOUT1_DUTY_CYCLE   (0.500                ),
  .CLKIN_PERIOD         (20.000               ),
  .REF_JITTER           (0.010                )
) pll (

  //Input Clock and Input Clock Control
  .CLKFBIN              (clkfbout_buf         ),
  .CLKIN                (clk                  ),

  //Status/Control
  .LOCKED               (locked               ),
  .RST                  (rst                  ),

  //Feedback Output
  .CLKFBOUT             (clkfbout             ),

  .CLKOUT0              (clkout0              ),
  .CLKOUT1              (clkout1              ),
  .CLKOUT2              (clkout2              ),
  .CLKOUT3              (clkout3              ),
  .CLKOUT4              (clkout4              ),
  .CLKOUT5              (clkout5              )
);

BUFG bufg_sdram_clk (
        .I(clkout0),
        .O(out_clk)
);

BUFG  pll_fb (
  .I (clkfbout),
  .O (clkfbout_buf)
);

BUFG phy_clock_out (
  .I(clkout1),
  .O(phy_bufout)
);

ODDR2 #(
  .DDR_ALIGNMENT  ("NONE"      ),      //Sets output alignment to NON
  .INIT           (1'b0        ),      //Sets the inital state to 0
  .SRTYPE         ("SYNC"      )       //Specified "SYNC" or "ASYNC" reset
) pad_buf (

  .Q              (phy_out_clk ),
  .C0             (phy_bufout  ),
  .C1             (~phy_bufout ),
  .CE             (1'b1        ),
  .D0             (1'b1        ),
  .D1             (1'b0        ),
  .R              (1'b0        ),
  .S              (1'b0        )
);


endmodule
module sf_camera #(
  parameter           BUFFER_SIZE = 12
)(
input                 clk,
input                 rst,

output      [31:0]    debug,

input                 i_camera_reset,
input                 i_auto_flash,
input                 i_manual_flash_on,
input                 i_reset_counts,
input                 i_enable,
input                 i_memory_ready,
output                o_inactive,
input                 i_image_debug_en,

output                o_captured,
output                o_clk_locked,
output                o_busy,
output      [31:0]    o_pixel_count,
output      [31:0]    o_row_count,

//Memory FIFO Interface
output                o_enable_dma,

output                o_rfifo_ready,
input                 i_rfifo_activate,
input                 i_rfifo_strobe,
output      [31:0]    o_rfifo_data,
output      [23:0]    o_rfifo_size,

//Physical Interface
output                o_cam_rst,
output                o_flash,

output                o_cam_in_clk,
input                 i_pix_clk,
input                 i_flash_strobe,
input                 i_vsync,
input                 i_hsync,
input       [7:0]     i_pix_data
);

//Local Parameters
//Registers/Wires
//Submodules

//20MHz Clock Genertors
sf_camera_clk_gen clk_gen(
  .clk              (clk                ),
  .rst              (rst                ),
  .locked           (o_clk_locked       ),
  .phy_out_clk      (o_cam_in_clk       )
);


sf_camera_reader#(
  .BUFFER_SIZE          (BUFFER_SIZE              )
)reader(
  .clk                  (clk                      ),
  .rst                  (rst                      ),

  .debug                (debug                    ),

  .i_camera_reset       (i_camera_reset           ),
  .i_clk_locked         (o_clk_locked             ),
  .i_memory_ready       (i_memory_ready           ),
  .o_inactive           (o_inactive               ),

  //Control
  .i_enable             (i_enable                 ),
  .i_reset_counts       (i_reset_counts           ),
  .i_image_debug_en     (i_image_debug_en         ),

  //Status
  .o_captured           (o_captured               ),
  .o_busy               (o_busy                   ),
  .o_row_count          (o_row_count              ),
  .o_pixel_count        (o_pixel_count            ),

  //Physical Interface
  .i_pix_clk            (i_pix_clk                ),
  .i_vsync              (i_vsync                  ),
  .i_hsync              (i_hsync                  ),
  .i_pix_data           (i_pix_data               ),

  //read
  .i_rfifo_strobe       (i_rfifo_strobe           ),
  .o_rfifo_ready        (o_rfifo_ready            ),
  .i_rfifo_activate     (i_rfifo_activate         ),
  .o_rfifo_size         (o_rfifo_size             ),
  .o_rfifo_data         (o_rfifo_data             )
);

//Asynchronous Logic
assign  o_flash             = (i_auto_flash) ? i_flash_strobe:
                                               i_manual_flash_on;
assign  o_cam_rst           = i_camera_reset;


//Synchronous Logic

endmodule
module sf_camera_controller (
input                 clk,
input                 rst,

//Physical Interface
output                o_cam_rst,
output                o_flash,
input                 i_flash_strobe,

output                o_cam_in_clk,

//Configuration Registers
input                 i_auto_flash,
input                 i_manual_flash_on,
input                 i_enable,
input                 i_camera_reset,

output                o_clk_locked,

//Core Controller
output                o_enable_dma,
output                o_enable_reader,
output                o_enable_interrupt

);

//Local Parameters
//Registers/Wires
//Submodules

//20MHz Clock Genertors
sf_camera_clk_gen clk_gen(
  .clk              (clk                ),
  .rst              (rst                ),
  .locked           (o_clk_locked       ),
  .phy_out_clk      (o_cam_in_clk       )
);

//Asynchronous Logic
assign  o_flash             = (i_auto_flash) ? i_flash_strobe:
                                               i_manual_flash_on;
assign  o_cam_rst           = i_camera_reset;

//Synchronous Logic
endmodule
module sf_camera_clk_gen (
input                 clk,
input                 rst,
output                locked,
output                phy_out_clk
);

//Local parameters
//Registers/Wires
wire                  clkfbout_buf;
wire                  clkfb;
wire                  clkout;
wire                  phy_bufout;
//Submodules
DCM_SP #(
  .CLKDV_DIVIDE         (2.500),
  .CLKFX_DIVIDE         (5),
  .CLKFX_MULTIPLY       (2),
  .CLKIN_DIVIDE_BY_2    ("FALSE"),
  .CLKIN_PERIOD         (20.0),
  .CLKOUT_PHASE_SHIFT   ("NONE"),
  .CLK_FEEDBACK         ("1X"),
  //.DESKEW_ASJUST        ("SYSTEM_SYNCHRONOUS"),
  .PHASE_SHIFT          (0),
  .STARTUP_WAIT         ("FALSE")
) dcm (
  //Input Clocks
  .CLKIN                (clk),  //Already went through a global clock buffer
  .CLKFB                (clkfbout_buf),

  //Output Clocks
  .CLK0                 (clkfb),
  .CLK90                (),
  .CLK180               (),
  .CLK270               (),
  .CLK2X                (),
  .CLK2X180             (),
  .CLKFX                (clkout),
  .CLKFX180             (),
  .CLKDV                (),

  //Ports for dynamic phase shifting
  .PSCLK                (1'b0),
  .PSEN                 (1'b0),
  .PSINCDEC             (1'b0),
  .PSDONE               (),

  //Status
  .LOCKED               (locked),
  .STATUS               (),

  .RST                  (rst),

  .DSSEN                (1'b0)
);


BUFG bufg_camera_clk (
  .I(clkout),
  .O(phy_bufout)
);

BUFG  pll_fb (
  .I (clkfb),
  .O (clkfbout_buf)
);

ODDR2 #(
  .DDR_ALIGNMENT        ("NONE"),     //Sets output alignment to NON
  .INIT                 (1'b0),       //Sets the inital state to 0
  .SRTYPE               ("SYNC")      //Specified "SYNC" or "ASYNC" reset
) pad_buf (

  .Q                    (phy_out_clk),
  .C0                   (phy_bufout),
  .C1                   (~phy_bufout),
  .CE                   (1'b1),
  .D0                   (1'b1),
  .D1                   (1'b0),
  .R                    (1'b0),
  .S                    (1'b0)
);


//Asynchronous Logic
//Synchronous Logic

endmodule
module dma_prog_rom #(
  parameter ROM_SIZE    = 6
) (
  input               clk,
  input               rst,

  input       [7:0]   i_rom_addr,
  input               i_rom_wr_strobe,
  input       [31:0]  i_rom_data,
  output  reg         o_rom_data_valid,
  output      [31:0]  o_rom_data,

  output              o_src_address,
  output              o_dest_address,
  output              o_count,
  output              o_flags,
  output              o_cross_src_port
);

//Local Parameter
//Registers/Wires
//Submodules
//Asynchronous Logic
//Synchronous Logic

endmodule
module sd_host_platform_cocotb (

input                 clk,
input                 rst,

//SD Stack Interface
output  reg           o_locked,
output  reg           o_out_clk,
output                o_out_clk_x2,

input                 i_sd_cmd_dir,
output                o_sd_cmd_in,
input                 i_sd_cmd_out,

input                 i_read_wait,

input                 i_sd_data_dir,
output  reg   [7:0]   o_sd_data_in,
input         [7:0]   i_sd_data_out,

output  reg           o_phy_out_clk,
inout                 io_phy_sd_cmd,
inout         [3:0]   io_phy_sd_data

);

reg           [7:0]   lock_count;
reg                   pos_edge_clk;
wire          [3:0]   data_out;
reg           [3:0]   top_nibble;
wire          [3:0]   in_remap;


assign  o_out_clk_x2 = clk;

assign  io_phy_sd_cmd = i_sd_cmd_dir  ? i_sd_cmd_out : 1'hZ;
assign  o_sd_cmd_in   = io_phy_sd_cmd;

assign  io_phy_sd_data= i_read_wait ? {1'bZ, 1'b0, 1'bZ, 1'bZ } :
                                      i_sd_data_dir ? data_out: 4'hZ;

assign  data_out      = !pos_edge_clk ? { i_sd_data_out[7],
                                          i_sd_data_out[6],
                                          i_sd_data_out[5],
                                          i_sd_data_out[4]} :
                                        { i_sd_data_out[3],
                                          i_sd_data_out[2],
                                          i_sd_data_out[1],
                                          i_sd_data_out[0]};
/*
assign  o_sd_data_in  = pos_edge_clk ?  { io_phy_sd_data[7],
                                          io_phy_sd_data[6],
                                          io_phy_sd_data[5],
                                          io_phy_sd_data[4]} :
                                        { io_phy_sd_data[3],
                                          io_phy_sd_data[2],
                                          io_phy_sd_data[1],
                                          io_phy_sd_data[0]};
*/
assign  in_remap      =                 { io_phy_sd_data[0],
                                          io_phy_sd_data[1],
                                          io_phy_sd_data[2],
                                          io_phy_sd_data[3]};


always @ (posedge o_out_clk_x2) begin
  if (o_phy_out_clk) begin
    pos_edge_clk    <=  1;
  end
  else begin
    pos_edge_clk    <=  0;
  end
end

always @ (posedge o_out_clk_x2) begin
  if (rst) begin
    o_sd_data_in    <=  0;
    top_nibble      <=  0;
  end
  else begin
    if (o_out_clk) begin
      top_nibble    <=  in_remap;
    end
    else begin
      o_sd_data_in  <=  {top_nibble, in_remap};
    end
  end
end

always @ (posedge o_out_clk_x2) begin
  if (rst) begin
    o_out_clk     <=  0;
    o_phy_out_clk <=  0;
    lock_count    <=  0;
    o_locked      <=  0;
  end
  else begin
    o_out_clk     <= ~o_out_clk;
    o_phy_out_clk <= ~o_phy_out_clk;
    if (lock_count < 4'hF) begin
      lock_count  <=  lock_count + 1;
    end
    else begin
      o_locked    <=  1;
    end

  end
end
endmodule
module sd_crc_7(
 input              bitval,     // Next input bit
 input              en,
 input              clk,        // Current bit valid (Clock)
 input              rst,        // Init crc value
 output reg [6:0]   crc         // Current output crc value
);

//Local Parameters
//Registers/Wires
wire         inv;

//Submodules
//Asynchronous Logic
//Synchronous Logic

assign inv = bitval ^ crc[6];                   // XOR required?

always @(posedge clk or posedge rst) begin
  if (rst) begin
    crc = 0;
  end
  else begin
    if (en==1) begin
      crc[6] = crc[5];
      crc[5] = crc[4];
      crc[4] = crc[3];
      crc[3] = crc[2] ^ inv;
      crc[2] = crc[1];
      crc[1] = crc[0];
      crc[0] = inv;
    end
  end
end

endmodule
module crc16_2bit #(
  parameter             POLYNOMIAL  =   16'h1021,
  parameter             SEED        =   16'h0000
)(
  input                 clk,
  input                 rst,
  input                 en,
  input                 bit0,
  input                 bit1,
  output  reg   [15:0]  crc
);

//local parameters
//registes/wires
wire         inv0;
wire         inv1;
//submodules
//asynchronous logic
assign inv1 = bit1 ^ crc[15];
assign inv0 = (bit0 ^ crc[14]);

always @ (posedge clk) begin
  if (rst) begin
    crc  <=  0;
  end
  else begin
    //Shift the output value
    if (en) begin
      crc[15] <= crc[13];
      crc[14] <= crc[12];
      crc[13] <= crc[11] ^ inv1;
      crc[12] <= crc[10] ^ inv0;
      crc[11] <= crc[9];
      crc[10] <= crc[8];
      crc[9]  <= crc[7];
      crc[8]  <= crc[6];
      crc[7]  <= crc[5];
      crc[6]  <= crc[4] ^ inv1;
      crc[5]  <= crc[3] ^ inv0;
      crc[4]  <= crc[2];
      crc[3]  <= crc[1];
      crc[2]  <= crc[0];
      crc[1]  <= inv1;
      crc[0]  <= inv0;
    end
  end
end

endmodule
module sd_crc_16(
 input              clk,        // Current bit valid (Clock)
 input              rst,        // Init crc value
 input              en,
 input              bitval,     // Next input bit
 output reg [15:0]  crc         // Current output crc value
);
//Local Parameters

//Registers/Wires
wire         inv;

//Submodules
//Asynchronous Logic
//Synchronsou Logic

assign inv = bitval ^ crc[15];  // XOR required?

always @(posedge clk or posedge rst) begin
  if (rst) begin
    crc = 0;
  end
  else begin
    if (en==1) begin
      crc[15] = crc[14];
      crc[14] = crc[13];
      crc[13] = crc[12];
      crc[12] = crc[11] ^ inv;
      crc[11] = crc[10];
      crc[10] = crc[9];
      crc[9]  = crc[8];
      crc[8]  = crc[7];
      crc[7]  = crc[6];
      crc[6]  = crc[5];
      crc[5]  = crc[4] ^ inv;
      crc[4]  = crc[3];
      crc[3]  = crc[2];
      crc[2]  = crc[1];
      crc[1]  = crc[0];
      crc[0]  = inv;
    end
  end
end
endmodule
module i2s_writer (
  rst,
  clk,

  //control/status
  enable,
  starved,

  //clock
  i2s_clock,

  //mem controller interface
  audio_data_request,
  audio_data_ack,
  audio_data,
  audio_lr_bit,

  //physical connections
  i2s_data,
  i2s_lr
);

parameter           DATA_SIZE = 32;

input               rst;
input               clk;

input               enable;

input               i2s_clock;

output  reg         audio_data_request;
input               audio_data_ack;
input       [23:0]  audio_data;
input               audio_lr_bit;

output  reg         i2s_data;
output  reg         i2s_lr;

output  reg         starved;

//parameter
parameter           START         = 4'h0;
parameter           REQUEST_DATA  = 4'h1;
parameter           DATA_READY    = 4'h2;

//registers/wires
reg         [7:0]   bit_count;
reg         [23:0]  new_audio_data;
reg                 new_audio_lr_bit;
reg         [23:0]  audio_shifter;

//writer state machine
reg         [3:0]   state;

//asynchronous logic

//synchronous logic
always @ (posedge rst or negedge i2s_clock) begin
  if (rst) begin
    bit_count           <=  DATA_SIZE -1;
    new_audio_data      <=  0;
    new_audio_lr_bit    <=  0;
    audio_shifter       <=  0;
    state               <=  START;
    starved             <=  0;
    i2s_data            <=  0;
    i2s_lr              <=  0;
    audio_data_request  <=  0;
  end
  else if (enable) begin
    starved           <=  0;
    case (state)
      START: begin
         audio_data_request       <=  1;
        if (audio_data_ack) begin
          audio_data_request     <=  0;
          state             <=  DATA_READY;
          new_audio_data    <=  {1'b0, audio_data[23:1]};
          //new_audio_data    <=  audio_data[23:0];
          new_audio_lr_bit  <=  audio_lr_bit;
        end
      end
      REQUEST_DATA: begin
        audio_data_request       <=  1;
        if (audio_data_ack) begin
          audio_data_request     <=  0;
          state             <=  DATA_READY;
          new_audio_data    <=  audio_data;
          new_audio_lr_bit  <=  audio_lr_bit;
        end
      end
      DATA_READY: begin
        //wait for the bit count to reach 0
        if (bit_count == DATA_SIZE - 2) begin
          state       <=  REQUEST_DATA;
        end
      end
      default: begin
        state       <=  REQUEST_DATA;
      end
    endcase

    //continusously shift data out
    if (bit_count == 0) begin
      if (state == DATA_READY) begin
        //put the new data into the shifter and reset the bit_count
        bit_count       <=  DATA_SIZE - 1;
        audio_shifter   <=  new_audio_data;
        i2s_lr          <=  new_audio_lr_bit;
        new_audio_data  <=  0;
        new_audio_lr_bit<=  0;
      end
      else begin
        //starved, can't do anything
        starved         <=  1;
        i2s_data        <=  0;
      end
    end
    else begin
      //shift out data
      bit_count         <=  bit_count - 1;
      i2s_data          <=  audio_shifter[23];
      audio_shifter     <=  {audio_shifter[22:0], 1'b0};
    end
  end
end

endmodule
module i2s_controller (
  input               rst,
  input               clk,

  input               enable,
  input               post_fifo_wave_en,

  input       [31:0]  clock_divider,

  //memory interface
  output      [23:0]  wfifo_size,
  output      [1:0]   wfifo_ready,
  input       [1:0]   wfifo_activate,
  input               wfifo_strobe,
  input       [31:0]  wfifo_data,

  output  reg         i2s_mclock,
  output  reg         i2s_clock,
  output              i2s_data,
  output              i2s_lr
);

`define DEFAULT_MCLOCK_DIVISOR `CLOCK_RATE / (`AUDIO_RATE) / 256

//registers/wires
reg         [31:0]  clock_count = 0;
reg         [31:0]  mclock_count = 0;

wire                audio_data_request;
wire                audio_data_ack;
wire        [23:0]  audio_data;
wire                audio_lr_bit;

//sub modules
i2s_mem_controller mcontroller (
  .rst                  (rst                ),
  .clk                  (clk                ),

  //control
  .enable               (enable             ),
  .post_fifo_wave_en    (post_fifo_wave_en  ),

  //clock
  .i2s_clock            (i2s_clock          ),

  .wfifo_size           (wfifo_size         ),
  .wfifo_ready          (wfifo_ready        ),
  .wfifo_activate       (wfifo_activate     ),
  .wfifo_strobe         (wfifo_strobe       ),
  .wfifo_data           (wfifo_data         ),

  //i2s writer
  .audio_data_request   (audio_data_request ),
  .audio_data_ack       (audio_data_ack     ),
  .audio_data           (audio_data         ),
  .audio_lr_bit         (audio_lr_bit       )
);

i2s_writer writer       (
  .rst                  (rst                ),
  .clk                  (clk                ),

  //control/clock
  .enable               (enable             ),
  .starved              (starved            ),

  //i2s clock
  .i2s_clock            (i2s_clock          ),

  //i2s writer
  .audio_data_request   (audio_data_request ),
  .audio_data_ack       (audio_data_ack     ),
  .audio_data           (audio_data         ),
  .audio_lr_bit         (audio_lr_bit       ),

  //i2s audio interface
  .i2s_data             (i2s_data           ),
  .i2s_lr               (i2s_lr             )
);

//asynchronous logic
//`define DEFAULT_MCLOCK_DIVISOR (`CLOCK_RATE / (`AUDIO_RATE * 256)) / 2
`define DEFAULT_MCLOCK_DIVISOR 1

//synchronous logic
//clock generator
always @(posedge clk) begin
  if (rst) begin
    i2s_clock     <=  0;
    clock_count   <=  0;
  end
  if (clock_count >= clock_divider) begin
    i2s_clock     <=  ~i2s_clock;
    clock_count   <= 0;
  end
  else begin
    clock_count   <=  clock_count + 1;
  end
end

always @(posedge clk) begin
  if (mclock_count >= `DEFAULT_MCLOCK_DIVISOR) begin
    i2s_mclock     <=  ~i2s_mclock;
    mclock_count   <= 0;
  end
  else begin
    mclock_count   <=  mclock_count + 1;
  end
end

endmodule
module waveform(
  clk,
  rst,
  wavelength,
  pos,
  value
);

input               clk;
input               rst;
input       [7:0]   pos;
output      [7:0]   wavelength;
output      [15:0]  value;

parameter WAVELENGTH = 44;

assign  wavelength = WAVELENGTH;
assign  value = wave[pos];

//register
wire [15:0] wave [WAVELENGTH:0];

assign wave[0]  =  16'h0000;
assign wave[1]  =  16'h1237; 
assign wave[2]  =  16'h240F;
assign wave[3]  =  16'h352C;
assign wave[4]  =  16'h4533;
assign wave[5]  =  16'h53D2;
assign wave[6]  =  16'h60BC;
assign wave[7]  =  16'h6BAE;
assign wave[8]  =  16'h746E;
assign wave[9]  =  16'h7AD0;
assign wave[10] =  16'h7EB2;
assign wave[11] =  16'h7FFF;
assign wave[12] =  16'h7EB2;
assign wave[13] =  16'h7AD0;
assign wave[14] =  16'h746E;
assign wave[15] =  16'h6BAE;
assign wave[16] =  16'h60BC;
assign wave[17] =  16'h53D2;
assign wave[18] =  16'h4533;
assign wave[19] =  16'h352C;
assign wave[20] =  16'h240F;
assign wave[21] =  16'h1237;
assign wave[22] =  16'h0000;
assign wave[23] =  16'hEDC9;
assign wave[24] =  16'hDBF1;
assign wave[25] =  16'hCAD4;
assign wave[26] =  16'hBACD;
assign wave[27] =  16'hAC2E;
assign wave[28] =  16'h9F43;
assign wave[29] =  16'h9452;
assign wave[30] =  16'h8B92;
assign wave[31] =  16'h8530;
assign wave[32] =  16'h814E;
assign wave[33] =  16'h8001;
assign wave[34] =  16'h814E;
assign wave[35] =  16'h8530;
assign wave[36] =  16'h8B92;
assign wave[37] =  16'h9452;
assign wave[38] =  16'h9F43;
assign wave[39] =  16'hAC2E;
assign wave[40] =  16'hBACD;
assign wave[41] =  16'hCAD4;
assign wave[42] =  16'hDBF1;
assign wave[43] =  16'hEDC9;

endmodule
module wb_bram #(
  parameter DATA_WIDTH = 32,
  parameter ADDR_WIDTH = 12,
  parameter MEM_FILE  = "NOTHING",
  parameter MEM_FILE_LENGTH = 0

)(
  input               clk,
  input               rst,

  //wishbone slave signals
  input               i_wbs_we,
  input               i_wbs_stb,
  input               i_wbs_cyc,
  input       [3:0]   i_wbs_sel,
  input       [31:0]  i_wbs_adr,
  input       [31:0]  i_wbs_dat,
  output reg  [31:0]  o_wbs_dat,
  output reg          o_wbs_ack,
  output reg          o_wbs_int
);

localparam            RAM_SIZE = ADDR_WIDTH - 1;
localparam            SLEEP_COUNT = 4;

wire  [31:0]        read_data;
reg   [31:0]        write_data;
reg   [RAM_SIZE:0]  ram_adr;
reg                 en_ram;

reg   [3:0]         ram_sleep;

bram#(
  .DATA_WIDTH      (DATA_WIDTH      ),
  .ADDR_WIDTH      (ADDR_WIDTH      ),
  .MEM_FILE        (MEM_FILE        ),
  .MEM_FILE_LENGTH (MEM_FILE_LENGTH )
)br(
  .clk             (clk             ),
  .rst             (rst             ),
  .en              (en_ram          ),
  .we              (i_wbs_we        ),
  .write_address   (ram_adr         ),
  .read_address    (ram_adr         ),
  .data_in         (write_data      ),
  .data_out        (read_data       )
);

//blocks
always @ (posedge clk) begin
  if (rst) begin
    o_wbs_dat       <= 32'h0;
    o_wbs_ack       <= 0;
    o_wbs_int       <= 0;
    ram_sleep       <= SLEEP_COUNT;
    ram_adr         <= 0;
    en_ram          <= 0;
  end
  else begin
    //when the master acks our ack, then put our ack down
    if (o_wbs_ack & !i_wbs_stb)begin
      o_wbs_ack     <= 0;
      en_ram        <= 0;
    end

    if (i_wbs_stb & i_wbs_cyc) begin
      //master is requesting somethign
      en_ram <= 1;
      //ram_adr <= i_wbs_adr[RAM_SIZE + 2:2];
      ram_adr <= i_wbs_adr[RAM_SIZE:0];
      if (i_wbs_we) begin
        //write request
        //the bram module will handle all the writes
        write_data <= i_wbs_dat;
//        $display ("write a:%h, d:%h", i_wbs_adr[RAM_SIZE:0], i_wbs_dat);
      end

      else begin
        //read request
        o_wbs_dat <= read_data;
        //i_wbs_dat <= i_wbs_adr;
//        $display ("read a:%h, d:%h", i_wbs_adr[RAM_SIZE:0], read_data);
      end
      if (ram_sleep > 0) begin
        ram_sleep <= ram_sleep - 1;
      end
      else begin
        o_wbs_ack <= 1;
        ram_sleep <= SLEEP_COUNT;
      end
    end
  end
end


endmodule
module vram(
  input         clk_in,   // system clock
  input         en_in,    // chip enable
  input         r_nw_in,  // read/write select (read: 0, write: 1)
  input  [10:0] a_in,     // memory address
  input  [ 7:0] d_in,     // data input
  output [ 7:0] d_out     // data output
);

wire       vram_bram_we;
wire [7:0] vram_bram_dout;

single_port_ram_sync #(.ADDR_WIDTH(11),
                       .DATA_WIDTH(8)) vram_bram(
  .clk(clk_in),
  .we(vram_bram_we),
  .addr_a(a_in),
  .din_a(d_in),
  .dout_a(vram_bram_dout)
);

assign vram_bram_we = (en_in) ? ~r_nw_in       : 1'b0;
assign d_out        = (en_in) ? vram_bram_dout : 8'h00;

endmodule
module wram(
  input         clk_in,   // system clock
  input         en_in,    // chip enable
  input         r_nw_in,  // read/write select (read: 0, write: 1)
  input  [10:0] a_in,     // memory address
  input  [ 7:0] d_in,     // data input
  output [ 7:0] d_out     // data output
);

wire       wram_bram_we;
wire [7:0] wram_bram_dout;

single_port_ram_sync #(.ADDR_WIDTH(11),
                       .DATA_WIDTH(8)) wram_bram(
  .clk(clk_in),
  .we(wram_bram_we),
  .addr_a(a_in),
  .din_a(d_in),
  .dout_a(wram_bram_dout)
);

assign wram_bram_we = (en_in) ? ~r_nw_in       : 1'b0;
assign d_out        = (en_in) ? wram_bram_dout : 8'h00;

endmodule
module nes_clkgen (
	input clk,
	input rst,

	output locked,
	output out_clk,
	output phy_out_clk
);

wire  clkfbout_buf;
wire  clkfbout;
wire  clkout0;
wire  clkout1;
wire  clkout2;
wire  clkout3;
wire  clkout4;
wire  clkout5;
wire  phy_bufout;


PLL_BASE #(
  .BANDWIDTH            ("OPTIMIZED"),
  .CLK_FEEDBACK         ("CLKFBOUT"),
  .COMPENSATION         ("SYSTEM_SYNCHRONOUS"),
  .DIVCLK_DIVIDE        (1),
  .CLKFBOUT_MULT        (18),
  .CLKFBOUT_PHASE       (0.000),
  .CLKOUT0_DIVIDE       (9),
//Simulations differ from real world in that the phase must be 0, not 90 degrees
`ifndef SIMULATION
  .CLKOUT0_PHASE        (180.00),
`else
  .CLKOUT0_PHASE        (0.00),
`endif
  .CLKOUT0_DUTY_CYCLE   (0.500),
  .CLKOUT1_DIVIDE       (9),
  .CLKOUT1_DUTY_CYCLE   (0.500),
  .CLKIN_PERIOD         (20.000),
  .REF_JITTER           (0.010)
) pll (

  //Input Clock and Input Clock Control
  .CLKFBIN              (clkfbout_buf),
  .CLKIN                (clk),

  //Status/Control
  .LOCKED               (locked),
  .RST                  (rst),

  //Feedback Output
  .CLKFBOUT             (clkfbout),

  .CLKOUT0              (clkout0),
  .CLKOUT1              (clkout1),
  .CLKOUT2              (clkout2),
  .CLKOUT3              (clkout3),
  .CLKOUT4              (clkout4),
  .CLKOUT5              (clkout5)
);

BUFG bufg_sdram_clk (
	.I(clkout0),
	.O(out_clk)
);

BUFG  pll_fb (
  .I (clkfbout),
  .O (clkfbout_buf)
);

BUFG phy_clock_out (
  .I(clkout1),
  .O(phy_bufout)
);

ODDR2 #(
	.DDR_ALIGNMENT        ("NONE"),	//Sets output alignment to NON
	.INIT                 (1'b0),			//Sets the inital state to 0
	.SRTYPE               ("SYNC")			//Specified "SYNC" or "ASYNC" reset
)	pad_buf (

	.Q                    (phy_out_clk),
	.C0                   (phy_bufout),
	.C1                   (~phy_bufout),
	.CE                   (1'b1),
	.D0                   (1'b1),
	.D1                   (1'b0),
	.R                    (1'b0),
	.S                    (1'b0)
);


endmodule
module cart (
  input              clk_in,           // system clock signal

  // Mapper config data.
  input       [39:0] cfg_in,           // cartridge config (from iNES header)
  input              cfg_upd_in,       // pulse signal on cfg_in update

  // PRG-ROM interface.
  input              prg_nce_in,       // prg-rom chip enable (active low)
  input       [14:0] prg_a_in,         // prg-rom address
  input              prg_r_nw_in,      // prg-rom read/write select
  input       [ 7:0] prg_d_in,         // prg-rom data in
  output      [ 7:0] prg_d_out,        // prg-rom data out

  // CHR-ROM interface.
  input       [13:0] chr_a_in,         // chr-rom address
  input              chr_r_nw_in,      // chr-rom read/write select
  input       [ 7:0] chr_d_in,         // chr-rom data in
  output      [ 7:0] chr_d_out,        // chr-rom data out
  output             ciram_nce_out,    // vram chip enable (active low)
  output             ciram_a10_out     // vram a10 value (controls mirroring)
);

wire        prgrom_bram_we;
wire [14:0] prgrom_bram_a;
wire [7:0]  prgrom_bram_dout;

// Block ram instance for PRG-ROM memory range (0x8000 - 0xFFFF).  Will eventually be
// replaced with SRAM.
single_port_ram_sync #(
  .ADDR_WIDTH   (15                   ),
  .DATA_WIDTH   (8                    ))
prgrom_bram     (
  .clk          (clk_in               ),
  .we           (prgrom_bram_we       ),
  .addr_a       (prgrom_bram_a        ),
  .din_a        (prg_d_in             ),
  .dout_a       (prgrom_bram_dout     )
);

assign prgrom_bram_we = (~prg_nce_in) ? ~prg_r_nw_in     : 1'b0;
assign prg_d_out      = (~prg_nce_in) ? prgrom_bram_dout : 8'h00;
assign prgrom_bram_a  = (cfg_in[33])  ? prg_a_in[14:0]   : { 1'b0, prg_a_in[13:0] };

wire       chrrom_pat_bram_we;
wire [7:0] chrrom_pat_bram_dout;

// Block ram instance for "CHR Pattern Table" memory range (0x0000 - 0x1FFF).
single_port_ram_sync #(
  .ADDR_WIDTH   (13                   ),
  .DATA_WIDTH   (8                    ))
chrrom_pat_bram (
  .clk          (clk_in               ),
  .we           (chrrom_pat_bram_we   ),
  .addr_a       (chr_a_in[12:0]       ),
  .din_a        (chr_d_in             ),
  .dout_a       (chrrom_pat_bram_dout )
);

assign ciram_nce_out      = ~chr_a_in[13];
assign ciram_a10_out      = (cfg_in[16])    ? chr_a_in[10] : chr_a_in[11];
assign chrrom_pat_bram_we = (ciram_nce_out) ? ~chr_r_nw_in : 1'b0;
assign chr_d_out          = (ciram_nce_out) ? chrrom_pat_bram_dout : 8'h00;

endmodule
module sprdma
(
  input  wire        clk_in,         // 100MHz system clock signal
  input  wire        rst_in,         // reset signal
  input  wire [15:0] cpumc_a_in,     // cpu address bus in (to snoop cpu writes of 0x4014)
  input  wire [ 7:0] cpumc_din_in,   // cpumc din bus in (to snoop cpu writes of 0x4014)
  input  wire [ 7:0] cpumc_dout_in,  // cpumc dout bus in (to receive sprdma read data)
  input  wire        cpu_r_nw_in,    // cpu write enable (to snoop cpu writes of 0x4014)
  output wire        active_out,     // high when sprdma is active (de-assert cpu ready signal)
  output reg  [15:0] cpumc_a_out,    // cpu address bus out (for dma cpu mem reads/writes)
  output reg  [ 7:0] cpumc_d_out,    // cpu data bus out (for dma mem writes)
  output reg         cpumc_r_nw_out  // cpu r_nw signal out (for dma mem writes)
);

// Symbolic state representations.
localparam [1:0] S_READY    = 2'h0,
                 S_ACTIVE   = 2'h1,
                 S_COOLDOWN = 2'h2;

reg [ 1:0] q_state, d_state; // current fsm state
reg [15:0] q_addr,  d_addr;  // current cpu address to be copied to sprite ram
reg [ 1:0] q_cnt,   d_cnt;   // counter to manage stages of dma copies
reg [ 7:0] q_data,  d_data;  // latch for data read from cpu mem

// Update FF state.
always @(posedge clk_in)
  begin
    if (rst_in)
      begin
        q_state <= S_READY;
        q_addr  <= 16'h0000;
        q_cnt   <= 2'h0;
        q_data  <= 8'h00;
      end
    else
      begin
        q_state <= d_state;
        q_addr  <= d_addr;
        q_cnt   <= d_cnt;
        q_data  <= d_data;
      end
  end

always @*
  begin
    // Default regs to current state.
    d_state = q_state;
    d_addr  = q_addr;
    d_cnt   = q_cnt;
    d_data  = q_data;

    // Default to no memory action.
    cpumc_a_out    = 16'h00;
    cpumc_d_out    = 8'h00;
    cpumc_r_nw_out = 1'b1;

    if (q_state == S_READY)
      begin
        // Detect write to 0x4014 to begin DMA.
        if ((cpumc_a_in == 16'h4014) && !cpu_r_nw_in)
          begin
            d_state = S_ACTIVE;
            d_addr  = { cpumc_din_in, 8'h00 };
          end
      end
    else if (q_state == S_ACTIVE)
      begin
        case (q_cnt)
          2'h0:
            begin
              cpumc_a_out = q_addr;
              d_cnt       = 2'h1;
            end
          2'h1:
            begin
              cpumc_a_out = q_addr;
              d_data      = cpumc_dout_in;
              d_cnt       = 2'h2;
            end
          2'h2:
            begin
              cpumc_a_out    = 16'h2004;
              cpumc_d_out    = q_data;
              cpumc_r_nw_out = 1'b0;
              d_cnt          = 2'h0;

              if (q_addr[7:0] == 8'hff)
                d_state = S_COOLDOWN;
              else
                d_addr = q_addr + 16'h0001;
            end
        endcase
      end
    else if (q_state == S_COOLDOWN)
      begin
        if (cpu_r_nw_in)
          d_state = S_READY;
      end
  end

assign active_out = (q_state == S_ACTIVE);

endmodule
module jp(
  input              clk,         // 100MHz system clock signal
  input              rst,         // reset signal

  input              i_wr,         // i_write enable signal
  input       [15:0] i_addr,       // 16-bit memory i_address
  input              i_din,        // data input bus
  output reg  [7:0]  o_dout,       // data output bus

  input       [7:0]  i_jp1_state,  //state of the joy pad 1
  input       [7:0]  i_jp2_state   //state of the joy pad 2
);

//Local Parameters
localparam [15:0] JOYPAD1_MMR_ADDR = 16'h4016;
localparam [15:0] JOYPAD2_MMR_ADDR = 16'h4017;

//Registers/Wires
reg   [15:0]          r_prev_addr;
wire                  w_new_addr;
reg                   r_wrote_1_flag;
reg   [8:0]           r_jp1_state;
reg   [8:0]           r_jp2_state;

//Submodules
//Asynchronous Logic
assign  w_new_addr  = (r_prev_addr != i_addr);
//Synchronous Logic

always @ (posedge clk) begin
  if (rst) begin
    o_dout                  <=  0;
    r_prev_addr             <=  0;
    r_wrote_1_flag          <=  0;
    r_jp1_state             <=  0;
    r_jp2_state             <=  0;
  end
  else begin
    //Only process a command when i_address changes from not this i_address to this i_address
    if (i_addr[15:1] == JOYPAD1_MMR_ADDR[15:1]) begin
      //User has accessed the joypad register(s), depeni_ding on the last
      //bit send the appropriate joystick information (1 or 2)
      o_dout              <= { 7'h00, ((i_addr[0]) ? r_jp2_state[0] : r_jp1_state[0]) };
      if (w_new_addr) begin
        if (i_wr && !i_addr[0]) begin
          if (!r_wrote_1_flag) begin
            if (i_din == 1'b1) begin
              r_wrote_1_flag    <= 1;
            end
          end
          else begin
            if (i_din == 1'b0) begin
              r_wrote_1_flag    <=  0;
              r_jp1_state     <=  {i_jp1_state, 1'b0};
              r_jp2_state     <=  {i_jp2_state, 1'b0};
            end
          end
        end
        //Shift appropriate JP read state on every read, after 8 reads, all subsequent reads should be 1
        else if (!i_wr && !i_addr[0]) begin
          r_jp1_state         <=  {1'b1, r_jp1_state[8:1]};
        end
        else if (!i_wr && i_addr[0]) begin
          r_jp2_state         <=  {1'b1, r_jp2_state[8:1]};
        end
      end
    end
    r_prev_addr             <=  i_addr;
  end
end
endmodule
module dual_port_ram_sync
#(
  parameter ADDR_WIDTH = 6,
  parameter DATA_WIDTH = 8
)
(
  input  wire                  clk,
  input  wire                  we,
  input  wire [ADDR_WIDTH-1:0] addr_a,
  input  wire [ADDR_WIDTH-1:0] addr_b,
  input  wire [DATA_WIDTH-1:0] din_a,
  output wire [DATA_WIDTH-1:0] dout_a,
  output wire [DATA_WIDTH-1:0] dout_b
);

reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
reg [ADDR_WIDTH-1:0] q_addr_a;
reg [ADDR_WIDTH-1:0] q_addr_b;

always @(posedge clk)
  begin
    if (we)
        ram[addr_a] <= din_a;
    q_addr_a <= addr_a;
    q_addr_b <= addr_b;
  end

assign dout_a = ram[q_addr_a];
assign dout_b = ram[q_addr_b];

endmodule
module single_port_ram_sync
#(
  parameter ADDR_WIDTH = 6,
  parameter DATA_WIDTH = 8
)
(
  input  wire                  clk,
  input  wire                  we,
  input  wire [ADDR_WIDTH-1:0] addr_a,
  input  wire [DATA_WIDTH-1:0] din_a,
  output wire [DATA_WIDTH-1:0] dout_a
);

reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
reg [ADDR_WIDTH-1:0] q_addr_a;

always @(posedge clk)
  begin
    if (we)
        ram[addr_a] <= din_a;
    q_addr_a <= addr_a;
  end

assign dout_a = ram[q_addr_a];

endmodule
module fifo
#(
  parameter DATA_BITS = 8,
  parameter ADDR_BITS = 3
)
(
  input  wire                 clk,      // 50MHz system clock
  input  wire                 reset,    // Reset signal
  input  wire                 rd_en,    // Read enable, pop front of queue
  input  wire                 wr_en,    // Write enable, add wr_data to end of queue
  input  wire [DATA_BITS-1:0] wr_data,  // Data to be written on wr_en
  output wire [DATA_BITS-1:0] rd_data,  // Current front of fifo data
  output wire                 full,     // FIFO is full (writes invalid)
  output wire                 empty     // FIFO is empty (reads invalid)
);

reg  [ADDR_BITS-1:0] q_rd_ptr;
wire [ADDR_BITS-1:0] d_rd_ptr;
reg  [ADDR_BITS-1:0] q_wr_ptr;
wire [ADDR_BITS-1:0] d_wr_ptr;
reg                  q_empty;
wire                 d_empty;
reg                  q_full;
wire                 d_full;

reg  [DATA_BITS-1:0] q_data_array [2**ADDR_BITS-1:0];
wire [DATA_BITS-1:0] d_data;

wire rd_en_prot;
wire wr_en_prot;

// FF update logic.  Synchronous reset.
always @(posedge clk)
  begin
    if (reset)
      begin
        q_rd_ptr <= 0;
        q_wr_ptr <= 0;
        q_empty  <= 1'b1;
        q_full   <= 1'b0;
      end
    else
      begin
        q_rd_ptr               <= d_rd_ptr;
        q_wr_ptr               <= d_wr_ptr;
        q_empty                <= d_empty;
        q_full                 <= d_full;
        q_data_array[q_wr_ptr] <= d_data;
      end
  end

// Derive "protected" read/write signals.
assign rd_en_prot = (rd_en && !q_empty);
assign wr_en_prot = (wr_en && !q_full);

// Handle writes.
assign d_wr_ptr = (wr_en_prot)  ? q_wr_ptr + 1'h1 : q_wr_ptr;
assign d_data   = (wr_en_prot)  ? wr_data         : q_data_array[q_wr_ptr];

// Handle reads.
assign d_rd_ptr = (rd_en_prot)  ? q_rd_ptr + 1'h1 : q_rd_ptr;

wire [ADDR_BITS-1:0] addr_bits_wide_1;
assign addr_bits_wide_1 = 1;

// Detect empty state:
//   1) We were empty before and there was no write.
//   2) We had one entry and there was a read.
assign d_empty = ((q_empty && !wr_en_prot) ||
                  (((q_wr_ptr - q_rd_ptr) == addr_bits_wide_1) && rd_en_prot));

// Detect full state:
//   1) We were full before and there was no read.
//   2) We had n-1 entries and there was a write.
assign d_full  = ((q_full && !rd_en_prot) ||
                  (((q_rd_ptr - q_wr_ptr) == addr_bits_wide_1) && wr_en_prot));

// Assign output signals to appropriate FFs.
assign rd_data = q_data_array[q_rd_ptr];
assign full    = q_full;
assign empty   = q_empty;

endmodule
module apu_length_counter
(
  input  wire       clk_in,           // system clock signal
  input  wire       rst_in,           // reset signal
  input  wire       en_in,            // enable signal (from $4015)
  input  wire       halt_in,          // disable length decrement
  input  wire       length_pulse_in,  // length pulse from frame counter
  input  wire [4:0] length_in,        // new length value
  input  wire       length_wr_in,     // update length to length_in
  output wire       en_out            // length counter is non-0
);

reg  [7:0] q_length, d_length;

always @(posedge clk_in)
  begin
    if (rst_in)
      begin
        q_length <= 8'h00;
      end
    else
      begin
        q_length <= d_length;
      end
  end

always @*
  begin
    d_length = q_length;

    if (!en_in)
      begin
        d_length = 8'h00;
      end
    else if (length_wr_in)
      begin
        case (length_in)
          5'h00: d_length = 8'h0A;
          5'h01: d_length = 8'hFE;
          5'h02: d_length = 8'h14;
          5'h03: d_length = 8'h02;
          5'h04: d_length = 8'h28;
          5'h05: d_length = 8'h04;
          5'h06: d_length = 8'h50;
          5'h07: d_length = 8'h06;
          5'h08: d_length = 8'hA0;
          5'h09: d_length = 8'h08;
          5'h0A: d_length = 8'h3C;
          5'h0B: d_length = 8'h0A;
          5'h0C: d_length = 8'h0E;
          5'h0D: d_length = 8'h0C;
          5'h0E: d_length = 8'h1A;
          5'h0F: d_length = 8'h0E;
          5'h10: d_length = 8'h0C;
          5'h11: d_length = 8'h10;
          5'h12: d_length = 8'h18;
          5'h13: d_length = 8'h12;
          5'h14: d_length = 8'h30;
          5'h15: d_length = 8'h14;
          5'h16: d_length = 8'h60;
          5'h17: d_length = 8'h16;
          5'h18: d_length = 8'hC0;
          5'h19: d_length = 8'h18;
          5'h1A: d_length = 8'h48;
          5'h1B: d_length = 8'h1A;
          5'h1C: d_length = 8'h10;
          5'h1D: d_length = 8'h1C;
          5'h1E: d_length = 8'h20;
          5'h1F: d_length = 8'h1E;
        endcase
      end
    else if (length_pulse_in && !halt_in && (q_length != 8'h00))
      begin
        d_length = q_length - 8'h01;
      end
  end

assign en_out = (q_length != 8'h00);

endmodule
module apu_envelope_generator
(
  input        clk_in,       // system clock signal
  input        rst_in,       // reset signal
  input        eg_pulse_in,  // 1 clk pulse for every env gen update
  input  [5:0] env_in,       // envelope value (e.g., via $4000)
  input        env_wr_in,    // envelope value write
  input        env_restart,  // envelope restart
  output [3:0] env_out       // output volume
);

reg  [5:0] q_reg;
wire [5:0] d_reg;
reg  [3:0] q_cnt,        d_cnt;
reg        q_start_flag, d_start_flag;

always @(posedge clk_in)
  begin
    if (rst_in)
      begin
        q_reg        <= 6'h00;
        q_cnt        <= 4'h0;
        q_start_flag <= 1'b0;
      end
    else
      begin
        q_reg        <= d_reg;
        q_cnt        <= d_cnt;
        q_start_flag <= d_start_flag;
      end
  end

reg  divider_pulse_in;
reg  divider_reload;
wire divider_pulse_out;

apu_div #(.PERIOD_BITS(4)) divider(
  .clk_in(clk_in),
  .rst_in(rst_in),
  .pulse_in(divider_pulse_in),
  .reload_in(divider_reload),
  .period_in(q_reg[3:0]),
  .pulse_out(divider_pulse_out)
);

always @*
  begin
    d_cnt        = q_cnt;
    d_start_flag = q_start_flag;

    divider_pulse_in = 1'b0;
    divider_reload   = 1'b0;

    // When the divider outputs a clock, one of two actions occurs: If the counter is non-zero, it
    // is decremented, otherwise if the loop flag is set, the counter is loaded with 15.
    if (divider_pulse_out)
      begin
        divider_reload = 1'b1;

        if (q_cnt != 4'h0)
          d_cnt = q_cnt - 4'h1;
        else if (q_reg[5])
          d_cnt = 4'hF;
      end

    // When clocked by the frame counter, one of two actions occurs: if the start flag is clear,
    // the divider is clocked, otherwise the start flag is cleared, the counter is loaded with 15,
    // and the divider's period is immediately reloaded.
    if (eg_pulse_in)
      begin
        if (q_start_flag == 1'b0)
          begin
            divider_pulse_in = 1'b1;
          end
        else
          begin
            d_start_flag = 1'b0;
            d_cnt        = 4'hF;
          end
      end

    if (env_restart)
      d_start_flag = 1'b1;
  end

assign d_reg = (env_wr_in) ? env_in : q_reg;

// The envelope unit's volume output depends on the constant volume flag: if set, the envelope
// parameter directly sets the volume, otherwise the counter's value is the current volume.
assign env_out = (q_reg[4]) ? q_reg[3:0] : q_cnt;

endmodule
module apu_frame_counter
(
  input             clk_in,              // system clock signal
  input             rst_in,              // reset signal
  input             cpu_cycle_pulse_in,  // 1 clk pulse on every cpu cycle
  input             apu_cycle_pulse_in,  // 1 clk pulse on every apu cycle
  input       [1:0] mode_in,             // mode ([0] = IRQ inhibit, [1] = sequence mode)
  input             mode_wr_in,          // update mode
  output reg        e_pulse_out,         // envelope and linear counter pulse (~240 Hz)
  output reg        l_pulse_out,         // length counter and sweep pulse (~120 Hz)
  output reg        f_pulse_out          // frame pulse (~60Hz, should drive IRQ)
);

reg [14:0] q_apu_cycle_cnt, d_apu_cycle_cnt;
reg        q_seq_mode,      d_seq_mode;
reg        q_irq_inhibit,   d_irq_inhibit;

always @(posedge clk_in)
  begin
    if (rst_in)
      begin
        q_apu_cycle_cnt <= 15'h0000;
        q_seq_mode      <= 1'b0;
        q_irq_inhibit   <= 1'b0;
      end
    else
      begin
        q_apu_cycle_cnt <= d_apu_cycle_cnt;
        q_seq_mode      <= d_seq_mode;
        q_irq_inhibit   <= d_irq_inhibit;
      end
  end

always @*
  begin
    d_apu_cycle_cnt = q_apu_cycle_cnt;
    d_seq_mode      = (mode_wr_in) ? mode_in[1] : q_seq_mode;
    d_irq_inhibit   = (mode_wr_in) ? mode_in[0] : q_irq_inhibit;

    e_pulse_out = 1'b0;
    l_pulse_out = 1'b0;
    f_pulse_out = 1'b0;

    if (apu_cycle_pulse_in)
      begin
        d_apu_cycle_cnt = q_apu_cycle_cnt + 15'h0001;

        if ((q_apu_cycle_cnt == 15'h0E90) || (q_apu_cycle_cnt == 15'h2BB1))
          begin
            e_pulse_out = 1'b1;
          end
        else if (q_apu_cycle_cnt == 15'h1D20)
          begin
            e_pulse_out = 1'b1;
            l_pulse_out = 1'b1;
          end
        else if (!q_seq_mode && (q_apu_cycle_cnt == 15'h3A42))
          begin
            e_pulse_out = 1'b1;
            l_pulse_out = 1'b1;
            f_pulse_out = ~q_irq_inhibit;

            d_apu_cycle_cnt = 15'h0000;
          end
        else if ((q_apu_cycle_cnt == 15'h48d0))
          begin
            e_pulse_out = q_seq_mode;
            l_pulse_out = q_seq_mode;

            d_apu_cycle_cnt = 15'h0000;
          end
      end

      if (cpu_cycle_pulse_in && mode_wr_in)
        d_apu_cycle_cnt = 15'h48d0;
  end

endmodule
module apu_div
#(
  parameter PERIOD_BITS = 16
)
(
  input                    clk_in,     // system clock signal
  input                    rst_in,     // reset signal
  input                    pulse_in,   // input pulse
  input                    reload_in,  // reset counter to period_in (no pulse_out generated)
  input  [PERIOD_BITS-1:0] period_in,  // new period value
  output                   pulse_out   // divided output pulse
);

reg  [PERIOD_BITS-1:0] q_cnt;
wire [PERIOD_BITS-1:0] d_cnt;

always @(posedge clk_in)
  begin
    if (rst_in)
      q_cnt <= 0;
    else
      q_cnt <= d_cnt;
  end

assign d_cnt     = (reload_in || (pulse_in && (q_cnt == 0))) ? period_in    :
                   (pulse_in)                                ? q_cnt - 1'h1 : q_cnt;
assign pulse_out = pulse_in && (q_cnt == 0);

endmodule