From b6a73f484331c3436ea60531eba87d9277573ae2 Mon Sep 17 00:00:00 2001 From: maksyuki Date: Wed, 29 Jan 2025 14:04:01 +0800 Subject: [PATCH] feat: modify some ip impls --- rtl/ip/simple_i2c_master.v | 172 +++++++++++++++++++++++++++++++++++++ rtl/ip/simpleuart.v | 13 +-- rtl/ip/spimemio.v | 47 ++++++---- 3 files changed, 209 insertions(+), 23 deletions(-) create mode 100644 rtl/ip/simple_i2c_master.v diff --git a/rtl/ip/simple_i2c_master.v b/rtl/ip/simple_i2c_master.v new file mode 100644 index 00000000..56d6e94a --- /dev/null +++ b/rtl/ip/simple_i2c_master.v @@ -0,0 +1,172 @@ +//////////////////////////////////////////////////////////////////// +//// //// +//// I2C Master controller Top-level //// +//// //// +//// Modified from original project on OpenCores. //// +//// The top level routine modified to remove wishbone //// +//// interface to match Raven simple interfaces. For the //// +//// copyright and other original code, see source file //// +//// i2c_master_byte_ctrl.v. //// +//// //// +///////////////////////////////////////////////////////////////////// + +module simple_i2c_master ( + input clk, // master clock input + input resetn, // synchronous active low reset + input [ 2:0] reg_cfg1_we, // config register 1 write enable (3 bits) + input [31:0] reg_cfg1_di, // config register 1 data input + output [31:0] reg_cfg1_do, // config register 1 data output + input reg_cfg2_we, // config register 2 write enable (1 bit) + input [31:0] reg_cfg2_di, // config register 2 data input + output [31:0] reg_cfg2_do, // config register 2 data output + input reg_dat_we, // data write enable input (1 bit) + input reg_dat_re, // data read enable input + input [31:0] reg_dat_di, // data input + output [31:0] reg_dat_do, // data output + // I2C signals + // i2c clock line + input scl_pad_i, // SCL-line input + output scl_pad_o, // SCL-line output (always 1'b0) + output scl_padoeb_o, // SCL-line output enable (active low) + // i2c data line + input sda_pad_i, // SDA-line input + output sda_pad_o, // SDA-line output (always 1'b0) + output sda_padoeb_o, // SDA-line output enable (active low) + output irq_o // Interrupt for incoming data +); + + // registers (in config register 1) + reg [15:0] prer; // clock prescale register + reg [ 7:0] ctr; // control register + + // registers (in config register 2) + reg [ 7:0] cr; // command register + wire [ 7:0] sr; // status register + + // registers (in data register) + reg [ 7:0] txr; // transmit register + wire [ 7:0] rxr; // receive register + + // done signal: command completed, clear command register + wire done; + + // core enable signal + wire core_en; + wire ien; + + // status register signals + wire irxack; + reg rxack; // received aknowledge from slave + reg tip; // transfer in progress + reg irq_flag; // interrupt pending flag + wire i2c_busy; // bus busy (start signal detected) + wire i2c_al; // i2c bus arbitration lost + reg al; // status register arbitration lost bit + + // + // module body + // + + assign reg_cfg1_do = {8'b0, ctr, prer}; + assign reg_cfg2_do = {24'b0, sr}; + assign reg_dat_do = done ? rxr : ~0; + + // generate registers + always @(posedge clk) begin + if (!resetn) begin + prer <= 16'hffff; + ctr <= 8'h0; + txr <= 8'h0; + end else begin + if (reg_cfg1_we[0]) prer[7:0] <= reg_cfg1_di[7:0]; + if (reg_cfg1_we[1]) prer[15:8] <= reg_cfg1_di[15:8]; + if (reg_cfg1_we[2]) ctr <= reg_cfg1_di[23:16]; + // Upper 8 bits are not used + + // Status register is not writeable + // Upper 24 bits are not used + + if (reg_dat_we) txr <= reg_dat_di[7:0]; + // Upper 24 bits are not used + end + end + + // generate command register (special case) + + always @(posedge clk) begin + if (!resetn) begin + cr <= 8'h0; + end else if (reg_cfg2_we) begin + if (core_en) cr <= reg_cfg2_di[7:0]; + end else begin + if (done | i2c_al) cr[7:4] <= 4'h0; // clear command bits when done + // or when aribitration lost + cr[2:1] <= 2'b0; // reserved bits + cr[0] <= 1'b0; // clear IRQ_ACK bit + end + end + + // decode command register + wire sta = cr[7]; + wire sto = cr[6]; + wire rd = cr[5]; + wire wr = cr[4]; + wire ack = cr[3]; + wire iack = cr[0]; + + // decode control register + assign core_en = ctr[7]; + assign ien = ctr[6]; + + // hook up byte controller block + i2c_master_byte_ctrl byte_controller ( + .clk (clk), + .nReset (resetn), + .ena (core_en), + .clk_cnt (prer), + .start (sta), + .stop (sto), + .read (rd), + .write (wr), + .ack_in (ack), + .din (txr), + .cmd_ack (done), + .ack_out (irxack), + .dout (rxr), + .i2c_busy(i2c_busy), + .i2c_al (i2c_al), + .scl_i (scl_pad_i), + .scl_o (scl_pad_o), + .scl_oen (scl_padoeb_o), + .sda_i (sda_pad_i), + .sda_o (sda_pad_o), + .sda_oen (sda_padoeb_o) + ); + + // status register block + interrupt request signal + always @(posedge clk) + if (!resetn) begin + al <= 1'b0; + rxack <= 1'b0; + tip <= 1'b0; + irq_flag <= 1'b0; + end else begin + al <= i2c_al | (al & ~sta); + rxack <= irxack; + tip <= (rd | wr); + irq_flag <= (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated + end + + // interrupt signal is only generated when IEN + // (interrupt enable bit) is set + assign irq_o = irq_flag && ien; + + // assign status register bits + assign sr[7] = rxack; + assign sr[6] = i2c_busy; + assign sr[5] = al; + assign sr[4:2] = 3'h0; // reserved + assign sr[1] = tip; + assign sr[0] = irq_flag; + +endmodule diff --git a/rtl/ip/simpleuart.v b/rtl/ip/simpleuart.v index 854adc26..ef600143 100644 --- a/rtl/ip/simpleuart.v +++ b/rtl/ip/simpleuart.v @@ -1,7 +1,7 @@ /* * PicoSoC - A simple example SoC using PicoRV32 * - * Copyright (C) 2017 Claire Xenia Wolf + * Copyright (C) 2017 Clifford Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,9 +17,7 @@ * */ -module simpleuart #( - parameter integer DEFAULT_DIV = 1 -) ( +module simpleuart ( input clk, input resetn, output ser_tx, @@ -31,7 +29,8 @@ module simpleuart #( input reg_dat_re, input [31:0] reg_dat_di, output [31:0] reg_dat_do, - output reg_dat_wait + output reg_dat_wait, + output irq_out ); reg [31:0] cfg_divider; @@ -51,9 +50,11 @@ module simpleuart #( assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; + assign irq_out = recv_buf_valid; + always @(posedge clk) begin if (!resetn) begin - cfg_divider <= DEFAULT_DIV; + cfg_divider <= 1; end else begin if (reg_div_we[0]) cfg_divider[7:0] <= reg_div_di[7:0]; if (reg_div_we[1]) cfg_divider[15:8] <= reg_div_di[15:8]; diff --git a/rtl/ip/spimemio.v b/rtl/ip/spimemio.v index 9ff9fa7d..45946e78 100644 --- a/rtl/ip/spimemio.v +++ b/rtl/ip/spimemio.v @@ -1,7 +1,7 @@ /* * PicoSoC - A simple example SoC using PicoRV32 * - * Copyright (C) 2017 Claire Xenia Wolf + * Copyright (C) 2017 Clifford Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,12 +24,19 @@ module spimemio ( output ready, input [23:0] addr, output reg [31:0] rdata, + input pass_thru, + input pass_thru_csb, + input pass_thru_sck, + input pass_thru_sdi, + output pass_thru_sdo, output flash_csb, output flash_clk, - output flash_io0_oe, - output flash_io1_oe, - output flash_io2_oe, - output flash_io3_oe, + output flash_csb_oeb, + output flash_clk_oeb, + output flash_io0_oeb, + output flash_io1_oeb, + output flash_io2_oeb, + output flash_io3_oeb, output flash_io0_do, output flash_io1_do, output flash_io2_do, @@ -85,7 +92,7 @@ module spimemio ( assign cfgreg_do[20] = config_cont; assign cfgreg_do[19:16] = config_dummy; assign cfgreg_do[15:12] = 0; - assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; + assign cfgreg_do[11:8] = {~flash_io3_oeb, ~flash_io2_oeb, ~flash_io1_oeb, ~flash_io0_oeb}; assign cfgreg_do[7:6] = 0; assign cfgreg_do[5] = flash_csb; assign cfgreg_do[4] = flash_clk; @@ -150,25 +157,30 @@ module spimemio ( xfer_io3_90 <= xfer_io3_do; end - assign flash_csb = config_en ? xfer_csb : config_csb; - assign flash_clk = config_en ? xfer_clk : config_clk; + assign flash_csb = pass_thru ? pass_thru_csb : (config_en ? xfer_csb : config_csb); + assign flash_clk = pass_thru ? pass_thru_sck : (config_en ? xfer_clk : config_clk); + assign flash_csb_oeb = pass_thru ? 1'b0 : ~resetn ? 1'b1 : 1'b0; + assign flash_clk_oeb = pass_thru ? 1'b0 : ~resetn ? 1'b1 : 1'b0; - assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0]; - assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1]; - assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2]; - assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3]; + assign flash_io0_oeb = pass_thru ? 1'b0 : ~resetn ? 1'b1 : (config_en ? ~xfer_io0_oe : ~config_oe[0]); + assign flash_io1_oeb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? ~xfer_io1_oe : ~config_oe[1]); + assign flash_io2_oeb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? ~xfer_io2_oe : ~config_oe[2]); + assign flash_io3_oeb = (pass_thru | ~resetn) ? 1'b1 : (config_en ? ~xfer_io3_oe : ~config_oe[3]); - assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0]; + assign flash_io0_do = pass_thru ? pass_thru_sdi : (config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0]); assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1]; assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2]; assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3]; + assign pass_thru_sdo = pass_thru ? flash_io1_di : 1'b0; + wire xfer_dspi = din_ddr && !din_qspi; wire xfer_ddr = din_ddr && din_qspi; spimemio_xfer xfer ( .clk (clk), - .resetn (xfer_resetn), + .resetn (resetn), + .xfer_resetn (xfer_resetn), .din_valid (din_valid), .din_ready (din_ready), .din_data (din_data), @@ -374,6 +386,7 @@ endmodule module spimemio_xfer ( input clk, resetn, + xfer_resetn, input din_valid, output din_ready, @@ -435,9 +448,9 @@ module spimemio_xfer ( xfer_tag_q <= xfer_tag; end - assign din_ready = din_valid && resetn && next_fetch; + assign din_ready = din_valid && xfer_resetn && next_fetch; - assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn; + assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && xfer_resetn; assign dout_data = ibuffer; assign dout_tag = xfer_tag_q; @@ -532,7 +545,7 @@ module spimemio_xfer ( end always @(posedge clk) begin - if (!resetn) begin + if (!resetn || !xfer_resetn) begin fetch <= 1; last_fetch <= 1; flash_csb <= 1;