//
|
//
|
// WISHBONE revB2 compiant I2C master core
|
// WISHBONE revB2 compiant I2C master core
|
//
|
//
|
// author: Richard Herveille
|
// author: Richard Herveille
|
// rev. 0.1 26-08-2001. Iinitial Verilog release
|
// rev. 0.1 26-08-2001. Iinitial Verilog release
|
//
|
//
|
|
|
`include "timescale.v"
|
`include "timescale.v"
|
`include "i2c_master_defines.v"
|
`include "i2c_master_defines.v"
|
|
|
module i2c_master_top(
|
module i2c_master_top(
|
wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o,
|
wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o,
|
wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o,
|
wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o,
|
scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o );
|
scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o );
|
|
|
// parameters
|
// parameters
|
parameter ARST_LVL = 1'b0; // asynchronous reset level
|
parameter ARST_LVL = 1'b0; // asynchronous reset level
|
|
|
//
|
//
|
// inputs & outputs
|
// inputs & outputs
|
//
|
//
|
|
|
// wishbone signals
|
// wishbone signals
|
input wb_clk_i; // master clock input
|
input wb_clk_i; // master clock input
|
input wb_rst_i; // synchronous active high reset
|
input wb_rst_i; // synchronous active high reset
|
input arst_i; // asynchronous reset
|
input arst_i; // asynchronous reset
|
input [2:0] wb_adr_i; // lower address bits
|
input [2:0] wb_adr_i; // lower address bits
|
input [7:0] wb_dat_i; // databus input
|
input [7:0] wb_dat_i; // databus input
|
output [7:0] wb_dat_o; // databus output
|
output [7:0] wb_dat_o; // databus output
|
reg [7:0] wb_dat_o;
|
reg [7:0] wb_dat_o;
|
input wb_we_i; // write enable input
|
input wb_we_i; // write enable input
|
input wb_stb_i; // stobe/core select signal
|
input wb_stb_i; // stobe/core select signal
|
input wb_cyc_i; // valid bus cycle input
|
input wb_cyc_i; // valid bus cycle input
|
output wb_ack_o; // bus cycle acknowledge output
|
output wb_ack_o; // bus cycle acknowledge output
|
output wb_inta_o; // interrupt request signal output
|
output wb_inta_o; // interrupt request signal output
|
reg wb_inta_o;
|
reg wb_inta_o;
|
|
|
// I2C signals
|
// I2C signals
|
// i2c clock line
|
// i2c clock line
|
input scl_pad_i; // SCL-line input
|
input scl_pad_i; // SCL-line input
|
output scl_pad_o; // SCL-line output (always 1'b0)
|
output scl_pad_o; // SCL-line output (always 1'b0)
|
output scl_padoen_o; // SCL-line output enable (active low)
|
output scl_padoen_o; // SCL-line output enable (active low)
|
// i2c data line
|
// i2c data line
|
input sda_pad_i; // SDA-line input
|
input sda_pad_i; // SDA-line input
|
output sda_pad_o; // SDA-line output (always 1'b0)
|
output sda_pad_o; // SDA-line output (always 1'b0)
|
output sda_padoen_o; // SDA-line output enable (active low)
|
output sda_padoen_o; // SDA-line output enable (active low)
|
|
|
|
|
//
|
//
|
// variable declarations
|
// variable declarations
|
//
|
//
|
|
|
// registers
|
// registers
|
reg [15:0] prer; // clock prescale register
|
reg [15:0] prer; // clock prescale register
|
reg [ 7:0] ctr; // control register
|
reg [ 7:0] ctr; // control register
|
reg [ 7:0] txr; // transmit register
|
reg [ 7:0] txr; // transmit register
|
wire [ 7:0] rxr; // receive register
|
wire [ 7:0] rxr; // receive register
|
reg [ 7:0] cr; // command register
|
reg [ 7:0] cr; // command register
|
wire [ 7:0] sr; // status register
|
wire [ 7:0] sr; // status register
|
|
|
// done signal: command completed, clear command register
|
// done signal: command completed, clear command register
|
wire done;
|
wire done;
|
|
|
// core enable signal
|
// core enable signal
|
wire core_en;
|
wire core_en;
|
|
wire ien;
|
|
|
// status register signals
|
// status register signals
|
wire irxack;
|
wire irxack;
|
reg rxack; // received aknowledge from slave
|
reg rxack; // received aknowledge from slave
|
reg tip; // transfer in progress
|
reg tip; // transfer in progress
|
reg irq_flag; // interrupt pending flag
|
reg irq_flag; // interrupt pending flag
|
wire i2c_busy; // bus busy (start signal detected)
|
wire i2c_busy; // bus busy (start signal detected)
|
|
|
//
|
//
|
// module body
|
// module body
|
//
|
//
|
|
|
// generate internal reset
|
// generate internal reset
|
wire rst_i = arst_i ^ ARST_LVL;
|
wire rst_i = arst_i ^ ARST_LVL;
|
|
|
// generate acknowledge output signal
|
// generate acknowledge output signal
|
assign wb_ack_o = wb_cyc_i && wb_stb_i; // because timing is always honored
|
assign wb_ack_o = wb_cyc_i && wb_stb_i; // because timing is always honored
|
|
|
// assign DAT_O
|
// assign DAT_O
|
always@(wb_adr_i or prer or ctr or txr or cr or rxr or sr)
|
always@(wb_adr_i or prer or ctr or txr or cr or rxr or sr)
|
begin
|
begin
|
case (wb_adr_i) // synopsis full_case parallel_case
|
case (wb_adr_i) // synopsis full_case parallel_case
|
3'b000: wb_dat_o = prer[ 7:0];
|
3'b000: wb_dat_o = prer[ 7:0];
|
3'b001: wb_dat_o = prer[15:8];
|
3'b001: wb_dat_o = prer[15:8];
|
3'b010: wb_dat_o = ctr;
|
3'b010: wb_dat_o = ctr;
|
3'b011: wb_dat_o = rxr; // write is transmit register (txr)
|
3'b011: wb_dat_o = rxr; // write is transmit register (txr)
|
3'b100: wb_dat_o = sr; // write is command register (cr)
|
3'b100: wb_dat_o = sr; // write is command register (cr)
|
3'b101: wb_dat_o = txr;
|
3'b101: wb_dat_o = txr;
|
3'b110: wb_dat_o = cr;
|
3'b110: wb_dat_o = cr;
|
endcase
|
endcase
|
end
|
end
|
|
|
|
|
// generate registers
|
// generate registers
|
always@(posedge wb_clk_i or negedge rst_i)
|
always@(posedge wb_clk_i or negedge rst_i)
|
if (!rst_i)
|
if (!rst_i)
|
begin
|
begin
|
prer <= #1 16'h0;
|
prer <= #1 16'h0;
|
ctr <= #1 8'h0;
|
ctr <= #1 8'h0;
|
txr <= #1 8'h0;
|
txr <= #1 8'h0;
|
cr <= #1 8'h0;
|
cr <= #1 8'h0;
|
end
|
end
|
else if (wb_rst_i)
|
else if (wb_rst_i)
|
begin
|
begin
|
prer <= #1 16'h0;
|
prer <= #1 16'h0;
|
ctr <= #1 8'h0;
|
ctr <= #1 8'h0;
|
txr <= #1 8'h0;
|
txr <= #1 8'h0;
|
cr <= #1 8'h0;
|
cr <= #1 8'h0;
|
end
|
end
|
else
|
else
|
if (wb_cyc_i && wb_stb_i && wb_we_i)
|
if (wb_cyc_i && wb_stb_i && wb_we_i)
|
begin
|
begin
|
if (!wb_adr_i[2])
|
if (!wb_adr_i[2])
|
case (wb_adr_i[1:0]) // synopsis full_case parallel_case
|
case (wb_adr_i[1:0]) // synopsis full_case parallel_case
|
2'b00 : prer [ 7:0] <= #1 wb_dat_i;
|
2'b00 : prer [ 7:0] <= #1 wb_dat_i;
|
2'b01 : prer [15:8] <= #1 wb_dat_i;
|
2'b01 : prer [15:8] <= #1 wb_dat_i;
|
2'b10 : ctr <= #1 wb_dat_i;
|
2'b10 : ctr <= #1 wb_dat_i;
|
2'b11 : txr <= #1 wb_dat_i;
|
2'b11 : txr <= #1 wb_dat_i;
|
endcase
|
endcase
|
else
|
else
|
if (core_en && (wb_adr_i[1:0] == 2'b00) ) // only take new commands when i2c core enabled, pending commands are finished
|
if (core_en && (wb_adr_i[1:0] == 2'b00) ) // only take new commands when i2c core enabled, pending commands are finished
|
cr <= #1 wb_dat_i;
|
cr <= #1 wb_dat_i;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (done)
|
if (done)
|
cr[7:4] <= #1 4'h0; // clear command bits when done
|
cr[7:4] <= #1 4'h0; // clear command bits when done
|
|
|
cr[2:1] <= #1 2'b00; // reserved bits
|
cr[2:1] <= #1 2'b00; // reserved bits
|
cr[0] <= #1 cr[0] && irq_flag; // clear when irq_flag cleared
|
cr[0] <= #1 cr[0] && irq_flag; // clear when irq_flag cleared
|
end
|
end
|
|
|
|
|
// decode command register
|
// decode command register
|
wire sta = cr[7];
|
wire sta = cr[7];
|
wire sto = cr[6];
|
wire sto = cr[6];
|
wire rd = cr[5];
|
wire rd = cr[5];
|
wire wr = cr[4];
|
wire wr = cr[4];
|
wire ack = cr[3];
|
wire ack = cr[3];
|
wire iack = cr[0];
|
wire iack = cr[0];
|
|
|
// decode control register
|
// decode control register
|
assign core_en = ctr[7];
|
assign core_en = ctr[7];
|
|
assign ien = ctr[6];
|
|
|
// hookup byte controller block
|
// hookup byte controller block
|
i2c_master_byte_ctrl byte_controller (
|
i2c_master_byte_ctrl byte_controller (
|
.clk(wb_clk_i),
|
.clk(wb_clk_i),
|
.rst(wb_rst_i),
|
.rst(wb_rst_i),
|
.nReset(rst_i),
|
.nReset(rst_i),
|
.ena(core_en),
|
.ena(core_en),
|
.clk_cnt(prer),
|
.clk_cnt(prer),
|
.start(sta),
|
.start(sta),
|
.stop(sto),
|
.stop(sto),
|
.read(rd),
|
.read(rd),
|
.write(wr),
|
.write(wr),
|
.ack_in(ack),
|
.ack_in(ack),
|
.din(txr),
|
.din(txr),
|
.cmd_ack(done),
|
.cmd_ack(done),
|
.ack_out(irxack),
|
.ack_out(irxack),
|
.dout(rxr),
|
.dout(rxr),
|
.i2c_busy(i2c_busy),
|
.i2c_busy(i2c_busy),
|
.scl_i(scl_pad_i),
|
.scl_i(scl_pad_i),
|
.scl_o(scl_pad_o),
|
.scl_o(scl_pad_o),
|
.scl_oen(scl_padoen_o),
|
.scl_oen(scl_padoen_o),
|
.sda_i(sda_pad_i),
|
.sda_i(sda_pad_i),
|
.sda_o(sda_pad_o),
|
.sda_o(sda_pad_o),
|
.sda_oen(sda_padoen_o)
|
.sda_oen(sda_padoen_o)
|
);
|
);
|
|
|
|
|
// status register block + interrupt request signal
|
// status register block + interrupt request signal
|
always@(posedge wb_clk_i or negedge rst_i)
|
always@(posedge wb_clk_i or negedge rst_i)
|
if (!rst_i)
|
if (!rst_i)
|
begin
|
begin
|
rxack <= #1 1'b0;
|
rxack <= #1 1'b0;
|
tip <= #1 1'b0;
|
tip <= #1 1'b0;
|
irq_flag <= #1 1'b0;
|
irq_flag <= #1 1'b0;
|
end
|
end
|
else if (wb_rst_i)
|
else if (wb_rst_i)
|
begin
|
begin
|
rxack <= #1 1'b0;
|
rxack <= #1 1'b0;
|
tip <= #1 1'b0;
|
tip <= #1 1'b0;
|
irq_flag <= #1 1'b0;
|
irq_flag <= #1 1'b0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
rxack <= #1 irxack;
|
rxack <= #1 irxack;
|
tip <= #1 (rd || wr);
|
tip <= #1 (rd || wr);
|
irq_flag <= #1 (done || irq_flag) && !iack; // interrupt request flag is always generated
|
irq_flag <= #1 (done || irq_flag) && !iack; // interrupt request flag is always generated
|
end
|
end
|
|
|
// generate interrupt request signals
|
// generate interrupt request signals
|
always@(posedge wb_clk_i or negedge rst_i)
|
always@(posedge wb_clk_i or negedge rst_i)
|
if (!rst_i)
|
if (!rst_i)
|
wb_inta_o <= #1 1'b0;
|
wb_inta_o <= #1 1'b0;
|
else if (wb_rst_i)
|
else if (wb_rst_i)
|
wb_inta_o <= #1 1'b0;
|
wb_inta_o <= #1 1'b0;
|
else
|
else
|
wb_inta_o <= #1 irq_flag && ctr[6]; // interrupt signal is only generated when IEN (interrupt enable bit is set)
|
wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)
|
|
|
// assign status register bits
|
// assign status register bits
|
assign sr[7] = rxack;
|
assign sr[7] = rxack;
|
assign sr[6] = i2c_busy;
|
assign sr[6] = i2c_busy;
|
assign sr[5:2] = 4'h0; // reserved
|
assign sr[5:2] = 4'h0; // reserved
|
assign sr[1] = tip;
|
assign sr[1] = tip;
|
assign sr[0] = irq_flag;
|
assign sr[0] = irq_flag;
|
|
|
endmodule
|
endmodule
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|