|
找到一个I2C Slave的代码,可惜Verlog看不懂,发上来给大家参考
* J: W# V3 \; O% P+ n2 E# L' o, Q! p8 V* M8 u
///////////////////////////////////////////////////////////////////////////////
5 h, Z- N6 f" @, j& _7 K% T c& n//
" l6 T3 Z4 V. Q+ e2 Q// Alacron Inc. - Confidential: All Rights Reserved
: `( B. O9 D$ `) |% U/ v: A7 }+ n// Copyright (C) 2003
! G" y+ T# Y8 @! g//
+ a( J0 G2 x- N// Title : I2C Slave Control Logic
9 ? }3 {6 b4 ]// File : I2CSLAVE.v# ~( e" i& F; e/ |2 H. W
// Author : Gabor Szakacs
$ E5 t; j1 m' F( a6 f. ], _// Created : 25-May-2004 - Adapted from I2CSLAVE.abl
1 H; C1 n6 S0 `, c/ t) Q+ t8 c//
5 @( j! l! s# s+ A6 T% W; [//
5 j) Q" j* Z/ w, ~///////////////////////////////////////////////////////////////////////////////5 M, A% y/ p- h' P& ~9 u& n# T# K& v
//
, r2 N- m' e8 U- g// Description :
) n2 H2 M; D# p' ^// This code implements an I2C slave-only controller./ Y! [% s5 Y6 r4 ^# e1 \9 {, O
// Access to internal registers uses the sub-address
7 L* u; W. |& O1 z( R// protocol like a serial EEPROM. No registers are
: w6 A; {3 |2 M7 \7 o7 m4 ]7 U( C// implemented in this module, however the module
3 W5 Z P9 R- i- Q% r7 T% w7 K// provides a simple bus interface to external registers.
1 k. N& c0 A4 \2 S1 z6 A" }// GLS - 12/13/00" y' v% z2 i7 M
// I2C inputs are oversampled by clk_in, which should run
4 a3 ]' {/ ?- [; P& e( q* ]9 V' Z// at a minimum of 5 MHz for a 100 KHz I2C bus. The3 z/ h* i- g' g9 V
// debouncing on the inputs has been tested at up to 80 MHz.
1 S; ]6 v5 s9 O7 D// The I2C 7-bit device address is set by i2c_address. Address' Q. G! t$ f% Q8 ?$ Q4 W) c8 k
// 0x6A was selected for FastImage because it doesn't
0 N. C; P% v: y0 W" T* p( B' ]/ A// conflict with other devices on board.
v. X/ q+ O! `0 `2 \( O6 J( L// Because of limitations in Xilinx Abel, the I/O buffers
" y3 b2 v [2 _. v) ~) v// for the I2C SDA and SCL signals were external to this
- i+ w. q$ O/ Q/ A k// macro.
0 ?* d1 n1 O" e. t7 ?: q// Three 8-bit buses are implemented for read data, write/ l% Z9 W2 b" O7 J# n
// data and subaddress. For a simple implementation where
: Y+ C" ]: l1 \2 l/ o$ V' Q// only one 8-bit register is required, the subaddress may
Z0 T7 J4 e) `) \. ]4 k- d8 _// be used as the register output using simple write and
' Z& r2 Y/ T. i6 l7 g2 X1 }// read protocol on the I2C bus. In this case looping the
6 N3 B9 f- D+ o1 q$ H// subaddress output to the read data bus allows register
2 |& P% A0 d4 C0 D0 A7 B// read-back.; H7 @1 @. R- g
// For use with multiple internal registers, the subaddress9 k- E/ P1 e+ X0 x
// provides the register address. The rd_wr_out output indicates2 d0 N* W- X# v" |* S! x% M
// the direction of the current I2C bus transaction and may0 C( ~! S* ~2 ~7 o" w, Y4 X/ k! J
// be used to enable read data onto an externally combined
; \& j( k7 V8 ^) D6 C// read/write data bus. The wr_pulse_out signal can be used as. }- \" H3 ] B/ n- B, |) b; a
// an active-high latch enable or clock enable for the
% p! o% d) t( j+ V$ ?// external registers. It comes on for one period of clk_in1 J! F/ j$ Q( J& L& Z
// and the subaddress and data are valid for at least one* T O' S, H$ O/ j0 H2 B0 j1 ^
// clk_in period before and after wr_pulse_out., ^9 X6 w+ x6 T, c' t
// A rd_pulse_out output goes high for one clk_in period at the
1 a8 P3 q9 n, D( ~; J) G// beginning of each data byte read. This indicates the
( I5 x/ C; b: _: T8 Q& o& N: r// time when external data is latched from the read data- N! }4 Q/ {) P. |
// bus. It may be used to create side-effects on read
2 m2 \; W2 J4 {/ s// such as clearing sticky status bits.
7 s* }: I: o) E ]//+ L! z* i8 c) ^5 G: n1 d
///////////////////////////////////////////////////////////////////////////////
% w0 `7 R8 ~: k [//
% {" r! m. D1 A9 | q) {// Modules Instantiated: none2 H2 Y# ?: E, @0 Y3 M6 {5 O2 o
/// c1 N! M% P/ L2 a6 I
///////////////////////////////////////////////////////////////////////////////
: V" f+ ?% ]5 e& r( C$ R/ [; f, ~//
+ T; p1 _' x+ I& ?3 J' ]// Modification History:
6 u: l4 c6 z1 X- f) X//' g' x) ^4 L, L1 l* l# m! ]( p
// Added clock enable to slow down state logic with fast input clock
8 s1 x; D2 I) K// 6/9/05 - GLS.
1 u* D3 R/ W1 G//
3 v7 ?6 n6 A* ?7 a6 p// l% B4 a1 c N+ g
///////////////////////////////////////////////////////////////////////////////
! [+ U. d( r% v$ E" ?1 P# k///////////////////////////////////////////////////////////////////////////////5 {/ o2 }" j4 a9 C( G0 ^% E0 v7 |
///////////////////////////////////////////////////////////////////////////////5 z$ x, l9 Y4 m4 _) k) K
`timescale 1 ns / 100 ps2 J1 v" ?: P0 s% x/ N
module I2Cslave
) \) ]& D+ v2 l5 T$ `) |(8 ^- L, M1 _9 @) m
sda_io,: |- R' j! x6 j5 J" E7 F! U8 K7 t
scl_in,( h7 i( K) J a, E6 h6 n
rd_bus_7_0_in,
. y$ D3 x+ f( O clk_in,% E) j$ f9 \: y" ?7 D( C
clr_in,
8 y) p% P$ z: I4 H @6 \" x4 V subaddr_7_0_out,
% D& M7 e' h4 } wr_bus_7_0_out,
) A- b5 Z* r9 J8 J ]# r wr_pulse_out,
6 h, o+ h: y/ o/ T! j rd_pulse_out,
; O( t# N7 x7 z# p; l6 f rd_wr_out
* k; P* |( v- }. S+ A);8 G1 j% ]- w7 t i! ?# T
// Inputs:7 k9 d9 R; i. c8 `# _2 R% o
// I2C inputs (SDA is I/O externally)3 M- w1 O: R: B
inout sda_io;2 f" J1 j8 }; @, x
input scl_in;$ c# ]5 L. j: ^* h7 x6 e
// 8-bit bus for reading registers- w" B+ o5 J+ a6 a& b! ?0 [$ }. t
input [7:0] rd_bus_7_0_in;
! u' d* F; Q5 ^) y$ Y// High-speed clock for state machine logic o2 L2 {7 l: X+ _2 x
input clk_in;6 Q* \! T s9 e7 g
// Asynchronous reset can be grounded for synthesis
1 R% v( Z. F7 \( {& |1 H" X1 Binput clr_in;5 u5 P8 I+ F' G
// Outputs:
, K2 ?7 A3 |" S3 l9 {( O- l6 T7 T// 8-bit subaddress for register selection
H" u/ L `& i7 E9 Loutput [7:0] subaddr_7_0_out;6 N3 @$ e# s8 r# |3 |$ x; {5 ?
reg [7:0] subaddr_7_0_out;% B& U5 \ ?! i, M: F& I ]* a! g
// 8-bit bus for writing registers
3 V$ S' H: A, aoutput [7:0] wr_bus_7_0_out;
& m c$ [' q- _. \& b! @( `- lreg [7:0] wr_bus_7_0_out;+ e9 Y* e, s# o( E- `0 A' Y
// I2C data output drive low signal (1 = drive SDA low)2 W& q. ?+ b# h* ]1 _# d( U7 x
reg drive_sda;( S- @: u; b6 W: u
// Register write pulse. On for one clk_in cycle.3 m: i% D h8 E9 }
output wr_pulse_out;6 a) |& L( n2 D0 \* V8 z. j
reg wr_pulse_out; L. `$ ]+ ~# C7 T' Q% m- f
// Register read pulse. On for one clk_in cycle.
( P! ] p- Z$ j" E# Eoutput rd_pulse_out;- b' q- N7 s6 v" X
reg rd_pulse_out;
. @9 B; h' a' d. x/ w// Read / not Write. For external bus drivers if necessary.
2 F3 T1 v) }& P a. r6 ]2 n; O3 goutput rd_wr_out;$ y% d* b; s8 i4 Y+ S; Y
reg rd_wr_out;: y) k, H, z. @) {
// Internal Nodes:6 B, X' m8 ~. j [
// I2C input debounced nodes:; r8 g# w8 h9 t9 k# @% j+ m
reg [3:0] sda_sr, scl_sr;" I2 p0 Y4 J5 e5 o2 L# D: b
reg sda, scl;
8 a/ E( k7 C5 L// I2C edge detection nodes:
* O8 h5 Z0 l* m: u9 {2 Dreg was_sda, was_scl;( A2 u0 z4 }: M% v1 F5 {, Q7 T% V
// Delayed pulses for address increment:& m: V4 F, {9 [7 y8 c2 h
reg rd_pls_dly, wr_pls_dly;
4 U2 B2 h' m+ r' Q s* M// I2C protocol state nodes:
1 r. ?2 n6 t: ]9 \4 mreg i2c_start, i2c_stop;: u. r& D; n; s% E* b
reg [2:0] byte_count;
" _" l* N6 W9 @reg ack_cyc;6 J+ o( r! R; j
reg addr_byte, addr_ack, subad_byte, subad_ack, data_byte;+ N. x0 S% D: U3 t
// Edge detection:
) j7 z2 F9 F; C9 i: n8 r5 Y7 n/ Sreg was_ack;$ S9 l6 L$ V/ L9 d
reg my_cyc;
7 j9 h( O1 n: u6 T1 t G/ w// Input data shift register7 ` u% W+ q! M3 R1 Q3 z# f, S" A
reg [7:0] in_sr;
" w/ n9 g& {+ [7 o// Output data shift register
+ E1 E* V8 ]4 p# W1 ?+ l+ breg [7:0] out_sr;
( k1 a- d* v, ]% _// internal node for bidirectional SDA line:7 w1 C. [" [! e$ q
wire sda_in;
; H* ?2 N+ m3 q0 E- j! OIBUF sda_ibuf (.I (sda_io), .O (sda_in));
) O( Z$ T2 E+ u0 \0 k) KOBUFE sda_obuf (.I (1'b0), .E (drive_sda), .O (sda_io));) l1 f) ]. q5 O' r6 D5 _. X
parameter i2c_address = 7'b0110101; // 6A write, 6B read
* E- k: v/ T7 ^) d1 g5 S6 J$ Y* s9 m
// Equations# G# n1 ?* Z, q# L. I! N- G
// Debounce, then delay debounced signals for edge detection7 r1 ]1 |7 N- l3 U* U
always @ (posedge clk_in or posedge clr_in)
0 h( }. q; u6 v( T if (clr_in)1 `& A: s1 Y; M, Z' B
begin
0 Y' o5 p4 W% h: R; c4 w sda_sr <= 4'b1111; // Start up assuming quiescent state of inputs
( B: @& [8 S- q8 ] sda <= 1; ]3 \1 X1 }& y( b9 T! S0 B Z
was_sda <= 0;/ i0 a1 {/ M9 c% S3 ~! F
scl_sr <= 4'b1111; // Start up assuming quiescent state of inputs& H y; S5 z# x4 |2 o5 i
scl <= 1;
" A {6 O) M% S1 t4 D9 {6 U was_scl <= 0;
# Q. a! W" }+ s1 q) P end
" B, M/ e' y G& r9 `! l" | else
' A& p: F. Z0 E% {. |+ H begin
0 \$ h0 d# s+ I* ] sda_sr <= {sda_sr[2:0], sda_in};
$ @" i- j/ x- p! x4 f# f: n if (sda_sr == 4'b0000) sda <= 0;
$ Y9 @3 a2 o: u; Y1 } Y else if (sda_sr == 4'b1111) sda <= 1;
3 ~# O y5 d L$ _5 E' g& X' k was_sda <= sda;
- ]. {! ^* z0 a) }* S scl_sr <= {scl_sr[2:0], scl_in}; t# V! |: @1 z" g
if (scl_sr == 4'b0000) scl <= 0;
3 f; z2 J( q( ?6 j/ R; X3 O else if (scl_sr == 4'b1111) scl <= 1;% P& q9 |5 H3 i& ]) i3 A" J( Y
was_scl <= scl;
2 ~4 _2 u& E, V, r% t. t' I end
3 t9 P5 M4 v4 C' D% E3 h// Detect start and stop conditions on I2C bus:2 h5 e5 t A) ]0 k
always @ (posedge clk_in or posedge clr_in)
, n2 x: X' E( F, o, j if (clr_in)
' B1 U# N; c7 P8 l+ Y: B2 m begin7 D# M8 Q4 T7 j& K, m; o9 v
i2c_start <= 0;
/ ~$ C. _5 q: O i2c_stop <= 0;
( G0 v( @# f9 ?! s+ l end
) Z; v0 W- a1 }# [ else9 H% S( Z8 s8 q2 B. J- u$ g
begin* M1 X: L0 p! @0 H
if (scl & was_scl & !sda & was_sda) i2c_start <= 1; // Falling edge of SDA with SCL high( r ~3 f9 ?7 ]& b* O9 I
else if (!scl & !was_scl) i2c_start <= 0; // Hold until SCL has fallen0 l! |9 c4 J2 s# }4 c2 q. D" H
i2c_stop <= scl & was_scl & sda & !was_sda ; // Rising edge of SDA with SCL high3 n- d% I2 C8 W; Y' p4 n, `+ ^2 o- J
// i2c_stop is only on for one clock cycle
! Y' V! o- N y end* y) g/ M! p$ T+ A) `2 S7 Q
// Increment bit counter on falling edges of the! ?6 E6 K( \% q3 Y: R, A
// SCL signal after the first in a packet.
, G! K+ n: M: D! z3 o( e+ }// Count bit position within bytes:; B+ ~/ a" U3 a8 ^4 Q8 C6 g
always @ (posedge clk_in or posedge i2c_start)
L+ d5 ?: h3 Q- e, P3 H if (i2c_start)- x4 t- r; ?$ F0 d% @' }2 V
begin
7 g( ? ~; f" g4 S: x ack_cyc <= 0;
|9 ]# a) g: s }: e byte_count <= 0;, V: E% a4 B6 `, m1 A& w
end5 g5 g1 J$ T0 k5 T9 d1 R
else if (!scl & was_scl & !i2c_start)
' x1 [8 f2 x5 C( L5 B6 e begin$ g$ U9 f2 d3 z1 c
// ack_cyc is really bit 3 of byte_count, counting from 0 to 8
, v7 [+ F# s1 M. M {ack_cyc,byte_count} <= ack_cyc ? 0 : {ack_cyc,byte_count} + 1;- E: a! }! u7 Q8 d
end
* O& r( Q- X# l' B0 o) @- ~3 H3 w// For edge detection of ack cycles:+ M! U4 j6 V' D/ A* u
always @ (posedge clk_in or posedge clr_in)
: l7 e, I. o, Z H7 C$ W if (clr_in)
+ K( {. E% R( o; A begin% k x# t, p% `# z
was_ack <= 0;
9 L9 k1 {! ^/ U5 O end& o# n; X/ ~: H$ I! z
else
4 d! a; p% n! F1 R+ z begin
( v1 S6 t, n% I' W8 m was_ack <= ack_cyc;
7 A1 f) T* _ E V: x# S# `# f end
1 L2 A2 w$ v( [5 r& c# g6 Zalways @ (posedge clk_in or posedge clr_in)) T! l2 x: j+ S
if (clr_in)" [3 H( J0 g( l* |! {8 f4 m- ^2 V
begin; Y6 j) }7 J5 e0 T* }# g$ A0 c
addr_byte <= 0;
8 N5 m* o0 Q# u/ n addr_ack <= 0;
" `! x0 z$ j" X' R; H subad_byte <= 0;
, _/ G; }% d4 e# u' ~6 ?0 M subad_ack <= 0;8 _2 ?; j5 u9 b$ F
wr_pulse_out <= 0;
- B/ L( j1 h$ Y7 `7 A7 V rd_pulse_out <= 0;* h J; n* I! P
end
* ~' S M' k: [# T4 J1 q else
/ C$ k; U% L& R& {$ m4 s S! L begin2 t8 B; f5 o7 K1 Y# `( N+ H" h
// addr_byte is on during the first byte transmitted after" R$ I* q: ^' y+ x) \4 j: g& Z
// a START condition.4 R: M% G* c8 a/ b
if (i2c_start) addr_byte <= 1;
: O( _4 g! B* [& E) a2 d else if (ack_cyc) addr_byte <= 0;
6 I+ ^& C$ z0 s# k3 W // addr_ack is on during acknowledge cycle of the address, \& n* V8 w9 O( z% e, f
// byte.. g0 x7 r+ ~( R+ }' f5 r% G
if (addr_byte & ack_cyc) addr_ack <= 1;2 y! | q; q! R) _, Y$ W5 \
else if (!ack_cyc) addr_ack <= 0;
. \9 _( M0 B- n2 c' `5 |- Z8 u // subad_byte is on for the second byte of my write cycle.
) D8 p5 A0 t; e4 n: h if (addr_ack & !ack_cyc & !rd_wr_out & my_cyc) subad_byte <= 1;
8 M* @4 h( ^! \$ {0 Z8 K/ `: y else if (ack_cyc) subad_byte <= 0; l( w, a9 }9 g4 U& n, w
// subad_ack is on during the acknowledge cycle of the
2 T$ @( M& a* q* Q2 e" R: u' E% i% m // subaddress byte.
& \+ ~) l+ a3 \: @4 E5 D! { if (subad_byte & ack_cyc) subad_ack <= 1;# z9 O5 [+ E' F) {
else if (!ack_cyc) subad_ack <= 0;& Q3 i) C, A6 g; D; n
// data_byte is on for my read or write data cycles. This is0 h. C) |" U( V' H
// any read cycle after the address, or write cycles after
1 S& w0 Y( S/ Y8 p [; @7 R // the subaddress. It remains on until the I2C STOP event or/ p% T5 r0 l4 M4 D5 i2 f
// any NACK.
9 l2 E' `& B2 o* a6 c* V if (addr_ack & !ack_cyc & rd_wr_out & my_cyc | subad_ack & !ack_cyc) data_byte <= 1;
7 k- H7 Z6 q# ?+ d; p else if (i2c_stop | ack_cyc & scl & sda) data_byte <= 0;
# f) g Z4 R6 e // wr_pulse_out is on for one clock cycle while the data# V) }' a) j3 j0 ^9 x8 O0 a8 D) h. L* j
// on the output bus is valid.0 E+ |& C+ @! M8 R" o; N/ l8 {+ N) Z
wr_pulse_out <= data_byte & !ack_cyc & was_ack & !rd_wr_out;
) P; G2 V1 m) d s6 V7 | // rd_pulse_out is on for one clock cycle when external
; c7 e+ x' K, |) R // read data is transfered into the output shift register
, Q& U0 R; u- b* A! X% Q // for transmission to the I2C bus.' ~+ y K7 w6 K/ [& o. V/ K
rd_pulse_out <= addr_ack & !ack_cyc & rd_wr_out & my_cyc // First read cycle2 f# {2 C# T, c& U! n' k, }
| data_byte & !ack_cyc & was_ack & rd_wr_out ; // Subsequent read cycles2 B0 `" s" b8 d% ^3 e6 q+ N
end
2 @6 q+ x& X& X6 f// wr_bus_7_0_out is loaded from the I2C input S/R at the; Z. V( O: K' g. B& z" b
// end of each write data cycle.
' |+ D% U8 I3 m$ B7 ualways @ (posedge clk_in or posedge clr_in)
N9 m! x$ V) q if (clr_in)
& [/ I7 c: ^2 e# b% Y; F+ G9 q s begin
- N% r4 q5 @7 J9 Y wr_bus_7_0_out <= 0;
+ I/ V1 \ [4 T end
2 Z# A+ b/ ?. _, l else if (data_byte & ack_cyc & !was_ack & !rd_wr_out)' {, G( D7 v* x! |
begin8 Z0 r1 L4 u9 {5 E
wr_bus_7_0_out <= in_sr;
; p4 i" I; m6 n- A7 }( K) ^* x end
2 w N) |8 J7 v# x' f# a// out_sr shifts data out to the I2C bus during read
) \4 s' i! f: d9 Q4 S// data cycles. Transitions occur after the falling" `0 W0 N1 S2 T5 ]7 r
// edge of SCL. Fills with 1's from right.9 R2 x( B3 q/ U; k% @
always @ (posedge clk_in or posedge clr_in)5 u& K' b! _. j( I& g: I
if (clr_in)
! V" W. M# x5 Y! G) m begin
; {3 \- |' W% Y# m' j out_sr <= 8'b11111111;. [% y( {2 Z6 S. F+ k
end
4 r/ J8 s4 ]0 c% |( m* C else9 M8 G1 X" s! a& `: H% v
begin
]# w. Q3 c2 e+ S9 U2 ` if (rd_pulse_out) out_sr <= rd_bus_7_0_in;7 I# s' Z0 T4 I& h/ Y# Z! j
else if (!scl & was_scl) out_sr <= {out_sr[6:0],1'b1};
8 o5 U% F8 o4 a; h0 y" K) C4 M7 I end
7 f5 @( F: s8 r) d, B// Delayed pulses for incrementing subaddress:9 W, Q2 s$ Y! V2 C3 i! n7 d
always @ (posedge clk_in or posedge clr_in)' b: k* N4 S3 X0 f
if (clr_in)' L( ~, ^( S; r1 _/ P0 N
begin
0 x+ j: @' `/ R9 H wr_pls_dly <= 0;5 z5 O2 y5 x' F4 Y" @% z6 a" w P
rd_pls_dly <= 0;4 @, n# j: u" W* R+ B; N
end9 v T; R4 e) t1 l
else
( K7 J) U: D; d0 d n begin0 k6 M+ ]' Q3 F. l/ K8 F
wr_pls_dly <= wr_pulse_out;8 K3 o( n. N6 B8 \) H
rd_pls_dly <= rd_pulse_out;
! D* ^ ?& r; k3 s, H% v end
4 h. p9 j' ?1 _2 P3 W// subaddr_7_0_out is loaded after the second byte of a write
2 e8 }+ V$ P6 M// cycle has fully shifted in. It increments after each- {8 S! b1 o+ z# N% a) B, W
// read or write access.3 _1 i+ j t5 z7 A9 E
always @ (posedge clk_in or posedge clr_in)+ x h Z3 I V- q z
if (clr_in)
0 i6 o( f! C1 Y* Z) ^, @+ ^ begin
) H6 v1 R1 ~3 U: G* ]( v' p# Z' h subaddr_7_0_out <= 0;+ `0 z" A* a6 I
end
r% V$ v* `" P; ^4 p0 }: p P else/ @2 }8 \) p! z* u/ y
begin* k& G' d9 p: b# T# ?' v! O: c
if (subad_byte & ack_cyc) subaddr_7_0_out <= in_sr;
]! ?. i0 W- n9 i // Leave Out this else clause for simple single register version
9 t' k' @6 t; K1 t. P1 f( \- i // In this case subaddr_7_0_out becomes the register output and should be' H( [- c3 w. ]
// wrapped back to rd_bus_7_0_in externally- S) b5 f2 z" Q9 a" U4 R
else if (wr_pls_dly | rd_pls_dly) subaddr_7_0_out <= subaddr_7_0_out + 1;
9 w% P# R- @$ p3 n @0 m" X3 k6 k end7 c. Z- J0 n' x- p6 `$ N
// Shift I2C data in after rising edge of SCL.
0 `2 Q2 |' I0 d0 Kalways @ (posedge clk_in or posedge clr_in)' ^) D8 N% {7 L+ d2 x
if (clr_in)
3 J! V! W& p" z begin# b" G) I* r# w" W# P3 F5 _5 e# H% k
in_sr <= 0;
9 ^; x, D2 N( l% ? S end
: G7 c0 \; W8 h else if (scl & !was_scl)- q5 W2 q$ n* _- _) G4 B' S: B; F
begin' j) n+ H. D; ]& Y! A) _
in_sr <= {in_sr[6:0],sda};
* @% N! D3 o& L( l% y; U. R9 V end
5 r2 U# x( Y# P* P; x// Read / not Write. For external bus drivers if necessary.
7 `# w4 G# _! n$ X0 T// Latch the Read bit of the address cycle.
$ d* J" n) ], B. F2 T @always @ (posedge clk_in or posedge clr_in)
& Y9 [5 s5 w3 m" @8 D if (clr_in): V. M- P/ b% y3 J) J2 c
begin
8 y2 q. B p( ?" Z: X2 c rd_wr_out <= 0;
' ~; h. B$ }' K6 w end- F$ V/ y" x$ G2 O
else if (addr_byte & ack_cyc), o) s* d1 n4 b! k
begin
5 O3 _ D# c; o7 N9 C: q rd_wr_out <= in_sr[0];3 ?8 K6 I! [) m4 T) G* J6 ?; q# M" C2 P
end4 m4 L- }/ H3 o* k
// Decode address. My cycle if address upper 7 bits; a3 V2 t5 R! v9 `
// match with i2c_address defined above.
4 J" ~; c4 e+ x$ P* H5 ualways @ (posedge clk_in or posedge i2c_start)
3 K# {2 w9 D% n if (i2c_start)2 e* L$ l2 _' s! T
begin
4 @& R: k+ [! @ {: R3 _ end
# ]7 w. C& J4 F8 h# M* i' X4 | else if (addr_byte & ack_cyc)
/ l. c& r" k, o begin9 c. R0 q3 R5 c
my_cyc <= (in_sr[7:1] == i2c_address);
" u3 [8 P/ t. r3 R- h end
# c- x5 v1 s4 J4 @" y( T// I2C data output drive low signal (1 = drive SDA low)
8 w8 d, ]- ?+ i0 Y/ y$ m3 d// Invert this signal for T input of OBUFT or IOBUF+ P0 u# p& Q: s! D0 d7 l
// or use it directly for OBUFE.8 C, i. r: T3 V3 a$ I
always @ (posedge clk_in or posedge clr_in)
: w: v Q. e# o/ p if (clr_in)5 t5 @* c6 d1 I5 H$ a
begin
) g( _: t- J6 v7 e/ a9 W drive_sda <= 0;
" \) Q; R# H h1 z' }) Z4 I8 G: G end
" F9 t9 A0 x: `: f% O5 a4 P else5 Q0 i t3 m. F5 n% Z/ F
begin4 e6 c6 c% t' i4 ?+ G/ f4 g# Q( H0 I
drive_sda <= my_cyc & addr_ack // Address acknowledge
$ ]- U9 h2 y5 r3 i | my_cyc & !rd_wr_out & ack_cyc // Write byte acknowledge& {+ \7 D. j: k; h8 L( A- D
| data_byte & rd_wr_out & !ack_cyc & !out_sr[7] ; // Read Data0 ~. `, f6 U0 [2 w! D0 T( a
end
, U; W7 e( f$ l- B' z. mendmodule // I2Cslave |
|