blob: 8913db66cf243698202c9f3332fc2699f181e6dd [file] [log] [blame]
// gpio control module
// address space:
// Ctrl Reg 0b00
// GPIO Input 0b01
// GPIO Output 0b10
// GPIO OutEnable 0b11
module gpioCtrl (
// system
input wire CLK,
input wire RSTb,
// control interface
input wire CTRL_WE,
input wire [3:0] CTRL_ADDR,
input wire [31:0] CTRL_DATA_IN,
output wire [31:0] CTRL_DATA_OUT,
// caravel gpio signaling
input wire [37:0] GPIO_IN,
output wire [37:0] GPIO_OUT,
output wire [37:0] GPIO_OEb,
// RAM interface
output wire RAM_CSb,
output wire RAM_WEb,
output wire [7:0] RAM_ADDR,
output wire [31:0] RAM_DATA_IN,
input wire [31:0] RAM_DATA_OUT
);
// constants input fsm
parameter sFSM_IN_STOP = 2'b00;
parameter sFSM_IN_SHIFT = 2'b01;
parameter sFSM_IN_STORE = 2'b10;
// constants output fsm
parameter sFSM_OUT_STOP = 2'b00;
parameter sFSM_OUT_LOAD = 2'b01;
parameter sFSM_OUT_SHIFT = 2'b10;
parameter sFSM_OUT_LOAD_NEXT = 2'b11;
// internal output signals
reg [31:0] CTRL_DATA_OUT_i;
reg RAM_WEb_i;
reg [31:0] RAM_ADDR_i;
reg [31:0] RAM_DATA_IN_i;
// control register
reg [31:0] CTRL_REG_Q;
reg [31:0] CTRL_REG_D;
// control register aliases
wire aSHIFT_IN_EN;
wire [4:0] aINPUT_SEL;
wire aSHIFT_OUT_EN;
wire [4:0] aOUTPUT_SEL;
wire aOUTPUT_LOOP;
wire [9:0] aOUTPUT_LEN;
wire aOUTPUT_LIMIT;
// data registers
reg [31:0] DATA_IN_Q;
reg [31:0] DATA_IN_D;
reg [31:0] DATA_OUT_Q;
reg [31:0] DATA_OUT_D;
reg [31:0] DATA_OE_Q;
reg [31:0] DATA_OE_D;
// Shift registers
reg [31:0] SHIFT_IN_Q;
reg [31:0] SHIFT_IN_D;
reg [31:0] SHIFT_OUT_Q;
reg [31:0] SHIFT_OUT_D;
// fsm registers
reg [1:0] FSM_IN_Q;
reg [1:0] FSM_IN_D;
reg [1:0] FSM_OUT_Q;
reg [1:0] FSM_OUT_D;
// fsm control signals
reg SET_SHIFT_DATA;
reg SET_OUT_DATA;
reg RST_SHIFT_IN_EN;
reg RST_SHIFT_OUT_EN;
reg OVERRIDE_RAM_ADDR;
reg RAM_CSb_IN;
reg RAM_CSb_OUT;
// bit counters
reg [9:0] BIT_IN_COUNT_Q;
reg [9:0] BIT_IN_COUNT_D;
reg [9:0] BIT_OUT_COUNT_Q;
reg [9:0] BIT_OUT_COUNT_D;
// module output
assign CTRL_DATA_OUT = CTRL_DATA_OUT_i;
assign GPIO_OUT[31:0] = DATA_OUT_Q;
assign GPIO_OUT[37:32] = 6'b000000;
assign GPIO_OEb[31:0] = ~(DATA_OE_Q);
assign GPIO_OEb[37:32] = 6'b111111;
assign RAM_WEb = RAM_WEb_i;
assign RAM_ADDR = RAM_ADDR_i;
assign RAM_DATA_IN = RAM_DATA_IN_i;
// control register read aliases (...is there a way to define real aliases?)
assign aSHIFT_OUT_EN = CTRL_REG_Q[0];
assign aOUTPUT_SEL = CTRL_REG_Q[5:1];
assign aSHIFT_IN_EN = CTRL_REG_Q[6];
assign aINPUT_SEL = CTRL_REG_Q[11:7];
assign aOUTPUT_LOOP = CTRL_REG_Q[12];
assign aOUTPUT_LEN = CTRL_REG_Q[22:13];
assign aOUTPUT_LIMIT = CTRL_REG_Q[23];
// control interface read access
always @(*) begin : interface_read_access
case (CTRL_ADDR[3:2])
// control register
2'b00: CTRL_DATA_OUT_i <= CTRL_REG_Q;
// input data
2'b01: CTRL_DATA_OUT_i <= DATA_IN_Q;
// output data
2'b10: CTRL_DATA_OUT_i <= DATA_OUT_Q;
// output enable
2'b11: CTRL_DATA_OUT_i <= DATA_OE_Q;
// something's wrong
default: CTRL_DATA_OUT_i <= 8'b0000_0000;
endcase
end
// control interface write access
always @(*) begin : interface_write_access
// default
CTRL_REG_D <= CTRL_REG_Q;
SET_OUT_DATA <= 1'b0;
DATA_OE_D <= DATA_OE_Q;
// actual write request
if (CTRL_WE == 1'b1) begin
// address selection
case (CTRL_ADDR[3:2])
// control register
2'b00: begin
CTRL_REG_D <= CTRL_DATA_IN;
end
// output data
2'b10: SET_OUT_DATA <= 1'b1;
// output enable
2'b11: DATA_OE_D <= CTRL_DATA_IN;
endcase
end
// auto set/reset shift enables
if (RST_SHIFT_IN_EN == 1'b1) CTRL_REG_D[6] <= 1'b0;
if (RST_SHIFT_OUT_EN == 1'b1) CTRL_REG_D[0] <= 1'b0;
//if (SET_SHIFT_OUT_EN == 1'b1) CTRL_REG_D[0] <= 1'b1;
end
// fsm data in
always @(*) begin : fsm_data_in
// default
FSM_IN_D <= FSM_IN_Q;
BIT_IN_COUNT_D <= BIT_IN_COUNT_Q;
RST_SHIFT_IN_EN <= 1'b0;
//RAM_CSb_IN <= 1'b1;
RAM_WEb_i <= 1'b1;
// fsm logic
case (FSM_IN_Q)
// input sampling inactive
sFSM_IN_STOP: begin
BIT_IN_COUNT_D <= 10'b00_0000_0000;
if (aSHIFT_IN_EN == 1'b1) begin
RST_SHIFT_IN_EN <= 1'b1;
FSM_IN_D <= sFSM_IN_SHIFT;
end
end
// input sampling active
sFSM_IN_SHIFT: begin
BIT_IN_COUNT_D <= BIT_IN_COUNT_Q + 1;
if (BIT_IN_COUNT_Q[4:0] == 5'b1_1110) FSM_IN_D <= sFSM_IN_STORE;
end
// store 32bit input data to ram
sFSM_IN_STORE: begin
BIT_IN_COUNT_D <= BIT_IN_COUNT_Q + 1;
//RAM_CSb_IN <= 1'b0;
RAM_WEb_i <= 1'b0;
if (BIT_IN_COUNT_Q[9:5] == 5'b1_1111) FSM_IN_D <= sFSM_IN_STOP;
else FSM_IN_D <= sFSM_IN_SHIFT;
end
// error
default: FSM_IN_D <= sFSM_IN_STOP;
endcase
end
// fsm data out
always @(*) begin : fsm_data_out
// default
FSM_OUT_D <= FSM_OUT_Q;
BIT_OUT_COUNT_D <= BIT_OUT_COUNT_Q;
RST_SHIFT_OUT_EN <= 1'b0;
SET_SHIFT_DATA <= 1'b0;
//RAM_CSb_OUT <= 1'b1;
OVERRIDE_RAM_ADDR <= 1'b0;
// fsm logic
case (FSM_OUT_Q)
// output generation inactive
sFSM_OUT_STOP: begin
BIT_OUT_COUNT_D <= 10'b11_1111_1111;
if (aSHIFT_OUT_EN == 1'b1) begin
RST_SHIFT_OUT_EN <= 1'b1;
//RAM_CSb_OUT <= 1'b0;
FSM_OUT_D <= sFSM_OUT_LOAD;
end
end
// load first 32bit output data from ram
sFSM_OUT_LOAD: begin
BIT_OUT_COUNT_D <= 10'b00_0000_0000;
SET_SHIFT_DATA <= 1'b1;
FSM_OUT_D <= sFSM_OUT_SHIFT;
end
// output generation active
sFSM_OUT_SHIFT: begin
BIT_OUT_COUNT_D <= BIT_OUT_COUNT_Q + 1;
// single shot: configured length reached
if ( aOUTPUT_LOOP == 1'b0
&& (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == aOUTPUT_LEN-1))
FSM_OUT_D <= sFSM_OUT_STOP;
// loop mode: configured length reached
else if ( aOUTPUT_LOOP == 1'b1
&& (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == (aOUTPUT_LEN-2))) begin
OVERRIDE_RAM_ADDR <= 1'b1;
//RAM_CSb_OUT <= 1'b0;
FSM_OUT_D <= sFSM_OUT_LOAD;
// need new 32-bit data
end else if (BIT_OUT_COUNT_Q[4:0] == 5'b1_1110) begin
//RAM_CSb_OUT <= 1'b0;
FSM_OUT_D <= sFSM_OUT_LOAD_NEXT;
end
end
// load next 32bit output data from ram
sFSM_OUT_LOAD_NEXT: begin
// single shot: max or configured length reached
if ( aOUTPUT_LOOP == 1'b0
&& ( BIT_OUT_COUNT_Q[9:5] == 5'b1_1111
|| (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == aOUTPUT_LEN-1)))
FSM_OUT_D <= sFSM_OUT_STOP;
// loop mode: max or configured length reached
else if ( aOUTPUT_LOOP == 1'b1
&& ( BIT_OUT_COUNT_Q[9:5] == 5'b1_1111
|| (aOUTPUT_LIMIT == 1'b1 && BIT_OUT_COUNT_Q == aOUTPUT_LEN-2))) begin
OVERRIDE_RAM_ADDR <= 1'b1;
//RAM_CSb_OUT <= 1'b0;
FSM_OUT_D <= sFSM_OUT_LOAD;
// continue generating data bits
end else begin
SET_SHIFT_DATA <= 1'b1;
BIT_OUT_COUNT_D <= BIT_OUT_COUNT_Q + 1;
FSM_OUT_D <= sFSM_OUT_SHIFT;
end
end
// error
default: FSM_OUT_D <= sFSM_OUT_STOP;
endcase
end
// input data path
always @(*) begin : input_data_path
reg vDataInMux;
// input registers
DATA_IN_D <= GPIO_IN[31:0];
// input multiplexer
vDataInMux = DATA_IN_Q[aINPUT_SEL];
// input shift register
SHIFT_IN_D <= {SHIFT_IN_Q[30:0], vDataInMux};
// ram data input
RAM_DATA_IN_i <= SHIFT_IN_Q;
end
// output data path
always @(*) begin : output_data_path
// default: output shift register
SHIFT_OUT_D <= {SHIFT_OUT_Q[30:0], 1'b0};
// set shift data
if(SET_SHIFT_DATA == 1'b1) SHIFT_OUT_D <= RAM_DATA_OUT;
// default: hold output data
DATA_OUT_D <= DATA_OUT_Q;
// bus write access
if (SET_OUT_DATA == 1'b1) DATA_OUT_D <= CTRL_DATA_IN;
// shift register input
if (FSM_OUT_Q != sFSM_OUT_STOP) DATA_OUT_D[aOUTPUT_SEL] <= SHIFT_OUT_Q[31];
end
// logic for ram access
always @(*) begin : ramAccessLogic
reg [4:0] vBitOutCountSum;
// default
RAM_CSb_IN <= 1'b1;
RAM_CSb_OUT <= 1'b1;
RAM_ADDR_i <= 32'h00_00_00_00;
if (OVERRIDE_RAM_ADDR == 1'b1) begin
RAM_CSb_OUT <= 1'b0;
RAM_ADDR_i <= 32'h00_00_00_00;
end else if (FSM_IN_Q != sFSM_IN_STOP) begin
RAM_CSb_IN <= 1'b0;
RAM_ADDR_i <= {BIT_IN_COUNT_Q[9:5], 2'b00};
end else if (FSM_OUT_Q != sFSM_OUT_STOP) begin
RAM_CSb_OUT <= 1'b0;
vBitOutCountSum = BIT_OUT_COUNT_Q[9:5] + 1;
RAM_ADDR_i <= {vBitOutCountSum, 2'b00};
end
end
//assign RAM_ADDR = (FSM_IN_Q != sFSM_IN_STOP) ? {BIT_IN_COUNT_Q[9:5], 2'b00} : {BIT_OUT_COUNT_Q[9:5] + 1, 2'b00};
assign RAM_CSb = RAM_CSb_IN & RAM_CSb_OUT;
// flip flops
always @(posedge CLK, negedge RSTb) begin : flip_flops
if(RSTb == 1'b0) begin
CTRL_REG_Q <= 32'h00_00_00_00;
DATA_IN_Q <= 32'h00_00_00_00;
DATA_OUT_Q <= 32'h00_00_00_00;
DATA_OE_Q <= 32'h00_00_00_00;
SHIFT_IN_Q <= 32'h00_00_00_00;
SHIFT_OUT_Q <= 32'h00_00_00_00;
FSM_IN_Q <= sFSM_IN_STOP;
FSM_OUT_Q <= sFSM_OUT_STOP;
BIT_IN_COUNT_Q <= 10'b00_0000_0000;
BIT_OUT_COUNT_Q <= 10'b00_0000_0000;
end else begin
CTRL_REG_Q <= CTRL_REG_D;
DATA_IN_Q <= DATA_IN_D;
DATA_OUT_Q <= DATA_OUT_D;
DATA_OE_Q <= DATA_OE_D;
SHIFT_IN_Q <= SHIFT_IN_D;
SHIFT_OUT_Q <= SHIFT_OUT_D;
FSM_IN_Q <= FSM_IN_D;
FSM_OUT_Q <= FSM_OUT_D;
BIT_IN_COUNT_Q <= BIT_IN_COUNT_D;
BIT_OUT_COUNT_Q <= BIT_OUT_COUNT_D;
end
end
endmodule