/*
 *                              .--------------. .----------------. .------------.
 *                             | .------------. | .--------------. | .----------. |
 *                             | | ____  ____ | | | ____    ____ | | |   ______ | |
 *                             | ||_   ||   _|| | ||_   \  /   _|| | | .' ___  || |
 *       ___  _ __   ___ _ __  | |  | |__| |  | | |  |   \/   |  | | |/ .'   \_|| |
 *      / _ \| '_ \ / _ \ '_ \ | |  |  __  |  | | |  | |\  /| |  | | || |       | |
 *       (_) | |_) |  __/ | | || | _| |  | |_ | | | _| |_\/_| |_ | | |\ `.___.'\| |
 *      \___/| .__/ \___|_| |_|| ||____||____|| | ||_____||_____|| | | `._____.'| |
 *           | |               | |            | | |              | | |          | |
 *           |_|               | '------------' | '--------------' | '----------' |
 *                              '--------------' '----------------' '------------'
 *
 *  openHMC - An Open Source Hybrid Memory Cube Controller
 *  (C) Copyright 2014 Computer Architecture Group - University of Heidelberg
 *  www.ziti.uni-heidelberg.de
 *  B6, 26
 *  68159 Mannheim
 *  Germany
 *
 *  Contact: openhmc@ziti.uni-heidelberg.de
 *  http://ra.ziti.uni-heidelberg.de/openhmc
 *
 *   This source file is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This source file is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this source file.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 */
`ifndef HMC_REQUESTER_DRIVER_SV
`define HMC_REQUESTER_DRIVER_SV

/* Driver is incomplete and not tested */
/* Use at your own risk */

