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