In spite of many errors that still need fixing, this is a major advance
over the previous commit. All verilog modules are in place more or less
as intended, with various functions such as the housekeeping SPI placed
on user area pads, with the ability to switch to user control from the
configuration. The pad control bits are local to the pads and loaded
via serial shift register, so that there are not hundreds of control wires
feeding into the user space. The user has three basic controls over each
pad: in, out, and outenb. Two timer/counters and an SPI master have been
added to the SoC. The SPI master shares I/O with the housekeeping SPI, so
that all housekeeping SPI registers can be accessed from the SoC directly.
diff --git a/verilog/rtl/mprj_ctrl.v b/verilog/rtl/mprj_ctrl.v
index 8970c41..cb67ac4 100644
--- a/verilog/rtl/mprj_ctrl.v
+++ b/verilog/rtl/mprj_ctrl.v
@@ -25,7 +25,10 @@
output serial_data_out,
// Read/write data to each GPIO pad from management SoC
- inout [IO_PADS-1:0] mgmt_gpio_io
+ input [IO_PADS-1:0] mgmt_gpio_in,
+ output [IO_PADS-1:0] mgmt_gpio_out,
+ output [IO_PADS-1:0] mgmt_gpio_outz,
+ output [IO_PADS-1:0] mgmt_gpio_oeb // Only JTAG and SDO connected
);
wire resetn;
wire valid;
@@ -58,7 +61,11 @@
.serial_clock(serial_clock),
.serial_resetn(serial_resetn),
.serial_data_out(serial_data_out),
- .mgmt_gpio_io(mgmt_gpio_io)
+ // .mgmt_gpio_io(mgmt_gpio_io)
+ .mgmt_gpio_in(mgmt_gpio_in),
+ .mgmt_gpio_out(mgmt_gpio_out),
+ .mgmt_gpio_outz(mgmt_gpio_outz),
+ .mgmt_gpio_oeb(mgmt_gpio_oeb)
);
endmodule
@@ -70,7 +77,7 @@
parameter CONFIG = 8'h 08,
parameter IO_PADS = 32,
parameter PWR_PADS = 32,
- parameter IO_CTRL_BITS = 14,
+ parameter IO_CTRL_BITS = 13,
parameter PWR_CTRL_BITS = 1
)(
input clk,
@@ -86,26 +93,35 @@
output serial_clock,
output serial_resetn,
output serial_data_out,
- inout [IO_PADS-1:0] mgmt_gpio_io
+ // inout [IO_PADS-1:0] mgmt_gpio_io
+ input [IO_PADS-1:0] mgmt_gpio_in,
+ output [IO_PADS-1:0] mgmt_gpio_out,
+ output [IO_PADS-1:0] mgmt_gpio_outz,
+ output [IO_PADS-1:0] mgmt_gpio_oeb
);
-`define START 2'b00
-`define XBYTE 2'b01
-`define LOAD 2'b10
+`define IDLE 2'b00
+`define START 2'b01
+`define XBYTE 2'b10
+`define LOAD 2'b11
localparam IO_BASE_ADR = (BASE_ADR | CONFIG);
localparam PWR_BASE_ADR = (BASE_ADR | CONFIG) + IO_PADS*4;
- localparam OEB = 1; // Offset of OEB in shift register block.
+ localparam OEB = 1; // Offset of output enable in shift register.
+ localparam INP_DIS = 3; // Offset of input disable in shift register.
reg [IO_CTRL_BITS-1:0] io_ctrl [IO_PADS-1:0]; // I/O control, 1 word per gpio pad
reg [PWR_CTRL_BITS-1:0] pwr_ctrl [PWR_PADS-1:0];// Power control, 1 word per power pad
- reg [IO_PADS-1:0] mgmt_gpio_out; // I/O read/write data, 1 bit per gpio pad
+ reg [IO_PADS-1:0] mgmt_gpio_out; // I/O write data, 1 bit per gpio pad
+ wire [IO_PADS-1:0] mgmt_gpio_outz; // I/O write data output when input disabled
+ wire [IO_PADS-1:0] mgmt_gpio_oeb;
reg xfer_ctrl; // Transfer control (1 bit)
wire [IO_PADS-1:0] io_ctrl_sel; // wishbone selects
wire [PWR_PADS-1:0] pwr_ctrl_sel;
wire io_data_sel;
wire xfer_sel;
+ wire [IO_PADS-1:0] mgmt_gpio_in;
assign xfer_sel = (iomem_addr[7:0] == XFER);
assign io_data_sel = (iomem_addr[7:0] == DATA);
@@ -114,14 +130,18 @@
// if OEB = 0 then mgmt_gpio_out --> mgmt_gpio_io; if OEB = 1 then
// mgmt_gpio_io --> mgmt_gpio_in. mgmt_gpio_in is always a copy of mgmt_gpio_io.
- assign mgmt_gpio_in = mgmt_gpio_io;
+ // assign mgmt_gpio_in = mgmt_gpio_io;
genvar i;
generate
for (i=0; i<IO_PADS; i=i+1) begin
assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
- assign mgmt_gpio_io[i] = (io_ctrl[0][i] + OEB == 1'b0) ?
- mgmt_gpio_out[i] : 1'bz;
+ // OEB is both tranferred by serial chain and output; that way
+ // each pad can selectively choose whether to have a dedicated
+ // signal for OEB, or to use it as a static configuration bit.
+ assign mgmt_gpio_oeb[i] = io_ctrl[OEB][i];
+ assign mgmt_gpio_outz[i] = (io_ctrl[INP_DIS][i] == 1'b1) ?
+ mgmt_gpio_out[i] : 1'bz;
end
endgenerate
@@ -145,8 +165,9 @@
if (io_data_sel) begin
iomem_rdata <= mgmt_gpio_in;
- mgmt_gpio_out <= 'd0;
- if (iomem_wstrb[0]) mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
+ if (iomem_wstrb[0]) begin
+ mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
+ end
end else if (xfer_sel) begin
iomem_rdata <= {31'd0, xfer_ctrl};
@@ -162,7 +183,9 @@
if (!resetn) begin
// NOTE: This needs to be set to the specific bit sequence
// that initializes every I/O pad to the appropriate state on
- // startup.
+ // startup, to match the startup state at each pad. Otherwise
+ // surprises happen if not all pad configurations are applied
+ // from the program code, and a transfer is initiated.
io_ctrl[i] <= 'd0;
end else begin
if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
@@ -213,7 +236,7 @@
always @(posedge clk or negedge resetn) begin
if (resetn == 1'b0) begin
- xfer_state <= `START;
+ xfer_state <= `IDLE;
xfer_count <= 4'd0;
pad_count <= 6'd0;
serial_resetn <= 1'b0;
@@ -222,7 +245,13 @@
end else begin
- if (xfer_state == `START) begin
+ if (xfer_state == `IDLE) begin
+ serial_resetn <= 1'b0;
+ serial_clock <= 1'b0;
+ if (xfer_ctrl == 1'b1) begin
+ xfer_state <= `START;
+ end
+ end else if (xfer_state == `START) begin
serial_resetn <= 1'b1;
serial_clock <= 1'b0;
xfer_count <= 6'd0;
@@ -266,7 +295,7 @@
end else if (xfer_count == 4'd3) begin
serial_resetn <= 1'b1;
serial_clock <= 1'b0;
- xfer_state <= `START;
+ xfer_state <= `IDLE;
end
end
end