blob: 002b51eb88daca1ea3b17eda77c248a638a22a2f [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2021 , Dinesh Annayya
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org>
//
//////////////////////////////////////////////////////////////////////
//// ////
//// OMS8051 I2C Master byte-controller Module ////
//// WISHBONE rev.B2 compliant I2C Master byte-controller ////
//// ////
//// This file is part of the OMS 8051 cores project ////
//// http://www.opencores.org/cores/oms8051mini/ ////
//// ////
//// Description ////
//// OMS 8051 definitions. ////
//// ////
//// To Do: ////
//// nothing ////
//// ////
//// Author(s): ////
//// -Richard Herveille , richard@asics.ws, www.asics.ws ////
//// -Dinesh Annayya, dinesha@opencores.org ////
//// ////
//// Revision : Jan 6, 2017 ////
//// ////
//////////////////////////////////////////////////////////////////////
//// v0.0 - Dinesh A, 6th Jan 2017
//// 1. Initail version picked from
//// http://www.opencores.org/projects/i2c/
//// 2. renaming of reset signal to aresetn and sresetn
//// v0.1 - Dinesh.A, 19th Jan 2017
//// 1. Lint Error fixes
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000 Authors and OPENCORES.ORG ////
//// ////
//// 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 source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "i2cm_defines.v"
module i2cm_byte_ctrl (
//
// inputs & outputs
//
input clk, // master clock
input sresetn, // synchronous active high reset
input aresetn, // asynchronous active low reset
input ena, // core enable signal
input [15:0] clk_cnt, // 4x SCL
// control inputs
input start,
input stop,
input read,
input write,
input ack_in,
input [7:0] din,
// status outputs
output reg cmd_ack,
output reg ack_out,
output i2c_busy,
output i2c_al,
output [7:0] dout,
// I2C signals
input scl_i,
output scl_o,
output scl_oen,
input sda_i,
output sda_o,
output sda_oen
);
//
// Variable declarations
//
// statemachine
parameter [4:0] ST_IDLE = 5'b0_0000;
parameter [4:0] ST_START = 5'b0_0001;
parameter [4:0] ST_READ = 5'b0_0010;
parameter [4:0] ST_WRITE = 5'b0_0100;
parameter [4:0] ST_ACK = 5'b0_1000;
parameter [4:0] ST_STOP = 5'b1_0000;
// signals for bit_controller
reg [3:0] core_cmd;
reg core_txd;
wire core_ack, core_rxd;
// signals for shift register
reg [7:0] sr; //8bit shift register
reg shift, ld;
// signals for state machine
wire go;
reg [2:0] dcnt;
wire cnt_done;
//
// Module body
//
// hookup bit_controller
i2cm_bit_ctrl u_bit_ctrl (
.clk ( clk ),
.sresetn ( sresetn ),
.aresetn ( aresetn ),
.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 )
);
// generate go-signal
assign go = (read | write | stop) & ~cmd_ack;
// assign dout output to shift-register
assign dout = sr;
// generate shift register
always @(posedge clk or negedge aresetn)
if (!aresetn)
sr <= 8'h0;
else if (!sresetn)
sr <= 8'h0;
else if (ld)
sr <= din;
else if (shift)
sr <= {sr[6:0], core_rxd};
// generate counter
always @(posedge clk or negedge aresetn)
if (!aresetn)
dcnt <= 3'h0;
else if (!sresetn)
dcnt <= 3'h0;
else if (ld)
dcnt <= 3'h7;
else if (shift)
dcnt <= dcnt - 3'h1;
assign cnt_done = ~(|dcnt);
//
// state machine
//
reg [4:0] c_state; // synopsys enum_state
always @(posedge clk or negedge aresetn)
if (!aresetn)
begin
core_cmd <= `I2C_CMD_NOP;
core_txd <= 1'b0;
shift <= 1'b0;
ld <= 1'b0;
cmd_ack <= 1'b0;
c_state <= ST_IDLE;
ack_out <= 1'b0;
end
else if (!sresetn | i2c_al)
begin
core_cmd <= `I2C_CMD_NOP;
core_txd <= 1'b0;
shift <= 1'b0;
ld <= 1'b0;
cmd_ack <= 1'b0;
c_state <= ST_IDLE;
ack_out <= 1'b0;
end
else
begin
// initially reset all signals
core_txd <= sr[7];
shift <= 1'b0;
ld <= 1'b0;
cmd_ack <= 1'b0;
case (c_state) // synopsys full_case parallel_case
ST_IDLE:
if (go)
begin
if (start)
begin
c_state <= ST_START;
core_cmd <= `I2C_CMD_START;
end
else if (read)
begin
c_state <= ST_READ;
core_cmd <= `I2C_CMD_READ;
end
else if (write)
begin
c_state <= ST_WRITE;
core_cmd <= `I2C_CMD_WRITE;
end
else // stop
begin
c_state <= ST_STOP;
core_cmd <= `I2C_CMD_STOP;
end
ld <= 1'b1;
end
ST_START:
if (core_ack)
begin
if (read)
begin
c_state <= ST_READ;
core_cmd <= `I2C_CMD_READ;
end
else
begin
c_state <= ST_WRITE;
core_cmd <= `I2C_CMD_WRITE;
end
ld <= 1'b1;
end
ST_WRITE:
if (core_ack)
if (cnt_done)
begin
c_state <= ST_ACK;
core_cmd <= `I2C_CMD_READ;
end
else
begin
c_state <= ST_WRITE; // stay in same state
core_cmd <= `I2C_CMD_WRITE; // write next bit
shift <= 1'b1;
end
ST_READ:
if (core_ack)
begin
if (cnt_done)
begin
c_state <= ST_ACK;
core_cmd <= `I2C_CMD_WRITE;
end
else
begin
c_state <= ST_READ; // stay in same state
core_cmd <= `I2C_CMD_READ; // read next bit
end
shift <= 1'b1;
core_txd <= ack_in;
end
ST_ACK:
if (core_ack)
begin
if (stop)
begin
c_state <= ST_STOP;
core_cmd <= `I2C_CMD_STOP;
end
else
begin
c_state <= ST_IDLE;
core_cmd <= `I2C_CMD_NOP;
// generate command acknowledge signal
cmd_ack <= 1'b1;
end
// assign ack_out output to bit_controller_rxd (contains last received bit)
ack_out <= core_rxd;
core_txd <= 1'b1;
end
else
core_txd <= ack_in;
ST_STOP:
if (core_ack)
begin
c_state <= ST_IDLE;
core_cmd <= `I2C_CMD_NOP;
// generate command acknowledge signal
cmd_ack <= 1'b1;
end
default: c_state <= ST_IDLE;
endcase
end
endmodule