class hmc_requester_driver #(parameter NUM_LANES=16) extends hmc_driver_base#(NUM_LANES);

	`uvm_component_param_utils(hmc_requester_driver#(.NUM_LANES(NUM_LANES)))

	function new(string name="hmc_requester_driver", uvm_component parent);
		super.new(name,parent);
		hmc_frp_port	= new("hmc_frp_port", this);
	endfunction : new

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);

		local_config = link_config.requester;
	endfunction : build_phase

	task run_phase(uvm_phase phase);
		super.run_phase(phase);

		forever begin
			if(vif.P_RST_N !== 1) begin
				next_state = RESET;
			end

			if (next_state != last_state)
				`uvm_info(get_type_name(),$psprintf("in state %s", next_state.name()), UVM_HIGH)

			last_state = next_state;

			fork
				begin
					case (next_state)
						RESET: reset();
						NULL_FLITS: null_flits();
						TS1: ts1();

				begin
					@(negedge vif.P_RST_N);

				end
				begin
				//	get_packets();
				end
			join_any
			disable fork;
		end

	endtask : run_phase

	task reset();

		vif.RXP = {NUM_LANES {1'bz}};
		vif.RXN = {NUM_LANES {1'bz}};
		vif.RXPS = 1'b1;

		seq_num = 1;
		last_rrp = 0;
		init_continue = 0;
		can_continue = 1;
		retry_buffer.reset();

		//wait for reset signal
		@(posedge vif.P_RST_N);

		#link_config.tINIT;

		set_init_continue();
		`uvm_info(get_type_name(),$psprintf("active = %0d retry prob = %0d", local_config.active, local_config.random_retry_probability), UVM_HIGH)

		vif.RXPS = 1'b1;

		#1us;
		reset_timestamp = $time;

		next_state = NULL_FLITS;
	endtask : reset

	task null_flits();
		int null_time;

		reset_lfsr();

		//wait for Responder to send NULLs
		while (!remote_status.get_all_lanes_locked())
			drive_fit({NUM_LANES {1'b0}});

		null_timestamp = $time;

		//wait at most tRESP2
		null_time_randomization_succeeds : assert (std::randomize(null_time) with {null_time > 0ns && null_time < link_config.tRESP2;});
		for (int i=0; i<null_time/link_config.bit_time; i++) begin
			drive_fit({NUM_LANES {1'b0}});
		end

		next_state = TS1;
	endtask : null_flits

	task ts1();
		int ts1_fits = 0;

		// Save the timestamp
		ts1_timestamp = $time;

		//wait for Responder to send TS1
		while (!remote_status.get_all_lanes_aligned())
			send_ts1(256); // 16 fits per sequence number, 16 sequence numbers

		//Send some (possibly incomplete) TS1 flits
		ts1_fits_randomization_succeeds : assert (std::randomize(ts1_fits) with {ts1_fits >= 0 && ts1_fits < 512;});
		send_ts1(ts1_fits);

		next_state = NULL_FLITS_2;
	endtask : ts1

	task null_flits_2();
		int null_flit_count;

		while (!remote_status.get_first_tret_received())
			drive_flit(128'h0);

		null_flit_count_randomization_succeeds : assert (std::randomize(null_flit_count) with {null_flit_count >= 1 && null_flit_count < 512;});

		//send NULL FLITs
		for (int i=0; i < null_flit_count; i++)
			drive_flit(128'h0);

		next_state = INITIAL_TRETS;
	endtask : null_flits_2

	function void drive_lanes(input bit[NUM_LANES-1:0] new_value);
		int i;

		bit[NUM_LANES-1:0] lanes_reordered;

		if (local_config.reverse_lanes) begin
			for (i = 0; i < NUM_LANES; i= i+1) begin
				lanes_reordered[i] = new_value[NUM_LANES-i-1];
			end
		end else begin
			lanes_reordered = new_value;
		end

		// TODO: wire delays?
		for (i = 0; i < local_config.width; i= i+1) begin
			vif.RXP[i] = lanes_reordered[i] ^ local_config.reverse_polarity[i];
			vif.RXN[i] = ~lanes_reordered[i] ^ local_config.reverse_polarity[i];
		end
	endfunction : drive_lanes

endclass : hmc_requester_driver

`endif // HMC_REQUESTER_DRIVER_SV

						NULL_FLITS_2: null_flits_2();
						INITIAL_TRETS: initial_trets();
						LINK_UP: link_up();
						START_RETRY_INIT: start_retry_init();
						CLEAR_RETRY: clear_retry();


`include "svunit_defines.svh"

//===================================
// (Failsafe) timeout
//===================================
`define SVUNIT_TIMEOUT 200us

module p4_proc_datapath_unit_test
#(
    parameter int HDR_LENGTH = 0
 );
    // Testcase name
    string name = $sformatf("p4_proc_datapath_hdrlen_%0d_ut", HDR_LENGTH);

    // SVUnit base testcase
    svunit_pkg::svunit_testcase svunit_ut;

    //===================================
    // DUT + testbench
    //===================================
    // This test suite references the common smartnic
    // testbench top level. The 'tb' module is
    // loaded into the tb_glbl scope, so is available
    // at tb_glbl.tb.
    //
    // Interaction with the testbench is expected to occur
    // via the testbench environment class (tb_env). A
    // reference to the testbench environment is provided
    // here for convenience.
    tb_pkg::tb_env env;

    // VitisNetP4 table agent
    vitisnetp4_verif_pkg::vitisnetp4_agent vitisnetp4_agent;

    p4_proc_reg_pkg::reg_p4_proc_config_t    p4_proc_config;
    p4_proc_reg_pkg::reg_p4_bypass_config_t  p4_bypass_config;
    p4_proc_reg_pkg::reg_trunc_config_t      trunc_config;

    //===================================
    // Import common testcase tasks
    //===================================
    `include "../common/tasks.svh"

    //===================================
    // Build
    //===================================
    function void build();
        svunit_ut = new(name);

        // Build testbench
        env = tb.build();
        env.set_debug_level(1);

        // Create P4 table agent
        vitisnetp4_agent = new(.hier_path(p4_dpic_hier_path)); // DPI-C P4 table agent requires hierarchical path to AXI-L write/read tasks

    endfunction

    //===================================
    // Setup for running the Unit Tests
    //===================================
    task setup();
        svunit_ut.setup();

        // start environment
        env.run();
        // Write hdr_length register (set hdr_length to 0B to disable split-join logic).
        p4_proc_config.hdr_length = HDR_LENGTH;
        env.p4_proc_reg_agent.write_p4_proc_config(p4_proc_config);

        // initialize p4_bypass_config.
        p4_bypass_config.p4_bypass_enable          = 1'b0;
        p4_bypass_config.p4_bypass_egr_port_num_0  = 1'b0;
        p4_bypass_config.p4_bypass_egr_port_type_0 =   '0;
        p4_bypass_config.p4_bypass_egr_port_num_1  = 1'b1;
        p4_bypass_config.p4_bypass_egr_port_type_1 =   '0;

        // initialize expected 'tuser' signal.
        tuser='{rss_enable: 1'b1, rss_entropy: '0};

        #100ns;
    endtask

    //===================================
    // Here we deconstruct anything we
    // need after running the Unit Tests
    //===================================
    task teardown();
        // Stop environment
        env.stop();

        svunit_ut.teardown();
    endtask

    //=======================================================================
    // TESTS
    //=======================================================================

    //===================================
    // All tests are defined between the
    // SVUNIT_TESTS_BEGIN/END macros
    //
    // Each individual test must be
    // defined between `SVTEST(_NAME_)
    // `SVTEST_END
    //
    // i.e.
    //   `SVTEST(mytest)
    //     <test code>
    //   `SVTEST_END
    //===================================

    `SVUNIT_TESTS_BEGIN

    `SVTEST(init)
        // Initialize VitisNetP4 tables
        vitisnetp4_agent.init();
    `SVTEST_END

    `include "../../../vitisnetp4/p4/sim/run_pkt_test_incl.svh"

    `SVTEST(test_fwd_p3)
        run_pkt_test ( .testdir("test-fwd-p3"), .tuser(tuser), .tdest(3) );
    `SVTEST_END

    `SVTEST(test_traffic_mux)
        string testdir_0 = "test-default";
        string testdir_1 = "test-fwd-p1";
        string filename;

        // reset rss_enable (when bypassing p4 processor).
        tuser.rss_enable = 1'b0;

        // force output tuser for ALL pkts (for consistency in p4-mode and p4-bypass-mode).
        force tb.axis_out_if[0].tuser = tuser;
        force tb.axis_out_if[1].tuser = tuser;

        write_p4_tables ( .testdir(testdir_1) );

        repeat (3) begin
            // post expected pkts to scoreboards.
            filename = {p4_sim_dir, testdir_1, "/packets_out.pcap"};
            env.pcap_to_scoreboard (.filename(filename), .tuser(tuser), .tdest(1),
                                    .scoreboard(env.scoreboard[1]) );

            filename = {p4_sim_dir, testdir_0, "/packets_out.pcap"};
            env.pcap_to_scoreboard (.filename(filename), .tuser(tuser),
                                    .scoreboard(env.scoreboard[0]) );

            // inject input pkts to drivers.
            filename = {p4_sim_dir, testdir_1, "/packets_in.pcap"};
            env.pcap_to_driver     (.filename(filename), .driver(env.driver[1]));

            filename = {p4_sim_dir, testdir_0, "/packets_in.pcap"};
            env.pcap_to_driver     (.filename(filename), .driver(env.driver[0]));

            #3us;  // time to allow packets to flow through DUT.

            // toggle p4_bypass register.
            p4_bypass_config.p4_bypass_enable = ~p4_bypass_config.p4_bypass_enable;
            env.p4_proc_reg_agent.write_p4_bypass_config(p4_bypass_config);

            #3us;  // time to allow 'p4_bypass' timer to expire.
        end

        for (int i=0; i < env.NUM_PROC_PORTS; i++) `FAIL_IF_LOG(env.scoreboard[i].report(msg) > 0, msg);

        release tb.axis_out_if[0].tuser;
        release tb.axis_out_if[1].tuser;

    `SVTEST_END

    `SVTEST(test_egr_pkt_trunc)
        string testdir_0 = "test-default";
        string testdir_1 = "test-fwd-p1";
        string filename;

        logic [15:0] len;

        write_p4_tables ( .testdir(testdir_1) );

        repeat (3) begin
            len =  $urandom_range(65,300);  // generate random max pkt length.

            // write trunc_config register.
            trunc_config.enable = 1'b1;
            trunc_config.trunc_enable = 1'b1;
            trunc_config.trunc_length = len;
            env.p4_proc_reg_agent.write_trunc_config(trunc_config);

            // set expected tuser fields
            tuser='{rss_enable: 1'b1, rss_entropy: '0};

            // post expected pkts to scoreboards.
            filename = {p4_sim_dir, testdir_1, "/packets_out.pcap"};
            env.pcap_to_scoreboard (.filename(filename), .tuser(tuser), .tdest(1),
                                    .scoreboard(env.scoreboard[1]), .len(len) );

            filename = {p4_sim_dir, testdir_0, "/packets_out.pcap"};
            env.pcap_to_scoreboard (.filename(filename), .tuser(tuser),
                                    .scoreboard(env.scoreboard[0]), .len(len) );

            // inject input pkts to drivers.
            filename = {p4_sim_dir, testdir_1, "/packets_in.pcap"};
            env.pcap_to_driver     (.filename(filename), .driver(env.driver[1]));

            filename = {p4_sim_dir, testdir_0, "/packets_in.pcap"};
            env.pcap_to_driver     (.filename(filename), .driver(env.driver[0]));

            #3us;  // time to allow packets to flow through DUT.
        end

        for (int i=0; i < env.NUM_PROC_PORTS; i++) `FAIL_IF_LOG(env.scoreboard[i].report(msg) > 0, msg);

    `SVTEST_END

    `SVTEST(test_unset_err_drops)
        int pkts=4, bytes=2048; // pkt and byte counts for 'test-unset'.

        fork
           begin
              // run packets from port 1 to port 1 (includes programming the p4 tables).
              run_pkt_test ( .testdir("test-unset"), .in_port(1), .out_port(1),
                             .check_scoreboards(0) );
              check_probe (DROPS_UNSET_ERR_PORT_1, pkts, bytes);
             `FAIL_UNLESS_EQUAL(env.scoreboard[1].got_processed(), 0);

              // run packets from port 0 to port 0 (skips reprogramming the p4 tables).
              run_pkt_test ( .testdir("test-unset"), .in_port(0), .out_port(0),
                             .check_scoreboards(0), .write_tables(0) );
              check_probe (DROPS_UNSET_ERR_PORT_0, pkts, bytes);
             `FAIL_UNLESS_EQUAL(env.scoreboard[0].got_processed(), 0);
           end
           begin
              // monitor output interfaces for any valid axi4s transactions.
              forever @(negedge tb.axis_out_if[0].aclk) begin
                 `FAIL_IF_LOG( tb.axis_out_if[0].tready && tb.axis_out_if[0].tvalid,
                               $sformatf("FAIL!!! Valid axi4s transaction received on output interface 0") )
                 `FAIL_IF_LOG( tb.axis_out_if[1].tready && tb.axis_out_if[1].tvalid,
                               $sformatf("FAIL!!! Valid axi4s transaction received on output interface 1") )
              end
           end
        join_any
    `SVTEST_END

    `SVTEST(test_p4_bypass)
        // reset rss_enable (when bypassing p4 processor).
        tuser.rss_enable = 1'b0;

        // Write p4_bypass register.
        p4_bypass_config.p4_bypass_enable = 1'b1;
        env.p4_proc_reg_agent.write_p4_bypass_config(p4_bypass_config);

        write_p4_tables ( .testdir("test-default-w-drops") );
        run_pkt_test ( .testdir("test-default"), .tuser(tuser), .write_tables(0) );
    `SVTEST_END

    `SVTEST(test_p4_bypass_w_traffic)
        // reset rss_enable (when bypassing p4 processor).
        tuser.rss_enable = 1'b0;

        // force output tuser for ALL pkts (for consistency in p4-mode and p4-bypass-mode).
        force tb.axis_out_if[0].tuser = tuser;

        fork
           run_pkt_test ( .testdir("test-default"), .tuser(tuser) );

           @(posedge tb.axis_out_if[0].tvalid) begin
               // Write p4_bypass register.
               p4_bypass_config.p4_bypass_enable = 1'b1;
               env.p4_proc_reg_agent.write_p4_bypass_config(p4_bypass_config);
           end
        join

        release tb.axis_out_if[0].tuser;

    `SVTEST_END

    `SVTEST(terminate)
        // Clean up VitisNetP4 driver
        vitisnetp4_agent.terminate();
    `SVTEST_END

    `SVUNIT_TESTS_END

endmodule

// 'Boilerplate' unit test wrapper code
// Builds unit test for a specific axi4s_split_join configuration in a way
// that maintains SVUnit compatibility

`define P4_PROC_DATAPATH_UNIT_TEST(HDR_LENGTH)\
  import svunit_pkg::svunit_testcase;\
  svunit_testcase svunit_ut;\
  p4_proc_datapath_unit_test #(HDR_LENGTH) test();\
  function void build();\
    test.build();\
    svunit_ut = test.svunit_ut;\
  endfunction\
  function void __register_tests();\
    test.__register_tests();\
  endfunction\
  task run();\
    test.run();\
  endtask

`P4_PROC_DATAPATH_UNIT_TEST(64)
endmodule

module p4_proc_datapath_hdrlen_256_unit_test;
`P4_PROC_DATAPATH_UNIT_TEST(256)
endmodule

module p4_proc_datapath_hdrlen_0_unit_test;
`P4_PROC_DATAPATH_UNIT_TEST(0)
endmodule


class `VITISNETP4_AGENT_NAME #(
) extends std_verif_pkg::agent;

    // Pointer to VitisNetP4 driver
    protected chandle _drv;

    // Pointer to Table context vector
    protected chandle _ctxPtr[$];

    //===================================
    // Methods
    //===================================
    // Constructor
    function new(input string name=`"`VITISNETP4_AGENT_NAME`", input string hier_path);
        super.new(name);
        this.__create(hier_path);
    endfunction

    // Destructor
    // [[ overrides std_verif_pkg::base.destroy() ]]
    function automatic void destroy();
        debug_msg("---------------- VitisNetP4: Destroy. -------------");
        // Destroy VitisNetP4 driver instance
        vitis_net_p4_dpi_pkg::XilVitisNetP4DpiDestroyEnv(_drv);
        super.destroy();
        debug_msg("---------------- VitisNetP4: Driver destroyed. -------------");
    endfunction

    // Create VitisNetP4 driver
    function void __create(
            input string hier_path
        );
        import vitis_net_p4_dpi_pkg::*;
        debug_msg("---------------- VitisNetP4: Create. -------------");
        if (this._drv == null) begin
            this._drv = XilVitisNetP4DpiCreateEnv(hier_path);
            debug_msg("---------------- VitisNetP4: Driver create done. -------------");
        end else begin
            debug_msg("---------------- VitisNetP4: Driver already exists. -------------");
        end
    endfunction

    // Initialize VitisNetP4 tables
    // - needs to be performed before any table accesses/programming
    task init();
        import `VITISNETP4_PKG_NAME::*;

        debug_msg("---------------- VitisNetP4: Init tables. -------------");
        initialize(this._ctxPtr, this._drv);
        debug_msg("---------------- VitisNetP4: Init tables done.. -------------");
    endtask

    // Reset VitisNetP4 tables
    // - reset VitisNetP4 IP to default state
    task reset_tables();
        import `VITISNETP4_PKG_NAME::*;

        debug_msg("---------------- VitisNetP4: Reset table state. -------------");
        reset_state(this._ctxPtr);
        debug_msg("---------------- VitisNetP4: Reset table state done.. -------------");
    endtask

    // Terminate VitisNetP4 drivers (tables, externs, etc.)
    task terminate();
        import `VITISNETP4_PKG_NAME::*;

        debug_msg("---------------- VitisNetP4: Terminate. -------------");
        if (this._drv == null) begin
            debug_msg("---------------- VitisNetP4: Terminate failed (Driver doesn't exist). -------------");
        end else begin
            terminate(this._ctxPtr);
            debug_msg("---------------- VitisNetP4: Terminate done. -------------");
        end
    endtask

    // vitisnetp4_table_init is based on the procedure described in the example_control.sv file of xilinx vitisnetp4_0 example design
    task table_init_from_file(input string filename);
        import xilinx_vitisnetp4_example_pkg::*;
        const bit VERBOSE = (this.get_debug_level() > 1);

        CliCmdStruct cli_cmds[$];
        CliCmdStruct cli_cmd;

        string table_format_str;
        strArray action_params;
        bitArray key, mask;
        bitArray response;
        int table_is_ternary;
        int action_id;
        int action_id_width;
        int entry_priority;
        int action_arg_widths[$];

        chandle CtxPtr[$] = this._ctxPtr;

        string __filename;
        int filename_len = filename.len;
        string filename_ext = filename.substr(filename.len-4,filename.len-1);

        // Always print this message to bracket print output from table driver
        // (no obvious way to disable driver output)
        print_msg("INFO: ", get_name(), "---------------- VitisNetP4: Initialize tables from file. -------------");

        reset_tables();

        // parse_cli_commands function adds '.txt' extension to filename input argument
        // (needs to be stripped if present
        if (filename_ext.compare(".txt"))
            __filename = filename;
        else
            __filename = filename.substr(0,filename.len-5);

        // Parse CLI command file (e.g. cli_commands.txt)
        parse_cli_commands(__filename, cli_cmds);

        for (int cmd_idx=0; cmd_idx<cli_cmds.size(); cmd_idx++) begin
           cli_cmd = cli_cmds[cmd_idx];
           case (cli_cmd.cmd_op)

               TBL_ADD: begin
                   table_format_str = `VITISNETP4_PKG_NAME::get_table_format_string(cli_cmd.table_name);
                   table_is_ternary = `VITISNETP4_PKG_NAME::table_is_ternary(cli_cmd.table_name);
                   action_id        = `VITISNETP4_PKG_NAME::get_action_id(cli_cmd.table_name, cli_cmd.action_name);
                   action_id_width  = `VITISNETP4_PKG_NAME::get_table_action_id_width(cli_cmd.table_name);
                   `VITISNETP4_PKG_NAME::get_action_arg_widths(cli_cmd.table_name, cli_cmd.action_name, action_arg_widths);
                   parse_match_fields(table_format_str, cli_cmd.match_fields, key, mask);
                   split_action_params_and_prio(table_is_ternary, cli_cmd.action_params, action_params, entry_priority);
                   parse_action_parameters(action_arg_widths, action_id, action_id_width, action_params, response);
                   if (VERBOSE) begin
                     $display("** Info: Adding entry to table %0s", cli_cmd.table_name);
                     $display("  - action:\t%0s", cli_cmd.action_name);
                     $display("  - match key:\t0x%0x", key);
                     $display("  - key mask:\t0x%0x", mask);
                     $display("  - response:\t0x%0x", response);
                     $display("  - priority:\t%0d", entry_priority);
                   end
                   `VITISNETP4_PKG_NAME::table_add(CtxPtr, cli_cmd.table_name, key, mask, response, entry_priority);
                   if (VERBOSE) $display("** Info: Entry has been added with handle %0d", cli_cmd.entry_id);
               end

               TBL_MODIFY : begin
                   action_id        = `VITISNETP4_PKG_NAME::get_action_id(cli_cmd.table_name, cli_cmd.action_name);
                   action_id_width  = `VITISNETP4_PKG_NAME::get_table_action_id_width(cli_cmd.table_name);
                   table_format_str = `VITISNETP4_PKG_NAME::get_table_format_string(cli_cmd.table_name);
                   `VITISNETP4_PKG_NAME::get_action_arg_widths(cli_cmd.table_name, cli_cmd.action_name, action_arg_widths);
                   parse_action_parameters(action_arg_widths, action_id, action_id_width, cli_cmd.action_params, response);

                     $display("  - acion:\t%0s", cli_cmd.action_name);
                     $display("  - response:\t0x%0x", response);
                   end
                   `VITISNETP4_PKG_NAME::table_modify(CtxPtr, cli_cmd.table_name, key, mask, response);
                   if (VERBOSE) $display("** Info: Entry has been modified with handle %0d", cli_cmd.entry_id);
               end

               TBL_DELETE : begin
                   table_format_str = `VITISNETP4_PKG_NAME::get_table_format_string(cli_cmd.table_name);
                   parse_match_fields(table_format_str, cli_cmd.match_fields, key, mask);
                   if (VERBOSE) begin
                     $display("** Info: Deleting entry from table %0s", cli_cmd.table_name);
                     $display("  - match key:\t0x%0x", key);
                     $display("  - key mask:\t0x%0x", mask);
                   end
                   `VITISNETP4_PKG_NAME::table_delete(CtxPtr, cli_cmd.table_name, key, mask);
                   if (VERBOSE) $display("** Info: Entry has been deleted with handle %0d", cli_cmd.entry_id);
               end

               TBL_CLEAR : begin
                   if (VERBOSE) $display("** Info: Deleting all entries from table %0s", cli_cmd.table_name);
                   `VITISNETP4_PKG_NAME::table_clear(CtxPtr, cli_cmd.table_name);
               end

               RST_STATE : begin
                   if (VERBOSE) $display("** Info: Reseting VitisNet IP instance to default state");
                   `VITISNETP4_PKG_NAME::reset_state(CtxPtr);
               end

           endcase
       end
        print_msg("INFO: ", get_name(), "---------------- VitisNetP4: Initialize tables from file Done. -------------");
    endtask

endclass : `VITISNETP4_AGENT_NAME


//
// Copyright (c) 2020, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// Neither the name of the Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

//
// Map OFS platform CCI-P interface the MPF interface.
//

`include "platform_if.vh"
`include "cci_mpf_if.vh"

`ifdef OFS_PLAT_PARAM_HOST_CHAN_NUM_PORTS

module ofs_plat_ccip_if_to_mpf
  #(
    parameter REGISTER_INPUTS = 1,
    parameter REGISTER_OUTPUTS = 1,
    // Number of stages to add when registering inputs or outputs
    parameter N_REG_STAGES = 1
    )
   (
    ofs_plat_host_ccip_if.to_fiu ofs_ccip,
    cci_mpf_if.to_afu mpf_ccip
    );

    logic clk;
    assign clk = ofs_ccip.clk;
    logic reset;
    assign reset = !ofs_ccip.reset_n;

    assign mpf_ccip.reset = reset;

    genvar s;
    generate
        if (REGISTER_OUTPUTS)
        begin : reg_out

                reg_af2cp_sTx[0].c0 <= cci_mpf_cvtC0TxToBase(mpf_ccip.c0Tx);
                reg_af2cp_sTx[0].c1 <= cci_mpf_cvtC1TxToBase(mpf_ccip.c1Tx);
                reg_af2cp_sTx[0].c2 <= mpf_ccip.c2Tx;
            end

            // Intermediate stages
            for (s = 0; s < N_REG_STAGES - 1; s = s + 1)
            begin
                always_ff @(posedge clk)
                begin
                    reg_af2cp_sTx[s+1] <= reg_af2cp_sTx[s];
                end
            end

            always_comb
            begin
                ofs_ccip.sTx = reg_af2cp_sTx[N_REG_STAGES - 1];
            end
        end
        else
        begin : wire_out
            always_comb
            begin
                ofs_ccip.sTx.c0 = cci_mpf_cvtC0TxToBase(mpf_ccip.c0Tx);
                ofs_ccip.sTx.c1 = cci_mpf_cvtC1TxToBase(mpf_ccip.c1Tx);
                ofs_ccip.sTx.c2 = mpf_ccip.c2Tx;
            end
        end
    endgenerate

    //
    // Buffer incoming read responses for timing
    //
    generate
        if (REGISTER_INPUTS)
        begin : reg_in
            (* preserve *) t_if_ccip_Rx reg_cp2af_sRx[N_REG_STAGES];

            always_ff @(posedge clk)
            begin
                reg_cp2af_sRx[N_REG_STAGES - 1] <= ofs_ccip.sRx;
            end

            // Intermediate stages
            for (s = N_REG_STAGES - 1; s > 0; s = s - 1)
            begin
                always_ff @(posedge clk)
                begin
                    reg_cp2af_sRx[s-1] <= reg_cp2af_sRx[s];
                end
            end

            always_comb
            begin
                mpf_ccip.c0Rx = reg_cp2af_sRx[0].c0;
                mpf_ccip.c1Rx = reg_cp2af_sRx[0].c1;

                mpf_ccip.c0TxAlmFull = reg_cp2af_sRx[0].c0TxAlmFull;
                mpf_ccip.c1TxAlmFull = reg_cp2af_sRx[0].c1TxAlmFull;
            end
        end
        else
        begin : wire_in
            always_comb
            begin
                mpf_ccip.c0Rx = ofs_ccip.sRx.c0;
                mpf_ccip.c1Rx = ofs_ccip.sRx.c1;

                mpf_ccip.c0TxAlmFull = ofs_ccip.sRx.c0TxAlmFull;
                mpf_ccip.c1TxAlmFull = ofs_ccip.sRx.c1TxAlmFull;
            end
        end
    endgenerate

endmodule // ofs_plat_ccip_if_to_mpf

`endif // OFS_PLAT_PARAM_HOST_CHAN_NUM_PORTS

            (* preserve *) t_if_ccip_Tx reg_af2cp_sTx[N_REG_STAGES];

            // Tx to register stages


//
// Copyright (c) 2016, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// Neither the name of the Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

`ifndef __CCI_MPF_SHIM_PWRITE_VH__
`define __CCI_MPF_SHIM_PWRITE_VH__

`include "cci_mpf_if.vh"

//
// Interface between edge modules and the partial write shim.
//
interface cci_mpf_shim_pwrite_if
  #(
    parameter N_WRITE_HEAP_ENTRIES = 0
    );

    typedef logic [$clog2(N_WRITE_HEAP_ENTRIES)-1 : 0] t_write_heap_idx;

    //
    // Forward write masks from AFU to the partial write shim, bypassing
    // the MPF pipeline.
    //
    logic wen;
    t_write_heap_idx widx;
    t_cci_clNum wclnum;
    t_cci_mpf_c1_PartialWriteHdr wpartial;

    //
    // Update write data with existing state for the unmodified portion.
    //
    logic upd_en;
    t_write_heap_idx upd_idx;
    t_cci_clNum upd_clNum;
    t_cci_clData upd_data;
    t_cci_mpf_clDataByteMask upd_mask;

    modport pwrite
       (
        input  wen,
        input  widx,
        input  wclnum,
        input  wpartial,

        output upd_en,
        output upd_idx,
        output upd_clNum,
        output upd_data,
        output upd_mask
        );

    modport pwrite_edge_afu
       (
        output wen,
        output widx,
        output wclnum,
        output wpartial
        );

    modport pwrite_edge_fiu
       (
        input  upd_en,
        input  upd_idx,
        input  upd_clNum,
        input  upd_data,
        input  upd_mask
        );

endinterface // cci_mpf_shim_pwrite_if

interface cci_mpf_shim_pwrite_lock_if
  #(
    parameter N_WRITE_HEAP_ENTRIES = 0
    );

    typedef logic [$clog2(N_WRITE_HEAP_ENTRIES)-1 : 0] t_write_heap_idx;

    //
    // Track AFU writes that haven't yet reached the FIU edge write data heap.
    // These writes may be delayed due to partial write updates. Write requests
    // can't be released to the FIU until the heap is consistent.
    //
    logic lock_idx_en;
    t_write_heap_idx lock_idx;
    logic unlock_idx_en;
    t_write_heap_idx unlock_idx;

    modport pwrite
       (
        input  lock_idx_en,
        input  lock_idx,
        input  unlock_idx_en,
        input  unlock_idx
        );

    modport pwrite_edge_fiu
       (
        output lock_idx_en,

        output unlock_idx_en,
        output unlock_idx
        );

endinterface // cci_mpf_shim_pwrite_lock_if

`endif // __CCI_MPF_SHIM_PWRITE_VH__


module Rsa256Core (
	input          i_clk,
	input          i_rst,
	input          i_start,
	input  [255:0] i_a, // cipher text y
	input  [255:0] i_d, // private key
	input  [255:0] i_n,
	output [255:0] o_a_pow_d, // plain text x
	output         o_finished
	);

	/*-------------------------------------------- submodule RsaMont tester --------------------------------------------*/
		// wire [255:0] test_a, test_b, test_n;
		// assign test_a = 256'hee3ca49fc758f320488c88d171560086a2d558079716b6a0bda315be47e025ba;
		// assign test_b = 256'hf91444d973e52a870d8900fa5648d11bda75686b4d15c6db0b8458d5d7d050d7;
		// assign test_n = 256'hc81f20fc0fe23f89dcf7296bbca44b3380ed1679ce2ad6477b5572929eff1324;

		// logic [255:0] test_result;
		// logic test_finished;
		// RsaMont mont(
		// 	.i_clk(i_clk),
		// 	.i_rst(i_rst),
		// 	.i_start(i_start),
		// 	.i_a(test_a),
		// 	.i_b(test_b),
		// 	.i_n(test_n),
		// 	.o_result(test_result),
		// 	.o_finished(test_finished)
		// );

	// operations for RSA256 decryption
	// namely, the Montgomery algorithm

	// parameters
	parameter S_IDLE = 2'd0;
	parameter S_PREP = 2'd1;
	parameter S_MONT = 2'd2;
	parameter S_CALC = 2'd3;

	// registers
	reg [1:0] state_r, state_w;
	reg [8:0] counter_r, counter_w; // 0 to 256

	reg mont_start_r, mont_start_w;	// mont_start_r used on both mont_Nmt and mont_Ntt, they will start and finish at the same time

	reg [255:0] d_r, d_w;			// d_r[i] used to determine whether to update m

	reg [255:0] t_r, t_w;
	reg [255:0] m_r, m_w;

	reg o_finished_r, o_finished_w;

	// submodules
	wire [255:0] prep_result;
	wire prep_finished;
	RsaPrep prep(
		.i_clk(i_clk),
		.i_rst(i_rst),
		.i_start(i_start),
		.i_a(i_a),
		.i_n(i_n),
		.o_result(prep_result),
		.o_finished(prep_finished)
	);

	wire [255:0] mont_Nmt_result;
	wire mont_Nmt_finished;
	RsaMont mont_Nmt(
		.i_clk(i_clk),
		.i_rst(i_rst),
		.i_start(mont_start_r), // do it when d[i] == 1 in S_MONT
		.i_n(i_n),
		.i_a(m_r), // namely m in the algorithm
		.i_b(t_r), // namely t in the algorithm
		.o_result(mont_Nmt_result),
		.o_finished(mont_Nmt_finished)
	);

	wire [255:0] mont_Ntt_result;
	wire mont_Ntt_finished;
	RsaMont mont_Ntt(
		.i_clk(i_clk),
		.i_rst(i_rst),
		.i_start(mont_start_r), // do it in every cycle of S_MONT
		.i_n(i_n),
		.i_a(t_r), // namely t in the algorithm
		.i_b(t_r), // namely t in the algorithm
		.o_result(mont_Ntt_result),
		.o_finished(mont_Ntt_finished)
	);

	assign o_a_pow_d = m_r;
	assign o_finished = o_finished_r;

	// state transition
	always @(*) begin
		state_w = state_r;
		case(state_r)
			// S_IDLE:  state_w = i_start ? S_PREP : S_IDLE;
			S_IDLE: begin
				if(i_start) state_w = S_PREP;
				else		state_w = S_IDLE;
			end
			// S_PREP:  state_w = prep_finished ? S_MONT : S_PREP;
			S_PREP: begin
				if(prep_finished) state_w = S_MONT;
				else			  state_w = S_PREP;
			end
			// S_MONT:  state_w = (mont_Nmt_finished && mont_Ntt_finished)? S_CALC : S_MONT;
			S_MONT: begin
				if(mont_Nmt_finished && mont_Ntt_finished)  state_w = S_CALC;
				else										state_w = S_MONT;
			end
			// S_CALC:  state_w = counter_r[8] ? S_IDLE : S_MONT;
			S_CALC: begin
				if(counter_r[8]) state_w = S_IDLE;
				else			 state_w = S_MONT;
			end
		endcase
	end

	// counter logic
	always @(*) begin
		counter_w = counter_r;
		case(state_r)
			S_IDLE: counter_w = 0;
			S_CALC: counter_w = counter_r + 1;
		endcase
	end

	// mont start logic
	always @(*) begin
		mont_start_w = 1'b0;
		case(state_r)
			S_PREP: mont_start_w = prep_finished;
			S_CALC: mont_start_w = 1'b1;
		endcase
	end

	// d logic
	always @(*) begin
		d_w = d_r;
		case(state_r)
			S_IDLE: if(i_start) d_w = i_d;
			S_CALC: d_w = d_r >> 1;
		endcase
	end

	// t logic
	always @(*) begin
		t_w = t_r;
		case(state_r)
			S_PREP: if(prep_finished) t_w = prep_result;
			S_MONT: if(mont_Ntt_finished) t_w = mont_Ntt_result;
		endcase
	end

	// output / m logic
	always @(*) begin
		m_w = m_r;
		case(state_r)
			S_PREP: m_w = 256'd1;
			S_MONT: if(mont_Nmt_finished && d_r[0])	m_w = mont_Nmt_result;
		endcase
	end

	// output signal logic
	always @(*) begin
		o_finished_w = 1'b0;
		case(state_r)
			S_CALC: if(counter_r[8]) o_finished_w = 1'b1;
		endcase
	end

	// sequential logic
	always_ff @(posedge i_clk or posedge i_rst) begin
		if(i_rst) begin
			state_r <= S_IDLE;
			counter_r <= 9'd0;
			t_r <= 256'd0;
			m_r <= 256'd1;
			d_r <= 256'd0;
			mont_start_r <= 1'b0;
			o_finished_r <= 1'b0;
		end
		else begin
			state_r <= state_w;
			counter_r <= counter_w;
			t_r <= t_w;
			m_r <= m_w;
			d_r <= d_w;
			mont_start_r <= mont_start_w;
			o_finished_r <= o_finished_w;
		end
	end
endmodule

module RsaPrep (
	input          i_clk,
	input          i_rst,
	input          i_start,
	input  [255:0] i_a,
	input  [255:0] i_n,
	output [255:0] o_result,
	output         o_finished
	);

	// do a * 2^(256) mod n

	parameter S_IDLE = 2'd0;
	parameter S_CALC = 2'd1;
	parameter S_DONE = 2'd2;

	logic [1:0] state_r, state_w;
	logic [7:0] counter_r, counter_w;

	logic [255:0] o_result_r, o_result_w;
	logic o_finished_r, o_finished_w; // namely m in the algorithm

	assign o_result = o_result_r;
	assign o_finished = o_finished_r;

	// state transition
	always @(*) begin
		state_w = state_r;
		case(state_r)
			// S_IDLE:  state_w = (i_start)? 			S_CALC : S_IDLE;
			S_IDLE: begin
				if(i_start) state_w = S_CALC;
				else		state_w = S_IDLE;
			end
			// S_CALC:  state_w = (counter_r == 255)? 	S_DONE : S_CALC;
			S_CALC: begin
				if(counter_r == 255) state_w = S_DONE;
				else				 state_w = S_CALC;
			end
			S_DONE:  state_w = S_IDLE;
		endcase
	end

	// counter logic
	always @(*) begin
		counter_w = counter_r;
		case(state_r)
			S_CALC:  counter_w = counter_r + 1;
			default: counter_w = 0;
		endcase
	end

	// output logic
	// assume i_a < i_n
	logic [256:0] a_leftshift_1;
	always @(*) begin
		o_result_w[255:0] = o_result_r[255:0];
		a_leftshift_1 = o_result_r << 1;
		case(state_r)
			S_IDLE: if(i_start) o_result_w[255:0] = i_a[255:0];
			S_CALC: begin
				if(a_leftshift_1 > i_n) o_result_w[255:0] = a_leftshift_1[256:0] - i_n[255:0];
				else 					o_result_w[255:0] = a_leftshift_1[255:0];
			end
		endcase
	end

	// output signal logic
	always @(*) begin
		o_finished_w = 1'b0;
		case(state_r)
			S_CALC: if(counter_r == 255) o_finished_w = 1'b1;
		endcase
	end

	// sequential logic
	always_ff @(posedge i_clk or posedge i_rst) begin
		if(i_rst) begin
			state_r <= S_IDLE;
			counter_r <= 8'd0;
			o_result_r <= 256'd0;
			o_finished_r <= 1'b0;
		end
		else begin
			state_r <= state_w;
			counter_r <= counter_w;
			o_result_r <= o_result_w;
			o_finished_r <= o_finished_w;
		end
	end
endmodule

module RsaMont (
	input          i_clk,
	input          i_rst,
	input          i_start,
	input  [255:0] i_n,
	input  [255:0] i_a,
	input  [255:0] i_b,
	output [255:0] o_result,
	output         o_finished
	);

	// do a * b * 2^(-256) mod n

	parameter S_IDLE = 2'd0;
	parameter S_CALC = 2'd1;
	parameter S_DONE = 2'd3;

	logic [1:0] state_r, state_w;
	logic [7:0] counter_r, counter_w;

	logic [255:0] a_r, a_w; // in order to get the i-th bit in the i-th cycle, shift right every cycle

	logic [256:0] o_result_r, o_result_w; // namely m in the algorithm, set 257 bits to prevent overflow when caculating, but just output 256 bits
	logic o_finished_r, o_finished_w;

	assign o_result = o_result_r[255:0];
	assign o_finished = o_finished_r;

	// state transition
	always @(*) begin
		state_w = state_r;
		case(state_r)
			// S_IDLE:  state_w = (i_start)? 			S_CALC : S_IDLE;
			S_IDLE: begin
				if(i_start) state_w = S_CALC;
				else		state_w = S_IDLE;
			end
			// S_CALC:  state_w = (counter_r == 255)? 	S_DONE : S_CALC;
			S_CALC: begin
				if(counter_r == 255) state_w = S_DONE;
				else				 state_w = S_CALC;
			end
			S_DONE:  state_w = S_IDLE;
		endcase
	end

	// counter logic
	always @(*) begin
		counter_w = counter_r;

	always @(*) begin
		a_w = a_r;
		case(state_r)
			S_IDLE: if(i_start) a_w = i_a;
			S_CALC: a_w = (a_r >> 1);
		endcase
	end

	// output logic
	logic [257:0] temp1; // the first result of m after the first if
	logic [257:0] temp2; // the second result of m after the second if
	logic [256:0] temp3; // do the right shift
	always @(*) begin
		o_result_w = o_result_r;
		if(counter_r == 0) o_result_w = 257'd0;
		case(state_r)
			S_CALC: begin
				if(a_r[0])	temp1 = o_result_r + i_b; // temp1 at most 258 bits since o_result_r + i_b at most 257 bits
				else		temp1 = o_result_r;

				if(temp1[0])	temp2 = temp1 + i_n; // temp2 at most 258 bits since temp1 + i_n at most 257 bits
				else			temp2 = temp1;

				temp3 = temp2 >> 1; // temp3 at most 257 bits since temp2 >> 1 at most 256 bits

				if(counter_r == 255) begin
					if(temp3 >= i_n)	o_result_w = temp3 - i_n;
					else 				o_result_w = temp3;
				end
				else o_result_w = temp3;
			end
		endcase
	end

	// output signal logic
	always @(*) begin
		o_finished_w = 1'b0;
		case(state_r)
			S_CALC: if(counter_r == 255) o_finished_w = 1'b1;
		endcase
	end

	// sequential logic
	always_ff @(posedge i_clk or posedge i_rst) begin
		if(i_rst) begin
			state_r <= S_IDLE;
			counter_r <= 8'd0;
			a_r <= 256'd0;
			o_result_r <= 257'd0;
			o_finished_r <= 1'b0;
		end
		else begin
			state_r <= state_w;
			counter_r <= counter_w;
			a_r <= a_w;
			o_result_r <= o_result_w;
			o_finished_r <= o_finished_w;
		end
	end
endmodule


module Audio (
	input i_clk,
	input i_rst_n,

	// SDRAM

	// I2C
	input  i_clk_100k,
	output o_I2C_SCLK,
	inout  io_I2C_SDAT,

	// AudPlayer
	inout  i_AUD_BCLK,
	inout  i_AUD_DACLRCK,
	output o_AUD_DACDAT,
);

	// design the FSM and states as you like
	parameter S_I2C  = 0;
	parameter S_PLAY = 1;

	reg [1:0] state_r, state_w;

	wire i2c_oen;
	wire i2c_done;
	reg i2c_done_r, i2c_done_w;

	wire dsp_oen;
	wire player_start;
	assign player_start = i2c_done_r && (state_r == S_PLAY);

	wire [19:0] stop_address;
	logic [19:0] addr_play;
	logic [15:0] data_play, dac_data;

	// if state_r = S_REC, then time = i_SRAM_ADDR[19:15]
	// if state_r = S_PLAY, then time = o_SRAM_ADDR[19:15]
	assign o_time = (state_r == S_REC) ? addr_record[19:15] : addr_play[19:15];
	// assign o_time = (state_r == S_REC) ? addr_record[6:2] : addr_play[6:2]; // only for tb

	// assign o_SRAM_ADDR = (state_r == S_REC) ? addr_record : addr_play[19:0];
	// assign io_SRAM_DQ  = (state_r == S_REC) ? data_record : 16'dz; // sram_dq as output
	// assign data_play   = (state_r != S_REC) ? io_SRAM_DQ : 16'd0; // sram_dq as input
	// assign o_SRAM_WE_N = (state_r == S_REC) ? 1'b0 : 1'b1;

	// assign o_SRAM_CE_N = 1'b0;
	// assign o_SRAM_OE_N = 1'b0;
	// assign o_SRAM_LB_N = 1'b0;
	// assign o_SRAM_UB_N = 1'b0;

	// below is a simple example for module division
	// you can design these as you like

	reg i2c_start_r, i2c_start_w;
	reg dsp_start_r, dsp_start_w;

	always @(*) begin
		i2c_start_w = i2c_start_r;
		dsp_start_w = dsp_start_r;
		if(i2c_done_r) i2c_start_w = 1'b0;
		if(player_start) dsp_start_w = 1'b1;
	end

	wire is_player_pause;

	// === I2cInitializer ===
	// sequentially sent out settings to initialize WM8731 with I2C protocal
	AudioInitializer i2c(
		.i_rst_n(i_rst_n),
		.i_clk(i_clk_100k),
		.i_start(i2c_start_r),
		.o_finished(i2c_done),
		.o_sclk(o_I2C_SCLK),
		.io_sdat(io_I2C_SDAT),
		.o_oen(i2c_oen) // you are outputing (you are not outputing only when you are "ack"ing.)
	);

	// === AudDSP ===
	// responsible for DSP operations including fast play and slow play at different speed
	// in other words, determine which data addr to be fetch for player
	AudioDSP dsp(
		.i_rst_n(i_rst_n),
		.i_clk(i_AUD_BCLK),
		.i_start(dsp_start_r),
		.i_pause(i_key_2),
		.i_speed(i_speed), // total 3 bits, use 3 switches
		.i_is_slow(i_is_slow), // 0 for fast play, 1 for slow play, use 1 switch
		.i_slow_mode(i_slow_mode), // 0 for constant interpolation, 1 for linear interpolation, use 1 switch
		.i_daclrck(i_AUD_DACLRCK),
		.i_sram_data(data_play),
		.i_sram_stop_addr(stop_address),
		.o_dac_data(dac_data),
		.o_en(dsp_oen),
		.o_is_pause(is_player_pause),
		.o_sram_addr(addr_play)
	);

	// === AudPlayer ===
	// receive data address from DSP and fetch data to sent to WM8731 with I2S protocal
	AudioPlayer player(
		.i_rst_n(i_rst_n),
		.i_bclk(i_AUD_BCLK),
		.i_daclrck(i_AUD_DACLRCK),
		.i_en(dsp_oen), // enable AudPlayer only when playing audio, work with AudDSP
		.i_dac_data(dac_data),
		.o_aud_dacdat(o_AUD_DACDAT)
	);

	// state machine
	always @(*) begin
		state_w = state_r;

	// i2c_done and logic
	always @(*) begin
		i2c_done_w = i2c_done_r;
		if(i2c_done) i2c_done_w = 1'b1;
	end

	always_ff @(posedge i_clk or negedge i_rst_n) begin
		if (!i_rst_n) begin
			state_r <= S_I2C;
			i2c_done_r <= 1'b0;

			i2c_start_r <= 1'b1;
			dsp_start_r <= 1'b0;
		end
		else begin
			state_r <= state_w;
			i2c_done_r <= i2c_done_w;

			i2c_start_r <= i2c_start_w;
			dsp_start_r <= dsp_start_w;
		end
	end

endmodule

		case(state_r)
			S_I2C: begin
				if(i2c_done) state_w = S_PLAY;
				else         state_w = S_I2C;
			end


/**********************************************************
 Start Date: 10 Sept 2015
 Author: Mayur Kubavat

 Module: AHB Slave Monitor
 Filename: ahb_smonitor.svh
**********************************************************/

class ahb_smonitor extends uvm_monitor;

        `uvm_component_utils(ahb_smonitor)

        virtual ahb_intf vif;
        ahb_sagent_config sagt_cfg;
        ahb_sxtn xtn;

        uvm_analysis_port#(ahb_sxtn) monitor_ap;

        //------------------------------------------------
        // Methods
        //------------------------------------------------

        extern function new(string name = "ahb_smonitor", uvm_component parent);
        extern function void build_phase(uvm_phase phase);
        extern function void connect_phase(uvm_phase phase);
        extern task run_phase(uvm_phase phase);
        extern task monitor();

endclass: ahb_smonitor

        //Constructor
        function ahb_smonitor::new(string name = "ahb_smonitor", uvm_component parent);
                super.new(name, parent);

                monitor_ap = new("monitor_ap", this);

        endfunction

        //Build

                if(!uvm_config_db#(ahb_sagent_config)::get(this, "", "ahb_sagent_config", sagt_cfg))
                begin
                        `uvm_fatal(get_full_name(), "Cannot get VIF from configuration database!")
                end

                super.build_phase(phase);
        endfunction

        //Connect
        function void ahb_smonitor::connect_phase(uvm_phase phase);
                vif = sagt_cfg.vif;
        endfunction

        //Run
        task ahb_smonitor::run_phase(uvm_phase phase);
                forever
                begin
                        fork
                                begin: mon
                                        monitor();
                                        disable wait_for_reset;
                                end
                                begin: wait_for_reset
                                        wait(!vif.HRESETn);
                                        xtn = ahb_sxtn::type_id::create("xtn");
                                        xtn.reset =  0;
                                        $cast(xtn.trans_type, vif.HTRANS);
                                        disable mon;
                                        monitor_ap.write(xtn);
                                        @(vif.smon_cb);
                                end
                        join
                end
        endtask

        //Monitor Bursts
        task ahb_smonitor::monitor();
        begin: mon1
                xtn = ahb_sxtn::type_id::create("xtn");

                do
                begin: collect
                        $cast(xtn.trans_type, vif.mmon_cb.HTRANS);
                        $cast(xtn.burst_mode, vif.mmon_cb.HBURST);
                        $cast(xtn.trans_size, vif.mmon_cb.HSIZE);
                        $cast(xtn.read_write, vif.mmon_cb.HWRITE);
                        $cast(xtn.response, vif.mmon_cb.HRESP);
                        xtn.address.push_back(vif.mmon_cb.HADDR);

                        if((xtn.trans_type == IDLE) && (vif.HRESETn == 1))
                        begin
                                @(vif.mmon_cb);
                                `uvm_info(get_type_name(), "IDLE Transaction Detected..", UVM_MEDIUM)
                                monitor_ap.write(xtn);
                                disable mon1;
                        end
                        else
                        begin
                                @(vif.mmon_cb);
                                if(vif.HRESP == 1)
                                begin
                                        `uvm_info(get_type_name(), $sformatf("ERROR Detected on Address %h", xtn.address[$]), UVM_MEDIUM)
                                        disable collect;
                                end

                                while(!vif.HREADY || (vif.HTRANS == 1))
                                begin
                                        @(vif.mmon_cb);
                                        if(vif.HRESP == 1)
                                        begin
                                                `uvm_info(get_type_name(), $sformatf("ERROR Detected on Address %h", xtn.address[$]), UVM_MEDIUM)
                                                disable collect;
                                        end
                                end

                                if(xtn.read_write == READ)
                                        xtn.read_data.push_back(vif.mmon_cb.HRDATA);
                                else
                                        xtn.write_data.push_back(vif.mmon_cb.HWDATA);
                        end
                end: collect
                while(vif.HTRANS == 3);

                `uvm_info(get_type_name(), "Received Packet From AHB Slave Monitor..", UVM_MEDIUM)
                xtn.print();
                monitor_ap.write(xtn);
        end
        endtask

function void ahb_smonitor::build_phase(uvm_phase phase);


class spi_subscriber extends uvm_subscriber#(spi_transaction);

	`uvm_component_utils(spi_subscriber)

	function new(string name = "spi_subscriber", uvm_component parent);
		super.new(name, parent);
	endfunction


// megafunction wizard: %FIFO%
// GENERATION: STANDARD
// VERSION: WM1.0
// MODULE: scfifo

// ============================================================
// File Name: VDP_FIFO.v
// Megafunction Name(s):
// 			scfifo
//
// Simulation Library Files(s):
// 			altera_mf
// ============================================================
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
//
// 13.1.4 Build 182 03/12/2014 SJ Full Version
// ************************************************************

//Copyright (C) 1991-2014 Altera Corporation
//Your use of Altera Corporation's design tools, logic functions
//and other software and tools, and its AMPP partner logic
//functions, and any output files from any of the foregoing
//(including device programming or simulation files), and any
//associated documentation or information are expressly subject
//to the terms and conditions of the Altera Program License
//Subscription Agreement, Altera MegaCore Function License
//Agreement, or other applicable license agreement, including,
//without limitation, that your use is for the sole purpose of
//programming logic devices manufactured by Altera and sold by
//Altera or its authorized distributors.  Please refer to the
//applicable agreement for further details.

// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module VDP_FIFO (
	clock,
	data,
	rdreq,
	wrreq,
	empty,
	full,
	q);

	input	  clock;
	input	[34:0]  data;
	input	  rdreq;
	input	  wrreq;
	output	  empty;
	output	  full;
	output	[34:0]  q;

	wire  sub_wire0;
	wire  sub_wire1;
	wire [34:0] sub_wire2;

	scfifo	scfifo_component (
				.clock (clock),
				.data (data),
				.rdreq (rdreq),
				.wrreq (wrreq),
				.empty (sub_wire0),
				.full (sub_wire1),
				.q (sub_wire2),
				.aclr (),
				.almost_empty (),
				.almost_full (),
				.sclr (),
				.usedw ());
	defparam
		scfifo_component.add_ram_output_register = "OFF",
		scfifo_component.intended_device_family = "Cyclone V",
		scfifo_component.lpm_hint = "RAM_BLOCK_TYPE=MLAB",
		scfifo_component.lpm_numwords = 4,
		scfifo_component.lpm_showahead = "ON",
		scfifo_component.lpm_type = "scfifo",
		scfifo_component.lpm_width = 35,
		scfifo_component.lpm_widthu = 2,
		scfifo_component.overflow_checking = "ON",
		scfifo_component.underflow_checking = "ON",
		scfifo_component.use_eab = "ON";

endmodule

// ============================================================
// CNX file retrieval info
// ============================================================
// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
// Retrieval info: PRIVATE: Clock NUMERIC "0"
// Retrieval info: PRIVATE: Depth NUMERIC "4"
// Retrieval info: PRIVATE: Empty NUMERIC "1"
// Retrieval info: PRIVATE: Full NUMERIC "1"
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0"
// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
// Retrieval info: PRIVATE: Optimize NUMERIC "0"
// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "1"
// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
// Retrieval info: PRIVATE: UsedW NUMERIC "0"
// Retrieval info: PRIVATE: Width NUMERIC "34"
// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
// Retrieval info: PRIVATE: diff_widths NUMERIC "0"
// Retrieval info: PRIVATE: msb_usedw NUMERIC "0"
// Retrieval info: PRIVATE: output_width NUMERIC "34"
// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
// Retrieval info: PRIVATE: rsFull NUMERIC "0"
// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
// Retrieval info: PRIVATE: wsFull NUMERIC "1"
// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
// Retrieval info: CONSTANT: LPM_HINT STRING "RAM_BLOCK_TYPE=MLAB"
// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "4"
// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON"
// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "34"
// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "2"
// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
// Retrieval info: CONSTANT: USE_EAB STRING "ON"
// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock"
// Retrieval info: USED_PORT: data 0 0 34 0 INPUT NODEFVAL "data[33..0]"
// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL "empty"
// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL "full"
// Retrieval info: USED_PORT: q 0 0 34 0 OUTPUT NODEFVAL "q[33..0]"
// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq"
// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq"
// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
// Retrieval info: CONNECT: @data 0 0 34 0 data 0 0 34 0
// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
// Retrieval info: CONNECT: q 0 0 34 0 @q 0 0 34 0
// Retrieval info: GEN_FILE: TYPE_NORMAL VDP_FIFO.v TRUE
// Retrieval info: GEN_FILE: TYPE_NORMAL VDP_FIFO.inc FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL VDP_FIFO.cmp FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL VDP_FIFO.bsf FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL VDP_FIFO_inst.v FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL VDP_FIFO_bb.v FALSE
// Retrieval info: LIB_FILE: altera_mf

	wire  empty = sub_wire0;
	wire  full = sub_wire1;


/* This file is part of JT12.

    JT12 program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JT12 program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with JT12.  If not, see <http://www.gnu.org/licenses/>.

    Author: Jose Tejada Gomez. Twitter: @topapate
    Version: 1.0
    Date: 21-03-2019
*/

module jt12_dout(
    // input             rst_n,
    input             clk,        // CPU clock
    input             flag_A,
    input             flag_B,
    input             busy,
    input      [5:0]  adpcma_flags,
    input             adpcmb_flag,
    input      [7:0]  psg_dout,
    input      [1:0]  addr,
    output reg [7:0]  dout
);

parameter use_ssg=0, use_adpcm=0;

always @(posedge clk) begin

    casez( addr )
        2'b00: dout <= {busy, 5'd0, flag_B, flag_A }; // YM2203
        2'b01: dout <= (use_ssg  ==1) ? psg_dout : {busy, 5'd0, flag_B, flag_A };
        2'b1?: dout <= (use_adpcm==1) ?
            { adpcmb_flag, 1'b0, adpcma_flags } :


ece_4305/M6 to M7 - Vanilla System/HDL/mmio_sys_vanilla.sv

`include "chu_io_map.svh"
module mmio_sys_vanilla
#(
   parameter N_SW = 8,
   parameter N_LED = 8
)
(
   input logic clk,
   input  logic reset,
   // FPro bus
   input  logic mmio_cs,
   input  logic mmio_wr,
   input  logic mmio_rd,
   input  logic [20:0] mmio_addr, // 11 LSB used; 2^6 slots; 2^5 reg each
   input  logic [31:0] mmio_wr_data,
   output logic [31:0] mmio_rd_data,
   // switches and LEDs
   input logic [N_SW-1:0] sw,
   output logic [N_LED-1:0] led,
   // uart
   input logic rx,
   output logic tx
);

   // declaration
   logic [63:0] mem_rd_array;
   logic [63:0] mem_wr_array;
   logic [63:0] cs_array;
   logic [4:0] reg_addr_array [63:0];
   logic [31:0] rd_data_array [63:0];
   logic [31:0] wr_data_array [63:0];

   // body
   // instantiate mmio controller
   chu_mmio_controller ctrl_unit
   (.clk(clk),
    .reset(reset),
    .mmio_cs(mmio_cs),
    .mmio_wr(mmio_wr),
    .mmio_rd(mmio_rd),
    .mmio_addr(mmio_addr),
    .mmio_wr_data(mmio_wr_data),
    .mmio_rd_data(mmio_rd_data),
    // slot interface
    .slot_cs_array(cs_array),
    .slot_mem_rd_array(mem_rd_array),
    .slot_mem_wr_array(mem_wr_array),
    .slot_reg_addr_array(reg_addr_array),
    .slot_rd_data_array(rd_data_array),

   // slot 0: system timer
   chu_timer timer_slot0
   (.clk(clk),
    .reset(reset),
    .cs(cs_array[`S0_SYS_TIMER]),
    .read(mem_rd_array[`S0_SYS_TIMER]),
    .write(mem_wr_array[`S0_SYS_TIMER]),
    .addr(reg_addr_array[`S0_SYS_TIMER]),
    .rd_data(rd_data_array[`S0_SYS_TIMER]),
    .wr_data(wr_data_array[`S0_SYS_TIMER])
    );

   // slot 1: UART
   chu_uart uart_slot1
   (.clk(clk),
    .reset(reset),
    .cs(cs_array[`S1_UART1]),
    .read(mem_rd_array[`S1_UART1]),
    .write(mem_wr_array[`S1_UART1]),
    .addr(reg_addr_array[`S1_UART1]),
    .rd_data(rd_data_array[`S1_UART1]),
    .wr_data(wr_data_array[`S1_UART1]),
    .tx(tx),
    .rx(rx)
    );
   //assign rd_data_array[1] = 32'h00000000;

   // slot 2: gpo
   chu_gpo #(.W(N_LED)) gpo_slot2
   (.clk(clk),
    .reset(reset),
    .cs(cs_array[`S2_LED]),
    .read(mem_rd_array[`S2_LED]),
    .write(mem_wr_array[`S2_LED]),
    .addr(reg_addr_array[`S2_LED]),
    .rd_data(rd_data_array[`S2_LED]),
    .wr_data(wr_data_array[`S2_LED]),
    .dout(led)
    );

   // slot 3: gpi
   chu_gpi #(.W(N_SW)) gpi_slot3
   (.clk(clk),
    .reset(reset),
    .cs(cs_array[`S3_SW]),
    .read(mem_rd_array[`S3_SW]),
    .write(mem_wr_array[`S3_SW]),
    .addr(reg_addr_array[`S3_SW]),
    .rd_data(rd_data_array[`S3_SW]),
    .wr_data(wr_data_array[`S3_SW]),
    .din(sw)
    );

   // assign 0's to all unused slot rd_data signals
   generate
      genvar i;
      for (i=4; i<64; i=i+1) begin:  unused_slot_gen
         assign rd_data_array[i] = 32'hffffffff;
      end
   endgenerate
endmodule

   // slot interface
   //output wire [63:0] slot_cs_array,
   //output wire [63:0] slot_mem_rd_array,
   //output wire [63:0] slot_mem_wr_array,
   //output wire [4:0]  slot_reg_addr_array [0:63],
   //input wire  [31:0] slot_rd_data_array [63:0],
   //output wire [31:0] slot_wr_data_array [63:0]
   // verilog not allow 2d-array port
   //output wire [64*4-1:0]  slot_reg_addr_1d,
   //input wire  [64*32-1:0] slot_rd_data_1d,
   //output wire [64*32-1:0] slot_wr_data_1d

//entity mmio_sys_vanilla is
//   generic(
//     N_LED: integer;
//     N_SW: integer
//	);
//   port(
//      -- FPro bus
//      clk          : in  std_logic;
//      reset        : in  std_logic;
//      mmio_cs      : in  std_logic;
//      mmio_wr      : in  std_logic;
//      mmio_rd      : in  std_logic;
//      mmio_addr    : in  std_logic_vector(20 downto 0); -- only 11 LSBs used
//      mmio_wr_data : in  std_logic_vector(31 downto 0);
//      mmio_rd_data : out std_logic_vector(31 downto 0);
//      -- switches and LEDs
//      sw           : in  std_logic_vector(N_SW-1 downto 0);
//      led          : out std_logic_vector(N_LED-1 downto 0);
//      -- uart
//      rx           : in  std_logic;
//      tx           : out std_logic
//   );
//end mmio_sys_vanilla;
//
//architecture arch of mmio_sys_vanilla is
//   signal cs_array       : std_logic_vector(63 downto 0);
//   signal reg_addr_array : slot_2d_reg_type;
//   signal mem_rd_array   : std_logic_vector(63 downto 0);
//   signal mem_wr_array   : std_logic_vector(63 downto 0);
//   signal rd_data_array  : slot_2d_data_type;
//   signal wr_data_array  : slot_2d_data_type;
//
//begin
//   --******************************************************************
//   --  MMIO controller instantiation
//   --******************************************************************
//   ctrl_unit : entity work.chu_mmio_controller
//      port map(
//         -- FPro bus interface
//         mmio_cs             => mmio_cs,
//         mmio_wr             => mmio_wr,
//         mmio_rd             => mmio_rd,
//         mmio_addr           => mmio_addr,
//         mmio_wr_data        => mmio_wr_data,
//         mmio_rd_data        => mmio_rd_data,
//         -- 64 slot interface
//         slot_cs_array       => cs_array,
//         slot_reg_addr_array => reg_addr_array,
//         slot_mem_rd_array   => mem_rd_array,
//         slot_mem_wr_array   => mem_wr_array,
//         slot_rd_data_array  => rd_data_array,
//         slot_wr_data_array  => wr_data_array
//      );
//
//   --******************************************************************
//   -- IO slots instantiations
//   --******************************************************************
//   -- slot 0: system timer
//   timer_slot0 : entity work.chu_timer
//      port map(
//         clk           => clk,
//         reset         => reset,
//         cs            => cs_array[S0_SYS_TIMER],
//         read          => mem_rd_array[S0_SYS_TIMER],
//         write         => mem_wr_array[S0_SYS_TIMER],
//         addr          => reg_addr_array[S0_SYS_TIMER],
//         rd_data       => rd_data_array[S0_SYS_TIMER],
//         wr_data       => wr_data_array[S0_SYS_TIMER]
//      );
//
//   -- slot 1: uart1
//   uart1_slot1 : entity work.chu_uart
//      generic map(FIFO_DEPTH_BIT => 6)
//      port map(
//         clk     => clk,
//         reset   => reset,
//         cs      => cs_array[S1_UART],
//         read    => mem_rd_array[S1_UART],
//         write   => mem_wr_array[S1_UART],
//         addr    => reg_addr_array[S1_UART],
//         rd_data => rd_data_array[S1_UART],
//         wr_data => wr_data_array[S1_UART],
//         -- external signals
//         tx      => tx,
//         rx      => rx
//      );
//
//   -- slot 2: GPO for LEDs
//   gpo_slot2 : entity work.chu_gpo
//      generic map(W => N_LED)
//      port map(
//         clk     => clk,
//         reset   => reset,
//         cs      => cs_array[S2_LED],
//         read    => mem_rd_array[S2_LED],
//         write   => mem_wr_array[S2_LED],
//         addr    => reg_addr_array[S2_LED],
//         rd_data => rd_data_array[S2_LED],
//         wr_data => wr_data_array[S2_LED],
//         -- external signal
//         dout    => led
//      );
//
//   -- slot 3: input port for switches
//   gpi_slot3 : entity work.chu_gpi
//      generic map(W => N_SW)
//      port map(
//         clk     => clk,
//         reset   => reset,
//         cs      => cs_array[S3_SW],
//         read    => mem_rd_array[S3_SW],
//         write   => mem_wr_array[S3_SW],
//         addr    => reg_addr_array[S3_SW],
//         rd_data => rd_data_array[S3_SW],
//         wr_data => wr_data_array[S3_SW],
//         -- external signal
//         din     => sw
//      );
//
//   -- assign 0's to all unused slot rd_data signals
//   gen_unused_slot : for i in 4 to 63 generate
//      rd_data_array(i) <= (others => '0');
//   end generate gen_unused_slot;
//end arch;

    .slot_wr_data_array(wr_data_array)
    );


ece_4305/M8 to M 13 - Sampler System/HDL/uart/baud_gen.sv

// baud rate generater (divisor)
// divided by (dvsr+1)
// Listing 12.1
module baud_gen
   (
    input  logic clk, reset,
    input  logic [10:0] dvsr,
    output logic tick
   );

   // declaration
   logic [10:0] r_reg;
   logic [10:0] r_next;

   // body
   // register
   always_ff @(posedge clk, posedge reset)
      if (reset)
         r_reg <= 0;
      else
         r_reg <= r_next;

   // next-state logic
   assign r_next = (r_reg==dvsr) ? 0 : r_reg + 1;
   // output logic


// Write an Assertion for the following condition
//The signal A should change on every posedge of the clock and  it should be stable during negedge of the clock
module ass;

    @(posedge clk) $changed(a);
  endsequence

  sequence seq_2;
    @(negedge clk) $stable(a);
  endsequence

  //calling assert property
    a_1 : assert property(seq_1);
    a_2: assert property(seq_2);

  initial begin
    $dumpfile("dump.vcd"); $dumpvars;
  end

endmodule

  bit clk, a;
  always #5 clk = ~clk; //clock generation

  initial begin
         a = 1;


module jk_ff_tb();
reg j,k, clk;
wire q, qbar;

jk_ff dut(.q(q), .qbar(qbar), .j(j), .k(k), .clk(clk));

initial
$monitor("simtime = %g, clk = %b, j = %b, k = %b, q = %b, qbar = %b", $time, clk, j, k, q, qbar);

initial
begin
  clk=0;
     forever #10 clk = ~clk;
end


/*Copyright 2020-2021 T-Head Semiconductor Co., Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// &ModuleBeg; @23
module pa_fdsu_top(
  cp0_fpu_icg_en,
  cp0_fpu_xx_dqnan,
  cp0_yy_clk_en,
  cpurst_b,
  ctrl_fdsu_ex1_sel,
  ctrl_xx_ex1_cmplt_dp,
  ctrl_xx_ex1_inst_vld,
  ctrl_xx_ex1_stall,
  ctrl_xx_ex1_warm_up,
  ctrl_xx_ex2_warm_up,
  ctrl_xx_ex3_warm_up,
  dp_xx_ex1_cnan,
  dp_xx_ex1_id,
  dp_xx_ex1_inf,
  dp_xx_ex1_qnan,
  dp_xx_ex1_rm,
  dp_xx_ex1_snan,
  dp_xx_ex1_zero,
  fdsu_fpu_debug_info,
  fdsu_fpu_ex1_cmplt,
  fdsu_fpu_ex1_cmplt_dp,
  fdsu_fpu_ex1_fflags,
  fdsu_fpu_ex1_special_sel,
  fdsu_fpu_ex1_special_sign,
  fdsu_fpu_ex1_stall,
  fdsu_fpu_no_op,
  fdsu_frbus_data,
  fdsu_frbus_fflags,
  fdsu_frbus_freg,
  fdsu_frbus_wb_vld,
  forever_cpuclk,
  frbus_fdsu_wb_grant,
  idu_fpu_ex1_dst_freg,
  idu_fpu_ex1_eu_sel,
  idu_fpu_ex1_func,
  idu_fpu_ex1_srcf0,
  idu_fpu_ex1_srcf1,
  pad_yy_icg_scan_en,
  rtu_xx_ex1_cancel,
  rtu_xx_ex2_cancel,
  rtu_yy_xx_async_flush,
  rtu_yy_xx_flush
);

// &Ports; @24
input           cp0_fpu_icg_en;
input           cp0_fpu_xx_dqnan;
input           cp0_yy_clk_en;
input           cpurst_b;
input           ctrl_fdsu_ex1_sel;
input           ctrl_xx_ex1_cmplt_dp;
input           ctrl_xx_ex1_inst_vld;
input           ctrl_xx_ex1_stall;
input           ctrl_xx_ex1_warm_up;
input           ctrl_xx_ex2_warm_up;
input           ctrl_xx_ex3_warm_up;
input   [2 :0]  dp_xx_ex1_cnan;
input   [2 :0]  dp_xx_ex1_id;
input   [2 :0]  dp_xx_ex1_inf;
input   [2 :0]  dp_xx_ex1_qnan;
input   [2 :0]  dp_xx_ex1_rm;
input   [2 :0]  dp_xx_ex1_snan;
input   [2 :0]  dp_xx_ex1_zero;
input           forever_cpuclk;
input           frbus_fdsu_wb_grant;
input   [4 :0]  idu_fpu_ex1_dst_freg;
input   [2 :0]  idu_fpu_ex1_eu_sel;
input   [9 :0]  idu_fpu_ex1_func;
input   [31:0]  idu_fpu_ex1_srcf0;
input   [31:0]  idu_fpu_ex1_srcf1;
input           pad_yy_icg_scan_en;
input           rtu_xx_ex1_cancel;
input           rtu_xx_ex2_cancel;
input           rtu_yy_xx_async_flush;
input           rtu_yy_xx_flush;
output  [4 :0]  fdsu_fpu_debug_info;
output          fdsu_fpu_ex1_cmplt;
output          fdsu_fpu_ex1_cmplt_dp;
output  [4 :0]  fdsu_fpu_ex1_fflags;
output  [7 :0]  fdsu_fpu_ex1_special_sel;
output  [3 :0]  fdsu_fpu_ex1_special_sign;
output          fdsu_fpu_ex1_stall;
output          fdsu_fpu_no_op;
output  [31:0]  fdsu_frbus_data;
output  [4 :0]  fdsu_frbus_fflags;
output  [4 :0]  fdsu_frbus_freg;
output          fdsu_frbus_wb_vld;

// &Regs; @25

// &Wires; @26
wire            cp0_fpu_icg_en;
wire            cp0_fpu_xx_dqnan;
wire            cp0_yy_clk_en;
wire            cpurst_b;
wire            ctrl_fdsu_ex1_sel;
wire            ctrl_xx_ex1_cmplt_dp;
wire            ctrl_xx_ex1_inst_vld;
wire            ctrl_xx_ex1_stall;

wire            ctrl_xx_ex2_warm_up;
wire            ctrl_xx_ex3_warm_up;
wire    [2 :0]  dp_xx_ex1_cnan;
wire    [2 :0]  dp_xx_ex1_id;
wire    [2 :0]  dp_xx_ex1_inf;
wire    [2 :0]  dp_xx_ex1_qnan;
wire    [2 :0]  dp_xx_ex1_rm;
wire    [2 :0]  dp_xx_ex1_snan;
wire    [2 :0]  dp_xx_ex1_zero;
wire            ex1_div;
wire    [23:0]  ex1_divisor;
wire    [12:0]  ex1_expnt_adder_op0;
wire    [12:0]  ex1_expnt_adder_op1;
wire            ex1_of_result_lfn;
wire            ex1_op0_id;
wire            ex1_op0_norm;
wire            ex1_op0_sign;
wire            ex1_op1_id;
wire            ex1_op1_id_vld;
wire            ex1_op1_norm;
wire            ex1_op1_sel;
wire    [12:0]  ex1_oper_id_expnt;
wire    [12:0]  ex1_oper_id_expnt_f;
wire    [51:0]  ex1_oper_id_frac;
wire    [51:0]  ex1_oper_id_frac_f;
wire            ex1_pipedown;
wire            ex1_pipedown_gate;
wire    [31:0]  ex1_remainder;
wire            ex1_result_sign;
wire    [2 :0]  ex1_rm;
wire            ex1_save_op0;
wire            ex1_save_op0_gate;
wire            ex1_sqrt;
wire            ex1_srt_skip;
wire    [9 :0]  ex2_expnt_adder_op0;
wire            ex2_of;
wire            ex2_pipe_clk;
wire            ex2_pipedown;
wire            ex2_potnt_of;
wire            ex2_potnt_uf;
wire            ex2_result_inf;
wire            ex2_result_lfn;
wire            ex2_rslt_denorm;
wire    [9 :0]  ex2_srt_expnt_rst;
wire            ex2_srt_first_round;
wire            ex2_uf;
wire            ex2_uf_srt_skip;
wire    [9 :0]  ex3_expnt_adjust_result;
wire    [25:0]  ex3_frac_final_rst;
wire            ex3_pipedown;
wire            ex3_rslt_denorm;
wire            fdsu_ex1_sel;
wire            fdsu_ex3_id_srt_skip;
wire            fdsu_ex3_rem_sign;
wire            fdsu_ex3_rem_zero;
wire    [23:0]  fdsu_ex3_result_denorm_round_add_num;
wire            fdsu_ex4_denorm_to_tiny_frac;
wire    [25:0]  fdsu_ex4_frac;
wire            fdsu_ex4_nx;
wire    [1 :0]  fdsu_ex4_potnt_norm;
wire            fdsu_ex4_result_nor;
wire    [4 :0]  fdsu_fpu_debug_info;
wire            fdsu_fpu_ex1_cmplt;
wire            fdsu_fpu_ex1_cmplt_dp;
wire    [4 :0]  fdsu_fpu_ex1_fflags;
wire    [7 :0]  fdsu_fpu_ex1_special_sel;
wire    [3 :0]  fdsu_fpu_ex1_special_sign;
wire            fdsu_fpu_ex1_stall;
wire            fdsu_fpu_no_op;
wire    [31:0]  fdsu_frbus_data;
wire    [4 :0]  fdsu_frbus_fflags;
wire    [4 :0]  fdsu_frbus_freg;
wire            fdsu_frbus_wb_vld;
wire            fdsu_yy_div;
wire    [9 :0]  fdsu_yy_expnt_rst;
wire            fdsu_yy_of;
wire            fdsu_yy_of_rm_lfn;
wire            fdsu_yy_op0_norm;
wire            fdsu_yy_op1_norm;
wire            fdsu_yy_potnt_of;
wire            fdsu_yy_potnt_uf;
wire            fdsu_yy_result_inf;
wire            fdsu_yy_result_lfn;
wire            fdsu_yy_result_sign;
wire    [2 :0]  fdsu_yy_rm;
wire            fdsu_yy_rslt_denorm;
wire            fdsu_yy_sqrt;
wire            fdsu_yy_uf;
wire    [4 :0]  fdsu_yy_wb_freg;
wire            forever_cpuclk;
wire            frbus_fdsu_wb_grant;
wire    [4 :0]  idu_fpu_ex1_dst_freg;
wire    [2 :0]  idu_fpu_ex1_eu_sel;
wire    [9 :0]  idu_fpu_ex1_func;
wire    [31:0]  idu_fpu_ex1_srcf0;
wire    [31:0]  idu_fpu_ex1_srcf1;
wire            pad_yy_icg_scan_en;
wire            rtu_xx_ex1_cancel;
wire            rtu_xx_ex2_cancel;
wire            rtu_yy_xx_async_flush;
wire            rtu_yy_xx_flush;
wire            srt_remainder_zero;
wire            srt_sm_on;
wire    [29:0]  total_qt_rt_30;

// &Instance("pa_fdsu_special"); @29
pa_fdsu_special  x_pa_fdsu_special (
  .cp0_fpu_xx_dqnan          (cp0_fpu_xx_dqnan         ),
  .dp_xx_ex1_cnan            (dp_xx_ex1_cnan           ),
  .dp_xx_ex1_id              (dp_xx_ex1_id             ),
  .dp_xx_ex1_inf             (dp_xx_ex1_inf            ),
  .dp_xx_ex1_qnan            (dp_xx_ex1_qnan           ),
  .dp_xx_ex1_snan            (dp_xx_ex1_snan           ),
  .dp_xx_ex1_zero            (dp_xx_ex1_zero           ),
  .ex1_div                   (ex1_div                  ),
  .ex1_op0_id                (ex1_op0_id               ),
  .ex1_op0_norm              (ex1_op0_norm             ),
  .ex1_op0_sign              (ex1_op0_sign             ),
  .ex1_op1_id                (ex1_op1_id               ),
  .ex1_op1_norm              (ex1_op1_norm             ),
  .ex1_result_sign           (ex1_result_sign          ),
  .ex1_sqrt                  (ex1_sqrt                 ),
  .ex1_srt_skip              (ex1_srt_skip             ),
  .fdsu_fpu_ex1_fflags       (fdsu_fpu_ex1_fflags      ),
  .fdsu_fpu_ex1_special_sel  (fdsu_fpu_ex1_special_sel ),
  .fdsu_fpu_ex1_special_sign (fdsu_fpu_ex1_special_sign)
);

// &Instance("pa_fdsu_prepare"); @30
pa_fdsu_prepare  x_pa_fdsu_prepare (
  .dp_xx_ex1_rm        (dp_xx_ex1_rm       ),
  .ex1_div             (ex1_div            ),
  .ex1_divisor         (ex1_divisor        ),
  .ex1_expnt_adder_op0 (ex1_expnt_adder_op0),
  .ex1_expnt_adder_op1 (ex1_expnt_adder_op1),
  .ex1_of_result_lfn   (ex1_of_result_lfn  ),
  .ex1_op0_id          (ex1_op0_id         ),
  .ex1_op0_sign        (ex1_op0_sign       ),
  .ex1_op1_id          (ex1_op1_id         ),
  .ex1_op1_id_vld      (ex1_op1_id_vld     ),
  .ex1_op1_sel         (ex1_op1_sel        ),
  .ex1_oper_id_expnt   (ex1_oper_id_expnt  ),
  .ex1_oper_id_expnt_f (ex1_oper_id_expnt_f),
  .ex1_oper_id_frac    (ex1_oper_id_frac   ),
  .ex1_oper_id_frac_f  (ex1_oper_id_frac_f ),
  .ex1_remainder       (ex1_remainder      ),
  .ex1_result_sign     (ex1_result_sign    ),
  .ex1_rm              (ex1_rm             ),
  .ex1_sqrt            (ex1_sqrt           ),
  .fdsu_ex1_sel        (fdsu_ex1_sel       ),
  .idu_fpu_ex1_func    (idu_fpu_ex1_func   ),
  .idu_fpu_ex1_srcf0   (idu_fpu_ex1_srcf0  ),
  .idu_fpu_ex1_srcf1   (idu_fpu_ex1_srcf1  )
);

// &Instance("pa_fdsu_srt"); @32
// &Instance("pa_fdsu_round"); @33
// &Instance("pa_fdsu_pack"); @34
// &Instance("pa_fdsu_srt_single", "x_pa_fdsu_srt"); @36
pa_fdsu_srt_single  x_pa_fdsu_srt (
  .cp0_fpu_icg_en                       (cp0_fpu_icg_en                      ),
  .cp0_yy_clk_en                        (cp0_yy_clk_en                       ),
  .ex1_divisor                          (ex1_divisor                         ),
  .ex1_expnt_adder_op1                  (ex1_expnt_adder_op1                 ),
  .ex1_oper_id_frac                     (ex1_oper_id_frac                    ),
  .ex1_oper_id_frac_f                   (ex1_oper_id_frac_f                  ),
  .ex1_pipedown                         (ex1_pipedown                        ),
  .ex1_pipedown_gate                    (ex1_pipedown_gate                   ),
  .ex1_remainder                        (ex1_remainder                       ),
  .ex1_save_op0                         (ex1_save_op0                        ),
  .ex1_save_op0_gate                    (ex1_save_op0_gate                   ),
  .ex2_expnt_adder_op0                  (ex2_expnt_adder_op0                 ),
  .ex2_of                               (ex2_of                              ),
  .ex2_pipe_clk                         (ex2_pipe_clk                        ),
  .ex2_pipedown                         (ex2_pipedown                        ),
  .ex2_potnt_of                         (ex2_potnt_of                        ),
  .ex2_potnt_uf                         (ex2_potnt_uf                        ),
  .ex2_result_inf                       (ex2_result_inf                      ),
  .ex2_result_lfn                       (ex2_result_lfn                      ),
  .ex2_rslt_denorm                      (ex2_rslt_denorm                     ),
  .ex2_srt_expnt_rst                    (ex2_srt_expnt_rst                   ),
  .ex2_srt_first_round                  (ex2_srt_first_round                 ),
  .ex2_uf                               (ex2_uf                              ),
  .ex2_uf_srt_skip                      (ex2_uf_srt_skip                     ),
  .ex3_frac_final_rst                   (ex3_frac_final_rst                  ),
  .ex3_pipedown                         (ex3_pipedown                        ),
  .fdsu_ex3_id_srt_skip                 (fdsu_ex3_id_srt_skip                ),
  .fdsu_ex3_rem_sign                    (fdsu_ex3_rem_sign                   ),
  .fdsu_ex3_rem_zero                    (fdsu_ex3_rem_zero                   ),
  .fdsu_ex3_result_denorm_round_add_num (fdsu_ex3_result_denorm_round_add_num),
  .fdsu_ex4_frac                        (fdsu_ex4_frac                       ),
  .fdsu_yy_div                          (fdsu_yy_div                         ),
  .fdsu_yy_of_rm_lfn                    (fdsu_yy_of_rm_lfn                   ),
  .fdsu_yy_op0_norm                     (fdsu_yy_op0_norm                    ),
  .fdsu_yy_op1_norm                     (fdsu_yy_op1_norm                    ),
  .fdsu_yy_sqrt                         (fdsu_yy_sqrt                        ),
  .forever_cpuclk                       (forever_cpuclk                      ),
  .pad_yy_icg_scan_en                   (pad_yy_icg_scan_en                  ),
  .srt_remainder_zero                   (srt_remainder_zero                  ),
  .srt_sm_on                            (srt_sm_on                           ),
  .total_qt_rt_30                       (total_qt_rt_30                      )
);

// &Instance("pa_fdsu_round_single", "x_pa_fdsu_round"); @37
pa_fdsu_round_single  x_pa_fdsu_round (
  .cp0_fpu_icg_en                       (cp0_fpu_icg_en                      ),
  .cp0_yy_clk_en                        (cp0_yy_clk_en                       ),
  .ex3_expnt_adjust_result              (ex3_expnt_adjust_result             ),
  .ex3_frac_final_rst                   (ex3_frac_final_rst                  ),
  .ex3_pipedown                         (ex3_pipedown                        ),
  .ex3_rslt_denorm                      (ex3_rslt_denorm                     ),
  .fdsu_ex3_id_srt_skip                 (fdsu_ex3_id_srt_skip                ),
  .fdsu_ex3_rem_sign                    (fdsu_ex3_rem_sign                   ),
  .fdsu_ex3_rem_zero                    (fdsu_ex3_rem_zero                   ),
  .fdsu_ex3_result_denorm_round_add_num (fdsu_ex3_result_denorm_round_add_num),
  .fdsu_ex4_denorm_to_tiny_frac         (fdsu_ex4_denorm_to_tiny_frac        ),
  .fdsu_ex4_nx                          (fdsu_ex4_nx                         ),
  .fdsu_ex4_potnt_norm                  (fdsu_ex4_potnt_norm                 ),
  .fdsu_ex4_result_nor                  (fdsu_ex4_result_nor                 ),
  .fdsu_yy_expnt_rst                    (fdsu_yy_expnt_rst                   ),
  .fdsu_yy_result_inf                   (fdsu_yy_result_inf                  ),
  .fdsu_yy_result_lfn                   (fdsu_yy_result_lfn                  ),
  .fdsu_yy_result_sign                  (fdsu_yy_result_sign                 ),
  .fdsu_yy_rm                           (fdsu_yy_rm                          ),
  .fdsu_yy_rslt_denorm                  (fdsu_yy_rslt_denorm                 ),
  .forever_cpuclk                       (forever_cpuclk                      ),
  .pad_yy_icg_scan_en                   (pad_yy_icg_scan_en                  ),
  .total_qt_rt_30                       (total_qt_rt_30                      )
);

// &Instance("pa_fdsu_pack_single", "x_pa_fdsu_pack"); @38
pa_fdsu_pack_single  x_pa_fdsu_pack (
  .fdsu_ex4_denorm_to_tiny_frac (fdsu_ex4_denorm_to_tiny_frac),
  .fdsu_ex4_frac                (fdsu_ex4_frac               ),
  .fdsu_ex4_nx                  (fdsu_ex4_nx                 ),
  .fdsu_ex4_potnt_norm          (fdsu_ex4_potnt_norm         ),
  .fdsu_ex4_result_nor          (fdsu_ex4_result_nor         ),
  .fdsu_frbus_data              (fdsu_frbus_data             ),
  .fdsu_frbus_fflags            (fdsu_frbus_fflags           ),
  .fdsu_frbus_freg              (fdsu_frbus_freg             ),
  .fdsu_yy_expnt_rst            (fdsu_yy_expnt_rst           ),
  .fdsu_yy_of                   (fdsu_yy_of                  ),
  .fdsu_yy_of_rm_lfn            (fdsu_yy_of_rm_lfn           ),
  .fdsu_yy_potnt_of             (fdsu_yy_potnt_of            ),
  .fdsu_yy_potnt_uf             (fdsu_yy_potnt_uf            ),
  .fdsu_yy_result_inf           (fdsu_yy_result_inf          ),
  .fdsu_yy_result_lfn           (fdsu_yy_result_lfn          ),
  .fdsu_yy_result_sign          (fdsu_yy_result_sign         ),
  .fdsu_yy_rslt_denorm          (fdsu_yy_rslt_denorm         ),
  .fdsu_yy_uf                   (fdsu_yy_uf                  ),
  .fdsu_yy_wb_freg              (fdsu_yy_wb_freg             )
);

// &Instance("pa_fdsu_ctrl"); @41
pa_fdsu_ctrl  x_pa_fdsu_ctrl (
  .cp0_fpu_icg_en          (cp0_fpu_icg_en         ),
  .cp0_yy_clk_en           (cp0_yy_clk_en          ),
  .cpurst_b                (cpurst_b               ),
  .ctrl_fdsu_ex1_sel       (ctrl_fdsu_ex1_sel      ),
  .ctrl_xx_ex1_cmplt_dp    (ctrl_xx_ex1_cmplt_dp   ),
  .ctrl_xx_ex1_inst_vld    (ctrl_xx_ex1_inst_vld   ),
  .ctrl_xx_ex1_stall       (ctrl_xx_ex1_stall      ),
  .ctrl_xx_ex1_warm_up     (ctrl_xx_ex1_warm_up    ),
  .ctrl_xx_ex2_warm_up     (ctrl_xx_ex2_warm_up    ),
  .ctrl_xx_ex3_warm_up     (ctrl_xx_ex3_warm_up    ),
  .ex1_div                 (ex1_div                ),
  .ex1_expnt_adder_op0     (ex1_expnt_adder_op0    ),
  .ex1_of_result_lfn       (ex1_of_result_lfn      ),
  .ex1_op0_id              (ex1_op0_id             ),
  .ex1_op0_norm            (ex1_op0_norm           ),
  .ex1_op1_id_vld          (ex1_op1_id_vld         ),
  .ex1_op1_norm            (ex1_op1_norm           ),
  .ex1_op1_sel             (ex1_op1_sel            ),
  .ex1_oper_id_expnt       (ex1_oper_id_expnt      ),
  .ex1_oper_id_expnt_f     (ex1_oper_id_expnt_f    ),
  .ex1_pipedown            (ex1_pipedown           ),
  .ex1_pipedown_gate       (ex1_pipedown_gate      ),
  .ex1_result_sign         (ex1_result_sign        ),
  .ex1_rm                  (ex1_rm                 ),
  .ex1_save_op0            (ex1_save_op0           ),
  .ex1_save_op0_gate       (ex1_save_op0_gate      ),
  .ex1_sqrt                (ex1_sqrt               ),
  .ex1_srt_skip            (ex1_srt_skip           ),
  .ex2_expnt_adder_op0     (ex2_expnt_adder_op0    ),
  .ex2_of                  (ex2_of                 ),
  .ex2_pipe_clk            (ex2_pipe_clk           ),
  .ex2_pipedown            (ex2_pipedown           ),
  .ex2_potnt_of            (ex2_potnt_of           ),
  .ex2_potnt_uf            (ex2_potnt_uf           ),
  .ex2_result_inf          (ex2_result_inf         ),
  .ex2_result_lfn          (ex2_result_lfn         ),
  .ex2_rslt_denorm         (ex2_rslt_denorm        ),
  .ex2_srt_expnt_rst       (ex2_srt_expnt_rst      ),
  .ex2_srt_first_round     (ex2_srt_first_round    ),
  .ex2_uf                  (ex2_uf                 ),
  .ex2_uf_srt_skip         (ex2_uf_srt_skip        ),
  .ex3_expnt_adjust_result (ex3_expnt_adjust_result),
  .ex3_pipedown            (ex3_pipedown           ),
  .ex3_rslt_denorm         (ex3_rslt_denorm        ),
  .fdsu_ex1_sel            (fdsu_ex1_sel           ),
  .fdsu_fpu_debug_info     (fdsu_fpu_debug_info    ),
  .fdsu_fpu_ex1_cmplt      (fdsu_fpu_ex1_cmplt     ),
  .fdsu_fpu_ex1_cmplt_dp   (fdsu_fpu_ex1_cmplt_dp  ),
  .fdsu_fpu_ex1_stall      (fdsu_fpu_ex1_stall     ),
  .fdsu_fpu_no_op          (fdsu_fpu_no_op         ),
  .fdsu_frbus_wb_vld       (fdsu_frbus_wb_vld      ),
  .fdsu_yy_div             (fdsu_yy_div            ),
  .fdsu_yy_expnt_rst       (fdsu_yy_expnt_rst      ),
  .fdsu_yy_of              (fdsu_yy_of             ),
  .fdsu_yy_of_rm_lfn       (fdsu_yy_of_rm_lfn      ),
  .fdsu_yy_op0_norm        (fdsu_yy_op0_norm       ),
  .fdsu_yy_op1_norm        (fdsu_yy_op1_norm       ),
  .fdsu_yy_potnt_of        (fdsu_yy_potnt_of       ),
  .fdsu_yy_potnt_uf        (fdsu_yy_potnt_uf       ),
  .fdsu_yy_result_inf      (fdsu_yy_result_inf     ),
  .fdsu_yy_result_lfn      (fdsu_yy_result_lfn     ),
  .fdsu_yy_result_sign     (fdsu_yy_result_sign    ),
  .fdsu_yy_rm              (fdsu_yy_rm             ),
  .fdsu_yy_rslt_denorm     (fdsu_yy_rslt_denorm    ),
  .fdsu_yy_sqrt            (fdsu_yy_sqrt           ),
  .fdsu_yy_uf              (fdsu_yy_uf             ),
  .fdsu_yy_wb_freg         (fdsu_yy_wb_freg        ),
  .forever_cpuclk          (forever_cpuclk         ),
  .frbus_fdsu_wb_grant     (frbus_fdsu_wb_grant    ),
  .idu_fpu_ex1_dst_freg    (idu_fpu_ex1_dst_freg   ),
  .idu_fpu_ex1_eu_sel      (idu_fpu_ex1_eu_sel     ),
  .pad_yy_icg_scan_en      (pad_yy_icg_scan_en     ),
  .rtu_xx_ex1_cancel       (rtu_xx_ex1_cancel      ),
  .rtu_xx_ex2_cancel       (rtu_xx_ex2_cancel      ),
  .rtu_yy_xx_async_flush   (rtu_yy_xx_async_flush  ),
  .rtu_yy_xx_flush         (rtu_yy_xx_flush        ),
  .srt_remainder_zero      (srt_remainder_zero     ),
  .srt_sm_on               (srt_sm_on              )
);

// &ModuleEnd; @44
endmodule


// Copyright 2024 OpenHW Group and Dolphin Design
//
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://solderpad.org/licenses/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1

// Contributor(s): Pascal Gouedo, Dolphin Design <pascal.gouedo@dolphin.fr>
//
// Design Name:    CV32E40P RTL Lint wrapper
//
// Description:    Wrapper file instantiating CV32E40P top and importing
//                 a configuration package to be used for RTL LINT checks.

module cv32e40p_wrapper (
    // Clock and Reset
    input logic clk_i,
    input logic rst_ni,

    input logic pulp_clock_en_i,
    input logic scan_cg_en_i,

    input logic [31:0] boot_addr_i,
    input logic [31:0] mtvec_addr_i,
    input logic [31:0] dm_halt_addr_i,
    input logic [31:0] hart_id_i,
    input logic [31:0] dm_exception_addr_i,

    // Instruction memory interface
    output logic        instr_req_o,
    input  logic        instr_gnt_i,
    input  logic        instr_rvalid_i,
    output logic [31:0] instr_addr_o,
    input  logic [31:0] instr_rdata_i,

    // Data memory interface
    output logic        data_req_o,
    input  logic        data_gnt_i,
    input  logic        data_rvalid_i,
    output logic        data_we_o,
    output logic [ 3:0] data_be_o,
    output logic [31:0] data_addr_o,
    output logic [31:0] data_wdata_o,
    input  logic [31:0] data_rdata_i,

    // Interrupt inputs
    input  logic [31:0] irq_i,
    output logic        irq_ack_o,
    output logic [ 4:0] irq_id_o,

    // Debug Interface
    input  logic debug_req_i,
    output logic debug_havereset_o,
    output logic debug_running_o,
    output logic debug_halted_o,

    // CPU Control Signals
    input  logic fetch_enable_i,
    output logic core_sleep_o
);

  import cv32e40p_config_pkg::*;

  // Instantiate the Core
  cv32e40p_top #(
      .COREV_PULP      (COREV_PULP),
      .COREV_CLUSTER   (COREV_CLUSTER),
      .FPU             (FPU),
      .FPU_ADDMUL_LAT  (FPU_ADDMUL_LAT),
      .FPU_OTHERS_LAT  (FPU_OTHERS_LAT),
      .ZFINX           (ZFINX),
      .NUM_MHPMCOUNTERS(1)
  ) top_i (
      .clk_i (clk_i),
      .rst_ni(rst_ni),

      .pulp_clock_en_i(pulp_clock_en_i),
      .scan_cg_en_i   (scan_cg_en_i),

      .boot_addr_i        (boot_addr_i),
      .mtvec_addr_i       (mtvec_addr_i),
      .dm_halt_addr_i     (dm_halt_addr_i),
      .hart_id_i          (hart_id_i),
      .dm_exception_addr_i(dm_exception_addr_i),

      .instr_req_o   (instr_req_o),
      .instr_gnt_i   (instr_gnt_i),
      .instr_rvalid_i(instr_rvalid_i),
      .instr_addr_o  (instr_addr_o),
      .instr_rdata_i (instr_rdata_i),

      .data_req_o   (data_req_o),
      .data_gnt_i   (data_gnt_i),
      .data_rvalid_i(data_rvalid_i),
      .data_we_o    (data_we_o),
      .data_be_o    (data_be_o),
      .data_addr_o  (data_addr_o),
      .data_wdata_o (data_wdata_o),
      .data_rdata_i (data_rdata_i),

      .irq_i    (irq_i),
      .irq_ack_o(irq_ack_o),
      .irq_id_o (irq_id_o),

      .debug_req_i      (debug_req_i),
      .debug_havereset_o(debug_havereset_o),
      .debug_running_o  (debug_running_o),
      .debug_halted_o   (debug_halted_o),

      .fetch_enable_i(fetch_enable_i),
      .core_sleep_o  (core_sleep_o)
  );


// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
// Author: Paul Scheffler <paulsc@iis.ee.ethz.ch>

/// This module wraps `addr_decode_dync` in its naturally-aligned power of two (NAPOT) variant,
/// alleviating the need to set the `Napot` parameter and using more descriptive `rule_t`
/// field names. See the `addr_decode`documentation for details.
module addr_decode_napot #(
  /// Highest index which can happen in a rule.
  parameter int unsigned NoIndices = 32'd0,
  /// Total number of rules.
  parameter int unsigned NoRules   = 32'd0,
  /// Address type inside the rules and to decode.
  parameter type         addr_t    = logic,
  /// Rule packed struct type.
  /// The NAPOT address decoder expects three fields in `rule_t`:
  ///
  /// typedef struct packed {
  ///   int unsigned idx;
  ///   addr_t       base;
  ///   addr_t       mask;
  /// } rule_t;
  ///
  ///  - `idx`:   index of the rule, has to be < `NoIndices`.
  ///  - `base`:  base address whose specified bits should match `addr_i`.
  ///  - `mask`:  set for bits which are to be checked to determine a match.
  parameter type         rule_t    = logic,
  /// Dependent parameter, do **not** overwite!
  ///
  /// Width of the `idx_o` output port.
  parameter int unsigned IdxWidth  = cf_math_pkg::idx_width(NoIndices),
  /// Dependent parameter, do **not** overwite!
  ///
  /// Type of the `idx_o` output port.
  parameter type         idx_t     = logic [IdxWidth-1:0]
) (
  /// Address to decode.
  input  addr_t               addr_i,
  /// Address map: rule with the highest array position wins on collision
  input  rule_t [NoRules-1:0] addr_map_i,
  /// Decoded index.
  output idx_t                idx_o,
  /// Decode is valid.
  output logic                dec_valid_o,
  /// Decode is not valid, no matching rule found.
  output logic                dec_error_o,
  /// Enable default port mapping.
  ///
  /// When not used, tie to `0`.
  input  logic                en_default_idx_i,
  /// Default port index.
  ///
  /// When `en_default_idx_i` is `1`, this will be the index when no rule matches.
  ///
  /// When not used, tie to `0`.
  input  idx_t                default_idx_i
);

  // Rename struct field names to those expected by `addr_decode`
  typedef struct packed {
    int unsigned  idx;
    addr_t        start_addr;
    addr_t        end_addr;
  } rule_range_t;

  addr_decode_dync #(

    .addr_map_i,
    .idx_o,
    .dec_valid_o,
    .dec_error_o,
    .en_default_idx_i,
    .default_idx_i,
    .config_ongoing_i ( 1'b0 )
);

endmodule

    .NoIndices ( NoIndices    ) ,
    .NoRules   ( NoRules      ),
    .addr_t    ( addr_t       ),
    .rule_t    ( rule_range_t ),


// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

/// cf_math_pkg: Constant Function Implementations of Mathematical Functions for HDL Elaboration
///
/// This package contains a collection of mathematical functions that are commonly used when defining
/// the value of constants in HDL code.  These functions are implemented as Verilog constants
/// functions.  Introduced in Verilog 2001 (IEEE Std 1364-2001), a constant function (§ 10.3.5) is a
/// function whose value can be evaluated at compile time or during elaboration.  A constant function
/// must be called with arguments that are constants.
package cf_math_pkg;

    /// Ceiled Division of Two Natural Numbers
    ///
    /// Returns the quotient of two natural numbers, rounded towards plus infinity.

        automatic longint remainder;

        `ifndef SYNTHESIS
        `ifndef COMMON_CELLS_ASSERTS_OFF
        if (dividend < 0) begin
            $fatal(1, "Dividend %0d is not a natural number!", dividend);
        end

        if (divisor < 0) begin
            $fatal(1, "Divisor %0d is not a natural number!", divisor);
        end

        if (divisor == 0) begin
            $fatal(1, "Division by zero!");
        end
        `endif
        `endif

        remainder = dividend;
        for (ceil_div = 0; remainder > 0; ceil_div++) begin
            remainder = remainder - divisor;
        end
    endfunction

    /// Index width required to be able to represent up to `num_idx` indices as a binary
    /// encoded signal.
    /// Ensures that the minimum width if an index signal is `1`, regardless of parametrization.
    ///
    /// Sample usage in type definition:
    /// As parameter:
    ///   `parameter type idx_t = logic[cf_math_pkg::idx_width(NumIdx)-1:0]`
    /// As typedef:
    ///   `typedef logic [cf_math_pkg::idx_width(NumIdx)-1:0] idx_t`
    function automatic integer unsigned idx_width (input integer unsigned num_idx);
        return (num_idx > 32'd1) ? unsigned'($clog2(num_idx)) : 32'd1;
    endfunction

endpackage

function automatic integer ceil_div (input longint dividend, input longint divisor);