Merge pull request #151 from retroSoC/dev

Dev
This commit is contained in:
Yuchi Miao authored and GitHub committed 2026-01-31 13:53:07 +08:00
commit 9ebba10462
12 files changed
+510 -296

No files matched your search

+9 -6
View File
@@ -76,12 +76,13 @@
#define reg_i2c0_status (*(volatile uint32_t*)0x1000601C)
// i2s
#define reg_i2s_mode (*(volatile uint32_t*)0x10007000)
#define reg_i2s_upbound (*(volatile uint32_t*)0x10007004)
#define reg_i2s_lowbound (*(volatile uint32_t*)0x10007008)
#define reg_i2s_recven (*(volatile uint32_t*)0x1000700C)
#define reg_i2s_txdata (*(volatile uint32_t*)0x10007010)
#define reg_i2s_rxdata (*(volatile uint32_t*)0x10007014)
#define reg_i2s_status (*(volatile uint32_t*)0x10007018)
#define reg_i2s_format (*(volatile uint32_t*)0x10007004)
#define reg_i2s_upbound (*(volatile uint32_t*)0x10007008)
#define reg_i2s_lowbound (*(volatile uint32_t*)0x1000700C)
#define reg_i2s_recven (*(volatile uint32_t*)0x10007010)
#define reg_i2s_txdata (*(volatile uint32_t*)0x10007014)
#define reg_i2s_rxdata (*(volatile uint32_t*)0x10007018)
#define reg_i2s_status (*(volatile uint32_t*)0x1000701C)
// 1-wire
#define reg_onewire_clkdiv (*(volatile uint32_t*)0x10008000)
#define reg_onewire_zerocnt (*(volatile uint32_t*)0x10008004)
@@ -157,6 +158,8 @@
#define reg_dvp_status (*(volatile uint32_t*)0x1000E008)
// sdio
#define reg_sdio_cfg (*(volatile uint32_t*)0x1000F000)
// gpu
#define reg_gpu_cfg (*(volatile uint32_t*)0x10010000)
// apb
// archinfo
#define reg_archinfo_sys (*(volatile uint32_t*)0x20000000)
+2 -1
View File
@@ -47,7 +47,7 @@ void app_info() {
printf(" contributor: MrAMS <https://github.com/MrAMS>\n");
printf(" license: MulanPSL-2.0 license\n\n");
printf(" series: retroSoC Mini\n");
printf(" specs: Gen2\n");
printf(" specs: Gen2 Plus\n");
printf(" version: %s(commit: %s)\n\n", RETROSOC_BRANCH, RETROSOC_COMMIT);
printf("User Processors:\n");
@@ -107,6 +107,7 @@ void app_info() {
printf(" 1 x SDRAM @0x%x\n", &reg_sdram_clkdiv);
printf(" 1 x DVP @0x%x\n", &reg_dvp_recven);
printf(" 1 x SDIO @0x%x\n", &reg_sdio_cfg);
printf(" 1 x GPU(mini) @0x%x\n", &reg_gpu_cfg);
printf(" 1 x ARCHINFO @0x%x\n", &reg_archinfo_sys);
printf(" 1 x RNG @0x%x\n", &reg_rng_ctrl);
printf(" 1 x UART1(ADV) @0x%x\n", &reg_uart1_lcr);
+9 -7
View File
@@ -18,6 +18,8 @@ void i2s_init(uint32_t mode) {
}
void i2s_simp_test() {
reg_i2s_mode = (uint32_t)1;
reg_i2s_format = (uint32_t)0;
for(uint32_t i = 0; i < 6; ++i) {
// while(reg_i2s_status & (uint32_t)1); // check if fifo is full or not
reg_i2s_txdata = test_data[i];
@@ -25,14 +27,14 @@ void i2s_simp_test() {
printf("i2s tx done\n");
reg_i2s_recven = (uint32_t)1;
for(uint32_t i = 0; i < 6; ++i) {
test_data[i] = reg_i2s_rxdata;
uint32_t tmp = 0;
for(uint32_t i = 0; i < 6; ) {
tmp = reg_i2s_rxdata;
if(tmp != 0) {
printf("rx data: %x\n", tmp);
++i;
}
}
reg_i2s_recven = (uint32_t)0;
for(uint32_t i = 0; i < 6; ++i) {
printf("test_data[%d]: %x\n", i, test_data[i]);
}
printf("i2s rx done\n");
}
+27 -173
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Yuchi Miao <miaoyuchi@ict.ac.cn>
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
@@ -8,18 +8,7 @@
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`ifndef NATV_I2S_DEF_SV
`define NATV_I2S_DEF_SV
// verilog_format: off
`define NATV_I2S_MODE 8'h00
`define NATV_I2S_UPBOUND 8'h04
`define NATV_I2S_LOWBOUND 8'h08
`define NATV_I2S_RECVEN 8'h0C
`define NATV_I2S_TXDATA 8'h10
`define NATV_I2S_RXDATA 8'h14
`define NATV_I2S_STATUS 8'h18
// verilog_format: on
`include "i2s_define.svh"
interface nv_i2s_if ();
logic mclk_o;
@@ -37,16 +26,14 @@ interface nv_i2s_if ();
input adcdat_i,
output irq_o
);
endinterface
`endif
module nmi_i2s (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic clk_aud_i ,
input logic clk_aud_i,
input logic rst_aud_n_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o,
@@ -55,20 +42,9 @@ module nmi_i2s (
// verilog_format: on
);
logic s_nmi_wr_hdshk, s_nmi_rd_hdshk;
logic s_nmi_ready_d, s_nmi_ready_q;
logic s_nmi_rdata_en;
logic [31:0] s_nmi_rdata_d, s_nmi_rdata_q;
logic s_i2s_mode_en;
logic s_i2s_mode_d, s_i2s_mode_q;
logic s_i2s_upbound_en;
logic [7:0] s_i2s_upbound_d, s_i2s_upbound_q;
logic s_i2s_lowbound_en;
logic [7:0] s_i2s_lowbound_d, s_i2s_lowbound_q;
logic s_i2s_recven_en;
logic s_i2s_recven_d, s_i2s_recven_q;
logic [1:0] s_i2s_status_d, s_i2s_status_q;
logic s_i2s_mode;
logic [1:0] s_i2s_format;
logic s_i2s_recven;
// tx fifo
logic s_tx_push_valid, s_tx_full, s_tx_empty;
logic s_tx_pop_valid, s_tx_pop_ready;
@@ -79,149 +55,25 @@ module nmi_i2s (
logic s_rx_pop_valid, s_rx_pop_ready;
logic [31:0] s_rx_push_data, s_rx_pop_data;
logic [7:0] s_rx_elem_num;
// common
logic s_tx_fifo_stall_d, s_tx_fifo_stall_q;
logic s_rx_fifo_stall_d, s_rx_fifo_stall_q;
assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb);
assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb));
assign nmi.ready = s_nmi_ready_q;
assign nmi.rdata = s_nmi_rdata_q;
assign dma_tx_stall_o = s_tx_fifo_stall_q;
assign dma_rx_stall_o = s_rx_fifo_stall_q;
assign s_i2s_mode_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_I2S_MODE;
assign s_i2s_mode_d = nmi.wdata[0];
dffer #(1) u_i2s_mode_dffer (
clk_i,
rst_n_i,
s_i2s_mode_en,
s_i2s_mode_d,
s_i2s_mode_q
);
assign s_i2s_upbound_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_I2S_UPBOUND;
assign s_i2s_upbound_d = nmi.wdata[7:0];
dfferh #(8) u_i2s_upbound_dfferh (
clk_i,
rst_n_i,
s_i2s_upbound_en,
s_i2s_upbound_d,
s_i2s_upbound_q
);
assign s_i2s_lowbound_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_I2S_LOWBOUND;
assign s_i2s_lowbound_d = nmi.wdata[7:0];
dffer #(8) u_i2s_lowbound_dffer (
clk_i,
rst_n_i,
s_i2s_lowbound_en,
s_i2s_lowbound_d,
s_i2s_lowbound_q
);
assign s_i2s_recven_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_I2S_RECVEN;
assign s_i2s_recven_d = nmi.wdata[0];
dffer #(1) u_i2s_recven_dffer (
clk_i,
rst_n_i,
s_i2s_recven_en,
s_i2s_recven_d,
s_i2s_recven_q
);
always_comb begin
s_tx_fifo_stall_d = s_tx_fifo_stall_q;
if (~s_tx_fifo_stall_q && s_tx_elem_num > s_i2s_upbound_q) begin
s_tx_fifo_stall_d = 1'b1;
end else if (s_tx_fifo_stall_q && s_tx_elem_num < s_i2s_lowbound_q) begin
s_tx_fifo_stall_d = 1'b0;
end
end
dffr #(1) u_tx_fifo_stall_dffr (
clk_i,
rst_n_i,
s_tx_fifo_stall_d,
s_tx_fifo_stall_q
);
always_comb begin
s_rx_fifo_stall_d = s_rx_fifo_stall_q;
if (~s_rx_fifo_stall_q && s_rx_elem_num < s_i2s_lowbound_q) begin
s_rx_fifo_stall_d = 1'b1;
end else if (s_rx_fifo_stall_q && s_rx_elem_num > s_i2s_upbound_q) begin
s_rx_fifo_stall_d = 1'b0;
end
end
dffr #(1) u_rx_fifo_stall_dffr (
clk_i,
rst_n_i,
s_rx_fifo_stall_d,
s_rx_fifo_stall_q
);
// TODO: need to handle when tx fifo is full(DMA is fine)
always_comb begin
s_tx_push_valid = 1'b0;
s_tx_push_data = '0;
if (s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_I2S_TXDATA) begin
s_tx_push_valid = 1'b1;
if (nmi.wstrb[0]) s_tx_push_data[7:0] = nmi.wdata[7:0];
if (nmi.wstrb[1]) s_tx_push_data[15:8] = nmi.wdata[15:8];
if (nmi.wstrb[2]) s_tx_push_data[23:16] = nmi.wdata[23:16];
if (nmi.wstrb[3]) s_tx_push_data[31:24] = nmi.wdata[31:24];
end
end
// [0] wr fifo full, [1] rd fifo empty
always_comb begin
s_i2s_status_d[0] = s_tx_full;
s_i2s_status_d[1] = s_rx_empty;
end
dffr #(2) u_i2s_status_dffr (
clk_i,
rst_n_i,
s_i2s_status_d,
s_i2s_status_q
);
assign s_nmi_ready_d = nmi.valid && (~s_nmi_ready_q);
dffr #(1) u_nmi_ready_dffr (
clk_i,
rst_n_i,
s_nmi_ready_d,
s_nmi_ready_q
);
assign s_nmi_rdata_en = s_nmi_rd_hdshk;
always_comb begin
s_rx_pop_valid = 1'b0;
s_nmi_rdata_d = s_nmi_rdata_q;
unique case (nmi.addr[7:0])
`NATV_I2S_MODE: s_nmi_rdata_d = {31'd0, s_i2s_mode_q};
`NATV_I2S_RXDATA: begin
if (s_nmi_rd_hdshk) begin
s_rx_pop_valid = 1'b1;
if (!s_rx_empty) s_nmi_rdata_d = s_rx_pop_data;
else s_nmi_rdata_d = '0;
end
end
`NATV_I2S_STATUS: s_nmi_rdata_d = {30'd0, s_i2s_status_q};
default: s_nmi_rdata_d = s_nmi_rdata_q;
endcase
end
dffer #(32) u_nmi_rdata_dffer (
clk_i,
rst_n_i,
s_nmi_rdata_en,
s_nmi_rdata_d,
s_nmi_rdata_q
i2s_reg u_i2s_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.nmi (nmi),
.mode_o (s_i2s_mode),
.format_o (s_i2s_format),
.recven_o (s_i2s_recven),
.tx_push_valid_o(s_tx_push_valid),
.tx_push_data_o (s_tx_push_data),
.tx_full_i (s_tx_full),
.tx_elem_num_i (s_tx_elem_num),
.rx_pop_valid_o (s_rx_pop_valid),
.rx_pop_data_i (s_rx_pop_data),
.rx_empty_i (s_rx_empty),
.rx_elem_num_i (s_rx_elem_num),
.dma_tx_stall_o (dma_tx_stall_o),
.dma_rx_stall_o (dma_rx_stall_o)
);
@@ -249,7 +101,7 @@ module nmi_i2s (
) u_rx_async_fifo (
.wr_clk_i (clk_aud_i),
.wr_rst_n_i(rst_aud_n_i),
.wr_en_i (s_rx_push_valid & s_i2s_recven_q),
.wr_en_i (s_rx_push_valid & s_i2s_recven),
.wr_data_i (s_rx_push_data),
.wr_full_o (s_rx_full),
.rd_clk_i (clk_i),
@@ -260,10 +112,12 @@ module nmi_i2s (
.elem_num_o(s_rx_elem_num)
);
i2s_core u_i2s_core (
.clk_i (clk_aud_i),
.rst_n_i (rst_aud_n_i),
.mode_i (s_i2s_mode_q),
.mode_i (s_i2s_mode),
.format_i (s_i2s_format),
.tx_valid_o(s_tx_pop_valid),
.tx_data_i (s_tx_pop_data),
.tx_empty_i(s_tx_empty),
+109
View File
@@ -0,0 +1,109 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "i2s_define.svh"
module i2s_clkgen (
input logic clk_i,
input logic rst_n_i,
input logic [1:0] format_i,
output logic sclk_pos_o,
output logic sclk_fall_o,
output logic sclk_o,
output logic lrck_o
);
logic [2:0] s_sclk_div_num;
logic [2:0] s_sclk_div_cnt_d, s_sclk_div_cnt_q;
logic s_sclk_d, s_sclk_q;
logic [4:0] s_lrck_div_num;
logic [4:0] s_lrck_div_cnt_d, s_lrck_div_cnt_q;
logic s_lrck_d, s_lrck_q;
assign sclk_pos_o = (~s_sclk_q) && (s_sclk_div_cnt_q == s_sclk_div_num);
assign sclk_fall_o = s_sclk_q && (s_sclk_div_cnt_q == s_sclk_div_num);
assign sclk_o = s_sclk_q;
assign lrck_o = s_lrck_q;
always_comb begin
s_sclk_div_num = 3'd5;
unique case (format_i)
`I2S_16b_48K: s_sclk_div_num = 3'd5;
`I2S_16b_96K: s_sclk_div_num = 3'd2;
`I2S_24b_48K: s_sclk_div_num = 3'd3;
`I2S_24b_96K: s_sclk_div_num = 3'd1;
endcase
end
always_comb begin
s_sclk_d = s_sclk_q;
if (s_sclk_div_cnt_q == s_sclk_div_num) begin
s_sclk_div_cnt_d = '0;
s_sclk_d = ~s_sclk_q;
end else begin
s_sclk_div_cnt_d = s_sclk_div_cnt_q + 3'd1;
end
end
dffr #(3) u_sclk_div_cnt_dffr (
clk_i,
rst_n_i,
s_sclk_div_cnt_d,
s_sclk_div_cnt_q
);
dffr #(1) u_sclk_dffr (
clk_i,
rst_n_i,
s_sclk_d,
s_sclk_q
);
always_comb begin
s_lrck_div_num = 5'd15;
unique case (format_i)
`I2S_16b_48K: s_lrck_div_num = 5'd15;
`I2S_16b_96K: s_lrck_div_num = 5'd15;
`I2S_24b_48K: s_lrck_div_num = 5'd23;
`I2S_24b_96K: s_lrck_div_num = 5'd23;
endcase
end
always_comb begin
s_lrck_d = s_lrck_q;
if (s_lrck_div_cnt_q == s_lrck_div_num) begin
s_lrck_div_cnt_d = '0;
s_lrck_d = ~s_lrck_q;
end else begin
s_lrck_div_cnt_d = s_lrck_div_cnt_q + 5'd1;
end
end
dffer #(5) u_lrck_div_cnt_dffer (
clk_i,
rst_n_i,
sclk_fall_o,
s_lrck_div_cnt_d,
s_lrck_div_cnt_q
);
dffer #(1) u_lrck_dffer (
clk_i,
rst_n_i,
sclk_fall_o,
s_lrck_d,
s_lrck_q
);
endmodule
+63 -84
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Yuchi Miao <miaoyuchi@ict.ac.cn>
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
@@ -13,6 +13,7 @@ module i2s_core (
input logic clk_i,
input logic rst_n_i,
input logic mode_i,
input logic [1:0] format_i,
output logic tx_valid_o,
input logic [31:0] tx_data_i,
input logic tx_empty_i,
@@ -23,33 +24,38 @@ module i2s_core (
// verilog_format: on
);
// clk_i / 8 / 32
logic [1:0] s_sclk_div_cnt_d, s_sclk_div_cnt_q;
logic s_sclk_d, s_sclk_q;
logic [3:0] s_lrck_div_cnt_d, s_lrck_div_cnt_q;
logic s_lrck_d, s_lrck_q;
// i2s clk
logic s_sclk_pos, s_sclk_fall;
logic [15:0] s_loopback_data;
logic [15:0] s_recv_data, s_send_data;
logic [15:0] s_recv_data_d, s_recv_data_q;
logic s_sclk, s_lrck;
// common
logic [23:0] s_loopback_data;
logic [23:0] s_recv_data, s_send_data;
logic [23:0] s_recv_data_d, s_recv_data_q;
logic [31:0] s_send_data_d, s_send_data_q;
logic s_recv_done, s_send_done;
logic s_recv_done_pos, s_send_done_pos;
logic s_recv_done_re, s_send_done_re;
logic s_recv_cnt_d, s_recv_cnt_q;
logic s_send_cnt_d, s_send_cnt_q;
// i2s
assign i2s.mclk_o = clk_i;
assign i2s.sclk_o = s_sclk;
assign i2s.lrck_o = s_lrck;
assign i2s.irq_o = '0;
edge_det_sync_re u_recv_done_edge_det_sync_re (
clk_i,
rst_n_i,
s_recv_done,
s_recv_done_pos
s_recv_done_re
);
edge_det_sync_re u_send_done_edge_det_sync_re (
clk_i,
rst_n_i,
s_send_done,
s_send_done_pos
s_send_done_re
);
always_comb begin
@@ -60,14 +66,22 @@ module i2s_core (
s_recv_data_d = s_recv_data_q;
if (!mode_i) s_loopback_data = s_recv_data;
else begin
if (s_recv_done_pos) begin
if (~rx_full_i && s_recv_cnt_q == '1) begin
if (s_recv_done_re) begin
if (format_i[1]) begin
s_recv_cnt_d = '0;
rx_valid_o = 1'b1;
rx_data_o = {s_recv_data, s_recv_data_q};
if (~rx_full_i) begin
rx_valid_o = 1'b1;
rx_data_o = {8'd0, s_recv_data};
end
end else begin
s_recv_cnt_d = s_recv_cnt_q + 1'b1;
s_recv_data_d = s_recv_data;
if (~rx_full_i && s_recv_cnt_q == 1'b1) begin
s_recv_cnt_d = '0;
rx_valid_o = 1'b1;
rx_data_o = {s_recv_data[15:0], s_recv_data_q[15:0]};
end else begin
s_recv_cnt_d = s_recv_cnt_q + 1'b1;
s_recv_data_d[15:0] = s_recv_data[15:0];
end
end
end
end
@@ -78,7 +92,7 @@ module i2s_core (
s_recv_cnt_d,
s_recv_cnt_q
);
dffr #(16) u_recv_data_dffr (
dffr #(24) u_recv_data_dffr (
clk_i,
rst_n_i,
s_recv_data_d,
@@ -92,16 +106,26 @@ module i2s_core (
s_send_data_d = s_send_data_q;
if (!mode_i) s_send_data = s_loopback_data;
else begin
s_send_data = s_send_data_q[15:0];
if (s_send_done_pos) begin
if (s_send_cnt_q == 1'b1) begin
s_send_cnt_d = '0;
s_send_data_d = {16'd0, s_send_data_q[31:16]};
end else if (~tx_empty_i) begin
if (format_i[1]) begin
s_send_data = s_send_data_q[23:0];
s_send_cnt_d = '0;
if (s_send_done_re && (~tx_empty_i)) begin // NOTE:
tx_valid_o = 1'b1;
s_send_cnt_d = s_send_cnt_q + 1'b1;
s_send_data_d = tx_data_i;
end
end else begin
s_send_data[15:0] = s_send_data_q[15:0];
if (s_send_done_re) begin
if (s_send_cnt_q == 1'b1) begin
s_send_cnt_d = '0;
s_send_data_d = {16'd0, s_send_data_q[31:16]};
end else if (~tx_empty_i) begin // NOTE:
tx_valid_o = 1'b1;
s_send_cnt_d = s_send_cnt_q + 1'b1;
s_send_data_d = tx_data_i;
end
end
end
end
end
@@ -119,59 +143,14 @@ module i2s_core (
);
assign i2s.mclk_o = clk_i;
assign i2s.sclk_o = s_sclk_q;
assign i2s.lrck_o = s_lrck_q;
assign i2s.irq_o = '0;
assign s_sclk_pos = (~s_sclk_q) && (s_sclk_div_cnt_q == '0);
assign s_sclk_fall = s_sclk_q && (s_sclk_div_cnt_q == '0);
always_comb begin
s_sclk_d = s_sclk_q;
if (s_sclk_div_cnt_q == '0) begin
s_sclk_div_cnt_d = '1;
s_sclk_d = ~s_sclk_q;
end else begin
s_sclk_div_cnt_d = s_sclk_div_cnt_q - 1'b1;
end
end
dffrh #(2) u_sclk_div_cnt_dffrh (
clk_i,
rst_n_i,
s_sclk_div_cnt_d,
s_sclk_div_cnt_q
);
dffr #(1) u_sclk_dffr (
clk_i,
rst_n_i,
s_sclk_d,
s_sclk_q
);
always_comb begin
s_lrck_d = s_lrck_q;
if (s_lrck_div_cnt_q == '0) begin
s_lrck_div_cnt_d = '1;
s_lrck_d = ~s_lrck_q;
end else begin
s_lrck_div_cnt_d = s_lrck_div_cnt_q - 1'b1;
end
end
dfferh #(4) u_lrck_div_cnt_dfferh (
clk_i,
rst_n_i,
s_sclk_fall,
s_lrck_div_cnt_d,
s_lrck_div_cnt_q
);
dffer #(1) u_lrck_dffer (
clk_i,
rst_n_i,
s_sclk_fall,
s_lrck_d,
s_lrck_q
i2s_clkgen u_i2s_clkgen (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.format_i (format_i),
.sclk_pos_o (s_sclk_pos),
.sclk_fall_o(s_sclk_fall),
.sclk_o (s_sclk),
.lrck_o (s_lrck)
);
@@ -179,24 +158,24 @@ module i2s_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.sclk_pos_i(s_sclk_pos),
.lrck_i (s_lrck_q),
.lrck_i (s_lrck),
.bitmode_i (format_i[1]),
.adcdat_i (i2s.adcdat_i),
.data_o (s_recv_data),
.done_o (s_recv_done)
);
i2s_send u_i2s_send (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.sclk_pos_i (s_sclk_pos),
.sclk_fall_i(s_sclk_fall),
.lrck_i (s_lrck_q),
.lrck_i (s_lrck),
.bitmode_i (format_i[1]),
.data_i (s_send_data),
.dacdat_o (i2s.dacdat_o),
.done_o (s_send_done)
);
endmodule
+30
View File
@@ -0,0 +1,30 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`ifndef NMI_I2S_DEF_SV
`define NMI_I2S_DEF_SV
// verilog_format: off
`define NMI_I2S_MODE 8'h00
`define NMI_I2S_FORMAT 8'h04
`define NMI_I2S_UPBOUND 8'h08
`define NMI_I2S_LOWBOUND 8'h0C
`define NMI_I2S_RECVEN 8'h10
`define NMI_I2S_TXDATA 8'h14
`define NMI_I2S_RXDATA 8'h18
`define NMI_I2S_STATUS 8'h1C
// verilog_format: on
`define I2S_16b_48K 2'd0
`define I2S_16b_96K 2'd1
`define I2S_24b_48K 2'd2
`define I2S_24b_96K 2'd3
`endif
+16 -11
View File
@@ -13,8 +13,9 @@ module i2s_recv (
input logic rst_n_i,
input logic sclk_pos_i,
input logic lrck_i,
input logic bitmode_i,
input logic adcdat_i,
output logic [15:0] data_o,
output logic [23:0] data_o,
output logic done_o
);
@@ -22,13 +23,17 @@ module i2s_recv (
logic s_lrck_dely_d, s_lrck_dely_q;
logic s_lrck_trg;
logic [4:0] s_bit_cnt_d, s_bit_cnt_q;
logic [15:0] s_recv_data_d, s_recv_data_q;
logic [15:0] s_data_d, s_data_q;
logic [4:0] s_bit_num;
logic [23:0] s_recv_data_d, s_recv_data_q;
logic [23:0] s_data_d, s_data_q;
assign s_bit_num = bitmode_i ? 5'd23 : 5'd15;
assign data_o = s_data_q;
assign done_o = s_bit_cnt_q == 5'd15;
assign done_o = s_bit_cnt_q == s_bit_num;
assign s_lrck_trg = lrck_i ^ s_lrck_dely_q;
assign s_lrck_dely_d = lrck_i;
dffer #(1) u_lrck_dely_dffer (
clk_i,
@@ -39,11 +44,10 @@ module i2s_recv (
);
// 0-15
always_comb begin
s_bit_cnt_d = s_bit_cnt_q;
if (s_lrck_trg) s_bit_cnt_d = '0;
else if (s_bit_cnt_q < 5'd15) begin
else if (s_bit_cnt_q < s_bit_num) begin
s_bit_cnt_d = s_bit_cnt_q + 1'b1;
end
end
@@ -58,11 +62,12 @@ module i2s_recv (
always_comb begin
s_recv_data_d = s_recv_data_q;
if (s_bit_cnt_q <= 5'd15) begin
s_recv_data_d[15-s_bit_cnt_q] = adcdat_i;
if (s_bit_cnt_q <= s_bit_num) begin
if (bitmode_i) s_recv_data_d[5'd23-s_bit_cnt_q] = adcdat_i;
else s_recv_data_d[5'd15-s_bit_cnt_q] = adcdat_i;
end
end
dffer #(16) u_recv_data_dffer (
dffer #(24) u_recv_data_dffer (
clk_i,
rst_n_i,
sclk_pos_i,
@@ -71,8 +76,8 @@ module i2s_recv (
);
assign s_data_d = s_bit_cnt_q == 5'd15 ? s_recv_data_d : s_data_q;
dffer #(16) u_data_dffer (
assign s_data_d = s_bit_cnt_q == s_bit_num ? s_recv_data_d : s_data_q;
dffer #(24) u_data_dffer (
clk_i,
rst_n_i,
sclk_pos_i,
+216
View File
@@ -0,0 +1,216 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "i2s_define.svh"
module i2s_reg (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
nmi_if.slave nmi,
output logic mode_o,
output logic [ 1:0] format_o,
output logic recven_o,
output logic tx_push_valid_o,
output logic [31:0] tx_push_data_o,
input logic tx_full_i,
input logic [ 7:0] tx_elem_num_i,
output logic rx_pop_valid_o,
input logic [31:0] rx_pop_data_i,
input logic rx_empty_i,
input logic [ 7:0] rx_elem_num_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o
// verilog_format: on
);
// nmi
logic s_nmi_wr_hdshk, s_nmi_rd_hdshk;
logic s_nmi_ready_d, s_nmi_ready_q;
logic s_nmi_rdata_en;
logic [31:0] s_nmi_rdata_d, s_nmi_rdata_q;
// register
logic s_i2s_mode_en;
logic s_i2s_mode_d, s_i2s_mode_q;
logic s_i2s_format_en;
logic [1:0] s_i2s_format_d, s_i2s_format_q;
logic s_i2s_upbound_en;
logic [7:0] s_i2s_upbound_d, s_i2s_upbound_q;
logic s_i2s_lowbound_en;
logic [7:0] s_i2s_lowbound_d, s_i2s_lowbound_q;
logic s_i2s_recven_en;
logic s_i2s_recven_d, s_i2s_recven_q;
logic [1:0] s_i2s_status_d, s_i2s_status_q;
// common
logic s_tx_fifo_stall_d, s_tx_fifo_stall_q;
logic s_rx_fifo_stall_d, s_rx_fifo_stall_q;
// nmi
assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb);
assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb));
assign nmi.ready = s_nmi_ready_q;
assign nmi.rdata = s_nmi_rdata_q;
// reg
assign mode_o = s_i2s_mode_q;
assign format_o = s_i2s_format_q;
assign recven_o = s_i2s_recven_q;
// dma
assign dma_tx_stall_o = s_tx_fifo_stall_q;
assign dma_rx_stall_o = s_rx_fifo_stall_q;
assign s_i2s_mode_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_I2S_MODE;
assign s_i2s_mode_d = nmi.wdata[0];
dffer #(1) u_i2s_mode_dffer (
clk_i,
rst_n_i,
s_i2s_mode_en,
s_i2s_mode_d,
s_i2s_mode_q
);
assign s_i2s_format_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_I2S_FORMAT;
assign s_i2s_format_d = nmi.wdata[1:0];
dffer #(2) u_i2s_format_dffer (
clk_i,
rst_n_i,
s_i2s_format_en,
s_i2s_format_d,
s_i2s_format_q
);
assign s_i2s_upbound_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_I2S_UPBOUND;
assign s_i2s_upbound_d = nmi.wdata[7:0];
dfferh #(8) u_i2s_upbound_dfferh (
clk_i,
rst_n_i,
s_i2s_upbound_en,
s_i2s_upbound_d,
s_i2s_upbound_q
);
assign s_i2s_lowbound_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_I2S_LOWBOUND;
assign s_i2s_lowbound_d = nmi.wdata[7:0];
dffer #(8) u_i2s_lowbound_dffer (
clk_i,
rst_n_i,
s_i2s_lowbound_en,
s_i2s_lowbound_d,
s_i2s_lowbound_q
);
assign s_i2s_recven_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_I2S_RECVEN;
assign s_i2s_recven_d = nmi.wdata[0];
dffer #(1) u_i2s_recven_dffer (
clk_i,
rst_n_i,
s_i2s_recven_en,
s_i2s_recven_d,
s_i2s_recven_q
);
always_comb begin
s_tx_fifo_stall_d = s_tx_fifo_stall_q;
if (~s_tx_fifo_stall_q && tx_elem_num_i > s_i2s_upbound_q) begin
s_tx_fifo_stall_d = 1'b1;
end else if (s_tx_fifo_stall_q && tx_elem_num_i < s_i2s_lowbound_q) begin
s_tx_fifo_stall_d = 1'b0;
end
end
dffr #(1) u_tx_fifo_stall_dffr (
clk_i,
rst_n_i,
s_tx_fifo_stall_d,
s_tx_fifo_stall_q
);
always_comb begin
s_rx_fifo_stall_d = s_rx_fifo_stall_q;
if (~s_rx_fifo_stall_q && rx_elem_num_i < s_i2s_lowbound_q) begin
s_rx_fifo_stall_d = 1'b1;
end else if (s_rx_fifo_stall_q && rx_elem_num_i > s_i2s_upbound_q) begin
s_rx_fifo_stall_d = 1'b0;
end
end
dffr #(1) u_rx_fifo_stall_dffr (
clk_i,
rst_n_i,
s_rx_fifo_stall_d,
s_rx_fifo_stall_q
);
// TODO: need to handle when tx fifo is full(DMA is fine)
always_comb begin
tx_push_valid_o = 1'b0;
tx_push_data_o = '0;
if (s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_I2S_TXDATA) begin
tx_push_valid_o = 1'b1;
if (nmi.wstrb[0]) tx_push_data_o[7:0] = nmi.wdata[7:0];
if (nmi.wstrb[1]) tx_push_data_o[15:8] = nmi.wdata[15:8];
if (nmi.wstrb[2]) tx_push_data_o[23:16] = nmi.wdata[23:16];
if (nmi.wstrb[3]) tx_push_data_o[31:24] = nmi.wdata[31:24];
end
end
always_comb begin
s_i2s_status_d[0] = tx_full_i;
s_i2s_status_d[1] = rx_empty_i;
end
dffr #(2) u_i2s_status_dffr (
clk_i,
rst_n_i,
s_i2s_status_d,
s_i2s_status_q
);
assign s_nmi_ready_d = nmi.valid && (~s_nmi_ready_q);
dffr #(1) u_nmi_ready_dffr (
clk_i,
rst_n_i,
s_nmi_ready_d,
s_nmi_ready_q
);
assign s_nmi_rdata_en = s_nmi_rd_hdshk;
always_comb begin
rx_pop_valid_o = 1'b0;
s_nmi_rdata_d = s_nmi_rdata_q;
unique case (nmi.addr[7:0])
`NMI_I2S_MODE: s_nmi_rdata_d = {31'd0, s_i2s_mode_q};
`NMI_I2S_FORMAT: s_nmi_rdata_d = {30'd0, s_i2s_format_q};
`NMI_I2S_RXDATA: begin
if (s_nmi_rd_hdshk) begin
rx_pop_valid_o = 1'b1;
if (!rx_empty_i) s_nmi_rdata_d = rx_pop_data_i;
else s_nmi_rdata_d = '0;
end
end
`NMI_I2S_STATUS: s_nmi_rdata_d = {30'd0, s_i2s_status_q};
default: s_nmi_rdata_d = s_nmi_rdata_q;
endcase
end
dffer #(32) u_nmi_rdata_dffer (
clk_i,
rst_n_i,
s_nmi_rdata_en,
s_nmi_rdata_d,
s_nmi_rdata_q
);
endmodule
+23 -10
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Yuchi Miao <miaoyuchi@ict.ac.cn>
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
@@ -14,7 +14,8 @@ module i2s_send (
input logic sclk_pos_i,
input logic sclk_fall_i,
input logic lrck_i,
input logic [15:0] data_i,
input logic bitmode_i,
input logic [23:0] data_i,
output logic dacdat_o,
output logic done_o
);
@@ -22,12 +23,16 @@ module i2s_send (
logic s_lrck_dely_d, s_lrck_dely_q;
logic s_lrck_trg;
logic [4:0] s_bit_cnt_d, s_bit_cnt_q;
logic [15:0] s_xfer_data_d, s_xfer_data_q;
logic [4:0] s_bit_num;
logic [23:0] s_xfer_data_d, s_xfer_data_q;
logic s_dacdat_d, s_dacdat_q;
assign dacdat_o = s_dacdat_q;
assign done_o = s_bit_cnt_q == 5'd15;
assign s_bit_num = bitmode_i ? 5'd23 : 5'd15;
assign s_lrck_trg = lrck_i ^ s_lrck_dely_q;
assign dacdat_o = s_dacdat_q;
assign done_o = s_bit_cnt_q == s_bit_num;
assign s_lrck_dely_d = lrck_i;
dffer #(1) u_lrck_dely_dffer (
@@ -38,12 +43,14 @@ module i2s_send (
s_lrck_dely_q
);
// 0-15
always_comb begin
s_bit_cnt_d = s_bit_cnt_q;
if (s_lrck_trg) s_bit_cnt_d = '0;
else if (s_bit_cnt_q < 5'd15) begin
s_bit_cnt_d = s_bit_cnt_q + 1'b1;
else begin
if (s_bit_cnt_q < s_bit_num) begin
s_bit_cnt_d = s_bit_cnt_q + 1'b1;
end
end
end
dffer #(5) u_bit_cnt_dffer (
@@ -56,7 +63,7 @@ module i2s_send (
assign s_xfer_data_d = s_lrck_trg ? data_i : s_xfer_data_q;
dffer #(16) u_xfer_data_dffer (
dffer #(24) u_xfer_data_dffer (
clk_i,
rst_n_i,
sclk_pos_i,
@@ -65,7 +72,13 @@ module i2s_send (
);
assign s_dacdat_d = s_bit_cnt_q <= 5'd15 ? s_xfer_data_q[15-s_bit_cnt_q] : s_dacdat_q;
always_comb begin
s_dacdat_d = s_dacdat_q;
if (s_bit_cnt_q <= s_bit_num) begin
if (bitmode_i) s_dacdat_d = s_xfer_data_q[5'd23-s_bit_cnt_q];
else s_dacdat_d = s_xfer_data_q[5'd15-s_bit_cnt_q];
end
end
dffer #(1) u_dacdat_dffer (
clk_i,
rst_n_i,
+2
View File
@@ -52,6 +52,8 @@
../../ip/native/spisd.sv
../../ip/native/i2c_core.sv
../../ip/native/i2c.sv
../../ip/native/i2s_reg.sv
../../ip/native/i2s_clkgen.sv
../../ip/native/i2s_recv.sv
../../ip/native/i2s_send.sv
../../ip/native/i2s_core.sv
+4 -4
View File
@@ -13,9 +13,9 @@
// `default_nettype none
module retrosoc_tb;
localparam real XTAL_CPU_FREQ = 24.0; // MHz
localparam real XTAL_CPU_FREQ = 24.0;
localparam real EXT_CPU_FREQ = 72.0;
localparam real AUD_CPU_FREQ = 12.288;
localparam real AUD_CPU_FREQ = 18.432;
reg r_ext_clk;
wire s_ext_clk;
@@ -392,8 +392,8 @@ module retrosoc_tb;
// #205541740;
// #382928081;
// #300000;
// #45050000;
#86869320;
#45050000;
// #86869320;
// #21149063;
// #1667652;
// #327820116;