Add apb directory
diff --git a/verilog/rtl/ips/apb/apb2per b/verilog/rtl/ips/apb/apb2per
deleted file mode 160000
index 537239d..0000000
--- a/verilog/rtl/ips/apb/apb2per
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 537239d4eb9110774164fd9f13283bb2fe7d0ea5
diff --git a/verilog/rtl/ips/apb/apb2per/apb2per.v b/verilog/rtl/ips/apb/apb2per/apb2per.v
new file mode 100644
index 0000000..77bf637
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb2per/apb2per.v
@@ -0,0 +1,103 @@
+module apb2per
+#(
+ parameter PER_ADDR_WIDTH = 32,
+ parameter APB_ADDR_WIDTH = 32
+)
+(
+ clk_i,
+ rst_ni,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ per_master_req_o,
+ per_master_add_o,
+ per_master_we_o,
+ per_master_wdata_o,
+ per_master_be_o,
+ per_master_gnt_i,
+ per_master_r_valid_i,
+ per_master_r_opc_i,
+ per_master_r_rdata_i
+);
+ //parameter PER_ADDR_WIDTH = 32;
+ //parameter APB_ADDR_WIDTH = 32;
+ input wire clk_i;
+ input wire rst_ni;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output wire [31:0] PRDATA;
+ output reg PREADY;
+ output wire PSLVERR;
+ output reg per_master_req_o;
+ output wire [PER_ADDR_WIDTH - 1:0] per_master_add_o;
+ output reg per_master_we_o;
+ output wire [31:0] per_master_wdata_o;
+ output wire [3:0] per_master_be_o;
+ input wire per_master_gnt_i;
+ input wire per_master_r_valid_i;
+ input wire per_master_r_opc_i;
+ input wire [31:0] per_master_r_rdata_i;
+ reg CS;
+ reg NS;
+ always @(posedge clk_i or negedge rst_ni)
+ if (rst_ni == 1'b0)
+ CS <= 1'd0;
+ else
+ CS <= NS;
+ always @(*) begin
+ per_master_we_o = 0;
+ per_master_req_o = 0;
+ PREADY = 0;
+ case (CS)
+ 1'd0:
+ if ((PSEL == 1) && (PENABLE == 1)) begin
+ per_master_req_o = 1;
+ if (PWRITE == 1)
+ per_master_we_o = 1'b1;
+ else
+ per_master_we_o = 1'b0;
+ if (per_master_gnt_i == 1) begin
+ if (PWRITE == 1) begin
+ PREADY = 1;
+ NS = 1'd0;
+ end
+ else begin
+ PREADY = 0;
+ NS = 1'd1;
+ end
+ end
+ else begin
+ PREADY = 0;
+ NS = 1'd0;
+ end
+ end
+ else begin
+ NS = 1'd0;
+ PREADY = 0;
+ end
+ 1'd1:
+ if (per_master_r_valid_i == 1) begin
+ PREADY = 1;
+ NS = 1'd0;
+ end
+ else begin
+ PREADY = 0;
+ NS = 1'd1;
+ end
+ default: NS = 1'd0;
+ endcase
+ end
+ assign PRDATA = per_master_r_rdata_i;
+ assign PSLVERR = 1'sb0;
+ assign per_master_add_o = PADDR;
+ assign per_master_wdata_o = PWDATA;
+ assign per_master_be_o = 1'sb1;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_event_unit b/verilog/rtl/ips/apb/apb_event_unit
deleted file mode 160000
index 0cd8574..0000000
--- a/verilog/rtl/ips/apb/apb_event_unit
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 0cd85740331eeec70d39ef9e68e536b6dbe16f2a
diff --git a/verilog/rtl/ips/apb/apb_event_unit/apb_event_unit.v b/verilog/rtl/ips/apb/apb_event_unit/apb_event_unit.v
new file mode 100644
index 0000000..39ef403
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_event_unit/apb_event_unit.v
@@ -0,0 +1,124 @@
+module apb_event_unit
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ clk_i,
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ irq_i,
+ event_i,
+ irq_o,
+ fetch_enable_i,
+ fetch_enable_o,
+ clk_gate_core_o,
+ core_busy_i
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire clk_i;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output reg PREADY;
+ output reg PSLVERR;
+ input wire [31:0] irq_i;
+ input wire [31:0] event_i;
+ output wire [31:0] irq_o;
+ input wire fetch_enable_i;
+ output wire fetch_enable_o;
+ output wire clk_gate_core_o;
+ input wire core_busy_i;
+ wire [31:0] events;
+ reg [2:0] psel_int;
+ wire [2:0] pready;
+ wire [2:0] pslverr;
+ wire [1:0] slave_address_int;
+ wire [95:0] prdata;
+ reg fetch_enable_ff1;
+ reg fetch_enable_ff2;
+ wire fetch_enable_int;
+ assign fetch_enable_o = fetch_enable_ff2 & fetch_enable_int;
+ assign slave_address_int = PADDR[5:4];
+ always @(*) begin
+ psel_int = 3'b000;
+ psel_int[slave_address_int] = PSEL;
+ end
+ always @(*)
+ if (psel_int != 2'b00) begin
+ PRDATA = prdata[slave_address_int * 32+:32];
+ PREADY = pready[slave_address_int];
+ PSLVERR = pslverr[slave_address_int];
+ end
+ else begin
+ PRDATA = 1'sb0;
+ PREADY = 1'b1;
+ PSLVERR = 1'b0;
+ end
+ generic_service_unit #(.APB_ADDR_WIDTH(APB_ADDR_WIDTH)) i_interrupt_unit(
+ .HCLK(HCLK),
+ .HRESETn(HRESETn),
+ .PADDR(PADDR),
+ .PWDATA(PWDATA),
+ .PWRITE(PWRITE),
+ .PSEL(psel_int[0]),
+ .PENABLE(PENABLE),
+ .PRDATA(prdata[0+:32]),
+ .PREADY(pready[0]),
+ .PSLVERR(pslverr[0]),
+ .signal_i(irq_i),
+ .irq_o(irq_o)
+ );
+ generic_service_unit #(.APB_ADDR_WIDTH(APB_ADDR_WIDTH)) i_event_unit(
+ .HCLK(HCLK),
+ .HRESETn(HRESETn),
+ .PADDR(PADDR),
+ .PWDATA(PWDATA),
+ .PWRITE(PWRITE),
+ .PSEL(psel_int[1]),
+ .PENABLE(PENABLE),
+ .PRDATA(prdata[32+:32]),
+ .PREADY(pready[1]),
+ .PSLVERR(pslverr[1]),
+ .signal_i(event_i),
+ .irq_o(events)
+ );
+ sleep_unit #(.APB_ADDR_WIDTH(APB_ADDR_WIDTH)) i_sleep_unit(
+ .HCLK(HCLK),
+ .HRESETn(HRESETn),
+ .PADDR(PADDR),
+ .PWDATA(PWDATA),
+ .PWRITE(PWRITE),
+ .PSEL(psel_int[2]),
+ .PENABLE(PENABLE),
+ .PRDATA(prdata[64+:32]),
+ .PREADY(pready[2]),
+ .PSLVERR(pslverr[2]),
+ .irq_i(|irq_o),
+ .event_i(|events),
+ .core_busy_i(core_busy_i),
+ .fetch_en_o(fetch_enable_int),
+ .clk_gate_core_o(clk_gate_core_o)
+ );
+ always @(posedge clk_i or negedge HRESETn)
+ if (~HRESETn) begin
+ fetch_enable_ff1 <= 1'b0;
+ fetch_enable_ff2 <= 1'b0;
+ end
+ else begin
+ fetch_enable_ff1 <= fetch_enable_i;
+ fetch_enable_ff2 <= fetch_enable_ff1;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_event_unit/generic_service_unit.v b/verilog/rtl/ips/apb/apb_event_unit/generic_service_unit.v
new file mode 100644
index 0000000..4da1941
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_event_unit/generic_service_unit.v
@@ -0,0 +1,102 @@
+module generic_service_unit
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ signal_i,
+ irq_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ input wire [31:0] signal_i;
+ output reg [31:0] irq_o;
+ reg [127:0] regs_q;
+ reg [127:0] regs_n;
+ reg [4:0] highest_pending_int;
+ wire [1:0] register_adr;
+ reg [31:0] irq_n;
+ assign register_adr = PADDR[3:2];
+ always @(*) begin : sv2v_autoblock_1
+ reg [0:1] _sv2v_jump;
+ _sv2v_jump = 2'b00;
+ highest_pending_int = 'b0;
+ irq_n = 32'b00000000000000000000000000000000;
+ begin : sv2v_autoblock_2
+ reg signed [31:0] i;
+ for (i = 0; i < 32; i = i + 1)
+ if (_sv2v_jump < 2'b10) begin
+ _sv2v_jump = 2'b00;
+ if (regs_q[64 + i]) begin
+ highest_pending_int = i;
+ _sv2v_jump = 2'b10;
+ end
+ end
+ if (_sv2v_jump != 2'b11)
+ _sv2v_jump = 2'b00;
+ end
+ if (_sv2v_jump == 2'b00)
+ if (regs_q[64+:32] != 'b0)
+ irq_n[highest_pending_int] = 1'b1;
+ end
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+ reg [31:0] pending_int;
+ always @(*) begin
+ regs_n = regs_q;
+ regs_n[32+:32] = 32'b00000000000000000000000000000000;
+ regs_n[0+:32] = 32'b00000000000000000000000000000000;
+ pending_int = (regs_q[96+:32] & signal_i) | regs_q[64+:32];
+ pending_int = pending_int | regs_q[32+:32];
+ begin : sv2v_autoblock_3
+ reg signed [31:0] i;
+ for (i = 0; i < 32; i = i + 1)
+ if (regs_q[i])
+ pending_int[i] = 1'b0;
+ end
+ if ((PSEL && PENABLE) && PWRITE)
+ case (register_adr)
+ 2'b00: regs_n[96+:32] = PWDATA;
+ 2'b01: pending_int = PWDATA;
+ 2'b10: regs_n[32+:32] = PWDATA;
+ 2'b11: regs_n[0+:32] = PWDATA;
+ endcase
+ regs_n[64+:32] = pending_int;
+ end
+ always @(*) begin
+ PRDATA = 'b0;
+ if ((PSEL && PENABLE) && !PWRITE)
+ case (register_adr)
+ 2'b00: PRDATA = regs_q[96+:32];
+ 2'b01: PRDATA = regs_q[64+:32];
+ default: PRDATA = 'b0;
+ endcase
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ regs_q <= {4 {32'b00000000000000000000000000000000}};
+ irq_o <= 32'b00000000000000000000000000000000;
+ end
+ else begin
+ regs_q <= regs_n;
+ irq_o <= irq_n;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_event_unit/include/defines_event_unit.sv b/verilog/rtl/ips/apb/apb_event_unit/include/defines_event_unit.sv
new file mode 100644
index 0000000..5ff98a5
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_event_unit/include/defines_event_unit.sv
@@ -0,0 +1,44 @@
+// Copyright 2017 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.
+
+///////////////////////////////////////////////
+// _____ _ _ //
+// | __ \ (_) | | //
+// | |__) |___ __ _ _ ___| |_ ___ _ __ ___ //
+// | _ // _ \/ _` | / __| __/ _ \ '__/ __| //
+// | | \ \ __/ (_| | \__ \ || __/ | \__ \ //
+// |_| \_\___|\__, |_|___/\__\___|_| |___/ //
+// __/ | //
+// |___/ //
+///////////////////////////////////////////////
+
+// total number of address space reserved for the apb_event_unit
+`define ADR_MAX_ADR 'd2 // number of bits needed to access all subunits
+
+`define IRQ 2'b00
+`define EVENT 2'b01
+`define SLEEP 2'b10
+
+// number of registers per (interrupt, event) service unit - 8 regs in total
+`define REGS_MAX_IDX 'd3 // number of bits needed to access all registers
+`define REGS_MAX_ADR 'd2
+
+`define REG_ENABLE 2'b00
+`define REG_PENDING 2'b01
+`define REG_SET_PENDING 2'b10
+`define REG_CLEAR_PENDING 2'b11
+
+`define REGS_SLEEP_MAX_IDX 'd1
+
+`define REG_SLEEP_CTRL 2'b0
+`define REG_SLEEP_STATUS 2'b1
+
+`define SLEEP_ENABLE 1'b0
+`define SLEEP_STATUS 1'b0
diff --git a/verilog/rtl/ips/apb/apb_event_unit/sleep_unit.v b/verilog/rtl/ips/apb/apb_event_unit/sleep_unit.v
new file mode 100644
index 0000000..21d8e5d
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_event_unit/sleep_unit.v
@@ -0,0 +1,118 @@
+module sleep_unit
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ irq_i,
+ event_i,
+ core_busy_i,
+ fetch_en_o,
+ clk_gate_core_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ input wire irq_i;
+ input wire event_i;
+ input wire core_busy_i;
+ output reg fetch_en_o;
+ output reg clk_gate_core_o;
+ reg [1:0] SLEEP_STATE_N;
+ reg [1:0] SLEEP_STATE_Q;
+ reg [63:0] regs_q;
+ reg [63:0] regs_n;
+ reg core_sleeping_int;
+ always @(*) begin
+ SLEEP_STATE_N = SLEEP_STATE_Q;
+ case (SLEEP_STATE_Q)
+ 2'd0:
+ if (regs_q[32])
+ if (~event_i)
+ SLEEP_STATE_N = 2'd1;
+ 2'd1:
+ if (event_i)
+ SLEEP_STATE_N = 2'd0;
+ else if (~core_busy_i && ~irq_i)
+ SLEEP_STATE_N = 2'd2;
+ 2'd2:
+ if (event_i)
+ SLEEP_STATE_N = 2'd0;
+ else if (irq_i)
+ SLEEP_STATE_N = 2'd1;
+ default: SLEEP_STATE_N = 2'd0;
+ endcase
+ end
+ always @(*) begin
+ fetch_en_o = 1'b1;
+ clk_gate_core_o = 1'b1;
+ core_sleeping_int = 1'b0;
+ case (SLEEP_STATE_Q)
+ 2'd0:
+ if (regs_q[32] && ~event_i)
+ fetch_en_o = 1'b0;
+ else
+ fetch_en_o = 1'b1;
+ 2'd1: fetch_en_o = 1'b0;
+ 2'd2: begin
+ clk_gate_core_o = (event_i ? 1'b1 : 1'b0);
+ core_sleeping_int = 1'b1;
+ fetch_en_o = 1'b0;
+ end
+ default: begin
+ fetch_en_o = 1'b1;
+ clk_gate_core_o = 1'b1;
+ core_sleeping_int = 1'b0;
+ end
+ endcase
+ end
+ wire [0:0] register_adr;
+ assign register_adr = PADDR[3:2];
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+ always @(*) begin
+ regs_n = regs_q;
+ regs_n[1'b0] = core_sleeping_int;
+ if (core_sleeping_int || event_i)
+ regs_n[32] = 1'b0;
+ if ((PSEL && PENABLE) && PWRITE)
+ case (register_adr)
+ 2'b00: regs_n[32+:32] = PWDATA;
+ endcase
+ end
+ always @(*) begin
+ PRDATA = 'b0;
+ if ((PSEL && PENABLE) && !PWRITE)
+ case (register_adr)
+ 2'b00: PRDATA = regs_q[32+:32];
+ 2'b01: PRDATA = regs_q[0+:32];
+ default: PRDATA = 'b0;
+ endcase
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ SLEEP_STATE_Q <= 2'd0;
+ regs_q <= {2 {32'b00000000000000000000000000000000}};
+ end
+ else begin
+ SLEEP_STATE_Q <= SLEEP_STATE_N;
+ regs_q <= regs_n;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_fll_if b/verilog/rtl/ips/apb/apb_fll_if
deleted file mode 160000
index d07fbbd..0000000
--- a/verilog/rtl/ips/apb/apb_fll_if
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit d07fbbdb910aab39a6d471de30c1913370d662e4
diff --git a/verilog/rtl/ips/apb/apb_fll_if/apb_fll_if.v b/verilog/rtl/ips/apb/apb_fll_if/apb_fll_if.v
new file mode 100644
index 0000000..154f629
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_fll_if/apb_fll_if.v
@@ -0,0 +1,202 @@
+module apb_fll_if
+#(
+ parameter APB_ADDR_WIDTH = 12
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ fll1_req,
+ fll1_wrn,
+ fll1_add,
+ fll1_data,
+ fll1_ack,
+ fll1_r_data,
+ fll1_lock,
+ fll2_req,
+ fll2_wrn,
+ fll2_add,
+ fll2_data,
+ fll2_ack,
+ fll2_r_data,
+ fll2_lock
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output wire [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ output reg fll1_req;
+ output wire fll1_wrn;
+ output wire [1:0] fll1_add;
+ output wire [31:0] fll1_data;
+ input wire fll1_ack;
+ input wire [31:0] fll1_r_data;
+ input wire fll1_lock;
+ output reg fll2_req;
+ output wire fll2_wrn;
+ output wire [1:0] fll2_add;
+ output wire [31:0] fll2_data;
+ input wire fll2_ack;
+ input wire [31:0] fll2_r_data;
+ input wire fll2_lock;
+ reg fll1_rd_access;
+ reg fll1_wr_access;
+ reg fll2_rd_access;
+ reg fll2_wr_access;
+ reg read_ready;
+ reg write_ready;
+ reg [31:0] read_data;
+ reg rvalid;
+ reg fll1_ack_sync0;
+ reg fll1_ack_sync;
+ reg fll2_ack_sync0;
+ reg fll2_ack_sync;
+ reg fll1_lock_sync0;
+ reg fll1_lock_sync;
+ reg fll2_lock_sync0;
+ reg fll2_lock_sync;
+ reg fll1_valid;
+ reg fll2_valid;
+ reg [2:0] state;
+ reg [2:0] state_next;
+ always @(posedge HCLK or negedge HRESETn)
+ if (!HRESETn) begin
+ fll1_ack_sync0 <= 1'b0;
+ fll1_ack_sync <= 1'b0;
+ fll2_ack_sync0 <= 1'b0;
+ fll2_ack_sync <= 1'b0;
+ fll1_lock_sync0 <= 1'b0;
+ fll1_lock_sync <= 1'b0;
+ fll2_lock_sync0 <= 1'b0;
+ fll2_lock_sync <= 1'b0;
+ state <= 3'd0;
+ end
+ else begin
+ fll1_ack_sync0 <= fll1_ack;
+ fll1_ack_sync <= fll1_ack_sync0;
+ fll2_ack_sync0 <= fll2_ack;
+ fll2_ack_sync <= fll2_ack_sync0;
+ fll1_lock_sync0 <= fll1_lock;
+ fll1_lock_sync <= fll1_lock_sync0;
+ fll2_lock_sync0 <= fll2_lock;
+ fll2_lock_sync <= fll2_lock_sync0;
+ state <= state_next;
+ end
+ always @(*) begin
+ state_next = 3'd0;
+ rvalid = 1'b0;
+ fll1_req = 1'b0;
+ fll2_req = 1'b0;
+ fll1_valid = 1'b0;
+ fll2_valid = 1'b0;
+ case (state)
+ 3'd0:
+ if (fll2_rd_access || fll2_wr_access) begin
+ fll2_valid = 1'b1;
+ state_next = 3'd3;
+ end
+ else if (fll1_rd_access || fll1_wr_access) begin
+ fll1_valid = 1'b1;
+ state_next = 3'd1;
+ end
+ 3'd1:
+ if (fll1_ack_sync) begin
+ fll1_req = 1'b0;
+ fll1_valid = 1'b0;
+ state_next = 3'd2;
+ rvalid = 1'b1;
+ end
+ else begin
+ fll1_req = 1'b1;
+ fll1_valid = 1'b1;
+ state_next = 3'd1;
+ end
+ 3'd2:
+ if (!fll1_ack_sync)
+ state_next = 3'd0;
+ else
+ state_next = 3'd2;
+ 3'd3:
+ if (fll2_ack_sync) begin
+ fll2_req = 1'b0;
+ fll2_valid = 1'b0;
+ state_next = 3'd4;
+ rvalid = 1'b1;
+ end
+ else begin
+ fll2_req = 1'b1;
+ fll2_valid = 1'b1;
+ state_next = 3'd3;
+ end
+ 3'd4:
+ if (!fll2_ack_sync)
+ state_next = 3'd0;
+ else
+ state_next = 3'd4;
+ endcase
+ end
+ always @(*) begin
+ fll1_wr_access = 1'b0;
+ fll2_wr_access = 1'b0;
+ write_ready = 1'b0;
+ if ((PSEL && PENABLE) && PWRITE)
+ case (PADDR[5:2])
+ 4'b0000, 4'b0001, 4'b0010, 4'b0011: begin
+ fll1_wr_access = 1'b1;
+ write_ready = rvalid;
+ end
+ 4'b0100, 4'b0101, 4'b0110, 4'b0111: begin
+ fll2_wr_access = 1'b1;
+ write_ready = rvalid;
+ end
+ default: write_ready = 1'b1;
+ endcase
+ end
+ always @(*) begin
+ fll1_rd_access = 1'b0;
+ fll2_rd_access = 1'b0;
+ read_ready = 1'b0;
+ read_data = 1'sb0;
+ if ((PSEL && PENABLE) && ~PWRITE)
+ case (PADDR[5:2])
+ 4'b0000, 4'b0001, 4'b0010, 4'b0011: begin
+ fll1_rd_access = 1'b1;
+ read_data = fll1_r_data;
+ read_ready = rvalid;
+ end
+ 4'b0100, 4'b0101, 4'b0110, 4'b0111: begin
+ fll2_rd_access = 1'b1;
+ read_data = fll2_r_data;
+ read_ready = rvalid;
+ end
+ 4'b1000: begin
+ read_data[1:0] = {fll2_lock_sync, fll1_lock_sync};
+ read_ready = 1'b1;
+ end
+ default: read_ready = 1'b1;
+ endcase
+ end
+ assign fll1_wrn = (fll1_valid ? ~PWRITE : 1'b0);
+ assign fll1_add = (fll1_valid ? PADDR[3:2] : {2 {1'sb0}});
+ assign fll1_data = (fll1_valid ? PWDATA : {32 {1'sb0}});
+ assign fll2_wrn = (fll2_valid ? ~PWRITE : 1'b0);
+ assign fll2_add = (fll2_valid ? PADDR[3:2] : {2 {1'sb0}});
+ assign fll2_data = (fll2_valid ? PWDATA : {32 {1'sb0}});
+ assign PREADY = (PWRITE ? write_ready : read_ready);
+ assign PRDATA = read_data;
+ assign PSLVERR = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_gpio b/verilog/rtl/ips/apb/apb_gpio
deleted file mode 160000
index d6e1e85..0000000
--- a/verilog/rtl/ips/apb/apb_gpio
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit d6e1e8593dad6043ff48c28a8a4158a1f396bd0e
diff --git a/verilog/rtl/ips/apb/apb_gpio/apb_gpio.v b/verilog/rtl/ips/apb/apb_gpio/apb_gpio.v
new file mode 100644
index 0000000..9278bd3
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_gpio/apb_gpio.v
@@ -0,0 +1,199 @@
+module apb_gpio
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ gpio_in,
+ gpio_in_sync,
+ gpio_out,
+ gpio_dir,
+ gpio_padcfg,
+ power_event,
+ interrupt
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ input wire [31:0] gpio_in;
+ output wire [31:0] gpio_in_sync;
+ output wire [31:0] gpio_out;
+ output wire [31:0] gpio_dir;
+ output reg [191:0] gpio_padcfg;
+ output reg power_event;
+ output reg interrupt;
+ reg [31:0] r_gpio_inten;
+ reg [31:0] r_gpio_inttype0;
+ reg [31:0] r_gpio_inttype1;
+ reg [31:0] r_gpio_out;
+ reg [31:0] r_gpio_dir;
+ reg [31:0] r_gpio_sync0;
+ reg [31:0] r_gpio_sync1;
+ reg [31:0] r_gpio_in;
+ reg [31:0] r_powerevent;
+ wire [31:0] s_gpio_rise;
+ wire [31:0] s_gpio_fall;
+ wire [31:0] s_is_int_rise;
+ wire [31:0] s_is_int_fall;
+ wire [31:0] s_is_int_lev0;
+ wire [31:0] s_is_int_lev1;
+ wire [31:0] s_is_int_all;
+ wire s_rise_int;
+ wire [3:0] s_apb_addr;
+ reg [31:0] r_status;
+ assign s_apb_addr = PADDR[5:2];
+ assign gpio_in_sync = r_gpio_sync1;
+ assign s_gpio_rise = r_gpio_sync1 & ~r_gpio_in;
+ assign s_gpio_fall = ~r_gpio_sync1 & r_gpio_in;
+ assign s_is_int_rise = (r_gpio_inttype1 & ~r_gpio_inttype0) & s_gpio_rise;
+ assign s_is_int_fall = (r_gpio_inttype1 & r_gpio_inttype0) & s_gpio_fall;
+ assign s_is_int_lev0 = (~r_gpio_inttype1 & r_gpio_inttype0) & ~r_gpio_in;
+ assign s_is_int_lev1 = (~r_gpio_inttype1 & ~r_gpio_inttype0) & r_gpio_in;
+ assign s_is_int_all = r_gpio_inten & (((s_is_int_rise | s_is_int_fall) | s_is_int_lev0) | s_is_int_lev1);
+ assign s_rise_int = |s_is_int_all;
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ interrupt <= 1'b0;
+ r_status <= 'h0;
+ end
+ else if (!interrupt && s_rise_int) begin
+ interrupt <= 1'b1;
+ r_status <= s_is_int_all;
+ end
+ else if ((((interrupt && PSEL) && PENABLE) && !PWRITE) && (s_apb_addr == 4'b0110)) begin
+ interrupt <= 1'b0;
+ r_status <= 'h0;
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ r_gpio_sync0 <= 'h0;
+ r_gpio_sync1 <= 'h0;
+ r_gpio_in <= 'h0;
+ end
+ else begin
+ r_gpio_sync0 <= gpio_in;
+ r_gpio_sync1 <= r_gpio_sync0;
+ r_gpio_in <= r_gpio_sync1;
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ r_gpio_inten <= 1'sb0;
+ r_gpio_inttype0 <= 1'sb0;
+ r_gpio_inttype1 <= 1'sb0;
+ r_gpio_out <= 1'sb0;
+ r_gpio_dir <= 1'sb0;
+ r_powerevent <= 1'sb0;
+ begin : sv2v_autoblock_1
+ reg signed [31:0] i;
+ for (i = 0; i < 32; i = i + 1)
+ gpio_padcfg[i * 6+:6] <= 6'b000010;
+ end
+ end
+ else if ((PSEL && PENABLE) && PWRITE)
+ case (s_apb_addr)
+ 4'b0000: r_gpio_dir <= PWDATA;
+ 4'b0010: r_gpio_out <= PWDATA;
+ 4'b0011: r_gpio_inten <= PWDATA;
+ 4'b0100: r_gpio_inttype0 <= PWDATA;
+ 4'b0101: r_gpio_inttype1 <= PWDATA;
+ 4'b0111: r_powerevent <= PWDATA;
+ 4'b1000: begin
+ gpio_padcfg[0+:6] <= PWDATA[5:0];
+ gpio_padcfg[6+:6] <= PWDATA[13:8];
+ gpio_padcfg[12+:6] <= PWDATA[21:16];
+ gpio_padcfg[18+:6] <= PWDATA[29:24];
+ end
+ 4'b1001: begin
+ gpio_padcfg[24+:6] <= PWDATA[5:0];
+ gpio_padcfg[30+:6] <= PWDATA[13:8];
+ gpio_padcfg[36+:6] <= PWDATA[21:16];
+ gpio_padcfg[42+:6] <= PWDATA[29:24];
+ end
+ 4'b1010: begin
+ gpio_padcfg[48+:6] <= PWDATA[5:0];
+ gpio_padcfg[54+:6] <= PWDATA[13:8];
+ gpio_padcfg[60+:6] <= PWDATA[21:16];
+ gpio_padcfg[66+:6] <= PWDATA[29:24];
+ end
+ 4'b1011: begin
+ gpio_padcfg[72+:6] <= PWDATA[5:0];
+ gpio_padcfg[78+:6] <= PWDATA[13:8];
+ gpio_padcfg[84+:6] <= PWDATA[21:16];
+ gpio_padcfg[90+:6] <= PWDATA[29:24];
+ end
+ 4'b1100: begin
+ gpio_padcfg[96+:6] <= PWDATA[5:0];
+ gpio_padcfg[102+:6] <= PWDATA[13:8];
+ gpio_padcfg[108+:6] <= PWDATA[21:16];
+ gpio_padcfg[114+:6] <= PWDATA[29:24];
+ end
+ 4'b1101: begin
+ gpio_padcfg[120+:6] <= PWDATA[5:0];
+ gpio_padcfg[126+:6] <= PWDATA[13:8];
+ gpio_padcfg[132+:6] <= PWDATA[21:16];
+ gpio_padcfg[138+:6] <= PWDATA[29:24];
+ end
+ 4'b1110: begin
+ gpio_padcfg[144+:6] <= PWDATA[5:0];
+ gpio_padcfg[150+:6] <= PWDATA[13:8];
+ gpio_padcfg[156+:6] <= PWDATA[21:16];
+ gpio_padcfg[162+:6] <= PWDATA[29:24];
+ end
+ 4'b1111: begin
+ gpio_padcfg[168+:6] <= PWDATA[5:0];
+ gpio_padcfg[174+:6] <= PWDATA[13:8];
+ gpio_padcfg[180+:6] <= PWDATA[21:16];
+ gpio_padcfg[186+:6] <= PWDATA[29:24];
+ end
+ endcase
+ always @(*)
+ case (s_apb_addr)
+ 4'b0000: PRDATA = r_gpio_dir;
+ 4'b0001: PRDATA = r_gpio_in;
+ 4'b0010: PRDATA = r_gpio_out;
+ 4'b0011: PRDATA = r_gpio_inten;
+ 4'b0100: PRDATA = r_gpio_inttype0;
+ 4'b0101: PRDATA = r_gpio_inttype1;
+ 4'b0110: PRDATA = r_status;
+ 4'b0111: PRDATA = r_powerevent;
+ 4'b1000: PRDATA = {2'b00, gpio_padcfg[18+:6], 2'b00, gpio_padcfg[12+:6], 2'b00, gpio_padcfg[6+:6], 2'b00, gpio_padcfg[0+:6]};
+ 4'b1001: PRDATA = {2'b00, gpio_padcfg[42+:6], 2'b00, gpio_padcfg[36+:6], 2'b00, gpio_padcfg[30+:6], 2'b00, gpio_padcfg[24+:6]};
+ 4'b1010: PRDATA = {2'b00, gpio_padcfg[66+:6], 2'b00, gpio_padcfg[60+:6], 2'b00, gpio_padcfg[54+:6], 2'b00, gpio_padcfg[48+:6]};
+ 4'b1011: PRDATA = {2'b00, gpio_padcfg[90+:6], 2'b00, gpio_padcfg[84+:6], 2'b00, gpio_padcfg[78+:6], 2'b00, gpio_padcfg[72+:6]};
+ 4'b1100: PRDATA = {2'b00, gpio_padcfg[114+:6], 2'b00, gpio_padcfg[108+:6], 2'b00, gpio_padcfg[102+:6], 2'b00, gpio_padcfg[96+:6]};
+ 4'b1101: PRDATA = {2'b00, gpio_padcfg[138+:6], 2'b00, gpio_padcfg[132+:6], 2'b00, gpio_padcfg[126+:6], 2'b00, gpio_padcfg[120+:6]};
+ 4'b1110: PRDATA = {2'b00, gpio_padcfg[162+:6], 2'b00, gpio_padcfg[156+:6], 2'b00, gpio_padcfg[150+:6], 2'b00, gpio_padcfg[144+:6]};
+ 4'b1111: PRDATA = {2'b00, gpio_padcfg[186+:6], 2'b00, gpio_padcfg[180+:6], 2'b00, gpio_padcfg[174+:6], 2'b00, gpio_padcfg[168+:6]};
+ default: PRDATA = 'h0;
+ endcase
+ always @(*) begin
+ power_event = 1'b0;
+ begin : sv2v_autoblock_2
+ reg signed [31:0] e;
+ for (e = 0; e < 32; e = e + 1)
+ if (r_powerevent[e] == 1'b1)
+ power_event = gpio_in[e];
+ end
+ end
+ assign gpio_out = r_gpio_out;
+ assign gpio_dir = r_gpio_dir;
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_i2c b/verilog/rtl/ips/apb/apb_i2c
deleted file mode 160000
index 0131c30..0000000
--- a/verilog/rtl/ips/apb/apb_i2c
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 0131c30607897959862302caa3910bfd3e9a422d
diff --git a/verilog/rtl/ips/apb/apb_i2c/apb_i2c.v b/verilog/rtl/ips/apb/apb_i2c/apb_i2c.v
new file mode 100644
index 0000000..b0c102e
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_i2c/apb_i2c.v
@@ -0,0 +1,154 @@
+module apb_i2c
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ interrupt_o,
+ scl_pad_i,
+ scl_pad_o,
+ scl_padoen_o,
+ sda_pad_i,
+ sda_pad_o,
+ sda_padoen_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ output reg interrupt_o;
+ input wire scl_pad_i;
+ output wire scl_pad_o;
+ output wire scl_padoen_o;
+ input wire sda_pad_i;
+ output wire sda_pad_o;
+ output wire sda_padoen_o;
+ wire [3:0] s_apb_addr;
+ reg [15:0] r_pre;
+ reg [7:0] r_ctrl;
+ reg [7:0] r_tx;
+ wire [7:0] s_rx;
+ reg [7:0] r_cmd;
+ wire [7:0] s_status;
+ wire s_done;
+ wire s_core_en;
+ wire s_ien;
+ wire s_irxack;
+ reg rxack;
+ reg tip;
+ reg irq_flag;
+ wire i2c_busy;
+ wire i2c_al;
+ reg al;
+ assign s_apb_addr = PADDR[5:2];
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ r_pre <= 'h0;
+ r_ctrl <= 'h0;
+ r_tx <= 'h0;
+ r_cmd <= 'h0;
+ end
+ else if ((PSEL && PENABLE) && PWRITE) begin
+ if (s_done | i2c_al)
+ r_cmd[7:4] <= 4'h0;
+ r_cmd[2:1] <= 2'b00;
+ r_cmd[0] <= 1'b0;
+ case (s_apb_addr)
+ 3'b000: r_pre <= PWDATA[15:0];
+ 3'b001: r_ctrl <= PWDATA[7:0];
+ 3'b100: r_tx <= PWDATA[7:0];
+ 3'b101:
+ if (s_core_en)
+ r_cmd <= PWDATA[7:0];
+ endcase
+ end
+ else begin
+ if (s_done | i2c_al)
+ r_cmd[7:4] <= 4'h0;
+ r_cmd[2:1] <= 2'b00;
+ r_cmd[0] <= 1'b0;
+ end
+ always @(*)
+ case (s_apb_addr)
+ 3'b000: PRDATA = {16'h0000, r_pre};
+ 3'b001: PRDATA = {24'h000000, r_ctrl};
+ 3'b010: PRDATA = {24'h000000, s_rx};
+ 3'b011: PRDATA = {24'h000000, s_status};
+ 3'b100: PRDATA = {24'h000000, r_tx};
+ 3'b101: PRDATA = {24'h000000, r_cmd};
+ default: PRDATA = 'h0;
+ endcase
+ wire sta = r_cmd[7];
+ wire sto = r_cmd[6];
+ wire rd = r_cmd[5];
+ wire wr = r_cmd[4];
+ wire ack = r_cmd[3];
+ wire iack = r_cmd[0];
+ assign s_core_en = r_ctrl[7];
+ assign s_ien = r_ctrl[6];
+ i2c_master_byte_ctrl byte_controller(
+ .clk(HCLK),
+ .nReset(HRESETn),
+ .ena(s_core_en),
+ .clk_cnt(r_pre),
+ .start(sta),
+ .stop(sto),
+ .read(rd),
+ .write(wr),
+ .ack_in(ack),
+ .din(r_tx),
+ .cmd_ack(s_done),
+ .ack_out(s_irxack),
+ .dout(s_rx),
+ .i2c_busy(i2c_busy),
+ .i2c_al(i2c_al),
+ .scl_i(scl_pad_i),
+ .scl_o(scl_pad_o),
+ .scl_oen(scl_padoen_o),
+ .sda_i(sda_pad_i),
+ .sda_o(sda_pad_o),
+ .sda_oen(sda_padoen_o)
+ );
+ always @(posedge HCLK or negedge HRESETn)
+ if (!HRESETn) begin
+ al <= 1'b0;
+ rxack <= 1'b0;
+ tip <= 1'b0;
+ irq_flag <= 1'b0;
+ end
+ else begin
+ al <= i2c_al | (al & ~sta);
+ rxack <= s_irxack;
+ tip <= rd | wr;
+ irq_flag <= ((s_done | i2c_al) | irq_flag) & ~iack;
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (!HRESETn)
+ interrupt_o <= 1'b0;
+ else
+ interrupt_o <= irq_flag && s_ien;
+ assign s_status[7] = rxack;
+ assign s_status[6] = i2c_busy;
+ assign s_status[5] = al;
+ assign s_status[4:2] = 3'h0;
+ assign s_status[1] = tip;
+ assign s_status[0] = irq_flag;
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_i2c/i2c_master_bit_ctrl.v b/verilog/rtl/ips/apb/apb_i2c/i2c_master_bit_ctrl.v
new file mode 100644
index 0000000..5b856b6
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_i2c/i2c_master_bit_ctrl.v
@@ -0,0 +1,303 @@
+module i2c_master_bit_ctrl (
+ clk,
+ nReset,
+ ena,
+ clk_cnt,
+ cmd,
+ cmd_ack,
+ busy,
+ al,
+ din,
+ dout,
+ scl_i,
+ scl_o,
+ scl_oen,
+ sda_i,
+ sda_o,
+ sda_oen
+);
+ input clk;
+ input nReset;
+ input ena;
+ input [15:0] clk_cnt;
+ input [3:0] cmd;
+ output reg cmd_ack;
+ output reg busy;
+ output reg al;
+ input din;
+ output reg dout;
+ input scl_i;
+ output wire scl_o;
+ output reg scl_oen;
+ input sda_i;
+ output wire sda_o;
+ output reg sda_oen;
+ reg [1:0] cSCL;
+ reg [1:0] cSDA;
+ reg [2:0] fSCL;
+ reg [2:0] fSDA;
+ reg sSCL;
+ reg sSDA;
+ reg dSCL;
+ reg dSDA;
+ reg dscl_oen;
+ reg sda_chk;
+ reg clk_en;
+ reg slave_wait;
+ reg [15:0] cnt;
+ reg [13:0] filter_cnt;
+ reg [17:0] c_state;
+ always @(posedge clk) dscl_oen <= scl_oen;
+ always @(posedge clk or negedge nReset)
+ if (!nReset)
+ slave_wait <= 1'b0;
+ else
+ slave_wait <= ((scl_oen & ~dscl_oen) & ~sSCL) | (slave_wait & ~sSCL);
+ wire scl_sync = (dSCL & ~sSCL) & scl_oen;
+ always @(posedge clk or negedge nReset)
+ if (~nReset) begin
+ cnt <= 16'h0000;
+ clk_en <= 1'b1;
+ end
+ else if ((~|cnt || !ena) || scl_sync) begin
+ cnt <= clk_cnt;
+ clk_en <= 1'b1;
+ end
+ else if (slave_wait) begin
+ cnt <= cnt;
+ clk_en <= 1'b0;
+ end
+ else begin
+ cnt <= cnt - 16'h0001;
+ clk_en <= 1'b0;
+ end
+ always @(posedge clk or negedge nReset)
+ if (!nReset) begin
+ cSCL <= 2'b00;
+ cSDA <= 2'b00;
+ end
+ else begin
+ cSCL <= {cSCL[0], scl_i};
+ cSDA <= {cSDA[0], sda_i};
+ end
+ always @(posedge clk or negedge nReset)
+ if (!nReset)
+ filter_cnt <= 14'h0000;
+ else if (!ena)
+ filter_cnt <= 14'h0000;
+ else if (~|filter_cnt)
+ filter_cnt <= clk_cnt >> 2;
+ else
+ filter_cnt <= filter_cnt - 1;
+ always @(posedge clk or negedge nReset)
+ if (!nReset) begin
+ fSCL <= 3'b111;
+ fSDA <= 3'b111;
+ end
+ else if (~|filter_cnt) begin
+ fSCL <= {fSCL[1:0], cSCL[1]};
+ fSDA <= {fSDA[1:0], cSDA[1]};
+ end
+ always @(posedge clk or negedge nReset)
+ if (~nReset) begin
+ sSCL <= 1'b1;
+ sSDA <= 1'b1;
+ dSCL <= 1'b1;
+ dSDA <= 1'b1;
+ end
+ else begin
+ sSCL <= (&fSCL[2:1] | &fSCL[1:0]) | (fSCL[2] & fSCL[0]);
+ sSDA <= (&fSDA[2:1] | &fSDA[1:0]) | (fSDA[2] & fSDA[0]);
+ dSCL <= sSCL;
+ dSDA <= sSDA;
+ end
+ reg sta_condition;
+ reg sto_condition;
+ always @(posedge clk or negedge nReset)
+ if (~nReset) begin
+ sta_condition <= 1'b0;
+ sto_condition <= 1'b0;
+ end
+ else begin
+ sta_condition <= (~sSDA & dSDA) & sSCL;
+ sto_condition <= (sSDA & ~dSDA) & sSCL;
+ end
+ always @(posedge clk or negedge nReset)
+ if (!nReset)
+ busy <= 1'b0;
+ else
+ busy <= (sta_condition | busy) & ~sto_condition;
+ reg cmd_stop;
+ always @(posedge clk or negedge nReset)
+ if (~nReset)
+ cmd_stop <= 1'b0;
+ else if (clk_en)
+ cmd_stop <= cmd == 4'b0010;
+ always @(posedge clk or negedge nReset)
+ if (~nReset)
+ al <= 1'b0;
+ else
+ al <= ((sda_chk & ~sSDA) & sda_oen) | ((|c_state & sto_condition) & ~cmd_stop);
+ always @(posedge clk)
+ if (sSCL & ~dSCL)
+ dout <= sSDA;
+ parameter [17:0] idle = 18'b000000000000000000;
+ parameter [17:0] start_a = 18'b000000000000000001;
+ parameter [17:0] start_b = 18'b000000000000000010;
+ parameter [17:0] start_c = 18'b000000000000000100;
+ parameter [17:0] start_d = 18'b000000000000001000;
+ parameter [17:0] start_e = 18'b000000000000010000;
+ parameter [17:0] stop_a = 18'b000000000000100000;
+ parameter [17:0] stop_b = 18'b000000000001000000;
+ parameter [17:0] stop_c = 18'b000000000010000000;
+ parameter [17:0] stop_d = 18'b000000000100000000;
+ parameter [17:0] rd_a = 18'b000000001000000000;
+ parameter [17:0] rd_b = 18'b000000010000000000;
+ parameter [17:0] rd_c = 18'b000000100000000000;
+ parameter [17:0] rd_d = 18'b000001000000000000;
+ parameter [17:0] wr_a = 18'b000010000000000000;
+ parameter [17:0] wr_b = 18'b000100000000000000;
+ parameter [17:0] wr_c = 18'b001000000000000000;
+ parameter [17:0] wr_d = 18'b010000000000000000;
+ always @(posedge clk or negedge nReset)
+ if (!nReset) begin
+ c_state <= idle;
+ cmd_ack <= 1'b0;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ else if (al) begin
+ c_state <= idle;
+ cmd_ack <= 1'b0;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ else begin
+ cmd_ack <= 1'b0;
+ if (clk_en)
+ case (c_state)
+ idle: begin
+ case (cmd)
+ 4'b0001: c_state <= start_a;
+ 4'b0010: c_state <= stop_a;
+ 4'b0100: c_state <= wr_a;
+ 4'b1000: c_state <= rd_a;
+ default: c_state <= idle;
+ endcase
+ scl_oen <= scl_oen;
+ sda_oen <= sda_oen;
+ sda_chk <= 1'b0;
+ end
+ start_a: begin
+ c_state <= start_b;
+ scl_oen <= scl_oen;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ start_b: begin
+ c_state <= start_c;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ start_c: begin
+ c_state <= start_d;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b0;
+ sda_chk <= 1'b0;
+ end
+ start_d: begin
+ c_state <= start_e;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b0;
+ sda_chk <= 1'b0;
+ end
+ start_e: begin
+ c_state <= idle;
+ cmd_ack <= 1'b1;
+ scl_oen <= 1'b0;
+ sda_oen <= 1'b0;
+ sda_chk <= 1'b0;
+ end
+ stop_a: begin
+ c_state <= stop_b;
+ scl_oen <= 1'b0;
+ sda_oen <= 1'b0;
+ sda_chk <= 1'b0;
+ end
+ stop_b: begin
+ c_state <= stop_c;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b0;
+ sda_chk <= 1'b0;
+ end
+ stop_c: begin
+ c_state <= stop_d;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b0;
+ sda_chk <= 1'b0;
+ end
+ stop_d: begin
+ c_state <= idle;
+ cmd_ack <= 1'b1;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ rd_a: begin
+ c_state <= rd_b;
+ scl_oen <= 1'b0;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ rd_b: begin
+ c_state <= rd_c;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ rd_c: begin
+ c_state <= rd_d;
+ scl_oen <= 1'b1;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ rd_d: begin
+ c_state <= idle;
+ cmd_ack <= 1'b1;
+ scl_oen <= 1'b0;
+ sda_oen <= 1'b1;
+ sda_chk <= 1'b0;
+ end
+ wr_a: begin
+ c_state <= wr_b;
+ scl_oen <= 1'b0;
+ sda_oen <= din;
+ sda_chk <= 1'b0;
+ end
+ wr_b: begin
+ c_state <= wr_c;
+ scl_oen <= 1'b1;
+ sda_oen <= din;
+ sda_chk <= 1'b0;
+ end
+ wr_c: begin
+ c_state <= wr_d;
+ scl_oen <= 1'b1;
+ sda_oen <= din;
+ sda_chk <= 1'b1;
+ end
+ wr_d: begin
+ c_state <= idle;
+ cmd_ack <= 1'b1;
+ scl_oen <= 1'b0;
+ sda_oen <= din;
+ sda_chk <= 1'b0;
+ end
+ endcase
+ end
+ assign scl_o = 1'b0;
+ assign sda_o = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_i2c/i2c_master_byte_ctrl.v b/verilog/rtl/ips/apb/apb_i2c/i2c_master_byte_ctrl.v
new file mode 100644
index 0000000..b3eb193
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_i2c/i2c_master_byte_ctrl.v
@@ -0,0 +1,202 @@
+module i2c_master_byte_ctrl (
+ clk,
+ nReset,
+ ena,
+ clk_cnt,
+ start,
+ stop,
+ read,
+ write,
+ ack_in,
+ din,
+ cmd_ack,
+ ack_out,
+ dout,
+ i2c_busy,
+ i2c_al,
+ scl_i,
+ scl_o,
+ scl_oen,
+ sda_i,
+ sda_o,
+ sda_oen
+);
+ input clk;
+ input nReset;
+ input ena;
+ input [15:0] clk_cnt;
+ input start;
+ input stop;
+ input read;
+ input write;
+ input ack_in;
+ input [7:0] din;
+ output reg cmd_ack;
+ output reg ack_out;
+ output wire i2c_busy;
+ output wire i2c_al;
+ output wire [7:0] dout;
+ input scl_i;
+ output wire scl_o;
+ output wire scl_oen;
+ input sda_i;
+ output wire sda_o;
+ output wire sda_oen;
+ parameter [4:0] ST_IDLE = 5'b00000;
+ parameter [4:0] ST_START = 5'b00001;
+ parameter [4:0] ST_READ = 5'b00010;
+ parameter [4:0] ST_WRITE = 5'b00100;
+ parameter [4:0] ST_ACK = 5'b01000;
+ parameter [4:0] ST_STOP = 5'b10000;
+ reg [3:0] core_cmd;
+ reg core_txd;
+ wire core_ack;
+ wire core_rxd;
+ reg [7:0] sr;
+ reg shift;
+ reg ld;
+ wire go;
+ reg [2:0] dcnt;
+ wire cnt_done;
+ i2c_master_bit_ctrl bit_controller(
+ .clk(clk),
+ .nReset(nReset),
+ .ena(ena),
+ .clk_cnt(clk_cnt),
+ .cmd(core_cmd),
+ .cmd_ack(core_ack),
+ .busy(i2c_busy),
+ .al(i2c_al),
+ .din(core_txd),
+ .dout(core_rxd),
+ .scl_i(scl_i),
+ .scl_o(scl_o),
+ .scl_oen(scl_oen),
+ .sda_i(sda_i),
+ .sda_o(sda_o),
+ .sda_oen(sda_oen)
+ );
+ assign go = ((read | write) | stop) & ~cmd_ack;
+ assign dout = sr;
+ always @(posedge clk or negedge nReset)
+ if (!nReset)
+ sr <= #(1) 8'h00;
+ else if (ld)
+ sr <= #(1) din;
+ else if (shift)
+ sr <= #(1) {sr[6:0], core_rxd};
+ always @(posedge clk or negedge nReset)
+ if (!nReset)
+ dcnt <= #(1) 3'h0;
+ else if (ld)
+ dcnt <= #(1) 3'h7;
+ else if (shift)
+ dcnt <= #(1) dcnt - 3'h1;
+ assign cnt_done = ~(|dcnt);
+ reg [4:0] c_state;
+ always @(posedge clk or negedge nReset)
+ if (!nReset) begin
+ core_cmd <= #(1) 4'b0000;
+ core_txd <= #(1) 1'b0;
+ shift <= #(1) 1'b0;
+ ld <= #(1) 1'b0;
+ cmd_ack <= #(1) 1'b0;
+ c_state <= #(1) ST_IDLE;
+ ack_out <= #(1) 1'b0;
+ end
+ else if (i2c_al) begin
+ core_cmd <= #(1) 4'b0000;
+ core_txd <= #(1) 1'b0;
+ shift <= #(1) 1'b0;
+ ld <= #(1) 1'b0;
+ cmd_ack <= #(1) 1'b0;
+ c_state <= #(1) ST_IDLE;
+ ack_out <= #(1) 1'b0;
+ end
+ else begin
+ core_txd <= #(1) sr[7];
+ shift <= #(1) 1'b0;
+ ld <= #(1) 1'b0;
+ cmd_ack <= #(1) 1'b0;
+ case (c_state)
+ ST_IDLE:
+ if (go) begin
+ if (start) begin
+ c_state <= #(1) ST_START;
+ core_cmd <= #(1) 4'b0001;
+ end
+ else if (read) begin
+ c_state <= #(1) ST_READ;
+ core_cmd <= #(1) 4'b1000;
+ end
+ else if (write) begin
+ c_state <= #(1) ST_WRITE;
+ core_cmd <= #(1) 4'b0100;
+ end
+ else begin
+ c_state <= #(1) ST_STOP;
+ core_cmd <= #(1) 4'b0010;
+ end
+ ld <= #(1) 1'b1;
+ end
+ ST_START:
+ if (core_ack) begin
+ if (read) begin
+ c_state <= #(1) ST_READ;
+ core_cmd <= #(1) 4'b1000;
+ end
+ else begin
+ c_state <= #(1) ST_WRITE;
+ core_cmd <= #(1) 4'b0100;
+ end
+ ld <= #(1) 1'b1;
+ end
+ ST_WRITE:
+ if (core_ack)
+ if (cnt_done) begin
+ c_state <= #(1) ST_ACK;
+ core_cmd <= #(1) 4'b1000;
+ end
+ else begin
+ c_state <= #(1) ST_WRITE;
+ core_cmd <= #(1) 4'b0100;
+ shift <= #(1) 1'b1;
+ end
+ ST_READ:
+ if (core_ack) begin
+ if (cnt_done) begin
+ c_state <= #(1) ST_ACK;
+ core_cmd <= #(1) 4'b0100;
+ end
+ else begin
+ c_state <= #(1) ST_READ;
+ core_cmd <= #(1) 4'b1000;
+ end
+ shift <= #(1) 1'b1;
+ core_txd <= #(1) ack_in;
+ end
+ ST_ACK:
+ if (core_ack) begin
+ if (stop) begin
+ c_state <= #(1) ST_STOP;
+ core_cmd <= #(1) 4'b0010;
+ end
+ else begin
+ c_state <= #(1) ST_IDLE;
+ core_cmd <= #(1) 4'b0000;
+ cmd_ack <= #(1) 1'b1;
+ end
+ ack_out <= #(1) core_rxd;
+ core_txd <= #(1) 1'b1;
+ end
+ else
+ core_txd <= #(1) ack_in;
+ ST_STOP:
+ if (core_ack) begin
+ c_state <= #(1) ST_IDLE;
+ core_cmd <= #(1) 4'b0000;
+ cmd_ack <= #(1) 1'b1;
+ end
+ endcase
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_i2c/i2c_master_defines.sv b/verilog/rtl/ips/apb/apb_i2c/i2c_master_defines.sv
new file mode 100644
index 0000000..673ecc4
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_i2c/i2c_master_defines.sv
@@ -0,0 +1,62 @@
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// WISHBONE rev.B2 compliant I2C Master controller defines ////
+//// ////
+//// ////
+//// Author: Richard Herveille ////
+//// richard@asics.ws ////
+//// www.asics.ws ////
+//// ////
+//// Downloaded from: http://www.opencores.org/projects/i2c/ ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2001 Richard Herveille ////
+//// richard@asics.ws ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+//// ////
+//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
+//// 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. ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+
+// CVS Log
+//
+// $Id: i2c_master_defines.v,v 1.3 2001-11-05 11:59:25 rherveille Exp $
+//
+// $Date: 2001-11-05 11:59:25 $
+// $Revision: 1.3 $
+// $Author: rherveille $
+// $Locker: $
+// $State: Exp $
+//
+// Change History:
+// $Log: not supported by cvs2svn $
+
+
+// I2C registers wishbone addresses
+
+// bitcontroller states
+`define I2C_CMD_NOP 4'b0000
+`define I2C_CMD_START 4'b0001
+`define I2C_CMD_STOP 4'b0010
+`define I2C_CMD_WRITE 4'b0100
+`define I2C_CMD_READ 4'b1000
+
+// Modelsim-ASE requires a timescale directive
+`timescale 1 ns / 1 ns
\ No newline at end of file
diff --git a/verilog/rtl/ips/apb/apb_node b/verilog/rtl/ips/apb/apb_node
deleted file mode 160000
index b69afc8..0000000
--- a/verilog/rtl/ips/apb/apb_node
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit b69afc8ab03c9bc0c399aa86a36ea91978b01ccc
diff --git a/verilog/rtl/ips/apb/apb_node/apb_node.v b/verilog/rtl/ips/apb/apb_node/apb_node.v
new file mode 100644
index 0000000..df901bf
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_node/apb_node.v
@@ -0,0 +1,101 @@
+module apb_node
+#(
+ parameter NB_MASTER = 8,
+ parameter APB_DATA_WIDTH = 32,
+ parameter APB_ADDR_WIDTH = 32
+ )
+(
+ penable_i,
+ pwrite_i,
+ paddr_i,
+ pwdata_i,
+ prdata_o,
+ pready_o,
+ pslverr_o,
+ penable_o,
+ pwrite_o,
+ paddr_o,
+ psel_o,
+ pwdata_o,
+ prdata_i,
+ pready_i,
+ pslverr_i,
+ START_ADDR_i,
+ END_ADDR_i
+);
+ //parameter NB_MASTER = 8;
+ //parameter APB_DATA_WIDTH = 32;
+ //parameter APB_ADDR_WIDTH = 32;
+ input wire penable_i;
+ input wire pwrite_i;
+ input wire [31:0] paddr_i;
+ input wire [31:0] pwdata_i;
+ output reg [31:0] prdata_o;
+ output reg pready_o;
+ output reg pslverr_o;
+ output reg [NB_MASTER - 1:0] penable_o;
+ output reg [NB_MASTER - 1:0] pwrite_o;
+ output reg [(NB_MASTER * 32) - 1:0] paddr_o;
+ output wire [NB_MASTER - 1:0] psel_o;
+ output reg [(NB_MASTER * 32) - 1:0] pwdata_o;
+ input wire [(NB_MASTER * 32) - 1:0] prdata_i;
+ input wire [NB_MASTER - 1:0] pready_i;
+ input wire [NB_MASTER - 1:0] pslverr_i;
+ input wire [(NB_MASTER * APB_ADDR_WIDTH) - 1:0] START_ADDR_i;
+ input wire [(NB_MASTER * APB_ADDR_WIDTH) - 1:0] END_ADDR_i;
+ genvar i;
+ integer s_loop1;
+ integer s_loop2;
+ integer s_loop3;
+ integer s_loop4;
+ integer s_loop5;
+ integer s_loop6;
+ integer s_loop7;
+ generate
+ for (i = 0; i < NB_MASTER; i = i + 1) begin : genblk1
+ assign psel_o[i] = (paddr_i >= START_ADDR_i[i * APB_ADDR_WIDTH+:APB_ADDR_WIDTH]) && (paddr_i <= END_ADDR_i[i * APB_ADDR_WIDTH+:APB_ADDR_WIDTH]);
+ end
+ endgenerate
+ always @(*)
+ for (s_loop1 = 0; s_loop1 < NB_MASTER; s_loop1 = s_loop1 + 1)
+ if (psel_o[s_loop1] == 1'b1)
+ penable_o[s_loop1] = penable_i;
+ else
+ penable_o[s_loop1] = 1'sb0;
+ always @(*)
+ for (s_loop2 = 0; s_loop2 < NB_MASTER; s_loop2 = s_loop2 + 1)
+ if (psel_o[s_loop2] == 1'b1)
+ pwrite_o[s_loop2] = pwrite_i;
+ else
+ pwrite_o[s_loop2] = 1'sb0;
+ always @(*)
+ for (s_loop3 = 0; s_loop3 < NB_MASTER; s_loop3 = s_loop3 + 1)
+ if (psel_o[s_loop3] == 1'b1)
+ paddr_o[s_loop3 * 32+:32] = paddr_i;
+ else
+ paddr_o[s_loop3 * 32+:32] = 1'sb0;
+ always @(*)
+ for (s_loop4 = 0; s_loop4 < NB_MASTER; s_loop4 = s_loop4 + 1)
+ if (psel_o[s_loop4] == 1'b1)
+ pwdata_o[s_loop4 * 32+:32] = pwdata_i;
+ else
+ pwdata_o[s_loop4 * 32+:32] = 1'sb0;
+ always @(*) begin
+ prdata_o = 1'sb0;
+ for (s_loop5 = 0; s_loop5 < NB_MASTER; s_loop5 = s_loop5 + 1)
+ if (psel_o[s_loop5] == 1'b1)
+ prdata_o = prdata_i[s_loop5 * 32+:32];
+ end
+ always @(*) begin
+ pready_o = 1'sb0;
+ for (s_loop6 = 0; s_loop6 < NB_MASTER; s_loop6 = s_loop6 + 1)
+ if (psel_o[s_loop6] == 1'b1)
+ pready_o = pready_i[s_loop6];
+ end
+ always @(*) begin
+ pslverr_o = 1'sb0;
+ for (s_loop7 = 0; s_loop7 < NB_MASTER; s_loop7 = s_loop7 + 1)
+ if (psel_o[s_loop7] == 1'b1)
+ pslverr_o = pslverr_i[s_loop7];
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_node/apb_node_wrap.v b/verilog/rtl/ips/apb/apb_node/apb_node_wrap.v
new file mode 100644
index 0000000..0c638bc
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_node/apb_node_wrap.v
@@ -0,0 +1,284 @@
+module apb_node_wrap
+#(
+ parameter NB_MASTER = 8,
+ parameter APB_DATA_WIDTH = 32,
+ parameter APB_ADDR_WIDTH = 32
+ )
+(
+ clk_i,
+ rst_ni,
+ apb_slave_paddr,
+ apb_slave_pwdata,
+ apb_slave_pwrite,
+ apb_slave_psel,
+ apb_slave_penable,
+ apb_slave_prdata,
+ apb_slave_pready,
+ apb_slave_pslverr,
+ apb_masters00_paddr,
+ apb_masters00_pwdata,
+ apb_masters00_pwrite,
+ apb_masters00_psel,
+ apb_masters00_penable,
+ apb_masters00_prdata,
+ apb_masters00_pready,
+ apb_masters00_pslverr,
+ apb_masters01_paddr,
+ apb_masters01_pwdata,
+ apb_masters01_pwrite,
+ apb_masters01_psel,
+ apb_masters01_penable,
+ apb_masters01_prdata,
+ apb_masters01_pready,
+ apb_masters01_pslverr,
+ apb_masters02_paddr,
+ apb_masters02_pwdata,
+ apb_masters02_pwrite,
+ apb_masters02_psel,
+ apb_masters02_penable,
+ apb_masters02_prdata,
+ apb_masters02_pready,
+ apb_masters02_pslverr,
+ apb_masters03_paddr,
+ apb_masters03_pwdata,
+ apb_masters03_pwrite,
+ apb_masters03_psel,
+ apb_masters03_penable,
+ apb_masters03_prdata,
+ apb_masters03_pready,
+ apb_masters03_pslverr,
+ apb_masters04_paddr,
+ apb_masters04_pwdata,
+ apb_masters04_pwrite,
+ apb_masters04_psel,
+ apb_masters04_penable,
+ apb_masters04_prdata,
+ apb_masters04_pready,
+ apb_masters04_pslverr,
+ apb_masters05_paddr,
+ apb_masters05_pwdata,
+ apb_masters05_pwrite,
+ apb_masters05_psel,
+ apb_masters05_penable,
+ apb_masters05_prdata,
+ apb_masters05_pready,
+ apb_masters05_pslverr,
+ apb_masters06_paddr,
+ apb_masters06_pwdata,
+ apb_masters06_pwrite,
+ apb_masters06_psel,
+ apb_masters06_penable,
+ apb_masters06_prdata,
+ apb_masters06_pready,
+ apb_masters06_pslverr,
+ apb_masters07_paddr,
+ apb_masters07_pwdata,
+ apb_masters07_pwrite,
+ apb_masters07_psel,
+ apb_masters07_penable,
+ apb_masters07_prdata,
+ apb_masters07_pready,
+ apb_masters07_pslverr,
+ apb_masters08_paddr,
+ apb_masters08_pwdata,
+ apb_masters08_pwrite,
+ apb_masters08_psel,
+ apb_masters08_penable,
+ apb_masters08_prdata,
+ apb_masters08_pready,
+ apb_masters08_pslverr,
+ start_addr_i,
+ end_addr_i
+);
+ //parameter NB_MASTER = 9;
+ //parameter APB_DATA_WIDTH = 32;
+ //parameter APB_ADDR_WIDTH = 32;
+ input wire clk_i;
+ input wire rst_ni;
+ input wire [APB_ADDR_WIDTH - 1:0] apb_slave_paddr;
+ input wire [APB_DATA_WIDTH - 1:0] apb_slave_pwdata;
+ input wire apb_slave_pwrite;
+ input wire apb_slave_psel;
+ input wire apb_slave_penable;
+ output wire [APB_DATA_WIDTH - 1:0] apb_slave_prdata;
+ output wire apb_slave_pready;
+ output wire apb_slave_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters00_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters00_pwdata;
+ output wire apb_masters00_pwrite;
+ output wire apb_masters00_psel;
+ output wire apb_masters00_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters00_prdata;
+ input wire apb_masters00_pready;
+ input wire apb_masters00_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters01_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters01_pwdata;
+ output wire apb_masters01_pwrite;
+ output wire apb_masters01_psel;
+ output wire apb_masters01_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters01_prdata;
+ input wire apb_masters01_pready;
+ input wire apb_masters01_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters02_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters02_pwdata;
+ output wire apb_masters02_pwrite;
+ output wire apb_masters02_psel;
+ output wire apb_masters02_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters02_prdata;
+ input wire apb_masters02_pready;
+ input wire apb_masters02_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters03_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters03_pwdata;
+ output wire apb_masters03_pwrite;
+ output wire apb_masters03_psel;
+ output wire apb_masters03_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters03_prdata;
+ input wire apb_masters03_pready;
+ input wire apb_masters03_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters04_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters04_pwdata;
+ output wire apb_masters04_pwrite;
+ output wire apb_masters04_psel;
+ output wire apb_masters04_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters04_prdata;
+ input wire apb_masters04_pready;
+ input wire apb_masters04_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters05_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters05_pwdata;
+ output wire apb_masters05_pwrite;
+ output wire apb_masters05_psel;
+ output wire apb_masters05_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters05_prdata;
+ input wire apb_masters05_pready;
+ input wire apb_masters05_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters06_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters06_pwdata;
+ output wire apb_masters06_pwrite;
+ output wire apb_masters06_psel;
+ output wire apb_masters06_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters06_prdata;
+ input wire apb_masters06_pready;
+ input wire apb_masters06_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters07_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters07_pwdata;
+ output wire apb_masters07_pwrite;
+ output wire apb_masters07_psel;
+ output wire apb_masters07_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters07_prdata;
+ input wire apb_masters07_pready;
+ input wire apb_masters07_pslverr;
+ output wire [APB_ADDR_WIDTH - 1:0] apb_masters08_paddr;
+ output wire [APB_DATA_WIDTH - 1:0] apb_masters08_pwdata;
+ output wire apb_masters08_pwrite;
+ output wire apb_masters08_psel;
+ output wire apb_masters08_penable;
+ input wire [APB_DATA_WIDTH - 1:0] apb_masters08_prdata;
+ input wire apb_masters08_pready;
+ input wire apb_masters08_pslverr;
+ input wire [(NB_MASTER * APB_ADDR_WIDTH) - 1:0] start_addr_i;
+ input wire [(NB_MASTER * APB_ADDR_WIDTH) - 1:0] end_addr_i;
+ genvar i;
+ wire [NB_MASTER - 1:0] penable;
+ wire [NB_MASTER - 1:0] pwrite;
+ wire [(NB_MASTER * 32) - 1:0] paddr;
+ wire [NB_MASTER - 1:0] psel;
+ wire [(NB_MASTER * 32) - 1:0] pwdata;
+ wire [(NB_MASTER * 32) - 1:0] prdata;
+ wire [NB_MASTER - 1:0] pready;
+ wire [NB_MASTER - 1:0] pslverr;
+ assign apb_masters00_penable = penable[0];
+ assign apb_masters00_pwrite = pwrite[0];
+ assign apb_masters00_paddr = paddr[0+:32];
+ assign apb_masters00_psel = psel[0];
+ assign apb_masters00_pwdata = pwdata[0+:32];
+ assign prdata[0+:32] = apb_masters00_prdata;
+ assign pready[0] = apb_masters00_pready;
+ assign pslverr[0] = apb_masters00_pslverr;
+ assign apb_masters01_penable = penable[1];
+ assign apb_masters01_pwrite = pwrite[1];
+ assign apb_masters01_paddr = paddr[32+:32];
+ assign apb_masters01_psel = psel[1];
+ assign apb_masters01_pwdata = pwdata[32+:32];
+ assign prdata[32+:32] = apb_masters01_prdata;
+ assign pready[1] = apb_masters01_pready;
+ assign pslverr[1] = apb_masters01_pslverr;
+ assign apb_masters02_penable = penable[2];
+ assign apb_masters02_pwrite = pwrite[2];
+ assign apb_masters02_paddr = paddr[64+:32];
+ assign apb_masters02_psel = psel[2];
+ assign apb_masters02_pwdata = pwdata[64+:32];
+ assign prdata[64+:32] = apb_masters02_prdata;
+ assign pready[2] = apb_masters02_pready;
+ assign pslverr[2] = apb_masters02_pslverr;
+ assign apb_masters03_penable = penable[3];
+ assign apb_masters03_pwrite = pwrite[3];
+ assign apb_masters03_paddr = paddr[96+:32];
+ assign apb_masters03_psel = psel[3];
+ assign apb_masters03_pwdata = pwdata[96+:32];
+ assign prdata[96+:32] = apb_masters03_prdata;
+ assign pready[3] = apb_masters03_pready;
+ assign pslverr[3] = apb_masters03_pslverr;
+ assign apb_masters04_penable = penable[4];
+ assign apb_masters04_pwrite = pwrite[4];
+ assign apb_masters04_paddr = paddr[128+:32];
+ assign apb_masters04_psel = psel[4];
+ assign apb_masters04_pwdata = pwdata[128+:32];
+ assign prdata[128+:32] = apb_masters04_prdata;
+ assign pready[4] = apb_masters04_pready;
+ assign pslverr[4] = apb_masters04_pslverr;
+ assign apb_masters05_penable = penable[5];
+ assign apb_masters05_pwrite = pwrite[5];
+ assign apb_masters05_paddr = paddr[160+:32];
+ assign apb_masters05_psel = psel[5];
+ assign apb_masters05_pwdata = pwdata[160+:32];
+ assign prdata[160+:32] = apb_masters05_prdata;
+ assign pready[5] = apb_masters05_pready;
+ assign pslverr[5] = apb_masters05_pslverr;
+ assign apb_masters06_penable = penable[6];
+ assign apb_masters06_pwrite = pwrite[6];
+ assign apb_masters06_paddr = paddr[192+:32];
+ assign apb_masters06_psel = psel[6];
+ assign apb_masters06_pwdata = pwdata[192+:32];
+ assign prdata[192+:32] = apb_masters06_prdata;
+ assign pready[6] = apb_masters06_pready;
+ assign pslverr[6] = apb_masters06_pslverr;
+ assign apb_masters07_penable = penable[7];
+ assign apb_masters07_pwrite = pwrite[7];
+ assign apb_masters07_paddr = paddr[224+:32];
+ assign apb_masters07_psel = psel[7];
+ assign apb_masters07_pwdata = pwdata[224+:32];
+ assign prdata[224+:32] = apb_masters07_prdata;
+ assign pready[7] = apb_masters07_pready;
+ assign pslverr[7] = apb_masters07_pslverr;
+ assign apb_masters08_penable = penable[8];
+ assign apb_masters08_pwrite = pwrite[8];
+ assign apb_masters08_paddr = paddr[256+:32];
+ assign apb_masters08_psel = psel[8];
+ assign apb_masters08_pwdata = pwdata[256+:32];
+ assign prdata[256+:32] = apb_masters08_prdata;
+ assign pready[8] = apb_masters08_pready;
+ assign pslverr[8] = apb_masters08_pslverr;
+ apb_node #(
+ .NB_MASTER(NB_MASTER),
+ .APB_DATA_WIDTH(APB_DATA_WIDTH),
+ .APB_ADDR_WIDTH(APB_ADDR_WIDTH)
+ ) apb_node_i(
+ .penable_i(apb_slave_penable),
+ .pwrite_i(apb_slave_pwrite),
+ .paddr_i(apb_slave_paddr),
+ .pwdata_i(apb_slave_pwdata),
+ .prdata_o(apb_slave_prdata),
+ .pready_o(apb_slave_pready),
+ .pslverr_o(apb_slave_pslverr),
+ .penable_o(penable),
+ .pwrite_o(pwrite),
+ .paddr_o(paddr),
+ .psel_o(psel),
+ .pwdata_o(pwdata),
+ .prdata_i(prdata),
+ .pready_i(pready),
+ .pslverr_i(pslverr),
+ .START_ADDR_i(start_addr_i),
+ .END_ADDR_i(end_addr_i)
+ );
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_pulpino b/verilog/rtl/ips/apb/apb_pulpino
deleted file mode 160000
index 6ed2cc8..0000000
--- a/verilog/rtl/ips/apb/apb_pulpino
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 6ed2cc81265682ef2d6b46eff3c2b84f5efc9573
diff --git a/verilog/rtl/ips/apb/apb_pulpino/apb_pulpino.v b/verilog/rtl/ips/apb/apb_pulpino/apb_pulpino.v
new file mode 100644
index 0000000..1c00fdb
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_pulpino/apb_pulpino.v
@@ -0,0 +1,174 @@
+module apb_pulpino
+#(
+ parameter APB_ADDR_WIDTH = 12, //APB slaves are 4KB by default
+ parameter BOOT_ADDR = 32'h8000
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ pad_cfg_o,
+ clk_gate_o,
+ pad_mux_o,
+ boot_addr_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ //parameter BOOT_ADDR = 32'h00008000;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ output wire [191:0] pad_cfg_o;
+ output wire [31:0] clk_gate_o;
+ output wire [31:0] pad_mux_o;
+ output wire [31:0] boot_addr_o;
+ reg [31:0] pad_mux_q;
+ reg [31:0] pad_mux_n;
+ reg [31:0] boot_adr_q;
+ reg [31:0] boot_adr_n;
+ reg [31:0] clk_gate_q;
+ reg [31:0] clk_gate_n;
+ reg [191:0] pad_cfg_q;
+ reg [191:0] pad_cfg_n;
+ wire [3:0] register_adr;
+ reg [1:0] status_n;
+ reg [1:0] status_q;
+ assign register_adr = PADDR[5:2];
+ assign pad_mux_o = pad_mux_q;
+ assign clk_gate_o = clk_gate_q;
+ assign pad_cfg_o = pad_cfg_q;
+ assign boot_addr_o = boot_adr_q;
+ always @(*) begin
+ pad_mux_n = pad_mux_q;
+ pad_cfg_n = pad_cfg_q;
+ clk_gate_n = clk_gate_q;
+ boot_adr_n = boot_adr_q;
+ status_n = status_q;
+ if ((PSEL && PENABLE) && PWRITE)
+ case (register_adr)
+ 4'b0000: pad_mux_n = PWDATA;
+ 4'b0001: clk_gate_n = PWDATA;
+ 4'b0010: boot_adr_n = PWDATA;
+ 4'b1000: begin
+ pad_cfg_n[0+:6] = PWDATA[5:0];
+ pad_cfg_n[6+:6] = PWDATA[13:8];
+ pad_cfg_n[12+:6] = PWDATA[21:16];
+ pad_cfg_n[18+:6] = PWDATA[29:24];
+ end
+ 4'b1001: begin
+ pad_cfg_n[24+:6] = PWDATA[5:0];
+ pad_cfg_n[30+:6] = PWDATA[13:8];
+ pad_cfg_n[36+:6] = PWDATA[21:16];
+ pad_cfg_n[42+:6] = PWDATA[29:24];
+ end
+ 4'b1010: begin
+ pad_cfg_n[48+:6] = PWDATA[5:0];
+ pad_cfg_n[54+:6] = PWDATA[13:8];
+ pad_cfg_n[60+:6] = PWDATA[21:16];
+ pad_cfg_n[66+:6] = PWDATA[29:24];
+ end
+ 4'b1011: begin
+ pad_cfg_n[72+:6] = PWDATA[5:0];
+ pad_cfg_n[78+:6] = PWDATA[13:8];
+ pad_cfg_n[84+:6] = PWDATA[21:16];
+ pad_cfg_n[90+:6] = PWDATA[29:24];
+ end
+ 4'b1100: begin
+ pad_cfg_n[96+:6] = PWDATA[5:0];
+ pad_cfg_n[102+:6] = PWDATA[13:8];
+ pad_cfg_n[108+:6] = PWDATA[21:16];
+ pad_cfg_n[114+:6] = PWDATA[29:24];
+ end
+ 4'b1101: begin
+ pad_cfg_n[120+:6] = PWDATA[5:0];
+ pad_cfg_n[126+:6] = PWDATA[13:8];
+ pad_cfg_n[132+:6] = PWDATA[21:16];
+ pad_cfg_n[138+:6] = PWDATA[29:24];
+ end
+ 4'b1110: begin
+ pad_cfg_n[144+:6] = PWDATA[5:0];
+ pad_cfg_n[150+:6] = PWDATA[13:8];
+ pad_cfg_n[156+:6] = PWDATA[21:16];
+ pad_cfg_n[162+:6] = PWDATA[29:24];
+ end
+ 4'b1111: begin
+ pad_cfg_n[168+:6] = PWDATA[5:0];
+ pad_cfg_n[174+:6] = PWDATA[13:8];
+ pad_cfg_n[180+:6] = PWDATA[21:16];
+ pad_cfg_n[186+:6] = PWDATA[29:24];
+ end
+ 4'b0101: status_n = PWDATA[1:0];
+ endcase
+ end
+ always @(*) begin
+ PRDATA = 'b0;
+ if ((PSEL && PENABLE) && !PWRITE)
+ case (register_adr)
+ 4'b0000: PRDATA = pad_mux_q;
+ 4'b0010: PRDATA = boot_adr_q;
+ 4'b0001: PRDATA = clk_gate_q;
+ 4'b1000: PRDATA = {2'b00, pad_cfg_q[18+:6], 2'b00, pad_cfg_q[12+:6], 2'b00, pad_cfg_q[6+:6], 2'b00, pad_cfg_q[0+:6]};
+ 4'b1001: PRDATA = {2'b00, pad_cfg_q[42+:6], 2'b00, pad_cfg_q[36+:6], 2'b00, pad_cfg_q[30+:6], 2'b00, pad_cfg_q[24+:6]};
+ 4'b1010: PRDATA = {2'b00, pad_cfg_q[66+:6], 2'b00, pad_cfg_q[60+:6], 2'b00, pad_cfg_q[54+:6], 2'b00, pad_cfg_q[48+:6]};
+ 4'b1011: PRDATA = {2'b00, pad_cfg_q[90+:6], 2'b00, pad_cfg_q[84+:6], 2'b00, pad_cfg_q[78+:6], 2'b00, pad_cfg_q[72+:6]};
+ 4'b1100: PRDATA = {2'b00, pad_cfg_q[114+:6], 2'b00, pad_cfg_q[108+:6], 2'b00, pad_cfg_q[102+:6], 2'b00, pad_cfg_q[96+:6]};
+ 4'b1101: PRDATA = {2'b00, pad_cfg_q[138+:6], 2'b00, pad_cfg_q[132+:6], 2'b00, pad_cfg_q[126+:6], 2'b00, pad_cfg_q[120+:6]};
+ 4'b1110: PRDATA = {2'b00, pad_cfg_q[162+:6], 2'b00, pad_cfg_q[156+:6], 2'b00, pad_cfg_q[150+:6], 2'b00, pad_cfg_q[144+:6]};
+ 4'b1111: PRDATA = {2'b00, pad_cfg_q[186+:6], 2'b00, pad_cfg_q[180+:6], 2'b00, pad_cfg_q[174+:6], 2'b00, pad_cfg_q[168+:6]};
+ 4'b0100: PRDATA = 32'b00000000000000001000000010000010;
+ 4'b0101: PRDATA = {30'b000000000000000000000000000000, status_q[1:0]};
+ default: PRDATA = 'b0;
+ endcase
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ pad_mux_q <= 32'b00000000000000000000000000000000;
+ clk_gate_q <= 1'sb1;
+ pad_cfg_q <= {32 {6'b000000}};
+ boot_adr_q <= BOOT_ADDR;
+ status_q <= 1'sb1;
+ pad_cfg_q[0+:6] <= 6'b000000;
+ pad_cfg_q[6+:6] <= 6'b000000;
+ pad_cfg_q[12+:6] <= 6'b000000;
+ pad_cfg_q[18+:6] <= 6'b000000;
+ pad_cfg_q[24+:6] <= 6'b000000;
+ pad_cfg_q[30+:6] <= 6'b000000;
+ pad_cfg_q[36+:6] <= 6'b000000;
+ pad_cfg_q[42+:6] <= 6'b000000;
+ pad_cfg_q[48+:6] <= 6'b000000;
+ pad_cfg_q[54+:6] <= 6'b000000;
+ pad_cfg_q[60+:6] <= 6'b000000;
+ pad_cfg_q[66+:6] <= 6'b000000;
+ pad_cfg_q[72+:6] <= 6'b000000;
+ pad_cfg_q[78+:6] <= 6'b000000;
+ pad_cfg_q[84+:6] <= 6'b000000;
+ pad_cfg_q[90+:6] <= 6'b000000;
+ pad_cfg_q[96+:6] <= 6'b000000;
+ pad_cfg_q[102+:6] <= 6'b000000;
+ pad_cfg_q[108+:6] <= 6'b000000;
+ pad_cfg_q[114+:6] <= 6'b000000;
+ pad_cfg_q[120+:6] <= 6'b000000;
+ end
+ else begin
+ pad_mux_q <= pad_mux_n;
+ clk_gate_q <= clk_gate_n;
+ pad_cfg_q <= pad_cfg_n;
+ boot_adr_q <= boot_adr_n;
+ status_q <= status_n;
+ end
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master b/verilog/rtl/ips/apb/apb_spi_master
deleted file mode 160000
index ae6db76..0000000
--- a/verilog/rtl/ips/apb/apb_spi_master
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit ae6db7620b20cd843a2e2daf17bf50e9be8ca8e7
diff --git a/verilog/rtl/ips/apb/apb_spi_master/apb_spi_master.v b/verilog/rtl/ips/apb/apb_spi_master/apb_spi_master.v
new file mode 100644
index 0000000..769ebd0
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/apb_spi_master.v
@@ -0,0 +1,305 @@
+module apb_spi_master
+#(
+ parameter BUFFER_DEPTH = 10,
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ events_o,
+ spi_clk,
+ spi_csn0,
+ spi_csn1,
+ spi_csn2,
+ spi_csn3,
+ spi_mode,
+ spi_sdo0,
+ spi_sdo1,
+ spi_sdo2,
+ spi_sdo3,
+ spi_sdi0,
+ spi_sdi1,
+ spi_sdi2,
+ spi_sdi3
+);
+ //parameter BUFFER_DEPTH = 10;
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output wire [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ output wire [1:0] events_o;
+ output wire spi_clk;
+ output wire spi_csn0;
+ output wire spi_csn1;
+ output wire spi_csn2;
+ output wire spi_csn3;
+ output wire [1:0] spi_mode;
+ output wire spi_sdo0;
+ output wire spi_sdo1;
+ output wire spi_sdo2;
+ output wire spi_sdo3;
+ input wire spi_sdi0;
+ input wire spi_sdi1;
+ input wire spi_sdi2;
+ input wire spi_sdi3;
+ localparam LOG_BUFFER_DEPTH = (BUFFER_DEPTH < 1 ? 0 : (BUFFER_DEPTH < 2 ? 1 : (BUFFER_DEPTH < 4 ? 2 : (BUFFER_DEPTH < 8 ? 3 : (BUFFER_DEPTH < 16 ? 4 : (BUFFER_DEPTH < 32 ? 5 : (BUFFER_DEPTH < 64 ? 6 : (BUFFER_DEPTH < 128 ? 7 : (BUFFER_DEPTH < 256 ? 8 : (BUFFER_DEPTH < 512 ? 9 : (BUFFER_DEPTH < 1024 ? 10 : (BUFFER_DEPTH < 2048 ? 11 : (BUFFER_DEPTH < 4096 ? 12 : (BUFFER_DEPTH < 8192 ? 13 : (BUFFER_DEPTH < 16384 ? 14 : (BUFFER_DEPTH < 32768 ? 15 : (BUFFER_DEPTH < 65536 ? 16 : (BUFFER_DEPTH < 131072 ? 17 : (BUFFER_DEPTH < 262144 ? 18 : (BUFFER_DEPTH < 524288 ? 19 : (BUFFER_DEPTH < 1048576 ? 20 : (BUFFER_DEPTH < 2097152 ? 21 : (BUFFER_DEPTH < 4194304 ? 22 : (BUFFER_DEPTH < 8388608 ? 23 : (BUFFER_DEPTH < 16777216 ? 24 : 25)))))))))))))))))))))))));
+ wire [7:0] spi_clk_div;
+ wire spi_clk_div_valid;
+ wire [31:0] spi_status;
+ wire [31:0] spi_addr;
+ wire [5:0] spi_addr_len;
+ wire [31:0] spi_cmd;
+ wire [5:0] spi_cmd_len;
+ wire [15:0] spi_data_len;
+ wire [15:0] spi_dummy_rd;
+ wire [15:0] spi_dummy_wr;
+ wire spi_swrst;
+ wire spi_rd;
+ wire spi_wr;
+ wire spi_qrd;
+ wire spi_qwr;
+ wire [3:0] spi_csreg;
+ wire [31:0] spi_data_tx;
+ wire spi_data_tx_valid;
+ wire spi_data_tx_ready;
+ wire [31:0] spi_data_rx;
+ wire spi_data_rx_valid;
+ wire spi_data_rx_ready;
+ wire [6:0] spi_ctrl_status;
+ wire [31:0] spi_ctrl_data_tx;
+ wire spi_ctrl_data_tx_valid;
+ wire spi_ctrl_data_tx_ready;
+ wire [31:0] spi_ctrl_data_rx;
+ wire spi_ctrl_data_rx_valid;
+ wire spi_ctrl_data_rx_ready;
+ wire s_eot;
+ wire [LOG_BUFFER_DEPTH:0] elements_tx;
+ wire [LOG_BUFFER_DEPTH:0] elements_rx;
+ reg [LOG_BUFFER_DEPTH:0] r_counter_tx;
+ reg [LOG_BUFFER_DEPTH:0] r_counter_rx;
+ wire [LOG_BUFFER_DEPTH:0] s_th_tx;
+ wire [LOG_BUFFER_DEPTH:0] s_th_rx;
+ wire [LOG_BUFFER_DEPTH:0] s_cnt_tx;
+ wire [LOG_BUFFER_DEPTH:0] s_cnt_rx;
+ wire s_rise_int_tx;
+ wire s_rise_int_rx;
+ reg s_int_tx;
+ reg s_int_rx;
+ wire s_int_en;
+ wire s_int_cnt_en;
+ wire s_int_rd_intsta;
+ reg [1:0] r_state_rx;
+ reg [1:0] s_state_rx_next;
+ reg [1:0] r_state_tx;
+ reg [1:0] s_state_tx_next;
+ localparam FILL_BITS = 7 - LOG_BUFFER_DEPTH;
+ assign s_rise_int_tx = elements_tx <= s_th_tx;
+ assign s_rise_int_rx = elements_rx >= s_th_rx;
+ assign spi_status = {{FILL_BITS {1'b0}}, elements_tx, {FILL_BITS {1'b0}}, elements_rx, 9'h000, spi_ctrl_status};
+ assign events_o[0] = s_int_tx | s_int_rx;
+ assign events_o[1] = s_eot;
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ r_state_tx <= 2'd0;
+ r_state_rx <= 2'd0;
+ end
+ else begin
+ r_state_tx <= s_state_tx_next;
+ r_state_rx <= s_state_rx_next;
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ r_counter_tx <= 'h0;
+ r_counter_rx <= 'h0;
+ end
+ else if (s_int_cnt_en) begin
+ if (spi_ctrl_data_tx_valid && spi_ctrl_data_tx_ready)
+ if (r_counter_tx == (s_cnt_tx - 1))
+ r_counter_tx <= 'h0;
+ else
+ r_counter_tx <= r_counter_tx + 1;
+ if (spi_ctrl_data_rx_valid && spi_ctrl_data_rx_ready)
+ if (r_counter_rx == (s_cnt_rx - 1))
+ r_counter_rx <= 'h0;
+ else
+ r_counter_rx <= r_counter_rx + 1;
+ end
+ else begin
+ r_counter_tx <= 'h0;
+ r_counter_rx <= 'h0;
+ end
+ always @(*) begin
+ s_state_tx_next = r_state_tx;
+ s_int_tx = 1'b0;
+ case (r_state_tx)
+ 2'd0:
+ if (s_rise_int_tx && s_int_en)
+ s_state_tx_next = 2'd1;
+ 2'd1: begin
+ s_int_tx = 1'b1;
+ s_state_tx_next = 2'd2;
+ end
+ 2'd2:
+ if (s_int_cnt_en) begin
+ if ((spi_ctrl_data_tx_valid && spi_ctrl_data_tx_ready) && (r_counter_tx == (s_cnt_tx - 1)))
+ s_state_tx_next = 2'd0;
+ end
+ else if (s_int_rd_intsta)
+ s_state_tx_next = 2'd0;
+ default: begin
+ s_state_tx_next = r_state_tx;
+ s_int_tx = 1'b0;
+ end
+ endcase
+ end
+ always @(*) begin
+ s_state_rx_next = r_state_rx;
+ s_int_rx = 1'b0;
+ case (r_state_rx)
+ 2'd0:
+ if (s_rise_int_rx && s_int_en)
+ s_state_rx_next = 2'd1;
+ 2'd1: begin
+ s_int_rx = 1'b1;
+ s_state_rx_next = 2'd2;
+ end
+ 2'd2:
+ if (s_int_cnt_en) begin
+ if ((spi_ctrl_data_rx_valid && spi_ctrl_data_rx_ready) && (r_counter_rx == (s_cnt_rx - 1)))
+ s_state_rx_next = 2'd0;
+ end
+ else if (s_int_rd_intsta)
+ s_state_rx_next = 2'd0;
+ endcase
+ end
+ spi_master_apb_if #(
+ .BUFFER_DEPTH(BUFFER_DEPTH),
+ .APB_ADDR_WIDTH(APB_ADDR_WIDTH)
+ ) u_axiregs(
+ .HCLK(HCLK),
+ .HRESETn(HRESETn),
+ .PADDR(PADDR),
+ .PWDATA(PWDATA),
+ .PWRITE(PWRITE),
+ .PSEL(PSEL),
+ .PENABLE(PENABLE),
+ .PRDATA(PRDATA),
+ .PREADY(PREADY),
+ .PSLVERR(PSLVERR),
+ .spi_clk_div(spi_clk_div),
+ .spi_clk_div_valid(spi_clk_div_valid),
+ .spi_status(spi_status),
+ .spi_addr(spi_addr),
+ .spi_addr_len(spi_addr_len),
+ .spi_cmd(spi_cmd),
+ .spi_cmd_len(spi_cmd_len),
+ .spi_data_len(spi_data_len),
+ .spi_dummy_rd(spi_dummy_rd),
+ .spi_dummy_wr(spi_dummy_wr),
+ .spi_swrst(spi_swrst),
+ .spi_rd(spi_rd),
+ .spi_wr(spi_wr),
+ .spi_qrd(spi_qrd),
+ .spi_qwr(spi_qwr),
+ .spi_csreg(spi_csreg),
+ .spi_int_th_rx(s_th_rx),
+ .spi_int_th_tx(s_th_tx),
+ .spi_int_cnt_rx(s_cnt_rx),
+ .spi_int_cnt_tx(s_cnt_tx),
+ .spi_int_en(s_int_en),
+ .spi_int_cnt_en(s_int_cnt_en),
+ .spi_int_rd_sta(s_int_rd_intsta),
+ .spi_data_tx(spi_data_tx),
+ .spi_data_tx_valid(spi_data_tx_valid),
+ .spi_data_tx_ready(spi_data_tx_ready),
+ .spi_data_rx(spi_data_rx),
+ .spi_data_rx_valid(spi_data_rx_valid),
+ .spi_data_rx_ready(spi_data_rx_ready)
+ );
+ spi_master_fifo #(
+ .DATA_WIDTH(32),
+ .BUFFER_DEPTH(BUFFER_DEPTH)
+ ) u_txfifo(
+ .clk_i(HCLK),
+ .rst_ni(HRESETn),
+ .clr_i(spi_swrst),
+ .elements_o(elements_tx),
+ .data_o(spi_ctrl_data_tx),
+ .valid_o(spi_ctrl_data_tx_valid),
+ .ready_i(spi_ctrl_data_tx_ready),
+ .valid_i(spi_data_tx_valid),
+ .data_i(spi_data_tx),
+ .ready_o(spi_data_tx_ready)
+ );
+ spi_master_fifo #(
+ .DATA_WIDTH(32),
+ .BUFFER_DEPTH(BUFFER_DEPTH)
+ ) u_rxfifo(
+ .clk_i(HCLK),
+ .rst_ni(HRESETn),
+ .clr_i(spi_swrst),
+ .elements_o(elements_rx),
+ .data_o(spi_data_rx),
+ .valid_o(spi_data_rx_valid),
+ .ready_i(spi_data_rx_ready),
+ .valid_i(spi_ctrl_data_rx_valid),
+ .data_i(spi_ctrl_data_rx),
+ .ready_o(spi_ctrl_data_rx_ready)
+ );
+ spi_master_controller u_spictrl(
+ .clk(HCLK),
+ .rstn(HRESETn),
+ .eot(s_eot),
+ .spi_clk_div(spi_clk_div),
+ .spi_clk_div_valid(spi_clk_div_valid),
+ .spi_status(spi_ctrl_status),
+ .spi_addr(spi_addr),
+ .spi_addr_len(spi_addr_len),
+ .spi_cmd(spi_cmd),
+ .spi_cmd_len(spi_cmd_len),
+ .spi_data_len(spi_data_len),
+ .spi_dummy_rd(spi_dummy_rd),
+ .spi_dummy_wr(spi_dummy_wr),
+ .spi_swrst(spi_swrst),
+ .spi_rd(spi_rd),
+ .spi_wr(spi_wr),
+ .spi_qrd(spi_qrd),
+ .spi_qwr(spi_qwr),
+ .spi_csreg(spi_csreg),
+ .spi_ctrl_data_tx(spi_ctrl_data_tx),
+ .spi_ctrl_data_tx_valid(spi_ctrl_data_tx_valid),
+ .spi_ctrl_data_tx_ready(spi_ctrl_data_tx_ready),
+ .spi_ctrl_data_rx(spi_ctrl_data_rx),
+ .spi_ctrl_data_rx_valid(spi_ctrl_data_rx_valid),
+ .spi_ctrl_data_rx_ready(spi_ctrl_data_rx_ready),
+ .spi_clk(spi_clk),
+ .spi_csn0(spi_csn0),
+ .spi_csn1(spi_csn1),
+ .spi_csn2(spi_csn2),
+ .spi_csn3(spi_csn3),
+ .spi_mode(spi_mode),
+ .spi_sdo0(spi_sdo0),
+ .spi_sdo1(spi_sdo1),
+ .spi_sdo2(spi_sdo2),
+ .spi_sdo3(spi_sdo3),
+ .spi_sdi0(spi_sdi0),
+ .spi_sdi1(spi_sdi1),
+ .spi_sdi2(spi_sdi2),
+ .spi_sdi3(spi_sdi3)
+ );
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master/spi_master_apb_if.v b/verilog/rtl/ips/apb/apb_spi_master/spi_master_apb_if.v
new file mode 100644
index 0000000..32690de
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/spi_master_apb_if.v
@@ -0,0 +1,209 @@
+`define log2(VALUE) ((VALUE) < ( 1 ) ? 0 : (VALUE) < ( 2 ) ? 1 : (VALUE) < ( 4 ) ? 2 : (VALUE) < ( 8 ) ? 3 : (VALUE) < ( 16 ) ? 4 : (VALUE) < ( 32 ) ? 5 : (VALUE) < ( 64 ) ? 6 : (VALUE) < ( 128 ) ? 7 : (VALUE) < ( 256 ) ? 8 : (VALUE) < ( 512 ) ? 9 : (VALUE) < ( 1024 ) ? 10 : (VALUE) < ( 2048 ) ? 11 : (VALUE) < ( 4096 ) ? 12 : (VALUE) < ( 8192 ) ? 13 : (VALUE) < ( 16384 ) ? 14 : (VALUE) < ( 32768 ) ? 15 : (VALUE) < ( 65536 ) ? 16 : (VALUE) < ( 131072 ) ? 17 : (VALUE) < ( 262144 ) ? 18 : (VALUE) < ( 524288 ) ? 19 : (VALUE) < ( 1048576 ) ? 20 : (VALUE) < ( 1048576 * 2 ) ? 21 : (VALUE) < ( 1048576 * 4 ) ? 22 : (VALUE) < ( 1048576 * 8 ) ? 23 : (VALUE) < ( 1048576 * 16 ) ? 24 : 25)
+
+`define REG_STATUS 4'b0000 // BASEREG + 0x00
+`define REG_CLKDIV 4'b0001 // BASEREG + 0x04
+`define REG_SPICMD 4'b0010 // BASEREG + 0x08
+`define REG_SPIADR 4'b0011 // BASEREG + 0x0C
+`define REG_SPILEN 4'b0100 // BASEREG + 0x10
+`define REG_SPIDUM 4'b0101 // BASEREG + 0x14
+`define REG_TXFIFO 4'b0110 // BASEREG + 0x18
+`define REG_RXFIFO 4'b1000 // BASEREG + 0x20
+`define REG_INTCFG 4'b1001 // BASEREG + 0x24
+`define REG_INTSTA 4'b1010 // BASEREG + 0x28
+
+module spi_master_apb_if
+#(
+ parameter BUFFER_DEPTH = 10,
+ parameter APB_ADDR_WIDTH = 12, //APB slaves are 4KB by default
+ parameter LOG_BUFFER_DEPTH = `log2(BUFFER_DEPTH)
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ spi_clk_div,
+ spi_clk_div_valid,
+ spi_status,
+ spi_addr,
+ spi_addr_len,
+ spi_cmd,
+ spi_cmd_len,
+ spi_csreg,
+ spi_data_len,
+ spi_dummy_rd,
+ spi_dummy_wr,
+ spi_int_th_tx,
+ spi_int_th_rx,
+ spi_int_cnt_tx,
+ spi_int_cnt_rx,
+ spi_int_en,
+ spi_int_cnt_en,
+ spi_int_rd_sta,
+ spi_swrst,
+ spi_rd,
+ spi_wr,
+ spi_qrd,
+ spi_qwr,
+ spi_data_tx,
+ spi_data_tx_valid,
+ spi_data_tx_ready,
+ spi_data_rx,
+ spi_data_rx_valid,
+ spi_data_rx_ready
+);
+ //parameter BUFFER_DEPTH = 10;
+ //parameter APB_ADDR_WIDTH = 12;
+ //parameter LOG_BUFFER_DEPTH = (BUFFER_DEPTH < 1 ? 0 : (BUFFER_DEPTH < 2 ? 1 : (BUFFER_DEPTH < 4 ? 2 : (BUFFER_DEPTH < 8 ? 3 : (BUFFER_DEPTH < 16 ? 4 : (BUFFER_DEPTH < 32 ? 5 : (BUFFER_DEPTH < 64 ? 6 : (BUFFER_DEPTH < 128 ? 7 : (BUFFER_DEPTH < 256 ? 8 : (BUFFER_DEPTH < 512 ? 9 : (BUFFER_DEPTH < 1024 ? 10 : (BUFFER_DEPTH < 2048 ? 11 : (BUFFER_DEPTH < 4096 ? 12 : (BUFFER_DEPTH < 8192 ? 13 : (BUFFER_DEPTH < 16384 ? 14 : (BUFFER_DEPTH < 32768 ? 15 : (BUFFER_DEPTH < 65536 ? 16 : (BUFFER_DEPTH < 131072 ? 17 : (BUFFER_DEPTH < 262144 ? 18 : (BUFFER_DEPTH < 524288 ? 19 : (BUFFER_DEPTH < 1048576 ? 20 : (BUFFER_DEPTH < 2097152 ? 21 : (BUFFER_DEPTH < 4194304 ? 22 : (BUFFER_DEPTH < 8388608 ? 23 : (BUFFER_DEPTH < 16777216 ? 24 : 25)))))))))))))))))))))))));
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ output reg [7:0] spi_clk_div;
+ output reg spi_clk_div_valid;
+ input wire [31:0] spi_status;
+ output reg [31:0] spi_addr;
+ output reg [5:0] spi_addr_len;
+ output reg [31:0] spi_cmd;
+ output reg [5:0] spi_cmd_len;
+ output reg [3:0] spi_csreg;
+ output reg [15:0] spi_data_len;
+ output reg [15:0] spi_dummy_rd;
+ output reg [15:0] spi_dummy_wr;
+ output reg [LOG_BUFFER_DEPTH:0] spi_int_th_tx;
+ output reg [LOG_BUFFER_DEPTH:0] spi_int_th_rx;
+ output reg [LOG_BUFFER_DEPTH:0] spi_int_cnt_tx;
+ output reg [LOG_BUFFER_DEPTH:0] spi_int_cnt_rx;
+ output reg spi_int_en;
+ output reg spi_int_cnt_en;
+ output wire spi_int_rd_sta;
+ output reg spi_swrst;
+ output reg spi_rd;
+ output reg spi_wr;
+ output reg spi_qrd;
+ output reg spi_qwr;
+ output wire [31:0] spi_data_tx;
+ output wire spi_data_tx_valid;
+ input wire spi_data_tx_ready;
+ input wire [31:0] spi_data_rx;
+ input wire spi_data_rx_valid;
+ output wire spi_data_rx_ready;
+ wire [3:0] write_address;
+ wire [3:0] read_address;
+ assign write_address = PADDR[5:2];
+ assign read_address = PADDR[5:2];
+ assign PSLVERR = 1'b0;
+ assign PREADY = 1'b1;
+ assign spi_int_rd_sta = ((PSEL & PENABLE) & ~PWRITE) & (read_address == 4'b1010);
+ always @(posedge HCLK or negedge HRESETn)
+ if (HRESETn == 1'b0) begin
+ spi_swrst <= 1'b0;
+ spi_rd <= 1'b0;
+ spi_wr <= 1'b0;
+ spi_qrd <= 1'b0;
+ spi_qwr <= 1'b0;
+ spi_clk_div_valid <= 1'b0;
+ spi_clk_div <= 1'sb0;
+ spi_cmd <= 1'sb0;
+ spi_addr <= 1'sb0;
+ spi_cmd_len <= 1'sb0;
+ spi_addr_len <= 1'sb0;
+ spi_data_len <= 1'sb0;
+ spi_dummy_rd <= 1'sb0;
+ spi_dummy_wr <= 1'sb0;
+ spi_csreg <= 1'sb0;
+ spi_int_th_tx <= 1'sb0;
+ spi_int_th_rx <= 1'sb0;
+ spi_int_cnt_tx <= 1'sb0;
+ spi_int_cnt_rx <= 1'sb0;
+ spi_int_cnt_en <= 1'b0;
+ spi_int_en <= 1'b0;
+ end
+ else if ((PSEL && PENABLE) && PWRITE) begin
+ spi_swrst <= 1'b0;
+ spi_rd <= 1'b0;
+ spi_wr <= 1'b0;
+ spi_qrd <= 1'b0;
+ spi_qwr <= 1'b0;
+ spi_clk_div_valid <= 1'b0;
+ case (write_address)
+ 4'b0000: begin
+ spi_rd <= PWDATA[0];
+ spi_wr <= PWDATA[1];
+ spi_qrd <= PWDATA[2];
+ spi_qwr <= PWDATA[3];
+ spi_swrst <= PWDATA[4];
+ spi_csreg <= PWDATA[11:8];
+ end
+ 4'b0001: begin
+ spi_clk_div <= PWDATA[7:0];
+ spi_clk_div_valid <= 1'b1;
+ end
+ 4'b0010: spi_cmd <= PWDATA;
+ 4'b0011: spi_addr <= PWDATA;
+ 4'b0100: begin
+ spi_cmd_len <= PWDATA[5:0];
+ spi_addr_len <= PWDATA[13:8];
+ spi_data_len[7:0] <= PWDATA[23:16];
+ spi_data_len[15:8] <= PWDATA[31:24];
+ end
+ 4'b0101: begin
+ spi_dummy_rd[7:0] <= PWDATA[7:0];
+ spi_dummy_rd[15:8] <= PWDATA[15:8];
+ spi_dummy_wr[7:0] <= PWDATA[23:16];
+ spi_dummy_wr[15:8] <= PWDATA[31:24];
+ end
+ 4'b1001: begin
+ spi_int_th_tx <= PWDATA[LOG_BUFFER_DEPTH:0];
+ spi_int_th_rx <= PWDATA[8 + LOG_BUFFER_DEPTH:8];
+ spi_int_cnt_tx <= PWDATA[16 + LOG_BUFFER_DEPTH:16];
+ spi_int_cnt_rx <= PWDATA[24 + LOG_BUFFER_DEPTH:24];
+ spi_int_cnt_en <= PWDATA[30];
+ spi_int_en <= PWDATA[31];
+ end
+ endcase
+ end
+ else begin
+ spi_swrst <= 1'b0;
+ spi_rd <= 1'b0;
+ spi_wr <= 1'b0;
+ spi_qrd <= 1'b0;
+ spi_qwr <= 1'b0;
+ spi_clk_div_valid <= 1'b0;
+ end
+ always @(*)
+ case (read_address)
+ 4'b0000: PRDATA = spi_status;
+ 4'b0001: PRDATA = {24'h000000, spi_clk_div};
+ 4'b0010: PRDATA = spi_cmd;
+ 4'b0011: PRDATA = spi_addr;
+ 4'b0100: PRDATA = {spi_data_len, 2'b00, spi_addr_len, 2'b00, spi_cmd_len};
+ 4'b0101: PRDATA = {spi_dummy_wr, spi_dummy_rd};
+ 4'b1000: PRDATA = spi_data_rx;
+ 4'b1001: begin
+ PRDATA = 1'sb0;
+ PRDATA[LOG_BUFFER_DEPTH:0] = spi_int_th_tx;
+ PRDATA[8 + LOG_BUFFER_DEPTH:8] = spi_int_th_rx;
+ PRDATA[16 + LOG_BUFFER_DEPTH:16] = spi_int_cnt_tx;
+ PRDATA[24 + LOG_BUFFER_DEPTH:24] = spi_int_cnt_rx;
+ PRDATA[30] = spi_int_cnt_en;
+ PRDATA[31] = spi_int_en;
+ end
+ default: PRDATA = 1'sb0;
+ endcase
+ assign spi_data_tx = PWDATA;
+ assign spi_data_tx_valid = ((PSEL & PENABLE) & PWRITE) & (write_address == 4'b0110);
+ assign spi_data_rx_ready = ((PSEL & PENABLE) & ~PWRITE) & (read_address == 4'b1000);
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master/spi_master_clkgen.v b/verilog/rtl/ips/apb/apb_spi_master/spi_master_clkgen.v
new file mode 100644
index 0000000..787aa57
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/spi_master_clkgen.v
@@ -0,0 +1,62 @@
+module spi_master_clkgen (
+ clk,
+ rstn,
+ en,
+ clk_div,
+ clk_div_valid,
+ spi_clk,
+ spi_fall,
+ spi_rise
+);
+ input wire clk;
+ input wire rstn;
+ input wire en;
+ input wire [7:0] clk_div;
+ input wire clk_div_valid;
+ output reg spi_clk;
+ output reg spi_fall;
+ output reg spi_rise;
+ reg [7:0] counter_trgt;
+ reg [7:0] counter_trgt_next;
+ reg [7:0] counter;
+ reg [7:0] counter_next;
+ reg spi_clk_next;
+ reg running;
+ always @(*) begin
+ spi_rise = 1'b0;
+ spi_fall = 1'b0;
+ if (clk_div_valid)
+ counter_trgt_next = clk_div;
+ else
+ counter_trgt_next = counter_trgt;
+ if (counter == counter_trgt) begin
+ counter_next = 0;
+ spi_clk_next = ~spi_clk;
+ if (spi_clk == 1'b0)
+ spi_rise = running;
+ else
+ spi_fall = running;
+ end
+ else begin
+ counter_next = counter + 1;
+ spi_clk_next = spi_clk;
+ end
+ end
+ always @(posedge clk or negedge rstn)
+ if (rstn == 1'b0) begin
+ counter_trgt <= 'h0;
+ counter <= 'h0;
+ spi_clk <= 1'b0;
+ running <= 1'b0;
+ end
+ else begin
+ counter_trgt <= counter_trgt_next;
+ if (!((spi_clk == 1'b0) && ~en)) begin
+ running <= 1'b1;
+ spi_clk <= spi_clk_next;
+ counter <= counter_next;
+ end
+ else
+ running <= 1'b0;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master/spi_master_controller.v b/verilog/rtl/ips/apb/apb_spi_master/spi_master_controller.v
new file mode 100644
index 0000000..83fb576
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/spi_master_controller.v
@@ -0,0 +1,488 @@
+`define SPI_STD 2'b00
+`define SPI_QUAD_TX 2'b01
+`define SPI_QUAD_RX 2'b10
+
+module spi_master_controller (
+ clk,
+ rstn,
+ eot,
+ spi_clk_div,
+ spi_clk_div_valid,
+ spi_status,
+ spi_addr,
+ spi_addr_len,
+ spi_cmd,
+ spi_cmd_len,
+ spi_data_len,
+ spi_dummy_rd,
+ spi_dummy_wr,
+ spi_csreg,
+ spi_swrst,
+ spi_rd,
+ spi_wr,
+ spi_qrd,
+ spi_qwr,
+ spi_ctrl_data_tx,
+ spi_ctrl_data_tx_valid,
+ spi_ctrl_data_tx_ready,
+ spi_ctrl_data_rx,
+ spi_ctrl_data_rx_valid,
+ spi_ctrl_data_rx_ready,
+ spi_clk,
+ spi_csn0,
+ spi_csn1,
+ spi_csn2,
+ spi_csn3,
+ spi_mode,
+ spi_sdo0,
+ spi_sdo1,
+ spi_sdo2,
+ spi_sdo3,
+ spi_sdi0,
+ spi_sdi1,
+ spi_sdi2,
+ spi_sdi3
+);
+ input wire clk;
+ input wire rstn;
+ output reg eot;
+ input wire [7:0] spi_clk_div;
+ input wire spi_clk_div_valid;
+ output reg [6:0] spi_status;
+ input wire [31:0] spi_addr;
+ input wire [5:0] spi_addr_len;
+ input wire [31:0] spi_cmd;
+ input wire [5:0] spi_cmd_len;
+ input wire [15:0] spi_data_len;
+ input wire [15:0] spi_dummy_rd;
+ input wire [15:0] spi_dummy_wr;
+ input wire [3:0] spi_csreg;
+ input wire spi_swrst;
+ input wire spi_rd;
+ input wire spi_wr;
+ input wire spi_qrd;
+ input wire spi_qwr;
+ input wire [31:0] spi_ctrl_data_tx;
+ input wire spi_ctrl_data_tx_valid;
+ output reg spi_ctrl_data_tx_ready;
+ output wire [31:0] spi_ctrl_data_rx;
+ output wire spi_ctrl_data_rx_valid;
+ input wire spi_ctrl_data_rx_ready;
+ output wire spi_clk;
+ output wire spi_csn0;
+ output wire spi_csn1;
+ output wire spi_csn2;
+ output wire spi_csn3;
+ output reg [1:0] spi_mode;
+ output wire spi_sdo0;
+ output wire spi_sdo1;
+ output wire spi_sdo2;
+ output wire spi_sdo3;
+ input wire spi_sdi0;
+ input wire spi_sdi1;
+ input wire spi_sdi2;
+ input wire spi_sdi3;
+ wire spi_rise;
+ wire spi_fall;
+ reg spi_clock_en;
+ reg spi_en_tx;
+ reg spi_en_rx;
+ reg [15:0] counter_tx;
+ reg counter_tx_valid;
+ reg [15:0] counter_rx;
+ reg counter_rx_valid;
+ reg [31:0] data_to_tx;
+ reg data_to_tx_valid;
+ wire data_to_tx_ready;
+ wire en_quad;
+ reg en_quad_int;
+ reg do_tx;
+ reg do_rx;
+ wire tx_done;
+ wire rx_done;
+ reg [1:0] s_spi_mode;
+ reg ctrl_data_valid;
+ reg spi_cs;
+ wire tx_clk_en;
+ wire rx_clk_en;
+ reg [2:0] ctrl_data_mux;
+ reg [4:0] state;
+ reg [4:0] state_next;
+ assign en_quad = (spi_qrd | spi_qwr) | en_quad_int;
+ spi_master_clkgen u_clkgen(
+ .clk(clk),
+ .rstn(rstn),
+ .en(spi_clock_en),
+ .clk_div(spi_clk_div),
+ .clk_div_valid(spi_clk_div_valid),
+ .spi_clk(spi_clk),
+ .spi_fall(spi_fall),
+ .spi_rise(spi_rise)
+ );
+ spi_master_tx u_txreg(
+ .clk(clk),
+ .rstn(rstn),
+ .en(spi_en_tx),
+ .tx_edge(spi_fall),
+ .tx_done(tx_done),
+ .sdo0(spi_sdo0),
+ .sdo1(spi_sdo1),
+ .sdo2(spi_sdo2),
+ .sdo3(spi_sdo3),
+ .en_quad_in(en_quad),
+ .counter_in(counter_tx),
+ .counter_in_upd(counter_tx_valid),
+ .data(data_to_tx),
+ .data_valid(data_to_tx_valid),
+ .data_ready(data_to_tx_ready),
+ .clk_en_o(tx_clk_en)
+ );
+ spi_master_rx u_rxreg(
+ .clk(clk),
+ .rstn(rstn),
+ .en(spi_en_rx),
+ .rx_edge(spi_rise),
+ .rx_done(rx_done),
+ .sdi0(spi_sdi0),
+ .sdi1(spi_sdi1),
+ .sdi2(spi_sdi2),
+ .sdi3(spi_sdi3),
+ .en_quad_in(en_quad),
+ .counter_in(counter_rx),
+ .counter_in_upd(counter_rx_valid),
+ .data(spi_ctrl_data_rx),
+ .data_valid(spi_ctrl_data_rx_valid),
+ .data_ready(spi_ctrl_data_rx_ready),
+ .clk_en_o(rx_clk_en)
+ );
+ always @(*) begin
+ data_to_tx = 'h0;
+ data_to_tx_valid = 1'b0;
+ spi_ctrl_data_tx_ready = 1'b0;
+ case (ctrl_data_mux)
+ 3'd0: begin
+ data_to_tx = 1'sb0;
+ data_to_tx_valid = 1'b0;
+ spi_ctrl_data_tx_ready = 1'b0;
+ end
+ 3'd1: begin
+ data_to_tx = 1'sb0;
+ data_to_tx_valid = 1'b1;
+ end
+ 3'd2: begin
+ data_to_tx = spi_cmd;
+ data_to_tx_valid = ctrl_data_valid;
+ spi_ctrl_data_tx_ready = 1'b0;
+ end
+ 3'd3: begin
+ data_to_tx = spi_addr;
+ data_to_tx_valid = ctrl_data_valid;
+ spi_ctrl_data_tx_ready = 1'b0;
+ end
+ 3'd4: begin
+ data_to_tx = spi_ctrl_data_tx;
+ data_to_tx_valid = spi_ctrl_data_tx_valid;
+ spi_ctrl_data_tx_ready = data_to_tx_ready;
+ end
+ endcase
+ end
+ always @(*) begin
+ spi_cs = 1'b1;
+ spi_clock_en = 1'b0;
+ counter_tx = 1'sb0;
+ counter_tx_valid = 1'b0;
+ counter_rx = 1'sb0;
+ counter_rx_valid = 1'b0;
+ state_next = state;
+ ctrl_data_mux = 3'd0;
+ ctrl_data_valid = 1'b0;
+ spi_en_rx = 1'b0;
+ spi_en_tx = 1'b0;
+ spi_status = 1'sb0;
+ s_spi_mode = 2'b10;
+ eot = 1'b0;
+ case (state)
+ 5'd0: begin
+ spi_status[0] = 1'b1;
+ s_spi_mode = 2'b10;
+ if (((spi_rd || spi_wr) || spi_qrd) || spi_qwr) begin
+ spi_cs = 1'b0;
+ spi_clock_en = 1'b1;
+ if (spi_cmd_len != 0) begin
+ s_spi_mode = (spi_qrd | spi_qwr ? 2'b01 : 2'b00);
+ counter_tx = {8'h00, spi_cmd_len};
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd2;
+ ctrl_data_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd1;
+ end
+ else if (spi_addr_len != 0) begin
+ s_spi_mode = (spi_qrd | spi_qwr ? 2'b01 : 2'b00);
+ counter_tx = {8'h00, spi_addr_len};
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd3;
+ ctrl_data_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd2;
+ end
+ else if (spi_data_len != 0)
+ if (spi_rd || spi_qrd) begin
+ s_spi_mode = (spi_qrd ? 2'b10 : 2'b00);
+ if (spi_dummy_rd != 0) begin
+ counter_tx = (en_quad ? {spi_dummy_rd[13:0], 2'b00} : spi_dummy_rd);
+ counter_tx_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ ctrl_data_mux = 3'd1;
+ state_next = 5'd4;
+ end
+ else begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = 5'd6;
+ end
+ end
+ else begin
+ s_spi_mode = (spi_qwr ? 2'b01 : 2'b00);
+ if (spi_dummy_wr != 0) begin
+ counter_tx = (en_quad ? {spi_dummy_wr[13:0], 2'b00} : spi_dummy_wr);
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd4;
+ end
+ else begin
+ counter_tx = spi_data_len;
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd4;
+ ctrl_data_valid = 1'b0;
+ spi_en_tx = 1'b1;
+ state_next = 5'd5;
+ end
+ end
+ end
+ else begin
+ spi_cs = 1'b1;
+ state_next = 5'd0;
+ end
+ end
+ 5'd1: begin
+ spi_status[1] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = 1'b1;
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ if (tx_done) begin
+ if (spi_addr_len != 0) begin
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ counter_tx = {8'h00, spi_addr_len};
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd3;
+ ctrl_data_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd2;
+ end
+ else if (spi_data_len != 0) begin
+ if (do_rx) begin
+ s_spi_mode = (en_quad ? 2'b10 : 2'b00);
+ if (spi_dummy_rd != 0) begin
+ counter_tx = (en_quad ? {spi_dummy_rd[13:0], 2'b00} : spi_dummy_rd);
+ counter_tx_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ ctrl_data_mux = 3'd1;
+ state_next = 5'd4;
+ end
+ else begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = 5'd6;
+ end
+ end
+ else begin
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ if (spi_dummy_wr != 0) begin
+ counter_tx = (en_quad ? {spi_dummy_wr[13:0], 2'b00} : spi_dummy_wr);
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd4;
+ end
+ else begin
+ counter_tx = spi_data_len;
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd4;
+ ctrl_data_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd5;
+ end
+ end
+ end
+ else
+ state_next = 5'd0;
+ end
+ else begin
+ spi_en_tx = 1'b1;
+ state_next = 5'd1;
+ end
+ end
+ 5'd2: begin
+ spi_en_tx = 1'b1;
+ spi_status[2] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = 1'b1;
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ if (tx_done)
+ if (spi_data_len != 0) begin
+ if (do_rx) begin
+ s_spi_mode = (en_quad ? 2'b10 : 2'b00);
+ if (spi_dummy_rd != 0) begin
+ counter_tx = (en_quad ? {spi_dummy_rd[13:0], 2'b00} : spi_dummy_rd);
+ counter_tx_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ ctrl_data_mux = 3'd1;
+ state_next = 5'd4;
+ end
+ else begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = 5'd6;
+ end
+ end
+ else begin
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ spi_en_tx = 1'b1;
+ if (spi_dummy_wr != 0) begin
+ counter_tx = (en_quad ? {spi_dummy_wr[13:0], 2'b00} : spi_dummy_wr);
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd1;
+ state_next = 5'd4;
+ end
+ else begin
+ counter_tx = spi_data_len;
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = 3'd4;
+ ctrl_data_valid = 1'b1;
+ state_next = 5'd5;
+ end
+ end
+ end
+ else
+ state_next = 5'd0;
+ end
+ 5'd3: begin
+ spi_status[3] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = 1'b1;
+ spi_en_tx = 1'b1;
+ end
+ 5'd4: begin
+ spi_en_tx = 1'b1;
+ spi_status[4] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = 1'b1;
+ s_spi_mode = (en_quad ? 2'b10 : 2'b00);
+ if (tx_done) begin
+ if (spi_data_len != 0) begin
+ if (do_rx) begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = 5'd6;
+ end
+ else begin
+ counter_tx = spi_data_len;
+ counter_tx_valid = 1'b1;
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ spi_clock_en = tx_clk_en;
+ spi_en_tx = 1'b1;
+ state_next = 5'd5;
+ end
+ end
+ else begin
+ eot = 1'b1;
+ state_next = 5'd0;
+ end
+ end
+ else begin
+ ctrl_data_mux = 3'd1;
+ spi_en_tx = 1'b1;
+ state_next = 5'd4;
+ end
+ end
+ 5'd5: begin
+ spi_status[5] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = tx_clk_en;
+ ctrl_data_mux = 3'd4;
+ ctrl_data_valid = 1'b1;
+ spi_en_tx = 1'b1;
+ s_spi_mode = (en_quad ? 2'b01 : 2'b00);
+ if (tx_done) begin
+ eot = 1'b1;
+ state_next = 5'd0;
+ spi_clock_en = 1'b0;
+ end
+ else
+ state_next = 5'd5;
+ end
+ 5'd6: begin
+ spi_status[6] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = rx_clk_en;
+ s_spi_mode = (en_quad ? 2'b10 : 2'b00);
+ if (rx_done)
+ state_next = 5'd7;
+ else begin
+ spi_en_rx = 1'b1;
+ state_next = 5'd6;
+ end
+ end
+ 5'd7: begin
+ spi_status[6] = 1'b1;
+ spi_cs = 1'b0;
+ spi_clock_en = 1'b0;
+ s_spi_mode = (en_quad ? 2'b10 : 2'b00);
+ if (spi_fall) begin
+ eot = 1'b1;
+ state_next = 5'd0;
+ end
+ else
+ state_next = 5'd7;
+ end
+ endcase
+ end
+ always @(posedge clk or negedge rstn)
+ if (rstn == 1'b0) begin
+ state <= 5'd0;
+ en_quad_int <= 1'b0;
+ do_rx <= 1'b0;
+ do_tx <= 1'b0;
+ spi_mode <= 2'b10;
+ end
+ else begin
+ state <= state_next;
+ spi_mode <= s_spi_mode;
+ if (spi_qrd || spi_qwr)
+ en_quad_int <= 1'b1;
+ else if (state_next == 5'd0)
+ en_quad_int <= 1'b0;
+ if (spi_rd || spi_qrd) begin
+ do_rx <= 1'b1;
+ do_tx <= 1'b0;
+ end
+ else if (spi_wr || spi_qwr) begin
+ do_rx <= 1'b0;
+ do_tx <= 1'b1;
+ end
+ else if (state_next == 5'd0) begin
+ do_rx <= 1'b0;
+ do_tx <= 1'b0;
+ end
+ end
+ assign spi_csn0 = ~spi_csreg[0] | spi_cs;
+ assign spi_csn1 = ~spi_csreg[1] | spi_cs;
+ assign spi_csn2 = ~spi_csreg[2] | spi_cs;
+ assign spi_csn3 = ~spi_csreg[3] | spi_cs;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master/spi_master_fifo.v b/verilog/rtl/ips/apb/apb_spi_master/spi_master_fifo.v
new file mode 100644
index 0000000..08e20a1
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/spi_master_fifo.v
@@ -0,0 +1,85 @@
+`define log2(VALUE) ((VALUE) < ( 1 ) ? 0 : (VALUE) < ( 2 ) ? 1 : (VALUE) < ( 4 ) ? 2 : (VALUE) < ( 8 ) ? 3 : (VALUE) < ( 16 ) ? 4 : (VALUE) < ( 32 ) ? 5 : (VALUE) < ( 64 ) ? 6 : (VALUE) < ( 128 ) ? 7 : (VALUE) < ( 256 ) ? 8 : (VALUE) < ( 512 ) ? 9 : (VALUE) < ( 1024 ) ? 10 : (VALUE) < ( 2048 ) ? 11 : (VALUE) < ( 4096 ) ? 12 : (VALUE) < ( 8192 ) ? 13 : (VALUE) < ( 16384 ) ? 14 : (VALUE) < ( 32768 ) ? 15 : (VALUE) < ( 65536 ) ? 16 : (VALUE) < ( 131072 ) ? 17 : (VALUE) < ( 262144 ) ? 18 : (VALUE) < ( 524288 ) ? 19 : (VALUE) < ( 1048576 ) ? 20 : (VALUE) < ( 1048576 * 2 ) ? 21 : (VALUE) < ( 1048576 * 4 ) ? 22 : (VALUE) < ( 1048576 * 8 ) ? 23 : (VALUE) < ( 1048576 * 16 ) ? 24 : 25)
+
+module spi_master_fifo
+#(
+ parameter DATA_WIDTH = 32,
+ parameter BUFFER_DEPTH = 2,
+ parameter LOG_BUFFER_DEPTH = `log2(BUFFER_DEPTH)
+)
+(
+ clk_i,
+ rst_ni,
+ clr_i,
+ elements_o,
+ data_o,
+ valid_o,
+ ready_i,
+ valid_i,
+ data_i,
+ ready_o
+);
+ //parameter DATA_WIDTH = 32;
+ //parameter BUFFER_DEPTH = 2;
+ //parameter LOG_BUFFER_DEPTH = (BUFFER_DEPTH < 1 ? 0 : (BUFFER_DEPTH < 2 ? 1 : (BUFFER_DEPTH < 4 ? 2 : (BUFFER_DEPTH < 8 ? 3 : (BUFFER_DEPTH < 16 ? 4 : (BUFFER_DEPTH < 32 ? 5 : (BUFFER_DEPTH < 64 ? 6 : (BUFFER_DEPTH < 128 ? 7 : (BUFFER_DEPTH < 256 ? 8 : (BUFFER_DEPTH < 512 ? 9 : (BUFFER_DEPTH < 1024 ? 10 : (BUFFER_DEPTH < 2048 ? 11 : (BUFFER_DEPTH < 4096 ? 12 : (BUFFER_DEPTH < 8192 ? 13 : (BUFFER_DEPTH < 16384 ? 14 : (BUFFER_DEPTH < 32768 ? 15 : (BUFFER_DEPTH < 65536 ? 16 : (BUFFER_DEPTH < 131072 ? 17 : (BUFFER_DEPTH < 262144 ? 18 : (BUFFER_DEPTH < 524288 ? 19 : (BUFFER_DEPTH < 1048576 ? 20 : (BUFFER_DEPTH < 2097152 ? 21 : (BUFFER_DEPTH < 4194304 ? 22 : (BUFFER_DEPTH < 8388608 ? 23 : (BUFFER_DEPTH < 16777216 ? 24 : 25)))))))))))))))))))))))));
+ input wire clk_i;
+ input wire rst_ni;
+ input wire clr_i;
+ output wire [LOG_BUFFER_DEPTH:0] elements_o;
+ output wire [DATA_WIDTH - 1:0] data_o;
+ output wire valid_o;
+ input wire ready_i;
+ input wire valid_i;
+ input wire [DATA_WIDTH - 1:0] data_i;
+ output wire ready_o;
+ reg [LOG_BUFFER_DEPTH - 1:0] pointer_in;
+ reg [LOG_BUFFER_DEPTH - 1:0] pointer_out;
+ reg [LOG_BUFFER_DEPTH:0] elements;
+ reg [DATA_WIDTH - 1:0] buffer [BUFFER_DEPTH - 1:0];
+ wire full;
+ integer loop1;
+ assign full = elements == BUFFER_DEPTH;
+ assign elements_o = elements;
+ always @(posedge clk_i or negedge rst_ni) begin : elements_sequential
+ if (rst_ni == 1'b0)
+ elements <= 0;
+ else if (clr_i)
+ elements <= 0;
+ else if ((ready_i && valid_o) && (!valid_i || full))
+ elements <= elements - 1;
+ else if (((!valid_o || !ready_i) && valid_i) && !full)
+ elements <= elements + 1;
+ end
+ always @(posedge clk_i or negedge rst_ni) begin : buffers_sequential
+ if (rst_ni == 1'b0) begin
+ for (loop1 = 0; loop1 < BUFFER_DEPTH; loop1 = loop1 + 1)
+ buffer[loop1] <= 0;
+ end
+ else if (valid_i && !full)
+ buffer[pointer_in] <= data_i;
+ end
+ always @(posedge clk_i or negedge rst_ni) begin : sequential
+ if (rst_ni == 1'b0) begin
+ pointer_out <= 0;
+ pointer_in <= 0;
+ end
+ else if (clr_i) begin
+ pointer_out <= 0;
+ pointer_in <= 0;
+ end
+ else begin
+ if (valid_i && !full)
+ if (pointer_in == $unsigned(BUFFER_DEPTH - 1))
+ pointer_in <= 0;
+ else
+ pointer_in <= pointer_in + 1;
+ if (ready_i && valid_o)
+ if (pointer_out == $unsigned(BUFFER_DEPTH - 1))
+ pointer_out <= 0;
+ else
+ pointer_out <= pointer_out + 1;
+ end
+ end
+ assign data_o = buffer[pointer_out];
+ assign valid_o = elements != 0;
+ assign ready_o = ~full;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master/spi_master_rx.v b/verilog/rtl/ips/apb/apb_spi_master/spi_master_rx.v
new file mode 100644
index 0000000..8885afc
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/spi_master_rx.v
@@ -0,0 +1,116 @@
+module spi_master_rx (
+ clk,
+ rstn,
+ en,
+ rx_edge,
+ rx_done,
+ sdi0,
+ sdi1,
+ sdi2,
+ sdi3,
+ en_quad_in,
+ counter_in,
+ counter_in_upd,
+ data,
+ data_ready,
+ data_valid,
+ clk_en_o
+);
+ input wire clk;
+ input wire rstn;
+ input wire en;
+ input wire rx_edge;
+ output wire rx_done;
+ input wire sdi0;
+ input wire sdi1;
+ input wire sdi2;
+ input wire sdi3;
+ input wire en_quad_in;
+ input wire [15:0] counter_in;
+ input wire counter_in_upd;
+ output wire [31:0] data;
+ input wire data_ready;
+ output reg data_valid;
+ output reg clk_en_o;
+ reg [31:0] data_int;
+ reg [31:0] data_int_next;
+ reg [15:0] counter;
+ reg [15:0] counter_trgt;
+ reg [15:0] counter_next;
+ reg [15:0] counter_trgt_next;
+ wire done;
+ wire reg_done;
+ reg [1:0] rx_CS;
+ reg [1:0] rx_NS;
+ assign reg_done = (!en_quad_in && (counter[4:0] == 5'b11111)) || (en_quad_in && (counter[2:0] == 3'b111));
+ assign data = data_int_next;
+ assign rx_done = done;
+ always @(*)
+ if (counter_in_upd)
+ counter_trgt_next = (en_quad_in ? {2'b00, counter_in[15:2]} : counter_in);
+ else
+ counter_trgt_next = counter_trgt;
+ assign done = (counter == (counter_trgt - 1)) && rx_edge;
+ always @(*) begin
+ rx_NS = rx_CS;
+ clk_en_o = 1'b0;
+ data_int_next = data_int;
+ data_valid = 1'b0;
+ counter_next = counter;
+ case (rx_CS)
+ 2'd0: begin
+ clk_en_o = 1'b0;
+ if (en)
+ rx_NS = 2'd1;
+ end
+ 2'd1: begin
+ clk_en_o = 1'b1;
+ if (rx_edge) begin
+ counter_next = counter + 1;
+ if (en_quad_in)
+ data_int_next = {data_int[27:0], sdi3, sdi2, sdi1, sdi0};
+ else
+ data_int_next = {data_int[30:0], sdi0};
+ if (rx_done) begin
+ counter_next = 0;
+ data_valid = 1'b1;
+ if (data_ready)
+ rx_NS = 2'd0;
+ else
+ rx_NS = 2'd3;
+ end
+ else if (reg_done) begin
+ data_valid = 1'b1;
+ if (~data_ready) begin
+ clk_en_o = 1'b0;
+ rx_NS = 2'd2;
+ end
+ end
+ end
+ end
+ 2'd3: begin
+ data_valid = 1'b1;
+ if (data_ready)
+ rx_NS = 2'd0;
+ end
+ 2'd2: begin
+ data_valid = 1'b1;
+ if (data_ready)
+ rx_NS = 2'd1;
+ end
+ endcase
+ end
+ always @(posedge clk or negedge rstn)
+ if (rstn == 0) begin
+ counter <= 0;
+ counter_trgt <= 'h8;
+ data_int <= 1'sb0;
+ rx_CS <= 2'd0;
+ end
+ else begin
+ counter <= counter_next;
+ counter_trgt <= counter_trgt_next;
+ data_int <= data_int_next;
+ rx_CS <= rx_NS;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_spi_master/spi_master_tx.v b/verilog/rtl/ips/apb/apb_spi_master/spi_master_tx.v
new file mode 100644
index 0000000..ede9996
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_spi_master/spi_master_tx.v
@@ -0,0 +1,115 @@
+module spi_master_tx (
+ clk,
+ rstn,
+ en,
+ tx_edge,
+ tx_done,
+ sdo0,
+ sdo1,
+ sdo2,
+ sdo3,
+ en_quad_in,
+ counter_in,
+ counter_in_upd,
+ data,
+ data_valid,
+ data_ready,
+ clk_en_o
+);
+ input wire clk;
+ input wire rstn;
+ input wire en;
+ input wire tx_edge;
+ output wire tx_done;
+ output wire sdo0;
+ output wire sdo1;
+ output wire sdo2;
+ output wire sdo3;
+ input wire en_quad_in;
+ input wire [15:0] counter_in;
+ input wire counter_in_upd;
+ input wire [31:0] data;
+ input wire data_valid;
+ output reg data_ready;
+ output reg clk_en_o;
+ reg [31:0] data_int;
+ reg [31:0] data_int_next;
+ reg [15:0] counter;
+ reg [15:0] counter_trgt;
+ reg [15:0] counter_next;
+ reg [15:0] counter_trgt_next;
+ wire done;
+ wire reg_done;
+ reg [0:0] tx_CS;
+ reg [0:0] tx_NS;
+ assign sdo0 = (en_quad_in ? data_int[28] : data_int[31]);
+ assign sdo1 = data_int[29];
+ assign sdo2 = data_int[30];
+ assign sdo3 = data_int[31];
+ assign tx_done = done;
+ assign reg_done = (!en_quad_in && (counter[4:0] == 5'b11111)) || (en_quad_in && (counter[2:0] == 3'b111));
+ always @(*)
+ if (counter_in_upd)
+ counter_trgt_next = (en_quad_in ? {2'b00, counter_in[15:2]} : counter_in);
+ else
+ counter_trgt_next = counter_trgt;
+ assign done = (counter == (counter_trgt - 1)) && tx_edge;
+ always @(*) begin
+ tx_NS = tx_CS;
+ clk_en_o = 1'b0;
+ data_int_next = data_int;
+ data_ready = 1'b0;
+ counter_next = counter;
+ case (tx_CS)
+ 1'd0: begin
+ clk_en_o = 1'b0;
+ if (en && data_valid) begin
+ data_int_next = data;
+ data_ready = 1'b1;
+ tx_NS = 1'd1;
+ end
+ end
+ 1'd1: begin
+ clk_en_o = 1'b1;
+ if (tx_edge) begin
+ counter_next = counter + 1;
+ data_int_next = (en_quad_in ? {data_int[27:0], 4'b0000} : {data_int[30:0], 1'b0});
+ if (tx_done) begin
+ counter_next = 0;
+ if (en && data_valid) begin
+ data_int_next = data;
+ data_ready = 1'b1;
+ tx_NS = 1'd1;
+ end
+ else begin
+ clk_en_o = 1'b0;
+ tx_NS = 1'd0;
+ end
+ end
+ else if (reg_done)
+ if (data_valid) begin
+ data_int_next = data;
+ data_ready = 1'b1;
+ end
+ else begin
+ clk_en_o = 1'b0;
+ tx_NS = 1'd0;
+ end
+ end
+ end
+ endcase
+ end
+ always @(posedge clk or negedge rstn)
+ if (~rstn) begin
+ counter <= 0;
+ counter_trgt <= 'h8;
+ data_int <= 'h0;
+ tx_CS <= 1'd0;
+ end
+ else begin
+ counter <= counter_next;
+ counter_trgt <= counter_trgt_next;
+ data_int <= data_int_next;
+ tx_CS <= tx_NS;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_timer b/verilog/rtl/ips/apb/apb_timer
deleted file mode 160000
index c8b851b..0000000
--- a/verilog/rtl/ips/apb/apb_timer
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c8b851bc43a22cb47f490e819b04fd0687b901f8
diff --git a/verilog/rtl/ips/apb/apb_timer/apb_timer.v b/verilog/rtl/ips/apb/apb_timer/apb_timer.v
new file mode 100644
index 0000000..a51a47d
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_timer/apb_timer.v
@@ -0,0 +1,71 @@
+module apb_timer
+#(
+ parameter APB_ADDR_WIDTH = 12, //APB slaves are 4KB by default
+ parameter TIMER_CNT = 2 // how many timers should be instantiated
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ irq_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ //parameter TIMER_CNT = 2;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output reg PREADY;
+ output reg PSLVERR;
+ output wire [(TIMER_CNT * 2) - 1:0] irq_o;
+ reg [TIMER_CNT - 1:0] psel_int;
+ wire [TIMER_CNT - 1:0] pready;
+ wire [TIMER_CNT - 1:0] pslverr;
+ wire [$clog2(TIMER_CNT) - 1:0] slave_address_int;
+ wire [(TIMER_CNT * 32) - 1:0] prdata;
+ assign slave_address_int = PADDR[$clog2(TIMER_CNT) + (2'd2 + 1):2'd2 + 2];
+ always @(*) begin
+ psel_int = 1'sb0;
+ psel_int[slave_address_int] = PSEL;
+ end
+ always @(*)
+ if (psel_int != {TIMER_CNT {1'sb0}}) begin
+ PRDATA = prdata[slave_address_int * 32+:32];
+ PREADY = pready[slave_address_int];
+ PSLVERR = pslverr[slave_address_int];
+ end
+ else begin
+ PRDATA = 1'sb0;
+ PREADY = 1'b1;
+ PSLVERR = 1'b0;
+ end
+ genvar k;
+ generate
+ for (k = 0; k < TIMER_CNT; k = k + 1) begin : TIMER_GEN
+ timer timer_i(
+ .HCLK(HCLK),
+ .HRESETn(HRESETn),
+ .PADDR(PADDR),
+ .PWDATA(PWDATA),
+ .PWRITE(PWRITE),
+ .PSEL(psel_int[k]),
+ .PENABLE(PENABLE),
+ .PRDATA(prdata[k * 32+:32]),
+ .PREADY(pready[k]),
+ .PSLVERR(pslverr[k]),
+ .irq_o(irq_o[(2 * k) + 1:2 * k])
+ );
+ end
+ endgenerate
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_timer/timer.v b/verilog/rtl/ips/apb/apb_timer/timer.v
new file mode 100644
index 0000000..7448cc8
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_timer/timer.v
@@ -0,0 +1,86 @@
+module timer
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ HCLK,
+ HRESETn,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ irq_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire HCLK;
+ input wire HRESETn;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ output reg [1:0] irq_o;
+ wire [1:0] register_adr;
+ assign register_adr = PADDR[4:2];
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+ reg [95:0] regs_q;
+ reg [95:0] regs_n;
+ reg [31:0] cycle_counter_n;
+ reg [31:0] cycle_counter_q;
+ wire [2:0] prescaler_int;
+ always @(*) begin
+ irq_o = 2'b00;
+ if (regs_q[64+:32] == 32'hffffffff)
+ irq_o[0] = 1'b1;
+ if ((regs_q[0+:32] != 'b0) && (regs_q[64+:32] == regs_q[0+:32]))
+ irq_o[1] = 1'b1;
+ end
+ assign prescaler_int = regs_q[37-:3];
+ always @(*) begin
+ regs_n = regs_q;
+ cycle_counter_n = cycle_counter_q + 1;
+ if ((irq_o[0] == 1'b1) || (irq_o[1] == 1'b1))
+ regs_n[64+:32] = 1'b0;
+ else if ((regs_q[32] && (prescaler_int != 'b0)) && (prescaler_int == cycle_counter_q))
+ regs_n[64+:32] = regs_q[64+:32] + 1;
+ else if (regs_q[32] && (regs_q[37-:3] == 'b0))
+ regs_n[64+:32] = regs_q[64+:32] + 1;
+ if (cycle_counter_q >= regs_q[32+:32])
+ cycle_counter_n = 32'b00000000000000000000000000000000;
+ if ((PSEL && PENABLE) && PWRITE)
+ case (register_adr)
+ 2'b00: regs_n[64+:32] = PWDATA;
+ 2'b01: regs_n[32+:32] = PWDATA;
+ 2'b10: begin
+ regs_n[0+:32] = PWDATA;
+ regs_n[64+:32] = 32'b00000000000000000000000000000000;
+ end
+ endcase
+ end
+ always @(*) begin
+ PRDATA = 'b0;
+ if ((PSEL && PENABLE) && !PWRITE)
+ case (register_adr)
+ 2'b00: PRDATA = regs_q[64+:32];
+ 2'b01: PRDATA = regs_q[32+:32];
+ 2'b10: PRDATA = regs_q[0+:32];
+ endcase
+ end
+ always @(posedge HCLK or negedge HRESETn)
+ if (~HRESETn) begin
+ regs_q <= {3 {32'b00000000000000000000000000000000}};
+ cycle_counter_q <= 32'b00000000000000000000000000000000;
+ end
+ else begin
+ regs_q <= regs_n;
+ cycle_counter_q <= cycle_counter_n;
+ end
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_uart_sv b/verilog/rtl/ips/apb/apb_uart_sv
deleted file mode 160000
index dfad6e0..0000000
--- a/verilog/rtl/ips/apb/apb_uart_sv
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit dfad6e04d19cc9481d3cd2750b45b970dc61271b
diff --git a/verilog/rtl/ips/apb/apb_uart_sv/apb_uart.v b/verilog/rtl/ips/apb/apb_uart_sv/apb_uart.v
new file mode 100644
index 0000000..9969081
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_uart_sv/apb_uart.v
@@ -0,0 +1,241 @@
+module apb_uart_sv
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ CLK,
+ RSTN,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ rx_i,
+ tx_o,
+ event_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire CLK;
+ input wire RSTN;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ input wire rx_i;
+ output wire tx_o;
+ output wire event_o;
+ parameter RBR = 3'h0;
+ parameter THR = 3'h0;
+ parameter DLL = 3'h0;
+ parameter IER = 3'h1;
+ parameter DLM = 3'h1;
+ parameter IIR = 3'h2;
+ parameter FCR = 3'h2;
+ parameter LCR = 3'h3;
+ parameter MCR = 3'h4;
+ parameter LSR = 3'h5;
+ parameter MSR = 3'h6;
+ parameter SCR = 3'h7;
+ parameter TX_FIFO_DEPTH = 16;
+ parameter RX_FIFO_DEPTH = 16;
+ wire [2:0] register_adr;
+ reg [79:0] regs_q;
+ reg [79:0] regs_n;
+ reg [1:0] trigger_level_n;
+ reg [1:0] trigger_level_q;
+ wire [7:0] rx_data;
+ wire parity_error;
+ wire [3:0] IIR_o;
+ reg [3:0] clr_int;
+ wire tx_ready;
+ reg apb_rx_ready;
+ wire rx_valid;
+ reg tx_fifo_clr_n;
+ reg tx_fifo_clr_q;
+ reg rx_fifo_clr_n;
+ reg rx_fifo_clr_q;
+ reg fifo_tx_valid;
+ wire tx_valid;
+ wire fifo_rx_valid;
+ reg fifo_rx_ready;
+ wire rx_ready;
+ reg [7:0] fifo_tx_data;
+ wire [8:0] fifo_rx_data;
+ wire [7:0] tx_data;
+ wire [$clog2(TX_FIFO_DEPTH):0] tx_elements;
+ wire [$clog2(RX_FIFO_DEPTH):0] rx_elements;
+ uart_rx uart_rx_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .rx_i(rx_i),
+ .cfg_en_i(1'b1),
+ .cfg_div_i({regs_q[(DLM + 'd8) * 8+:8], regs_q[(DLL + 'd8) * 8+:8]}),
+ .cfg_parity_en_i(regs_q[(LCR * 8) + 3]),
+ .cfg_bits_i(regs_q[(LCR * 8) + 1-:2]),
+ .busy_o(),
+ .err_o(parity_error),
+ .err_clr_i(1'b1),
+ .rx_data_o(rx_data),
+ .rx_valid_o(rx_valid),
+ .rx_ready_i(rx_ready)
+ );
+ uart_tx uart_tx_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .tx_o(tx_o),
+ .busy_o(),
+ .cfg_en_i(1'b1),
+ .cfg_div_i({regs_q[(DLM + 'd8) * 8+:8], regs_q[(DLL + 'd8) * 8+:8]}),
+ .cfg_parity_en_i(regs_q[(LCR * 8) + 3]),
+ .cfg_bits_i(regs_q[(LCR * 8) + 1-:2]),
+ .cfg_stop_bits_i(regs_q[(LCR * 8) + 2]),
+ .tx_data_i(tx_data),
+ .tx_valid_i(tx_valid),
+ .tx_ready_o(tx_ready)
+ );
+ io_generic_fifo #(
+ .DATA_WIDTH(9),
+ .BUFFER_DEPTH(RX_FIFO_DEPTH)
+ ) uart_rx_fifo_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .clr_i(rx_fifo_clr_q),
+ .elements_o(rx_elements),
+ .data_o(fifo_rx_data),
+ .valid_o(fifo_rx_valid),
+ .ready_i(fifo_rx_ready),
+ .valid_i(rx_valid),
+ .data_i({parity_error, rx_data}),
+ .ready_o(rx_ready)
+ );
+ io_generic_fifo #(
+ .DATA_WIDTH(8),
+ .BUFFER_DEPTH(TX_FIFO_DEPTH)
+ ) uart_tx_fifo_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .clr_i(tx_fifo_clr_q),
+ .elements_o(tx_elements),
+ .data_o(tx_data),
+ .valid_o(tx_valid),
+ .ready_i(tx_ready),
+ .valid_i(fifo_tx_valid),
+ .data_i(fifo_tx_data),
+ .ready_o()
+ );
+ uart_interrupt #(
+ .TX_FIFO_DEPTH(TX_FIFO_DEPTH),
+ .RX_FIFO_DEPTH(RX_FIFO_DEPTH)
+ ) uart_interrupt_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .IER_i(regs_q[(IER * 8) + 2-:3]),
+ .RDA_i(regs_n[(LSR * 8) + 5]),
+ .CTI_i(1'b0),
+ .error_i(regs_n[(LSR * 8) + 2]),
+ .rx_elements_i(rx_elements),
+ .tx_elements_i(tx_elements),
+ .trigger_level_i(trigger_level_q),
+ .clr_int_i(clr_int),
+ .interrupt_o(event_o),
+ .IIR_o(IIR_o)
+ );
+ always @(*) begin
+ regs_n = regs_q;
+ trigger_level_n = trigger_level_q;
+ fifo_tx_valid = 1'b0;
+ tx_fifo_clr_n = 1'b0;
+ rx_fifo_clr_n = 1'b0;
+ regs_n[LSR * 8] = fifo_rx_valid;
+ regs_n[(LSR * 8) + 2] = fifo_rx_data[8];
+ regs_n[(LSR * 8) + 5] = ~(|tx_elements);
+ regs_n[(LSR * 8) + 6] = tx_ready & ~(|tx_elements);
+ if ((PSEL && PENABLE) && PWRITE)
+ case (register_adr)
+ THR:
+ if (regs_q[(LCR * 8) + 7])
+ regs_n[(DLL + 'd8) * 8+:8] = PWDATA[7:0];
+ else begin
+ fifo_tx_data = PWDATA[7:0];
+ fifo_tx_valid = 1'b1;
+ end
+ IER:
+ if (regs_q[(LCR * 8) + 7])
+ regs_n[(DLM + 'd8) * 8+:8] = PWDATA[7:0];
+ else
+ regs_n[IER * 8+:8] = PWDATA[7:0];
+ LCR: regs_n[LCR * 8+:8] = PWDATA[7:0];
+ FCR: begin
+ rx_fifo_clr_n = PWDATA[1];
+ tx_fifo_clr_n = PWDATA[2];
+ trigger_level_n = PWDATA[7:6];
+ end
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ PRDATA = 'b0;
+ apb_rx_ready = 1'b0;
+ fifo_rx_ready = 1'b0;
+ clr_int = 4'b0000;
+ if ((PSEL && PENABLE) && !PWRITE)
+ case (register_adr)
+ RBR:
+ if (regs_q[(LCR * 8) + 7])
+ PRDATA = {24'b000000000000000000000000, regs_q[(DLL + 'd8) * 8+:8]};
+ else begin
+ fifo_rx_ready = 1'b1;
+ PRDATA = {24'b000000000000000000000000, fifo_rx_data[7:0]};
+ clr_int = 4'b1000;
+ end
+ LSR: begin
+ PRDATA = {24'b000000000000000000000000, regs_q[LSR * 8+:8]};
+ clr_int = 4'b1100;
+ end
+ LCR: PRDATA = {24'b000000000000000000000000, regs_q[LCR * 8+:8]};
+ IER:
+ if (regs_q[(LCR * 8) + 7])
+ PRDATA = {24'b000000000000000000000000, regs_q[(DLM + 'd8) * 8+:8]};
+ else
+ PRDATA = {24'b000000000000000000000000, regs_q[IER * 8+:8]};
+ IIR: begin
+ PRDATA = {28'b0000000000000000000000001100, IIR_o};
+ clr_int = 4'b0100;
+ end
+ default:
+ ;
+ endcase
+ end
+ always @(posedge CLK or negedge RSTN)
+ if (~RSTN) begin
+ regs_q[IER * 8+:8] <= 8'h00;
+ regs_q[IIR * 8+:8] <= 8'h01;
+ regs_q[LCR * 8+:8] <= 8'h00;
+ regs_q[MCR * 8+:8] <= 8'h00;
+ regs_q[LSR * 8+:8] <= 8'h60;
+ regs_q[MSR * 8+:8] <= 8'h00;
+ regs_q[SCR * 8+:8] <= 8'h00;
+ regs_q[(DLM + 'd8) * 8+:8] <= 8'h00;
+ regs_q[(DLL + 'd8) * 8+:8] <= 8'h00;
+ trigger_level_q <= 2'b00;
+ tx_fifo_clr_q <= 1'b0;
+ rx_fifo_clr_q <= 1'b0;
+ end
+ else begin
+ regs_q <= regs_n;
+ trigger_level_q <= trigger_level_n;
+ tx_fifo_clr_q <= tx_fifo_clr_n;
+ rx_fifo_clr_q <= rx_fifo_clr_n;
+ end
+ assign register_adr = {PADDR[2:0]};
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_uart_sv/apb_uart_sv.v b/verilog/rtl/ips/apb/apb_uart_sv/apb_uart_sv.v
new file mode 100644
index 0000000..9969081
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_uart_sv/apb_uart_sv.v
@@ -0,0 +1,241 @@
+module apb_uart_sv
+#(
+ parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
+)
+(
+ CLK,
+ RSTN,
+ PADDR,
+ PWDATA,
+ PWRITE,
+ PSEL,
+ PENABLE,
+ PRDATA,
+ PREADY,
+ PSLVERR,
+ rx_i,
+ tx_o,
+ event_o
+);
+ //parameter APB_ADDR_WIDTH = 12;
+ input wire CLK;
+ input wire RSTN;
+ input wire [APB_ADDR_WIDTH - 1:0] PADDR;
+ input wire [31:0] PWDATA;
+ input wire PWRITE;
+ input wire PSEL;
+ input wire PENABLE;
+ output reg [31:0] PRDATA;
+ output wire PREADY;
+ output wire PSLVERR;
+ input wire rx_i;
+ output wire tx_o;
+ output wire event_o;
+ parameter RBR = 3'h0;
+ parameter THR = 3'h0;
+ parameter DLL = 3'h0;
+ parameter IER = 3'h1;
+ parameter DLM = 3'h1;
+ parameter IIR = 3'h2;
+ parameter FCR = 3'h2;
+ parameter LCR = 3'h3;
+ parameter MCR = 3'h4;
+ parameter LSR = 3'h5;
+ parameter MSR = 3'h6;
+ parameter SCR = 3'h7;
+ parameter TX_FIFO_DEPTH = 16;
+ parameter RX_FIFO_DEPTH = 16;
+ wire [2:0] register_adr;
+ reg [79:0] regs_q;
+ reg [79:0] regs_n;
+ reg [1:0] trigger_level_n;
+ reg [1:0] trigger_level_q;
+ wire [7:0] rx_data;
+ wire parity_error;
+ wire [3:0] IIR_o;
+ reg [3:0] clr_int;
+ wire tx_ready;
+ reg apb_rx_ready;
+ wire rx_valid;
+ reg tx_fifo_clr_n;
+ reg tx_fifo_clr_q;
+ reg rx_fifo_clr_n;
+ reg rx_fifo_clr_q;
+ reg fifo_tx_valid;
+ wire tx_valid;
+ wire fifo_rx_valid;
+ reg fifo_rx_ready;
+ wire rx_ready;
+ reg [7:0] fifo_tx_data;
+ wire [8:0] fifo_rx_data;
+ wire [7:0] tx_data;
+ wire [$clog2(TX_FIFO_DEPTH):0] tx_elements;
+ wire [$clog2(RX_FIFO_DEPTH):0] rx_elements;
+ uart_rx uart_rx_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .rx_i(rx_i),
+ .cfg_en_i(1'b1),
+ .cfg_div_i({regs_q[(DLM + 'd8) * 8+:8], regs_q[(DLL + 'd8) * 8+:8]}),
+ .cfg_parity_en_i(regs_q[(LCR * 8) + 3]),
+ .cfg_bits_i(regs_q[(LCR * 8) + 1-:2]),
+ .busy_o(),
+ .err_o(parity_error),
+ .err_clr_i(1'b1),
+ .rx_data_o(rx_data),
+ .rx_valid_o(rx_valid),
+ .rx_ready_i(rx_ready)
+ );
+ uart_tx uart_tx_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .tx_o(tx_o),
+ .busy_o(),
+ .cfg_en_i(1'b1),
+ .cfg_div_i({regs_q[(DLM + 'd8) * 8+:8], regs_q[(DLL + 'd8) * 8+:8]}),
+ .cfg_parity_en_i(regs_q[(LCR * 8) + 3]),
+ .cfg_bits_i(regs_q[(LCR * 8) + 1-:2]),
+ .cfg_stop_bits_i(regs_q[(LCR * 8) + 2]),
+ .tx_data_i(tx_data),
+ .tx_valid_i(tx_valid),
+ .tx_ready_o(tx_ready)
+ );
+ io_generic_fifo #(
+ .DATA_WIDTH(9),
+ .BUFFER_DEPTH(RX_FIFO_DEPTH)
+ ) uart_rx_fifo_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .clr_i(rx_fifo_clr_q),
+ .elements_o(rx_elements),
+ .data_o(fifo_rx_data),
+ .valid_o(fifo_rx_valid),
+ .ready_i(fifo_rx_ready),
+ .valid_i(rx_valid),
+ .data_i({parity_error, rx_data}),
+ .ready_o(rx_ready)
+ );
+ io_generic_fifo #(
+ .DATA_WIDTH(8),
+ .BUFFER_DEPTH(TX_FIFO_DEPTH)
+ ) uart_tx_fifo_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .clr_i(tx_fifo_clr_q),
+ .elements_o(tx_elements),
+ .data_o(tx_data),
+ .valid_o(tx_valid),
+ .ready_i(tx_ready),
+ .valid_i(fifo_tx_valid),
+ .data_i(fifo_tx_data),
+ .ready_o()
+ );
+ uart_interrupt #(
+ .TX_FIFO_DEPTH(TX_FIFO_DEPTH),
+ .RX_FIFO_DEPTH(RX_FIFO_DEPTH)
+ ) uart_interrupt_i(
+ .clk_i(CLK),
+ .rstn_i(RSTN),
+ .IER_i(regs_q[(IER * 8) + 2-:3]),
+ .RDA_i(regs_n[(LSR * 8) + 5]),
+ .CTI_i(1'b0),
+ .error_i(regs_n[(LSR * 8) + 2]),
+ .rx_elements_i(rx_elements),
+ .tx_elements_i(tx_elements),
+ .trigger_level_i(trigger_level_q),
+ .clr_int_i(clr_int),
+ .interrupt_o(event_o),
+ .IIR_o(IIR_o)
+ );
+ always @(*) begin
+ regs_n = regs_q;
+ trigger_level_n = trigger_level_q;
+ fifo_tx_valid = 1'b0;
+ tx_fifo_clr_n = 1'b0;
+ rx_fifo_clr_n = 1'b0;
+ regs_n[LSR * 8] = fifo_rx_valid;
+ regs_n[(LSR * 8) + 2] = fifo_rx_data[8];
+ regs_n[(LSR * 8) + 5] = ~(|tx_elements);
+ regs_n[(LSR * 8) + 6] = tx_ready & ~(|tx_elements);
+ if ((PSEL && PENABLE) && PWRITE)
+ case (register_adr)
+ THR:
+ if (regs_q[(LCR * 8) + 7])
+ regs_n[(DLL + 'd8) * 8+:8] = PWDATA[7:0];
+ else begin
+ fifo_tx_data = PWDATA[7:0];
+ fifo_tx_valid = 1'b1;
+ end
+ IER:
+ if (regs_q[(LCR * 8) + 7])
+ regs_n[(DLM + 'd8) * 8+:8] = PWDATA[7:0];
+ else
+ regs_n[IER * 8+:8] = PWDATA[7:0];
+ LCR: regs_n[LCR * 8+:8] = PWDATA[7:0];
+ FCR: begin
+ rx_fifo_clr_n = PWDATA[1];
+ tx_fifo_clr_n = PWDATA[2];
+ trigger_level_n = PWDATA[7:6];
+ end
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ PRDATA = 'b0;
+ apb_rx_ready = 1'b0;
+ fifo_rx_ready = 1'b0;
+ clr_int = 4'b0000;
+ if ((PSEL && PENABLE) && !PWRITE)
+ case (register_adr)
+ RBR:
+ if (regs_q[(LCR * 8) + 7])
+ PRDATA = {24'b000000000000000000000000, regs_q[(DLL + 'd8) * 8+:8]};
+ else begin
+ fifo_rx_ready = 1'b1;
+ PRDATA = {24'b000000000000000000000000, fifo_rx_data[7:0]};
+ clr_int = 4'b1000;
+ end
+ LSR: begin
+ PRDATA = {24'b000000000000000000000000, regs_q[LSR * 8+:8]};
+ clr_int = 4'b1100;
+ end
+ LCR: PRDATA = {24'b000000000000000000000000, regs_q[LCR * 8+:8]};
+ IER:
+ if (regs_q[(LCR * 8) + 7])
+ PRDATA = {24'b000000000000000000000000, regs_q[(DLM + 'd8) * 8+:8]};
+ else
+ PRDATA = {24'b000000000000000000000000, regs_q[IER * 8+:8]};
+ IIR: begin
+ PRDATA = {28'b0000000000000000000000001100, IIR_o};
+ clr_int = 4'b0100;
+ end
+ default:
+ ;
+ endcase
+ end
+ always @(posedge CLK or negedge RSTN)
+ if (~RSTN) begin
+ regs_q[IER * 8+:8] <= 8'h00;
+ regs_q[IIR * 8+:8] <= 8'h01;
+ regs_q[LCR * 8+:8] <= 8'h00;
+ regs_q[MCR * 8+:8] <= 8'h00;
+ regs_q[LSR * 8+:8] <= 8'h60;
+ regs_q[MSR * 8+:8] <= 8'h00;
+ regs_q[SCR * 8+:8] <= 8'h00;
+ regs_q[(DLM + 'd8) * 8+:8] <= 8'h00;
+ regs_q[(DLL + 'd8) * 8+:8] <= 8'h00;
+ trigger_level_q <= 2'b00;
+ tx_fifo_clr_q <= 1'b0;
+ rx_fifo_clr_q <= 1'b0;
+ end
+ else begin
+ regs_q <= regs_n;
+ trigger_level_q <= trigger_level_n;
+ tx_fifo_clr_q <= tx_fifo_clr_n;
+ rx_fifo_clr_q <= rx_fifo_clr_n;
+ end
+ assign register_adr = {PADDR[2:0]};
+ assign PREADY = 1'b1;
+ assign PSLVERR = 1'b0;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_uart_sv/io_generic_fifo.v b/verilog/rtl/ips/apb/apb_uart_sv/io_generic_fifo.v
new file mode 100644
index 0000000..f9c1329
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_uart_sv/io_generic_fifo.v
@@ -0,0 +1,83 @@
+module io_generic_fifo
+#(
+ parameter DATA_WIDTH = 32,
+ parameter BUFFER_DEPTH = 2,
+ parameter LOG_BUFFER_DEPTH = $clog2(BUFFER_DEPTH)
+)
+(
+ clk_i,
+ rstn_i,
+ clr_i,
+ elements_o,
+ data_o,
+ valid_o,
+ ready_i,
+ valid_i,
+ data_i,
+ ready_o
+);
+ //parameter DATA_WIDTH = 32;
+ //parameter BUFFER_DEPTH = 2;
+ //parameter LOG_BUFFER_DEPTH = $clog2(BUFFER_DEPTH);
+ input wire clk_i;
+ input wire rstn_i;
+ input wire clr_i;
+ output wire [LOG_BUFFER_DEPTH:0] elements_o;
+ output wire [DATA_WIDTH - 1:0] data_o;
+ output wire valid_o;
+ input wire ready_i;
+ input wire valid_i;
+ input wire [DATA_WIDTH - 1:0] data_i;
+ output wire ready_o;
+ reg [LOG_BUFFER_DEPTH - 1:0] pointer_in;
+ reg [LOG_BUFFER_DEPTH - 1:0] pointer_out;
+ reg [LOG_BUFFER_DEPTH:0] elements;
+ reg [DATA_WIDTH - 1:0] buffer [BUFFER_DEPTH - 1:0];
+ wire full;
+ reg [31:0] loop1;
+ assign full = elements == BUFFER_DEPTH;
+ assign elements_o = elements;
+ always @(posedge clk_i or negedge rstn_i) begin : elements_sequential
+ if (rstn_i == 1'b0)
+ elements <= 0;
+ else if (clr_i)
+ elements <= 0;
+ else if ((ready_i && valid_o) && (!valid_i || full))
+ elements <= elements - 1;
+ else if (((!valid_o || !ready_i) && valid_i) && !full)
+ elements <= elements + 1;
+ end
+ always @(posedge clk_i or negedge rstn_i) begin : buffers_sequential
+ if (rstn_i == 1'b0) begin
+ for (loop1 = 0; loop1 < BUFFER_DEPTH; loop1 = loop1 + 1)
+ buffer[loop1] <= 0;
+ end
+ else if (valid_i && !full)
+ buffer[pointer_in] <= data_i;
+ end
+ always @(posedge clk_i or negedge rstn_i) begin : sequential
+ if (rstn_i == 1'b0) begin
+ pointer_out <= 0;
+ pointer_in <= 0;
+ end
+ else if (clr_i) begin
+ pointer_out <= 0;
+ pointer_in <= 0;
+ end
+ else begin
+ if (valid_i && !full)
+ if (pointer_in == $unsigned(BUFFER_DEPTH - 1))
+ pointer_in <= 0;
+ else
+ pointer_in <= pointer_in + 1;
+ if (ready_i && valid_o)
+ if (pointer_out == $unsigned(BUFFER_DEPTH - 1))
+ pointer_out <= 0;
+ else
+ pointer_out <= pointer_out + 1;
+ end
+ end
+ assign data_o = buffer[pointer_out];
+ assign valid_o = elements != 0;
+ assign ready_o = ~full;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_uart_sv/uart_interrupt.v b/verilog/rtl/ips/apb/apb_uart_sv/uart_interrupt.v
new file mode 100644
index 0000000..3a89ff6
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_uart_sv/uart_interrupt.v
@@ -0,0 +1,77 @@
+module uart_interrupt
+#(
+ parameter TX_FIFO_DEPTH = 32,
+ parameter RX_FIFO_DEPTH = 32
+)
+(
+ clk_i,
+ rstn_i,
+ IER_i,
+ RDA_i,
+ CTI_i,
+ error_i,
+ rx_elements_i,
+ tx_elements_i,
+ trigger_level_i,
+ clr_int_i,
+ interrupt_o,
+ IIR_o
+);
+ //parameter TX_FIFO_DEPTH = 32;
+ //parameter RX_FIFO_DEPTH = 32;
+ input wire clk_i;
+ input wire rstn_i;
+ input wire [2:0] IER_i;
+ input wire RDA_i;
+ input wire CTI_i;
+ input wire error_i;
+ input wire [$clog2(RX_FIFO_DEPTH):0] rx_elements_i;
+ input wire [$clog2(TX_FIFO_DEPTH):0] tx_elements_i;
+ input wire [1:0] trigger_level_i;
+ input wire [3:0] clr_int_i;
+ output wire interrupt_o;
+ output wire [3:0] IIR_o;
+ reg [3:0] iir_n;
+ reg [3:0] iir_q;
+ reg trigger_level_reached;
+ always @(*) begin
+ trigger_level_reached = 1'b0;
+ case (trigger_level_i)
+ 2'b00:
+ if ($unsigned(rx_elements_i) == 1)
+ trigger_level_reached = 1'b1;
+ 2'b01:
+ if ($unsigned(rx_elements_i) == 4)
+ trigger_level_reached = 1'b1;
+ 2'b10:
+ if ($unsigned(rx_elements_i) == 8)
+ trigger_level_reached = 1'b1;
+ 2'b11:
+ if ($unsigned(rx_elements_i) == 14)
+ trigger_level_reached = 1'b1;
+ default:
+ ;
+ endcase
+ end
+ always @(*) begin
+ if (clr_int_i == 4'b0000)
+ iir_n = iir_q;
+ else
+ iir_n = iir_q & ~clr_int_i;
+ if (IER_i[2] & error_i)
+ iir_n = 4'b1100;
+ else if (IER_i[0] & (trigger_level_reached | RDA_i))
+ iir_n = 4'b1000;
+ else if (IER_i[0] & CTI_i)
+ iir_n = 4'b1000;
+ else if (IER_i[1] & (tx_elements_i == 0))
+ iir_n = 4'b0100;
+ end
+ always @(posedge clk_i or negedge rstn_i)
+ if (~rstn_i)
+ iir_q <= 4'b0001;
+ else
+ iir_q <= iir_n;
+ assign IIR_o = iir_q;
+ assign interrupt_o = ~iir_q[0];
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_uart_sv/uart_rx.v b/verilog/rtl/ips/apb/apb_uart_sv/uart_rx.v
new file mode 100644
index 0000000..c25ded6
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_uart_sv/uart_rx.v
@@ -0,0 +1,179 @@
+module uart_rx (
+ clk_i,
+ rstn_i,
+ rx_i,
+ cfg_div_i,
+ cfg_en_i,
+ cfg_parity_en_i,
+ cfg_bits_i,
+ busy_o,
+ err_o,
+ err_clr_i,
+ rx_data_o,
+ rx_valid_o,
+ rx_ready_i
+);
+ input wire clk_i;
+ input wire rstn_i;
+ input wire rx_i;
+ input wire [15:0] cfg_div_i;
+ input wire cfg_en_i;
+ input wire cfg_parity_en_i;
+ input wire [1:0] cfg_bits_i;
+ output wire busy_o;
+ output reg err_o;
+ input wire err_clr_i;
+ output wire [7:0] rx_data_o;
+ output reg rx_valid_o;
+ input wire rx_ready_i;
+ reg [2:0] CS;
+ reg [2:0] NS;
+ reg [7:0] reg_data;
+ reg [7:0] reg_data_next;
+ reg [2:0] reg_rx_sync;
+ reg [2:0] reg_bit_count;
+ reg [2:0] reg_bit_count_next;
+ reg [2:0] s_target_bits;
+ reg parity_bit;
+ reg parity_bit_next;
+ reg sampleData;
+ reg [15:0] baud_cnt;
+ reg baudgen_en;
+ reg bit_done;
+ reg start_bit;
+ reg set_error;
+ wire s_rx_fall;
+ assign busy_o = CS != 3'd0;
+ always @(*)
+ case (cfg_bits_i)
+ 2'b00: s_target_bits = 3'h4;
+ 2'b01: s_target_bits = 3'h5;
+ 2'b10: s_target_bits = 3'h6;
+ 2'b11: s_target_bits = 3'h7;
+ endcase
+ always @(*) begin
+ NS = CS;
+ sampleData = 1'b0;
+ reg_bit_count_next = reg_bit_count;
+ reg_data_next = reg_data;
+ rx_valid_o = 1'b0;
+ baudgen_en = 1'b0;
+ start_bit = 1'b0;
+ parity_bit_next = parity_bit;
+ set_error = 1'b0;
+ case (CS)
+ 3'd0:
+ if (s_rx_fall) begin
+ NS = 3'd1;
+ baudgen_en = 1'b1;
+ start_bit = 1'b1;
+ end
+ 3'd1: begin
+ parity_bit_next = 1'b0;
+ baudgen_en = 1'b1;
+ start_bit = 1'b1;
+ if (bit_done)
+ NS = 3'd2;
+ end
+ 3'd2: begin
+ baudgen_en = 1'b1;
+ parity_bit_next = parity_bit ^ reg_rx_sync[2];
+ case (cfg_bits_i)
+ 2'b00: reg_data_next = {3'b000, reg_rx_sync[2], reg_data[4:1]};
+ 2'b01: reg_data_next = {2'b00, reg_rx_sync[2], reg_data[5:1]};
+ 2'b10: reg_data_next = {1'b0, reg_rx_sync[2], reg_data[6:1]};
+ 2'b11: reg_data_next = {reg_rx_sync[2], reg_data[7:1]};
+ endcase
+ if (bit_done) begin
+ sampleData = 1'b1;
+ if (reg_bit_count == s_target_bits) begin
+ reg_bit_count_next = 'h0;
+ NS = 3'd3;
+ end
+ else
+ reg_bit_count_next = reg_bit_count + 1;
+ end
+ end
+ 3'd3: begin
+ baudgen_en = 1'b1;
+ rx_valid_o = 1'b1;
+ if (rx_ready_i)
+ if (cfg_parity_en_i)
+ NS = 3'd4;
+ else
+ NS = 3'd5;
+ end
+ 3'd4: begin
+ baudgen_en = 1'b1;
+ if (bit_done) begin
+ if (parity_bit != reg_rx_sync[2])
+ set_error = 1'b1;
+ NS = 3'd5;
+ end
+ end
+ 3'd5: begin
+ baudgen_en = 1'b1;
+ if (bit_done)
+ NS = 3'd0;
+ end
+ default: NS = 3'd0;
+ endcase
+ end
+ always @(posedge clk_i or negedge rstn_i)
+ if (rstn_i == 1'b0) begin
+ CS <= 3'd0;
+ reg_data <= 8'hff;
+ reg_bit_count <= 'h0;
+ parity_bit <= 1'b0;
+ end
+ else begin
+ if (bit_done)
+ parity_bit <= parity_bit_next;
+ if (sampleData)
+ reg_data <= reg_data_next;
+ reg_bit_count <= reg_bit_count_next;
+ if (cfg_en_i)
+ CS <= NS;
+ else
+ CS <= 3'd0;
+ end
+ assign s_rx_fall = ~reg_rx_sync[1] & reg_rx_sync[2];
+ always @(posedge clk_i or negedge rstn_i)
+ if (rstn_i == 1'b0)
+ reg_rx_sync <= 3'b111;
+ else if (cfg_en_i)
+ reg_rx_sync <= {reg_rx_sync[1:0], rx_i};
+ else
+ reg_rx_sync <= 3'b111;
+ always @(posedge clk_i or negedge rstn_i)
+ if (rstn_i == 1'b0) begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b0;
+ end
+ else if (baudgen_en) begin
+ if (!start_bit && (baud_cnt == cfg_div_i)) begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b1;
+ end
+ else if (start_bit && (baud_cnt == {1'b0, cfg_div_i[15:1]})) begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b1;
+ end
+ else begin
+ baud_cnt <= baud_cnt + 1;
+ bit_done <= 1'b0;
+ end
+ end
+ else begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b0;
+ end
+ always @(posedge clk_i or negedge rstn_i)
+ if (rstn_i == 1'b0)
+ err_o <= 1'b0;
+ else if (err_clr_i)
+ err_o <= 1'b0;
+ else if (set_error)
+ err_o <= 1'b1;
+ assign rx_data_o = reg_data;
+endmodule
diff --git a/verilog/rtl/ips/apb/apb_uart_sv/uart_tx.v b/verilog/rtl/ips/apb/apb_uart_sv/uart_tx.v
new file mode 100644
index 0000000..e84068a
--- /dev/null
+++ b/verilog/rtl/ips/apb/apb_uart_sv/uart_tx.v
@@ -0,0 +1,152 @@
+module uart_tx (
+ clk_i,
+ rstn_i,
+ tx_o,
+ busy_o,
+ cfg_en_i,
+ cfg_div_i,
+ cfg_parity_en_i,
+ cfg_bits_i,
+ cfg_stop_bits_i,
+ tx_data_i,
+ tx_valid_i,
+ tx_ready_o
+);
+ input wire clk_i;
+ input wire rstn_i;
+ output reg tx_o;
+ output wire busy_o;
+ input wire cfg_en_i;
+ input wire [15:0] cfg_div_i;
+ input wire cfg_parity_en_i;
+ input wire [1:0] cfg_bits_i;
+ input wire cfg_stop_bits_i;
+ input wire [7:0] tx_data_i;
+ input wire tx_valid_i;
+ output reg tx_ready_o;
+ reg [2:0] CS;
+ reg [2:0] NS;
+ reg [7:0] reg_data;
+ reg [7:0] reg_data_next;
+ reg [2:0] reg_bit_count;
+ reg [2:0] reg_bit_count_next;
+ reg [2:0] s_target_bits;
+ reg parity_bit;
+ reg parity_bit_next;
+ reg sampleData;
+ reg [15:0] baud_cnt;
+ reg baudgen_en;
+ reg bit_done;
+ assign busy_o = CS != 3'd0;
+ always @(*)
+ case (cfg_bits_i)
+ 2'b00: s_target_bits = 3'h4;
+ 2'b01: s_target_bits = 3'h5;
+ 2'b10: s_target_bits = 3'h6;
+ 2'b11: s_target_bits = 3'h7;
+ endcase
+ always @(*) begin
+ NS = CS;
+ tx_o = 1'b1;
+ sampleData = 1'b0;
+ reg_bit_count_next = reg_bit_count;
+ reg_data_next = {1'b1, reg_data[7:1]};
+ tx_ready_o = 1'b0;
+ baudgen_en = 1'b0;
+ parity_bit_next = parity_bit;
+ case (CS)
+ 3'd0: begin
+ if (cfg_en_i)
+ tx_ready_o = 1'b1;
+ if (tx_valid_i) begin
+ NS = 3'd1;
+ sampleData = 1'b1;
+ reg_data_next = tx_data_i;
+ end
+ end
+ 3'd1: begin
+ tx_o = 1'b0;
+ parity_bit_next = 1'b0;
+ baudgen_en = 1'b1;
+ if (bit_done)
+ NS = 3'd2;
+ end
+ 3'd2: begin
+ tx_o = reg_data[0];
+ baudgen_en = 1'b1;
+ parity_bit_next = parity_bit ^ reg_data[0];
+ if (bit_done)
+ if (reg_bit_count == s_target_bits) begin
+ reg_bit_count_next = 'h0;
+ if (cfg_parity_en_i)
+ NS = 3'd3;
+ else
+ NS = 3'd4;
+ end
+ else begin
+ reg_bit_count_next = reg_bit_count + 1;
+ sampleData = 1'b1;
+ end
+ end
+ 3'd3: begin
+ tx_o = parity_bit;
+ baudgen_en = 1'b1;
+ if (bit_done)
+ NS = 3'd4;
+ end
+ 3'd4: begin
+ tx_o = 1'b1;
+ baudgen_en = 1'b1;
+ if (bit_done)
+ if (cfg_stop_bits_i)
+ NS = 3'd5;
+ else
+ NS = 3'd0;
+ end
+ 3'd5: begin
+ tx_o = 1'b1;
+ baudgen_en = 1'b1;
+ if (bit_done)
+ NS = 3'd0;
+ end
+ default: NS = 3'd0;
+ endcase
+ end
+ always @(posedge clk_i or negedge rstn_i)
+ if (rstn_i == 1'b0) begin
+ CS <= 3'd0;
+ reg_data <= 8'hff;
+ reg_bit_count <= 'h0;
+ parity_bit <= 1'b0;
+ end
+ else begin
+ if (bit_done)
+ parity_bit <= parity_bit_next;
+ if (sampleData)
+ reg_data <= reg_data_next;
+ reg_bit_count <= reg_bit_count_next;
+ if (cfg_en_i)
+ CS <= NS;
+ else
+ CS <= 3'd0;
+ end
+ always @(posedge clk_i or negedge rstn_i)
+ if (rstn_i == 1'b0) begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b0;
+ end
+ else if (baudgen_en) begin
+ if (baud_cnt == cfg_div_i) begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b1;
+ end
+ else begin
+ baud_cnt <= baud_cnt + 1;
+ bit_done <= 1'b0;
+ end
+ end
+ else begin
+ baud_cnt <= 'h0;
+ bit_done <= 1'b0;
+ end
+endmodule