TA的每日心情 | 奋斗 2019-11-21 15:17 |
---|
签到天数: 1 天 [LV.1]初来乍到
|
找到一个I2C Slave的代码,可惜Verlog看不懂,发上来给大家参考! t U) p# _. Q2 l- e, o
& m6 l9 j* D( O4 n) S5 S///////////////////////////////////////////////////////////////////////////////" p: l' Q* i/ O
//4 d; _$ t6 G* b4 @$ P) v* m! [
// Alacron Inc. - Confidential: All Rights Reserved1 j4 C4 p( k$ G2 D* M) r: M
// Copyright (C) 2003( p- T2 c- `) ?! Y
//4 k f8 z) r: t
// Title : I2C Slave Control Logic) o/ P. |9 i8 O |
// File : I2CSLAVE.v' S/ U5 B( o! u& v3 a. X- ^( U
// Author : Gabor Szakacs
8 M, v* F) x6 u8 j2 f1 q3 I// Created : 25-May-2004 - Adapted from I2CSLAVE.abl
" a4 ~) d) [6 L8 v6 J//
0 N& j4 u' y3 Z" V/ |! a//7 y* c4 I# `6 ]: b' }9 a
///////////////////////////////////////////////////////////////////////////////
0 l4 z: X. U* U! R1 I( S//
4 H1 u6 J, F/ p" v, d# c" E/ x// Description :
! B5 o, p5 _6 J1 ^1 k1 }" U// This code implements an I2C slave-only controller.
; a! E# Z/ h3 c6 u4 B& N7 Q! g// Access to internal registers uses the sub-address
! m/ Q( ~. D( [9 z// protocol like a serial EEPROM. No registers are. {0 w0 y+ |4 @( h: b
// implemented in this module, however the module
* S5 { K3 Z, b3 K Z- ^// provides a simple bus interface to external registers.- x: z( q. J- J1 p) i& l) f5 x
// GLS - 12/13/00: v8 S9 V; P4 C0 n; p k+ u
// I2C inputs are oversampled by clk_in, which should run8 u9 q! x% Q$ l3 ^( V" w. a
// at a minimum of 5 MHz for a 100 KHz I2C bus. The% J/ R! u# s2 O, e4 \0 i
// debouncing on the inputs has been tested at up to 80 MHz.5 ^- R: S* A0 ^# W- l
// The I2C 7-bit device address is set by i2c_address. Address
3 T" J3 Q- O4 Y5 ?// 0x6A was selected for FastImage because it doesn't$ x, Q7 K" c% T3 m; O9 X
// conflict with other devices on board.
0 F2 g: E' C/ q6 j6 G, Z, x( l// Because of limitations in Xilinx Abel, the I/O buffers0 V5 d& v% T5 [ r, J e" n6 Y; y
// for the I2C SDA and SCL signals were external to this6 |% w0 M4 z: F, `% E8 k
// macro.
: a7 o) i, [$ e9 n// Three 8-bit buses are implemented for read data, write7 o0 o7 u+ R- B( x e( ^; \
// data and subaddress. For a simple implementation where* S" ^$ r1 `/ W8 T
// only one 8-bit register is required, the subaddress may
* y, s, j% U# r" R// be used as the register output using simple write and
, C/ {9 R* |2 G! m b. N' F$ w3 {// read protocol on the I2C bus. In this case looping the! `# M# a+ `$ N
// subaddress output to the read data bus allows register b* L8 w; T+ q3 H$ m/ v7 S2 q
// read-back.
: M5 i) S- d2 D8 w: k// For use with multiple internal registers, the subaddress
2 I4 U5 _$ h u" b- d: g( ^( A// provides the register address. The rd_wr_out output indicates
# x. M8 d' m7 _3 A( z// the direction of the current I2C bus transaction and may
) Q5 u0 X: ]' a$ ^6 K {' U// be used to enable read data onto an externally combined
* E' ~: ^5 @: b% ] ^1 U! I% ]// read/write data bus. The wr_pulse_out signal can be used as
6 j. I& f! d( t! Z2 k// an active-high latch enable or clock enable for the' M- y% X; r0 }7 Y
// external registers. It comes on for one period of clk_in4 i, Y) q* [7 s5 F4 {4 V
// and the subaddress and data are valid for at least one M+ e. F2 y" Q/ v1 s9 b
// clk_in period before and after wr_pulse_out.$ l) p; p6 g4 y( ]% q3 @5 T
// A rd_pulse_out output goes high for one clk_in period at the
4 ^& i% ?+ ]9 Y8 F# e; N// beginning of each data byte read. This indicates the
8 r% d6 X7 E8 E0 j2 A9 {7 B8 Q+ X// time when external data is latched from the read data
, C7 B/ E" e! m1 \% \+ P// bus. It may be used to create side-effects on read
0 C+ ]5 Z- r8 j// such as clearing sticky status bits.
! f/ ?4 p) O6 } e, V5 `//
; A; @: G3 G% S1 k* n# c///////////////////////////////////////////////////////////////////////////////
0 K: c9 O. K( R) D7 ^* M//
% I/ I/ O" v: j: V- Z& G& G5 J. ]' ^// Modules Instantiated: none6 t8 X& J* C5 J5 E: R
//7 |9 Q- Q M9 Z% X' ?2 M
///////////////////////////////////////////////////////////////////////////////
+ W$ v* o" P- ]; g* ~4 S//( x) _1 x5 f$ a# }7 O+ c6 b( u
// Modification History:
' I" @% ?: I9 E5 d- Q2 p" f) h- J//
8 h; f% l$ u) r- c3 c/ Q// Added clock enable to slow down state logic with fast input clock
" F3 e+ f% R! N' ]6 w+ O' M// 6/9/05 - GLS.
2 o( a1 b U4 _. I. a//3 H. w/ M2 A- F' {2 A& v( u
//
) ]4 J6 W4 X- m4 t% D: t. u; V///////////////////////////////////////////////////////////////////////////////$ @, q/ ]$ p# R% H$ Q1 _
///////////////////////////////////////////////////////////////////////////////
7 y$ n- J) z! e2 |+ n1 ^; F///////////////////////////////////////////////////////////////////////////////* D% S. }1 d$ n
`timescale 1 ns / 100 ps
, G* |4 O/ H! G9 X1 imodule I2Cslave
0 _5 K4 D' |1 F% Q9 j- I(: y& a/ Y: d/ e0 P5 t% L( m
sda_io,
) K% T4 S1 ?0 T scl_in,1 R$ O: x9 p7 Y% j$ K
rd_bus_7_0_in,% u" y- T3 f/ ~
clk_in, A1 T1 [# J5 |0 I' L
clr_in,
& O( ~- E) J; f subaddr_7_0_out,
0 h Y( q' n, y) P& y wr_bus_7_0_out,
+ l2 @: J; K% T6 i6 |$ B, u. v wr_pulse_out,5 I! O! F, G0 }
rd_pulse_out,
0 }$ m" ?) y1 T/ q0 H rd_wr_out7 R6 U7 @* O( w# o' ^
);; V% v: g: J- J- }; ?/ Y
// Inputs:
; O1 @* _% g& @+ e" }# R. {// I2C inputs (SDA is I/O externally)$ S* D6 L0 s$ o. d5 g7 H- Z) j
inout sda_io;0 s# x4 U! m( i Y0 X; M! E( |3 i- P
input scl_in;* V# r$ T, w. [& X% x1 X
// 8-bit bus for reading registers
4 s L U% g1 T( n: ninput [7:0] rd_bus_7_0_in;5 r, e _4 W3 o7 ?9 D# j6 R
// High-speed clock for state machine logic
. n& W9 {5 P1 h+ Finput clk_in;2 y& x* W' O9 R
// Asynchronous reset can be grounded for synthesis2 B$ K$ f- i6 c [6 r1 H
input clr_in;7 u. s( W% o6 y. P. y0 ^% Z7 z* I( H$ M
// Outputs:) z/ D, E; H* b- W
// 8-bit subaddress for register selection0 y( P4 y7 Y( t0 j& h' h
output [7:0] subaddr_7_0_out;8 t( P2 g+ [2 I$ R
reg [7:0] subaddr_7_0_out;- @/ }. [! f; M/ G; _
// 8-bit bus for writing registers
/ s' y4 V6 H! `8 E# G7 eoutput [7:0] wr_bus_7_0_out;$ A2 T6 N( g- }2 f1 t) V! e6 K
reg [7:0] wr_bus_7_0_out;% S" ~! J& Z* q# J
// I2C data output drive low signal (1 = drive SDA low)8 ~. N I7 F H. X8 @
reg drive_sda;
% W- ]" X# Q7 ?& x* `5 U3 m// Register write pulse. On for one clk_in cycle.9 E5 X- U0 I- J; c* u) ]+ q
output wr_pulse_out;2 j1 k" U( o2 E/ u p
reg wr_pulse_out;) Q% s) b& R: p+ m
// Register read pulse. On for one clk_in cycle.! J9 j& x" a- A! ~$ @, i2 U; W6 z% B
output rd_pulse_out;- n/ a8 i6 S, Q4 l9 g' W+ p) o
reg rd_pulse_out;
: z7 K+ F3 f5 q4 C7 ?* Q// Read / not Write. For external bus drivers if necessary.2 l h( \2 d) D2 q: h2 U- T
output rd_wr_out;. O1 {$ ]. D0 x6 ~
reg rd_wr_out;6 M- w+ A2 q' i0 X; m% `: h
// Internal Nodes:3 M3 @* K+ g% ~+ ?% S; s) J6 ~
// I2C input debounced nodes:
& k8 d) {9 ]8 s% B" K0 p+ C. Dreg [3:0] sda_sr, scl_sr;
4 }& e% ^, L0 ], f6 K4 O8 sreg sda, scl;& f7 C8 B" ^6 e3 d9 r- _/ a/ ^
// I2C edge detection nodes:
& e7 Y6 e$ q! O6 ureg was_sda, was_scl;7 G. L; C8 ^) _
// Delayed pulses for address increment:
) f: m) t! ?) B) }reg rd_pls_dly, wr_pls_dly;9 w0 B+ A$ v5 S: e r( t7 Z
// I2C protocol state nodes:
+ f! p$ x/ o. {! v/ ]' y' \2 xreg i2c_start, i2c_stop;& _8 P) D! P& q& l* F
reg [2:0] byte_count;( ?! U* }1 {; x, R" K0 a( @3 j! V
reg ack_cyc;8 V5 n) n( ^. U* i
reg addr_byte, addr_ack, subad_byte, subad_ack, data_byte;
/ @, u4 E3 Y; M; ~// Edge detection:. M7 t6 {1 s: ^
reg was_ack;
7 j* H& ]' {( G6 r oreg my_cyc;
/ W c+ v: L. s; l4 b3 F4 h// Input data shift register3 K$ W0 W! D' _5 i7 g" I) w% ^
reg [7:0] in_sr;5 y6 O$ m" I5 l' M, L: V2 z; Z1 o
// Output data shift register4 r3 `: o9 |! ~* Z4 n% O+ t" z4 B
reg [7:0] out_sr;) L9 @. H* a5 \% F# o3 n7 H5 M; G
// internal node for bidirectional SDA line:
. \, a8 @; Q9 ]% q& X, d2 twire sda_in;
C# z* Y! P6 G) Z% j& w, Y8 BIBUF sda_ibuf (.I (sda_io), .O (sda_in));/ Z3 z, R0 p2 W
OBUFE sda_obuf (.I (1'b0), .E (drive_sda), .O (sda_io));
" c2 k& x% P. ^) D7 ?0 M' ]parameter i2c_address = 7'b0110101; // 6A write, 6B read' l6 d9 \2 A) q
! C7 k3 l- @# [- A( T5 i9 Y0 p' m, y
// Equations
' ]9 Q+ t8 e% G// Debounce, then delay debounced signals for edge detection1 h4 t+ h; F/ l& ]
always @ (posedge clk_in or posedge clr_in)% K1 r! u i7 {6 u1 K W
if (clr_in)* R5 m$ p0 t* U+ e! J
begin
4 v" F6 P9 P6 c4 I0 V" ` sda_sr <= 4'b1111; // Start up assuming quiescent state of inputs
! a- K# P1 g: ?* f- G: f sda <= 1;" m( d% f6 A9 T$ i- Y" g4 B: e* G9 f6 k
was_sda <= 0;
( u, k) b' d, M+ \$ u @ scl_sr <= 4'b1111; // Start up assuming quiescent state of inputs
. h, W; K/ @ h. T scl <= 1;
( y2 j% m" e, W; S9 J was_scl <= 0;
' v7 e V" }7 x! \8 T end$ x( d: x& T# D- X
else
; c% o% u, e* `. Z begin
! ~- ?1 _" R. ]; ?9 U9 { sda_sr <= {sda_sr[2:0], sda_in};
4 L6 t$ ~2 Y; ^3 Y: A8 T; E if (sda_sr == 4'b0000) sda <= 0;! ~, s* I# ~/ T6 r: m) K$ {
else if (sda_sr == 4'b1111) sda <= 1;
! l0 q4 T+ b; R- m0 N2 n" b& U% t7 o was_sda <= sda;
0 z u* @' Y; E9 {. m, r# a4 q scl_sr <= {scl_sr[2:0], scl_in};4 D. G4 W/ u T5 z/ {, q
if (scl_sr == 4'b0000) scl <= 0;
. D- {% @: ?- Y8 @ else if (scl_sr == 4'b1111) scl <= 1;
! t! l" s; u0 Q$ E7 d3 z a was_scl <= scl;
3 m# z1 y2 ]2 ]/ e& V end
! L% Y3 g( N1 ^// Detect start and stop conditions on I2C bus:* K' X/ e4 u7 N' ^- i7 R
always @ (posedge clk_in or posedge clr_in) V$ c/ ~7 n+ ^8 \) ~2 U
if (clr_in)
" y2 U5 O' s# a: i begin
8 L9 m7 B( Q9 k2 P4 C% m i2c_start <= 0;) \8 z2 a7 s0 M) x
i2c_stop <= 0;& r/ x9 C4 I* B3 H1 c
end: W8 A* G6 h Z5 D' i9 V
else
* `8 l2 e4 W! { begin
& S) N4 D# V4 }9 T \: C if (scl & was_scl & !sda & was_sda) i2c_start <= 1; // Falling edge of SDA with SCL high
* K& {% `1 R% `4 o8 U& s p! U" T* P1 ~ else if (!scl & !was_scl) i2c_start <= 0; // Hold until SCL has fallen) C8 S* f b: a: X
i2c_stop <= scl & was_scl & sda & !was_sda ; // Rising edge of SDA with SCL high
7 L. K: K8 L, t8 H! j // i2c_stop is only on for one clock cycle
9 L9 r6 V' O5 Q end
! A2 @$ c: m8 [5 n" X// Increment bit counter on falling edges of the! m6 b! ^' s& y9 J7 V
// SCL signal after the first in a packet.
, }- n8 O( |8 B/ {// Count bit position within bytes:
& }+ V4 A' I6 C5 ^+ d7 l' x% Kalways @ (posedge clk_in or posedge i2c_start)
t: J. }2 O* I( e if (i2c_start)
4 i& a% P: D p6 }) H begin' i7 ^8 D' J" M f1 X5 W" f% t
ack_cyc <= 0;
- T4 P/ @4 [7 T& e. L byte_count <= 0;" Z# ~5 d9 Y Y" S" P2 N8 j, } D E
end
/ H4 @8 g4 `+ K$ A else if (!scl & was_scl & !i2c_start)8 E$ f: E5 o I3 c7 b- U# r3 j
begin
9 o( }' W5 d4 G" ^0 {! B( d2 d // ack_cyc is really bit 3 of byte_count, counting from 0 to 8
1 g d9 v3 ?2 j9 I: d9 S+ |6 ^, e8 i {ack_cyc,byte_count} <= ack_cyc ? 0 : {ack_cyc,byte_count} + 1;; J( z; m, K. ~8 J. Y
end; p: k s: s5 d+ p! o& Z, @
// For edge detection of ack cycles:, Q1 F0 K8 B0 B2 ?% H
always @ (posedge clk_in or posedge clr_in) v9 h1 j2 ^: h$ G
if (clr_in)
' {/ X7 N5 h( ]1 Y begin
0 c3 t$ l& y7 k- o3 J' H; g was_ack <= 0;
. k1 r4 a9 x& @% ]. B+ h( U, L e end
# M- b N. H; k( m6 _! J else
. Y) z. \ h- Y begin
4 ~3 c4 n& x( M: b/ } was_ack <= ack_cyc;0 O7 ]! i# K2 C
end
4 i. a2 h9 o5 i$ Y* C" walways @ (posedge clk_in or posedge clr_in)
2 n( v0 \, Y2 V, j if (clr_in)
6 R( k( P5 F! m. F begin
/ }& r5 W+ \, g# k. K" c addr_byte <= 0;
1 ?) T9 \* y+ `: d addr_ack <= 0;( p! f, q7 D0 S* M0 C( L$ j- K
subad_byte <= 0;
, U( F) t6 z) k. t5 b subad_ack <= 0;
% ]; Z2 h# U2 _* e& ] wr_pulse_out <= 0;* g! `6 K* _7 h0 k$ o3 @$ `, B9 X
rd_pulse_out <= 0;
* u, K0 O9 e0 Z7 m end4 x4 x$ X6 x0 N( W3 C" p. U6 J
else
3 r( d/ X: L# s, e# X begin
/ v. N9 m7 r4 M) J% w // addr_byte is on during the first byte transmitted after
/ Z4 M- L4 j v8 P // a START condition.; N5 |1 b6 n0 j! B/ l
if (i2c_start) addr_byte <= 1;" a& @3 g6 h0 \% s; ]$ N
else if (ack_cyc) addr_byte <= 0;0 z( r% z" P }! k
// addr_ack is on during acknowledge cycle of the address
9 F5 q/ D$ Z0 `0 ]; x3 q5 V // byte.
7 ~$ `- A$ A+ W; w, m/ J if (addr_byte & ack_cyc) addr_ack <= 1;( ]6 H. n3 O# ^3 q/ j
else if (!ack_cyc) addr_ack <= 0;. U! ?9 }0 W) o3 R
// subad_byte is on for the second byte of my write cycle.
6 f8 s3 ^4 O e3 e, K2 H if (addr_ack & !ack_cyc & !rd_wr_out & my_cyc) subad_byte <= 1;& O% \3 Q5 C# V$ T3 G1 K7 ^
else if (ack_cyc) subad_byte <= 0;* X. y3 j+ t! b }8 s1 F) X& n
// subad_ack is on during the acknowledge cycle of the
9 X0 p5 [' z' W3 m4 ] // subaddress byte.) |( o+ c: I* J; {: Z; e9 k
if (subad_byte & ack_cyc) subad_ack <= 1;8 _+ C; ]2 ?) T4 @( s e) J: N; P9 u
else if (!ack_cyc) subad_ack <= 0;
: ` c/ z) d8 C; I // data_byte is on for my read or write data cycles. This is
, o" F4 c! p4 [" u // any read cycle after the address, or write cycles after* B* w5 S7 A j2 p2 y! \1 J! P
// the subaddress. It remains on until the I2C STOP event or
+ d! D, L/ H% A // any NACK.
5 B! t; ], D s. w* U1 O; I) X6 X if (addr_ack & !ack_cyc & rd_wr_out & my_cyc | subad_ack & !ack_cyc) data_byte <= 1;
8 R, u9 E5 w) ~0 l else if (i2c_stop | ack_cyc & scl & sda) data_byte <= 0;7 t' s" i4 u! }" ]+ `5 j: Z: H
// wr_pulse_out is on for one clock cycle while the data
7 g/ ^: N- J9 R // on the output bus is valid.
) O2 ^) [" L* p" C: V# b wr_pulse_out <= data_byte & !ack_cyc & was_ack & !rd_wr_out;
5 T6 X5 w$ O8 F: P // rd_pulse_out is on for one clock cycle when external
5 j: N5 O) g- V" N7 @' a, s" q // read data is transfered into the output shift register8 Y) Y! J: h! Y5 a# ]# K' L
// for transmission to the I2C bus.0 b( |' E% i5 l
rd_pulse_out <= addr_ack & !ack_cyc & rd_wr_out & my_cyc // First read cycle5 [8 B. u$ F) `( T/ b. h
| data_byte & !ack_cyc & was_ack & rd_wr_out ; // Subsequent read cycles
6 x# P2 W' j1 z E& \" R end
: K3 ~- g6 \; c( \// wr_bus_7_0_out is loaded from the I2C input S/R at the/ e9 O+ C0 ]9 Z, y3 u N
// end of each write data cycle.9 o7 u, G& b( s$ v# d3 l
always @ (posedge clk_in or posedge clr_in)
' F" Q$ y2 {5 ]5 u if (clr_in)& |+ l( C9 N1 e# p J' K" U! g
begin" F+ v0 C# S6 g# E
wr_bus_7_0_out <= 0;5 z" b- {& ~; C' ^3 z/ {0 g
end
# W! ?. l# H4 F5 F1 | else if (data_byte & ack_cyc & !was_ack & !rd_wr_out)1 L' Y, u: d, n9 M% w/ t
begin
3 H: `; R- Q9 p6 U* p wr_bus_7_0_out <= in_sr;
/ t# ?% N5 ~! V% I9 s! r& `/ O end
6 R6 a" t; `7 x9 U3 T// out_sr shifts data out to the I2C bus during read
) Q9 A. x+ d T1 Y9 i0 N8 [// data cycles. Transitions occur after the falling, V3 t9 V8 B& p- F
// edge of SCL. Fills with 1's from right.# S9 _5 S5 e" H8 G2 _
always @ (posedge clk_in or posedge clr_in)0 K5 C7 Q; o# K) P; n) T+ v
if (clr_in)
3 _6 S" C" f! c* T; b8 { begin/ k9 E9 d4 Y9 R2 K; @0 p2 b9 G- ^" Y
out_sr <= 8'b11111111;. ]/ K% S) r, g6 w) ^
end
8 o) z' o/ N6 ~2 d. m8 l0 j( H else
' N! k6 j" ~3 ^6 Z9 |" n' y* E begin. z# x# p0 p# E( M$ @: ~8 |
if (rd_pulse_out) out_sr <= rd_bus_7_0_in;
; A; n, k! ]5 f' Y% Y! ]+ C else if (!scl & was_scl) out_sr <= {out_sr[6:0],1'b1};# {7 y% s4 k- R+ J4 P
end
* b7 |1 T* o- t// Delayed pulses for incrementing subaddress:" A" _) e$ b0 Y) u/ k2 r7 A" X+ @$ c
always @ (posedge clk_in or posedge clr_in)
! V. f* y9 V( ^. F% x if (clr_in)
' I1 V! e6 o' G N2 x3 E# Y begin0 v) ~6 x0 m% T/ Q/ z
wr_pls_dly <= 0;* r7 t2 Y/ {/ Y4 Q
rd_pls_dly <= 0;
5 T; b* L; e5 m9 t' W end
! |, k+ y. T3 Q* c0 X5 N) X else2 |" Z9 X; y! t) u, W0 l0 N% H& `
begin
7 \9 L. A3 P, M) f4 E" H H wr_pls_dly <= wr_pulse_out;+ U4 l$ D* ^+ D
rd_pls_dly <= rd_pulse_out;
3 F8 a- U7 G& m( [ end8 E4 z; W" {* a7 i: w6 R
// subaddr_7_0_out is loaded after the second byte of a write) ^" v2 @* S# x' e) l
// cycle has fully shifted in. It increments after each- P" {( G, y' H. d) `
// read or write access.0 G! T$ p; g4 q8 Z; L e4 H
always @ (posedge clk_in or posedge clr_in)
* y1 d% R6 W4 n2 d1 C' t if (clr_in)
6 F8 c' j1 V* T begin2 e% x9 Z4 K- ~ r9 V) V
subaddr_7_0_out <= 0;" E* V+ k% M- E/ g4 N
end) ? J& F# D i4 |, [- K; k% b: p/ R
else" [* w3 V( F' d$ h- V
begin$ a2 e+ U/ }# u
if (subad_byte & ack_cyc) subaddr_7_0_out <= in_sr;
' Z- s' U# C+ E; I" {! @ // Leave Out this else clause for simple single register version: m2 s4 t2 f0 m) E/ h0 H( s- `2 A9 P6 Q
// In this case subaddr_7_0_out becomes the register output and should be! N! }, _' |- }( ^9 {! m3 d' P) p
// wrapped back to rd_bus_7_0_in externally2 ^" N& j4 g: i4 d$ Q
else if (wr_pls_dly | rd_pls_dly) subaddr_7_0_out <= subaddr_7_0_out + 1;
! P5 m1 Q# G+ F% y5 E end
& g7 _7 D2 p8 Q1 K& z) J/ l: C4 ~/ ?// Shift I2C data in after rising edge of SCL. a$ v& a" ?% [2 `$ f5 H
always @ (posedge clk_in or posedge clr_in); }% L; ]4 f6 m8 B$ [% X% m. r
if (clr_in)6 g" m1 O! F5 z
begin
6 F$ G, @* J. @9 `2 y$ b" `: l: C in_sr <= 0;# Z [3 H; `% _6 K, n
end
9 f% e' O3 S% y# c+ b else if (scl & !was_scl)7 r0 p5 g, v# T2 y5 Q1 x5 M
begin
* n( c& W1 h. K( S4 v in_sr <= {in_sr[6:0],sda};- u5 N2 A1 c' C8 j
end$ ?0 M1 G. J, `- C
// Read / not Write. For external bus drivers if necessary.
0 I9 k* p8 |( a6 D3 Q# N// Latch the Read bit of the address cycle.- [7 J3 M" j& y) a) F5 v; c
always @ (posedge clk_in or posedge clr_in)# D, A- D, H K7 `3 T$ P0 R& V
if (clr_in)2 ]) l* M l% r- ^3 ?
begin
) q( H0 Y D# [/ G v/ p, m rd_wr_out <= 0;
2 ]: W- L6 H' U0 M end
; H& q0 _( x5 V& z2 }) I9 R else if (addr_byte & ack_cyc)/ M6 y5 `$ G9 d3 g0 ^3 h
begin: B+ C1 ? e' j; ?, q# b
rd_wr_out <= in_sr[0];
9 D$ l" b4 I/ D end) B$ t5 ~5 a3 U/ M0 F
// Decode address. My cycle if address upper 7 bits Y, h+ _1 b7 j* E: w3 r: d
// match with i2c_address defined above.
( Q, \( b& }( D0 aalways @ (posedge clk_in or posedge i2c_start)
; ^. R, S) J7 _% O if (i2c_start)' }# m. P1 A% h- |% U
begin4 R& f2 [6 j) t
end
+ R! t2 i, p% K, m( V) ]' U else if (addr_byte & ack_cyc)
$ Y3 S2 o9 P# v) a* h9 ? begin
2 T) [9 E8 A; \$ v1 {8 q; X, v my_cyc <= (in_sr[7:1] == i2c_address);
+ ], f+ }2 e# x end
' O- V0 ]1 W# R- `" A- U// I2C data output drive low signal (1 = drive SDA low)
) ]- ?7 ]$ d5 P7 E9 G" Z4 S// Invert this signal for T input of OBUFT or IOBUF
$ u& k3 S! O8 d" x0 o// or use it directly for OBUFE.9 g# y% d4 B2 K I* Q/ `. j6 k; T4 N
always @ (posedge clk_in or posedge clr_in)
/ e* S5 | e6 z0 ]- C if (clr_in)
; E6 R* v9 Q Z begin
" X9 T! |( t- X9 \/ F drive_sda <= 0;' `) y7 |' b* T! E/ {: C7 X& N
end
: ]& S2 s8 T" z" Y( E else* x- w U* ~" {( V8 @
begin, j! Q5 \/ |1 L& m8 W* o
drive_sda <= my_cyc & addr_ack // Address acknowledge1 o) s2 p+ r8 H- S: v
| my_cyc & !rd_wr_out & ack_cyc // Write byte acknowledge
+ a- [: P q+ ~8 ]: \ | data_byte & rd_wr_out & !ack_cyc & !out_sr[7] ; // Read Data
@! n7 B& w/ {9 g p end
) e$ K7 q% M4 j5 x7 Sendmodule // I2Cslave |
|