(********************************************************************************)
(*                                                                              *)
(* $Id: tpu-iic.html,v 1.1 2003/09/23 07:55:12 jbm Exp $                         *)
(*                                                                              *)
(* Function:    IIC   - IIC bus master                                          *)
(*                                                                              *)
(* Creation Date: 24.6.98                   From: New                           *)
(*                                                                              *)
(* Author:      A. Morbach                                                      *)
(*              arno-morbach@web.de                                             *)
(*                                                                              *)
(* Description:                                                                 *)
(* ------------                                                                 *)
(* This function provides an easy way to connect IIC devices to the 68332 or    *)
(* 68376. Two adjacent channels are used, the first one provides the user inter-*)
(* face. The function has been tested with IIC EEPROMs, but it should work with *)
(* several other IIC slaves. Since the TPU is always master of the IIC bus,     *)
(* there is no limit of the response time. If there are other TPU functions,    *)
(* the transfer time will go up, but it will not be disturbed.                  *)
(* The following description assumes, that you are familiar with the IIC bus    *)
(* and its addressing scheme.                                                   *)
(*                                                                              *)
(* The IIC bus is an open collector coupled bus. The TPU ports are not open     *)
(* collector, but with the TPU as bus master there is a solution: Just use the  *)
(* first TPU channel N as SCL in output mode. Use a pullup resitor to force high*)
(* level while the uC is in reset. The second channel N+1 will work as SDA. It  *)
(* is used as output and input. To meet the IIC specs, there is a resistor /    *)
(* diode combination in series with the TPU pin.                                *)
(*                                                                              *)
(* -------------|                       _____                                   *)
(*      uC      |     ----|<|----    ---| R2|------>VCC                         *)
(*              |     |    D    |    |  -----                                   *)
(*  TPU pin SDA |-----+         +----+                         SDA              *)
(*              |     |  _____  |    |--------------------------------          *)
(*              |     ---| R1|---                                               *)
(* -------------|        -----                                                  *)
(*                                                                              *)
(* R1 = 10kOhm to provide the SDA level to the TPU pin in input mode.           *)
(* R2 = 3.32kOhm pullup for the IIC bus. This is the minimum resistance,        *)
(* because the uC is only capable of sinking 1.6mA. With only one or two devices*)
(* connected it shouldn't be a problem.                                         *)
(* D is a shottky diode to build the equivalent of an open collector output.    *)
(*                                                                              *)
(* There are two modes of operation: Read one byte from, or write one byte to   *)
(* a connected IIC device. The mode is defined by the lsb of IIC_SLAVE_ADDRESS. *)
(*                                                                              *)
(* Read mode:                                                                   *)
(* First the slave address is sent, with R/W bit set to 0.                      *)
(* Then the byte address is sent.                                               *)
(* After acknowlegde, a start condition is generated and the slave address is   *)
(* transmitted again, with R/W bit set to 1.                                    *)
(* Next, the data byte is read into IIC_DATA.                                   *)
(*                                                                              *)
(* Write mode:                                                                  *)
(* First the slave address is sent, with R/W bit set to 0.                      *)
(* Then the byte address is sent.                                               *)
(* Next the data byte in IIC_DATA is transmitted.                               *)
(*                                                                              *)
(* The termination of the transfer is reported by setting the msb in IIC_STATE. *)
(* If there was a missing acknowlegde the value of IIC_STATE is 0x8100.         *)
(* IIC_STATE should be set to 0 before a transmission is started,  because      *)
(* some time will go by before the IIC function can reset IIC_STATE itself.     *)
(* If the software is too fast it could otherwise see the msb set and think that*)
(* the transmission is over, although it has not yet been started.              *)
(*                                                                              *)
(* name:                Written By:             Location  Bits:                 *)
(* -----                -----------             ---------------                 *)
(* IIC_SLAVE_ADDRESS    CPU                     Parameter0  8..15               *)
(*                      Slave adress of the IIC device which is HW decoded.     *)
(*                      The last bit (LSB) defines if the following transfer    *)
(*                      is read or write. See IIC specifications.               *)
(*                                                                              *)
(* IIC_BYTE_ADDRESS     CPU                     Parameter0  0..7                *)
(*                      Byte address. Only the IIC device which was addressed   *)
(*                      by the previous IIC_SLAVE_ADDRESS will use this         *)
(*                      IIC_BYTE_ADDRESS.                                       *)
(*                                                                              *)
(* IIC_DATA             CPU / TPU               Parameter1  0..7                *)
(*                      In write mode this byte will be sent. In read mode the  *)
(*                      received byte will be here to be read by CPU.           *)
(*                                                                              *)
(* IIC_SHIFT_REGISTER   TPU                     Parameter2  0..7                *)
(*                      holds the data to be shifted out or in.                 *)
(*                                                                              *)
(* IIC_COUNT            TPU                     Parameter3  0..3                *)
(*                      is used to count SCL edges, to determine if the         *)
(*                      actual state is to be ended.                            *)
(*                                                                              *)
(* IIC_CLK_LOW_TIME     CPU                     Parameter4 0..15                *)
(*                      defines the minimum clock low time. The same            *)
(*                      time is used as high time, which is normally            *)
(*                      lower (about 4us instead of 4.7us as low time).         *)
(*                      CLK_LOW_TIME must be 2 or greater. Even with            *)
(*                      a very slow TCR1 CLK_LOW_TIME = 1 is not                *)
(*                      allowed, because of the internal timing. The            *)
(*                      really used time is between CLK_LOW_TIME - 1 and        *)
(*                      CLK_LOW_TIME. So 1 could degrade to 0, which            *)
(*                      would be too fast.                                      *)
(*                      The setting of this register depends on the system      *)
(*                      frequency and the prescaler of TCR1. Only TCR1 is used  *)
(*                      in this implemetation, but it can easily changed.       *)
(*                      CLK_LOW_TIME counts TCR1 transitions.                   *)
(*                                                                              *)
(* IIC_STATE            CPU / TPU               Parameter5 0..15                *)
(*                      The transmission of bits over the IIC bus is            *)
(*                      divided into several states. The actual state           *)
(*                      is stored in the lower byte of STATE. To see            *)
(*                      how the states are coded, see the table                 *)
(*                      following this header.                                  *)
(*                      The high byte of STATE gives a status of                *)
(*                      operation. It is to be reset before starting a          *)
(*                      transmission.                                           *)
(*                      STATE(8..15) = 0x00: transmission in progress.          *)
(*                      STATE(8..15) = 0x80: transmission is complete           *)
(*                                           without error.                     *)
(*                      STATE(8..15) = 0x81: transmission is complete           *)
(*                                           with error: missing                *)
(*                                           acknowledge.                       *)
(*                                                                              *)
(* HSQ1   HSQ0         Action                                                   *)
(* ----   ----         ------                                                   *)
(*  x       x          HSQ is not used                                          *)
(*                                                                              *)
(* HSR1   HSR0         Action                                                   *)
(* ----   ----         ------                                                   *)
(*  0       1          Initiate transfer                                        *)
(*  1       0          No action                                                *)
(*  1       1          Initialize ports                                         *)
(*                                                                              *)
(* flag1                1: Read operation of IIC device                         *)
(*                      0: Write operation of IIC device                        *)
(*                                                                              *)
(* flag0                1: Data IO is under way                                 *)
(*                      0: Control bits are generated                           *)
(*                                                                              *)
(* Links Accepted: NO              Links Generated: NO                          *)
(*                                                                              *)
(* Interrupts Generated After:   Each complete transfer                         *)
(*                                                                              *)
(*                                                                              *)
(* Every state (stored in IIC_STATE) begins with SCL = 0.                       *)
(*                                                                              *)
(*               flag1 = 1 (read)      |          flag1 = 0 (write)             *)
(* ---------------------------------------------------------------------------  *)
(* State by name   | IIC_STATE | flag0 | State by name   | IIC_STATE | flag0    *)
(* ---------------------------------------------------------------------------  *)
(* SLAVE_ADR_OUT   |   03      |   1   | SLAVE_ADR_OUT   |   03      |   1      *)
(* REC_ACKNOWLEDGE |   03      |   0   | REC_ACKNOWLEDGE |   03      |   0      *)
(* ---------------------------------------------------------------------------  *)
(* BYTE_ADR_OUT    |   05      |   1   | BYTE_ADR_OUT    |   05      |   1      *)
(* REC_ACKNOWLEDGE |   05      |   0   | REC_ACKNOWLEDGE |   05      |   0      *)
(* ---------------------------------------------------------------------------  *)
(* START_CONDITION |   40      |   0   |                 |           |          *)
(* ---------------------------------------------------------------------------  *)
(* SLAVE_ADR_OUT   |   09      |   1   | DATA_OUT        |   09      |   1      *)
(* REC_ACKNOWLEDGE |   09      |   0   | REC_ACKNOWLEDGE |   09      |   0      *)
(* ---------------------------------------------------------------------------  *)
(* DATA_IN         |   80      |   1   |                 |           |          *)
(* SEND_NO_ACK     |   80      |   0   |                 |           |          *)
(* ---------------------------------------------------------------------------  *)
(* STOP_CONDITION  |   20      |   0   | STOP_CONDITION  |   20      |   0      *)
(*                                                                              *)
(*                                                                              *)
(*                                                                              *)
(* START_CONDITION:                                                             *)
(*                                                                              *)
(*      ---+          +---------------------                                    *)
(* SCL     |          |                                                         *)
(*         +----------+                                                         *)
(*                                                                              *)
(*      +++++-------------------+                                               *)
(* SDA      +                   |                                               *)
(*      +++++                   +-----------                                    *)
(*                                                                              *)
(*         ^          ^         ^                                               *)
(*         |          |         +-- 2. IIC_RIS_CT:      SDA Output Low          *)
(*         |          |                                                         *)
(*         |          +------------ 1. IIC_RIS_CT:      SDA Output High         *)
(*         |                                                                    *)
(*         +----------------------- IIC_FAL_CT: SDA Output High                 *)
(*                                                                              *)
(* Next state is 09 with flag0 = 1.                                             *)
(*                                                                              *)
(*                                                                              *)
(*                                                                              *)
(* STOP_CONDITION:                                                              *)
(*                                                                              *)
(*      ---+          +---------------------                                    *)
(* SCL     |          |                                                         *)
(*         +----------+                                                         *)
(*                                                                              *)
(*      +++++                   +-----------                                    *)
(* SDA      +                   |                                               *)
(*      +++++-------------------+                                               *)
(*                                                                              *)
(*         ^          ^         ^                                               *)
(*         |          |         +-- 2. IIC_RIS_CT:      SDA Output High         *)
(*         |          |                                                         *)
(*         |          +------------ 1. IIC_RIS_CT:      SDA Output Low          *)
(*         |                                                                    *)
(*         +----------------------- IIC_FAL_CT: SDA Output Low                  *)
(*                                                                              *)
(* There is no next state, no further matches are set up. STATUS = 80.          *)
(*                                                                              *)
(*                                                                              *)
(*                                                                              *)
(* SEND_NO_ACK:                                                                 *)
(*                                                                              *)
(*      ---+          +-----                                                    *)
(* SCL     |          |                                                         *)
(*         +----------+                                                         *)
(*                                                                              *)
(*      +++++---------------                                                    *)
(* SDA      +                                                                   *)
(*      +++++                                                                   *)
(*                                                                              *)
(*         ^          ^                                                         *)
(*         |          +------------ IIC_RIS_CT: SDA Output High                 *)
(*         |                                                                    *)
(*         +----------------------- IIC_FAL_CT: SDA Output High                 *)
(*                                                                              *)
(* Next state is 20 with flag0 = 0.                                             *)
(*                                                                              *)
(*                                                                              *)
(*                                                                              *)
(* REC_ACKNOWLEDGE:                                                             *)
(*                                                                              *)
(*      ---+          +-----                                                    *)
(* SCL     |          |                                                         *)
(*         +----------+                                                         *)
(*                                                                              *)
(*      +++++----------+----                                                    *)
(* SDA      +          +                                                        *)
(*      +++++----------+----                                                    *)
(*                                                                              *)
(*        ^          ^                                                          *)
(*         |          +------------ IIC_RIS_CT: SDA checked if low              *)
(*         |                                                                    *)
(*         +----------------------- IIC_FAL_CT: SDA Input                       *)
(*                                                                              *)
(* If SDA is high, then STATUS = 81. No further matches.                        *)
(* If SDA is low then next state depends on current state and flag1.            *)
(*                                                                              *)
(* current state | flag1 | next state and flag0                                 *)
(* ----------------------------------------------                               *)
(*      03       |   1   |     05           1                                   *)
(*      03       |   0   |     05           1                                   *)
(*      05       |   1   |     40           0                                   *)
(*      05       |   0   |     09           1                                   *)
(*      09       |   1   |     80           1                                   *)
(*      09       |   0   |     20           0                                   *)
(*                                                                              *)

%macro IIC_ADDRESS              'prm0'.
%macro IIC_DATA                 'prm1'.
%macro IIC_SHIFT_REGISTER       'prm2'.
%macro IIC_COUNT                'prm3'.
%macro IIC_CLK_LOW_TIME         'prm4'.
%macro IIC_STATE                'prm5'.

%macro IIC_BIT_START            '#$C0'.
%macro IIC_BIT_STOP             '#$20'.
%macro IIC_BIT_NOACK            '#$C0'.

(************************************************************************)
(*                                                                      *)
(* ENTRY name:  IIC_INIT                                                *)
(*                                                                      *)
(* PRELOAD PARAMETER :  IIC_ADDRESS                                     *)
(*                                                                      *)
(* ENTER WHEN : HSR = %11                                               *)
(*                                                                      *)
(* ACTION: Initialize portpins, SCL high, SDA high.                     *)
(*      Don't activate any matches.                                     *)
(************************************************************************)
%entry start_address *; ram p<-@IIC_ADDRESS; disable_match; name = IIC_INIT;
cond hsr1=1,hsr0=1.

IIC_INIT:
        (* drive SCL high. SCL should already be high due to external pullup *)
        chan pin := high, TBS := out_m1_c1, PAC := no_change,
        disable_mtsr.

        au chan_reg := chan_reg + #$10. (* change to Channel SDA *)

        nop.                            (* wait for next channel *)


        (* drive SDA high. Since SDA is externally coupled by a diode, *)
        (* the bus will be high due to external pullup *)
        chan pin := high, TBS := out_m1_c1, PAC := no_change; disable_mtsr.

        end.

(************************************************************************)
(*                                                                      *)
(* ENTRY name:  IIC_START_TRANSFER                                      *)
(*                                                                      *)
(* PRELOAD PARAMETER :  IIC_ADDRESS                                     *)
(*                                                                      *)
(* ENTER WHEN : HSR = %01                                               *)
(*                                                                      *)
(* ACTION:                                                              *)
(*      Initiate Transfer                                               *)
(*      Load IIC_SHIFT_REGISTER with IIC_ADRESS. Clear R/W bit in       *)
(*      IIC_SHIFT_REGISTER because the first transmission is always a   *)
(*      write to the IIC device.                                        *)
(*      Store read or write operation in flag1.                         *)
(*      Set IIC_STATE to 03.                                            *)
(*      Set IIC_COUNT to 8 for 8 bit transmission.                      *)
(*      Set flag0 to 1 to transmit data.                                *)
(*      Generate Start Condition by setting SDA to low while SCL is     *)
(*      high.                                                           *)
(*                                                                      *)
(*      Set up match time for falling SCL edge.                         *)
(************************************************************************)
%entry start_address *; ram p<-@IIC_ADDRESS; disable_match;
name = IIC_START_TRANSFER;
cond hsr1=0, hsr0=1.


IIC_START_TRANSFER:
        au p_high :=>> p_high, ccl;             (* RW bit into carry flag *)
        chan set flag0.                         (* begin with data transmission *)

        au p_high :=<< p_high.                  (* Back again. RW bit is now 0 *)
                                                (* Every transmission begins with RW=0 *)
        ram p -> @IIC_SHIFT_REGISTER.           (* load shift register *)

        if C = 0 then goto IIC_START_WRITE, flush;      (* set flag1 if RW bit is 1 *)
        chan tbs := out_m1_c1; enable_mtsr, clear flag1.

IIC_START_READ:
        chan set flag1.                 (* RW bit is 1: set flag1 *)

IIC_START_WRITE:
        au p := #$03.                   (* state 03 at the beginning *)

IIC_START_CONT:
        ram p -> @IIC_STATE.                    (* state machine begins with 03 to send slave address *)

        au chan_reg := chan_reg + #$10.         (* change to next channel, SDA *)

        au p := #8.                             (* 8 bits to be sent *)

        (* SDA is low, Start condition *)
        chan pin := low, tbs := out_m1_c1, pac := no_change; disable_mtsr.

        au chan_reg := chan_reg + #$F0.         (* Back to SCL *)

        ram p -> @IIC_COUNT;
        goto IIC_NEXT_EDGE_LOW, flush.

(************************************************************************)
(* ENTRY name:  IIC_FAL_IO                                              *)
(* PRELOAD PARAMETER : IIC_STATE                                        *)
(* ENTER WHEN : HSR = %00                                               *)
(*              SCL = 0                                                 *)
(*              flag0 = 1 (Data bits)                                   *)
(* ACTION:                                                              *)
(*      A falling edge of SCL occured. Data bit has to be processed.    *)
(*      If state is 80 (DATA_IN) just a match for the next rising edge  *)
(*      has to be set up.                                               *)
(*      Otherwise the msb of the shift register is output at SDA.       *)
(*                                                                      *)
(*      Set up match time for rising SCL edge.                          *)
(************************************************************************)
%entry  start_address *; ram p <- @IIC_STATE;
name = IIC_FAL_IO;
cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 0, flag0 = 1.

IIC_FAL_IO:
        au p_low :=<< p_low, ccl.       (* get msb into C *)

        if Z = 1 then goto IIC_NEXT_EDGE_HIGH, flush.   (* STATE = 80: do nothing *)
                                                (* SDA is already in input mode, because *)
                                                (* of acknowledge check. *)

IIC_FAL_OUT:
(* STATE = 03, 05 or 09. The msb of the shift register should be put out at SDA *)
        ram diob <- @IIC_SHIFT_REGISTER.        (* get shift register into diob *)

        au chan_reg := chan_reg + #$10.         (* switch to SDA *)

        au diob :=<< diob, ccl.                 (* get msb into C *)

        if C = 0 then goto IIC_FAL_OUT_LOW;
        chan tbs := out_m1_c1.                  (* set pin to output *)

        chan pin := low, pac := no_change.      (* Pin is low. No matter what C is *)

IIC_FAL_OUT_HI:
        chan pin := high.                       (* If C=0 this is not executed *)

IIC_FAL_OUT_LOW:
        au chan_reg := chan_reg + #$F0.         (* switch back to SCL *)

        ram diob -> @IIC_SHIFT_REGISTER;        (* store shift register *)
        goto IIC_NEXT_EDGE_HIGH, flush.         (* set up next edge *)

(************************************************************************)
(* ENTRY name:  IIC_RIS_IO                                              *)
(* STATE(S) ENTERED:                                                  *)
(* PRELOAD PARAMETER :                                                *)
(* ENTER WHEN : HSR = %00                                             *)
(*              SCL = 1                                               *)
(*              flag0 = 1 (Data bits)                                   *)
(* ACTION:                                                              *)
(*      A rising edge of SCL occured. Data bit has to be processed.     *)
(*      If state is 80 (DATA_IN) the pin state of SDA is stored into the*)
(*      lsb of IIC_SHIFT_REGISTER, which has been shiftet left before.  *)
(*      If state is 03, 05 or 09 nothing special has to be done.        *)
(*      In all modes IIC_COUNT is decremented. If IIC_COUNT reaches 0   *)
(*      a switch to the next state is performed.                        *)
(*      Otherwise the msb of the shift register is output at SDA.       *)
(*                                                                      *)
(*      Set up match time for rising SCL edge.                          *)
(************************************************************************)
%entry  start_address *; ram p <- @IIC_STATE;
name = IIC_RIS_IO;
cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 1, flag0 = 1.

IIC_RIS_IO:
        au p_low :=<< p_low, ccl.       (* get away with msb *)

        if Z = 0 then goto IIC_RIS_OUT, flush.  (* STATE = 03, 05 or 09: goto output mode *)
                                                (* do nothing with shift register *)

IIC_RIS_INP:
        ram diob <- @IIC_SHIFT_REGISTER.        (* get shift register into diob *)

        au chan_reg := chan_reg + #$10.         (* switch to SDA *)

        au diob :=<< diob.                      (* get ready to insert lsb *)

        if psl = 0 then goto IIC_RIS_INP_LO, flush.

        au diob := diob + 1.                    (* set lsb since the pin is high *)

IIC_RIS_INP_LO:
        au chan_reg := chan_reg + #$F0.         (* switch back to SCL *)

        ram diob -> @IIC_SHIFT_REGISTER.        (* store new data into shift register *)

IIC_RIS_OUT:
        ram p <- @IIC_COUNT.                    (* get counter into p *)

        au p := p - 1, ccl;                     (* decrement bit count *)
        ram p -> @IIC_COUNT.                    (* store bit count *)

        if Z = 0 then goto IIC_NEXT_EDGE_LOW, flush.    (* if not Z there are still *)
                                                        (* bits to be tranfered *)

(* All bits have been transfered. Now we have to switch to the handling of ack, start or stop. *)
        ram p <- @IIC_STATE.

        au p_low :=<< p_low, ccl;
        ram diob <- @IIC_SHIFT_REGISTER.        (* received data into diob *)

        if Z = 0 then goto IIC_RIS_RECACK, flush.       (* In state 03, 05 and 09 acknowledge has *)
                                                        (* to be received. *)

IIC_RIS_NOACK:
(* in state 80 no acknowledge is to be sent out. *)
        ram diob -> @IIC_DATA.          (* store received data into IIC_DATA *)

        au p_high := @IIC_BIT_NOACK.

        ram p -> @IIC_SHIFT_REGISTER;   (* set up bit pattern for stop condition *)
        au diob := 1.                   (* 1 rising edge *)

        ram diob -> @IIC_COUNT.

IIC_RIS_RECACK:
        if TRUE then goto IIC_NEXT_EDGE_LOW, flush;     (* setup next edge *)
        chan clear flag0.               (* control bit is following, state keeps the same *)

(************************************************************************)
(* ENTRY name:  IIC_FAL_CT                                              *)
(* STATE(S) ENTERED:                                                  *)
(* PRELOAD PARAMETER :                                                *)
(* ENTER WHEN : HSR = %00                                             *)
(*              SCL = 0                                               *)
(*              flag0 = 0 (Control bits: ack, start or stop)            *)
(* ACTION:                                                              *)
(*      A falling edge of SCL occured. Control bit has to be processed. *)
(*      If state is 03, 05 or 09, SDA is set to input.                  *)
(*      if state is 20, 40 or 80, the msb of the shift register is put  *)
(*      out at SDA.                                                     *)
(*                                                                      *)
(*      Set up match time for rising SCL edge.                          *)
(************************************************************************)
%entry  start_address *; ram p <- @IIC_STATE; name = IIC_FAL_CT;
cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 0, flag0 = 0.

IIC_FAL_CT:
        au p_low :=>> p_low, ccl.

        if C = 0 then goto IIC_FAL_CT_STSTNOACK, flush. (* STATE = 80, 40 or 20: *)

IIC_FAL_CT_ACK:
(* with the states 03, 05 and 09, the reception of the acknowledge bit is to be *)
(* arranged. SDA is to be switched to input. *)

        au chan_reg := chan_reg + #$10. (* switch to SDA *)

        chan tbs := in_m1_c1, pac := no_detect. (* SDA to input *)

        au chan_reg := chan_reg + #$F0. (* switch back to SCL *)

        goto IIC_NEXT_EDGE_HIGH, flush.         (* do nothing, just generate rising edge *)

IIC_FAL_CT_STSTNOACK:
(* With all three states 20, 40 and 80, the content of the shift register is to be *)
(* put out at SDA *)
        ram p <- @IIC_SHIFT_REGISTER.

        au chan_reg := chan_reg + #$10. (* switch to SDA *)

        au p :=<< p, ccl.               (* set C with msb *)


        if C = 0 then goto IIC_FAL_CT_LO_OUT, flush;
        chan tbs := out_m1_c1, pac := no_change, pin := low.    (* SDA to output *)

        chan pin := high.

IIC_FAL_CT_LO_OUT:
        au chan_reg := chan_reg + #$F0. (* switch back to SCL *)

        ram p -> @IIC_SHIFT_REGISTER;   (* store new value into shift register *)
        goto IIC_NEXT_EDGE_HIGH, flush.         (* do nothing, just generate rising edge *)

(************************************************************************)
(*                                                                      *)
(* ENTRY name:  IIC_RIS_CT                                              *)
(*                                                                      *)
(* STATE(S) ENTERED:                                                    *)
(*                                                                      *)
(* PRELOAD PARAMETER :  IIC_COUNT                                       *)
(*                                                                      *)
(* ENTER WHEN : HSR = %00                                               *)
(*              SCL = 1                                                 *)
(*              flag0 = 0 (Control bits: ack, start or stop)            *)
(* ACTION:                                                              *)
(*      A rising edge of SCL occured or this is the second match with   *)
(*      SCL high (start or stop). Control bit has to be processed.      *)
(*      With SCL high (start, stop: 2. match) the next state has to be  *)
(*      determined. A lot of decisions have to be made. They are        *)
(*      explained in the code section.                                  *)
(*      flag0, IIC_SHIFT_REGISTER, IIC_COUNT and IIC_STATE are set up   *)
(*      for the beginning of the next state.                            *)
(*                                                                      *)
(*      Set up match time for rising SCL edge.                          *)
(************************************************************************)
%entry  start_address *; ram p <- @IIC_STATE;
name = IIC_RIS_CT;
cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 1, flag0 = 0.

IIC_RIS_CT:
        au p_low :=>> p_low, ccl;       (* Shift lsb into C *)
        ram diob <- @IIC_COUNT.         (* get Count into diob *)

        if C = 1 then goto IIC_RIS_CT_ACK, flush.       (* STATE = 03, 05 or 09 *)

IIC_RIS_CT_STSTNOACK:
(* STATE = 20, 40 or 80 *)
        ram p <- @IIC_SHIFT_REGISTER.   (* get Shift register  *)

        au chan_reg := chan_reg + #$10. (* switch to SDA *)

        au p :=<< p, ccl.               (* set C with msb *)

(* at this output are no glitches allowed, because SCL is already high. With SCL high, *)
(* there are no unwanted edges at SDA allowed.*)
        chan tbs := out_m1_c1, pac := no_change;        (* SDA to output *)
        if C = 0 then goto IIC_RIS_CT_LO_OUT, flush.

        chan pin := high;
        if TRUE then goto IIC_RIS_CT_CONT, flush.

IIC_RIS_CT_LO_OUT:
        chan pin := low.

IIC_RIS_CT_CONT:
        au chan_reg := chan_reg + #$F0. (* switch back to SCL *)

        au diob := diob - 1, ccl;       (* decrement COUNT *)
        ram p -> @IIC_SHIFT_REGISTER.   (* store new value into shift register *)

        ram diob -> @IIC_COUNT.         (* store IIC_COUNT *)

        if Z = 0 then goto IIC_NEXT_EDGE_HIGH, flush.   (* still one edge left *)

        ram p <- @IIC_STATE.            (* get state *)

        au p_low :=<< p_low, ccl.

        if Z = 1 then goto IIC_RIS_CT_NOACK, flush.     (* STATE = 80 *)

        au p_low :=<< p_low, ccl.

        if Z = 1 then goto IIC_RIS_CT_START, flush.     (* STATE = 40 *)

IIC_RIS_CT_STOP:
(* STATE = 20 *)
        au p := $8000;
        ram p -> @IIC_STATE.            (* STATE = 80: end of transmission, no errors *)

        chan disable_mtsr.              (* no further matches *)

        chan cir;                       (* generate interrupt *)
        end.

IIC_RIS_CT_NOACK:
(* STATE = 80 *)
        au p_high := @IIC_BIT_STOP.

        ram p -> @IIC_SHIFT_REGISTER.   (* set up bit pattern for stop condition *)

        au p := #$20.                   (* next state will be 20 *)

        au diob := #2.                  (* 2 rising edges *)

        goto IIC_RIS_CT_SETUP, flush.   (* with p and diob set, goto setup *)

IIC_RIS_CT_START:
(* STATE = 40 *)
        ram p <- @IIC_ADDRESS.          (* get slave address into p *)

        ram p -> @IIC_SHIFT_REGISTER.   (* and then into SHIFT_REGISTER *)

        au p := #$09;                   (* next state is 09 *)
        chan set flag0.                 (* data IO *)

IIC_RIS_CT_SETUP8:
        au diob := #8.                  (* 8 bits to be sent *)

IIC_RIS_CT_SETUP:
(* The registers IIC_STATE and IIC_COUNT are loaded with the values of p and diob *)
        ram p -> @IIC_STATE.            (* store next state *)

        ram diob -> @IIC_COUNT.         (* store count *)

        goto IIC_NEXT_EDGE_LOW, flush.  (* next time it will be a falling edge *)

IIC_RIS_CT_ACK:
(* STATE = 03, 05 or 09 *)
(* p_low is 01 02 or 08 depending on the current state (03, 05 09) *)
        au chan_reg := chan_reg + #$10. (* switch to SDA *)

        au p_low :=>> p_low.            (* shift state right *)

        if psl = 1 then goto IIC_RIS_CT_RECNOACK, flush.        (* SDA = 1: No Ack *)

IIC_RIS_CT_RECACK:
        au chan_reg := chan_reg + #$F0. (* switch back to SCL *)

        au p_low :=>> p_low, ccl.       (* shift state right, the second time *)

        if C = 1 then goto IIC_RIS_CT_BYT, flush.       (* STATE = 05 *)

        if Z = 1 then goto IIC_RIS_CT_FIRSLV, flush.    (* STATE = 03 *)

IIC_RIS_CT_SECSLV:
(* STATE = 09 *)
        if flag1 = 0 then goto IIC_RIS_CT_DATA, flush.  (* STATE = 09, flag1 = 0 *)

(* STATE = 09, flag1 = 1 *)
        au p := #$80;           (* next state is 80 *)
        chan set flag0.         (* data IO *)

        goto IIC_RIS_CT_SETUP8, flush.  (* store IIC_STATE and IIC_COUNT *)

IIC_RIS_CT_DATA:
(* STATE = 09, flag1 = 0 *)
        au p_high := @IIC_BIT_STOP.

        ram p -> @IIC_SHIFT_REGISTER.   (* set up bit pattern for stop condition *)

        au p := #$20.           (* next state is 20 *)

        au diob := #2.          (* 2 rising edges *)

        goto IIC_RIS_CT_SETUP, flush.   (* store IIC_STATE and IIC_COUNT *)

IIC_RIS_CT_FIRSLV:
(* STATE = 03 *)
        au p := #$05;           (* next state is 05 *)
        chan set flag0.         (* data IO *)

        goto IIC_RIS_CT_SETUP8, flush.  (* store IIC_STATE and IIC_COUNT *)

IIC_RIS_CT_BYT:
(* STATE = 05 *)
        if flag1 = 0 then goto IIC_RIS_CT_DATA_OUT, flush.      (* STATE = 05, flag1 = 0 *)

IIC_RIS_CT_START_COND:
(* STATE = 05, flag1 = 1 *)
        au p_high := @IIC_BIT_START.

        ram p -> @IIC_SHIFT_REGISTER.   (* set up bit pattern for stop condition *)

        au p := #$40.           (* next state is 40 *)

        au diob := #2.          (* 2 rising edges *)

        goto IIC_RIS_CT_SETUP, flush.   (* store IIC_STATE and IIC_COUNT *)

IIC_RIS_CT_DATA_OUT:
(* STATE = 05, flag1 = 0 *)
        ram p <- @IIC_DATA.     (* get data byte into p_high *)

        au p_high := p_low.     (* get low byte into high byte *)

        ram p -> @IIC_SHIFT_REGISTER.   (* and store it in IIC_SHIFT_REGISTER *)

        au p := #$09;           (* next state is 09 *)
        chan set flag0.         (* data IO *)

        goto IIC_RIS_CT_SETUP8, flush.  (* store IIC_STATE and IIC_COUNT *)

IIC_RIS_CT_RECNOACK:
(* still in SDA channel *)
        au chan_reg := chan_reg + #$F0. (* switch back to SCL *)

        au p_high := #$81.                      (* end with error bit set *)

        ram p -> @IIC_STATE.            (* STATE = 81: end of transmission *)
                                        (* error: missing acknowledge *)

        chan disable_mtsr.

        chan cir;               (* generate interrupt *)
        end.

(**********************************************************************)
(**********************************************************************)
IIC_NEXT_EDGE_HIGH:
        chan pac := high;
        if TRUE then goto IIC_SET_NEXT_EDGE, flush.

IIC_NEXT_EDGE_LOW:
        chan pac := low.

IIC_SET_NEXT_EDGE:
        au ert := tcr1;
        ram diob <- @IIC_CLK_LOW_TIME.

        au ert := ert + diob;
        chan write_mer, neg_lsl, neg_tdl, neg_mrl.

        nop.

        end.

(**********************************************************************)
(**********************************************************************)

%entry  start_address End_of_Link;
name = IIC_UNDEF;
cond hsr1=0,hsr0=0, lsr = 1, m/tsr = 0.

%entry  start_address End_of_Link;
name = IIC_UNDEF;
cond hsr1=0,hsr0=0, lsr = 1, m/tsr = 1.

%entry start_address End_of_Link;
name = IIC_UNDEF;
cond hsr1=1,hsr0=0.