diff options
-rw-r--r-- | fpga/src/I2C.bs | 43 | ||||
-rw-r--r-- | fpga/src/TopSim.bs | 13 |
2 files changed, 36 insertions, 20 deletions
diff --git a/fpga/src/I2C.bs b/fpga/src/I2C.bs index 292691b..2752acd 100644 --- a/fpga/src/I2C.bs +++ b/fpga/src/I2C.bs @@ -8,7 +8,8 @@ struct I2CStatus = { -- | This bit is low when a message is being sent, and gets raised after: -- -- - We finished sending an address, but a NACK was received. - -- - We finished reading a byte, including sending an ACK or NACK bit. + -- - We finished reading a byte, including starting to send an ACK or NACK + -- bit. -- - We finished writing a byte, including reading an ACK or NACK bit. -- -- When this bit is `True`, writing to it will cause a new read or write, @@ -23,10 +24,10 @@ struct I2CStatus = busIdle :: Bool ; -- | The last ACK bit we received from sending an address. Writing to this -- bit does not affect the internal state of the I²C controller. - addrAck :: Bool + addrAckBit :: Bool ; -- | The last ACK bit we received during a write, or the next ACK bit we'll -- send during a read. - dataAck :: Bool + dataAckBit :: Bool ; -- | A flag set if we detect during a START condition that we've lost -- arbitration. If this occurs, no read or write will occur, and the read -- or write should be retried later. Writing to this bit does not affect @@ -69,7 +70,7 @@ data I2CBusState SendAddrBitWait (Bit 3) (Bit 1) | -- | We're sending an address, and about to lower SCL. SendAddrBitLowerSCL (Bit 3) (Bit 1) - | -- | We're lowering SDA as part of getting the ACK bit after sending an + | -- | We're raising SDA as part of getting the ACK bit after sending an -- address. GetAddrAckSDA | -- | We're raising SCL to start the clock cycle in which we'll get the ACK @@ -105,13 +106,15 @@ mkI2C' :: Bit 1 -> Bit 1 -> Wire (Bit 1) -> Wire (Bit 1) -> Reg (Bit 8) -> Reg (Bit 8) -> Reg I2CStatus -> Module () mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module state :: Reg I2CBusState <- mkReg Idle + savedAddr :: Reg (Bit 8) <- mkReg 0 + savedData :: Reg (Bit 8) <- mkReg 0 rules "debug": when True ==> $display (fshow state) - "remain Idle": when Idle <- state, statusReg.notBusy ==> do + "remain Idle": when Idle <- state, statusReg.ready ==> do state := Idle txSCL := 1 txSDA := 1 - "triggered from Idle": when Idle <- state, not statusReg.notBusy ==> + "triggered from Idle": when Idle <- state, not statusReg.ready ==> if rxSDA == 0 then do statusReg := statusReg { ready = True; busIdle = True; arbitrationLost = True } state := Idle @@ -123,10 +126,14 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module txSDA := 0 "StartSDA": when StartSDA <- state ==> do state := SendAddrBitSDA 7 + savedAddr := addrReg + savedData := if savedAddr[0:0] == 1 -- R/!W + then 0 -- R + else dataReg -- !W txSCL := 0 txSDA := 0 "SendAddrBitSDA": when SendAddrBitSDA n <- state ==> do - let bit = addrReg[n:n] + let bit = savedAddr[n:n] state := SendAddrBitRaiseSCL n bit txSCL := 0 txSDA := bit @@ -147,16 +154,16 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module "GetAddrAckSDA": when GetAddrAckSDA <- state ==> do state := GetAddrAckRaiseSCL txSCL := 0 - txSDA := 0 + txSDA := 1 "GetAddrAckRaiseSCL": when GetAddrAckRaiseSCL <- state ==> do state := GetAddrAckReadSDA txSCL := 1 txSDA := 1 "GetAddrAckReadSDA": when GetAddrAckReadSDA <- state ==> do - statusReg := statusReg { addrAck = unpack rxSDA } + statusReg := statusReg { addrAckBit = unpack rxSDA } state := if rxSDA == 1 -- NACK then TODO - else if addrReg[0:0] == 0 -- R/!W + else if savedAddr[0:0] == 0 -- R/!W then TODO -- !W else ReadLowerSCL 7 1 txSCL := 1 @@ -172,7 +179,7 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module txSCL := 1 txSDA := 1 "ReadReadSDA": when ReadReadSDA n <- state ==> do - dataReg := dataReg [6:0] ++ rxSDA + savedData := savedData [6:0] ++ rxSDA state := if n == 0 then ReadAckLowerSCL else ReadLowerSCL (n - 1) 1 @@ -183,14 +190,18 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module txSCL := 0 txSDA := 1 "ReadAckWriteSDA": when ReadAckWriteSDA <- state ==> do - let bit = pack statusReg.dataAck + let bit = pack statusReg.dataAckBit + statusReg := statusReg { ready = True } + dataReg := savedData state := ReadAckRaiseSCL bit 1 txSCL := 0 txSDA := bit "ReadAckRaiseSCL": when ReadAckRaiseSCL bit time <- state ==> do state := if time == 1 then ReadAckRaiseSCL bit (time - 1) - else TODO + else if bit == 0 + then ReadLowerSCL 7 1 -- ACK + else TODO -- NACK txSCL := 1 txSDA := bit return () @@ -204,10 +215,10 @@ mkI2C rxSCL rxSDA = module addrReg <- mkReg 0 dataReg <- mkReg 0 statusReg <- mkReg (I2CStatus - { notBusy = False + { ready = True ; busIdle = False - ; addrAck = False - ; dataAck = False + ; addrAckBit = False + ; dataAckBit = False ; arbitrationLost = False ; rsvd = 0 }) diff --git a/fpga/src/TopSim.bs b/fpga/src/TopSim.bs index d4a5812..4721a42 100644 --- a/fpga/src/TopSim.bs +++ b/fpga/src/TopSim.bs @@ -32,12 +32,17 @@ mkTopSim = module timer :: Reg (Bit 16) <- mkReg 0 rules "t0000": when (timer == 0x0000) ==> do - i2c.addrReg := 0x01 + i2c.addrReg := 0x20 ++ (1 :: Bit 1) i2c.dataReg := 0x00 "t0001": when (timer == 0x0001) ==> do - i2c.statusReg := i2c.statusReg { notBusy = True } - "t0022": when (timer == 0x0022) ==> rxSDA := 0 - "t0025": when (timer == 0x0025) ==> rxSDA := 1 + i2c.statusReg := i2c.statusReg { ready = False; dataAckBit = False } + "t0022": when (timer == 0x0023) ==> rxSDA := 0 + "t0025": when (timer == 0x0027) ==> rxSDA := 1 + "t0049": when (timer == 0x0049) ==> do + i2c.addrReg := 0x20 ++ (0 :: Bit 1) + i2c.dataReg := 0x00 + "t004a": when (timer == 0x004a) ==> do + i2c.statusReg := i2c.statusReg { ready = False } "advance timer": when True ==> timer := timer + 1 "finish": when (timer == 0x00ff) ==> $finish {- |