diff options
-rw-r--r-- | fpga/src/I2C.bs | 85 | ||||
-rw-r--r-- | fpga/src/TopSim.bs | 16 |
2 files changed, 89 insertions, 12 deletions
diff --git a/fpga/src/I2C.bs b/fpga/src/I2C.bs index 2752acd..2a0614f 100644 --- a/fpga/src/I2C.bs +++ b/fpga/src/I2C.bs @@ -79,6 +79,22 @@ data I2CBusState | -- | We're reading SDA, which should be the ACK bit after sending an -- address. GetAddrAckReadSDA + | -- | TODO + WriteLowerSCL (Bit 1) (Bit 3) + | -- | TODO + WriteWriteSDA (Bit 3) + | -- | TODO + WriteRaiseSCL (Bit 1) (Bit 3) (Bit 1) + | -- | TODO + WriteAckLowerSCL (Bit 1) + | -- | TODO + WriteAckRaiseSDA + | -- | TODO + WriteAckRaiseSCL + | -- | TODO + WriteAckReadSDA + | -- | TODO + TODO | -- | We're about to either lower SCL or keep it low as part of reading a -- byte from a device. ReadLowerSCL (Bit 3) (Bit 1) @@ -98,7 +114,13 @@ data I2CBusState -- hold, the second is the number of cycles to hold it for. ReadAckRaiseSCL (Bit 1) (Bit 1) | -- | TODO - TODO + StopLowerSCL + | -- | TODO + StopLowerSDA + | -- | TODO + StopRaiseSCL + | -- | TODO + StopRaiseSDA deriving (Bits, FShow) -- | Runs an I²C interface on the current clock. @@ -164,8 +186,44 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module state := if rxSDA == 1 -- NACK then TODO else if savedAddr[0:0] == 0 -- R/!W - then TODO -- !W - else ReadLowerSCL 7 1 + then WriteLowerSCL 1 7 -- !W + else ReadLowerSCL 7 1 -- R + txSCL := 1 + txSDA := 1 + "WriteLowerSCL": when WriteLowerSCL bit n <- state ==> do + state := WriteWriteSDA n + txSCL := 0 + txSDA := bit + "WriteWriteSDA": when WriteWriteSDA n <- state ==> do + let bit = savedData[n:n] + state := WriteRaiseSCL bit n 1 + txSCL := 0 + txSDA := bit + "WriteRaiseSCL": when WriteRaiseSCL bit n time <- state ==> do + state := if time == 1 + then WriteRaiseSCL bit n (time - 1) + else if n == 0 + then WriteAckLowerSCL bit + else WriteLowerSCL bit (n - 1) + txSCL := 1 + txSDA := bit + "WriteAckLowerSCL": when WriteAckLowerSCL bit <- state ==> do + state := WriteAckRaiseSDA + txSCL := 0 + txSDA := bit + "WriteAckRaiseSDA": when WriteAckRaiseSDA <- state ==> do + state := WriteAckRaiseSCL + txSCL := 0 + txSDA := 1 + "WriteAckRaiseSCL": when WriteAckRaiseSCL <- state ==> do + state := WriteAckReadSDA + txSCL := 1 + txSDA := 1 + "WriteAckReadSDA": when WriteAckReadSDA <- state ==> do + statusReg := statusReg { ready = True; dataAckBit = unpack rxSDA } + state := if rxSDA == 1 -- NACK + then StopLowerSCL + else TODO txSCL := 1 txSDA := 1 "ReadLowerSCL": when ReadLowerSCL n time <- state ==> do @@ -201,9 +259,26 @@ mkI2C' rxSCL rxSDA txSCL txSDA addrReg dataReg statusReg = module then ReadAckRaiseSCL bit (time - 1) else if bit == 0 then ReadLowerSCL 7 1 -- ACK - else TODO -- NACK + else StopLowerSCL -- NACK txSCL := 1 txSDA := bit + "StopLowerSCL": when StopLowerSCL <- state ==> do + state := StopLowerSDA + txSCL := 0 + txSDA := 1 + "StopLowerSDA": when StopLowerSDA <- state ==> do + state := StopRaiseSCL + txSCL := 0 + txSDA := 0 + "StopRaiseSCL": when StopRaiseSCL <- state ==> do + state := StopRaiseSDA + txSCL := 1 + txSDA := 0 + "StopRaiseSDA": when StopRaiseSDA <- state ==> do + state := Idle + statusReg := statusReg { busIdle = True } + txSCL := 1 + txSDA := 1 return () -- | Returns an I²C interface that runs on the current clock. This is not what @@ -216,7 +291,7 @@ mkI2C rxSCL rxSDA = module dataReg <- mkReg 0 statusReg <- mkReg (I2CStatus { ready = True - ; busIdle = False + ; busIdle = True ; addrAckBit = False ; dataAckBit = False ; arbitrationLost = False diff --git a/fpga/src/TopSim.bs b/fpga/src/TopSim.bs index c512edc..e4e65c9 100644 --- a/fpga/src/TopSim.bs +++ b/fpga/src/TopSim.bs @@ -32,17 +32,19 @@ mkTopSim = module timer :: Reg (Bit 16) <- mkReg 0 rules "t0000": when (timer == 0x0000) ==> do - i2c.addrReg := 0x20 ++ (1 :: Bit 1) - i2c.dataReg := 0x00 + i2c.addrReg := 0x20 ++ (0 :: Bit 1) + i2c.dataReg := 0x12 "t0001": when (timer == 0x0001) ==> do i2c.statusReg := i2c.statusReg { ready = False; dataAckBit = True } + "t0002": when (timer == 0x0002) ==> do + i2c.addrReg := 0x20 ++ (0 :: Bit 1) + i2c.dataReg := 0xaa "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 } + -- "t0047": when (timer == 0x0047) ==> rxSDA := 0 + -- "t0051": when (timer == 0x004b) ==> rxSDA := 1 + -- "t004b": when (timer == 0x004b) ==> do + -- i2c.statusReg := i2c.statusReg { ready = False } "advance timer": when True ==> timer := timer + 1 "finish": when (timer == 0x00ff) ==> $finish {- |