"""Test some more complex stimuli."""

from hdltools.sim import HDLSimulationObject
from hdltools.sim.simulation import HDLSimulation
from hdltools.vcd import VCDDump
from hdltools.vcd.generator import VCDGenerator
from collections import deque
import sys


class HDLSPIMaster(HDLSimulationObject):
    """SPI Master."""

    def __init__(self, identifier=None, clk_period=1, tx_size=8):
        """Initialize."""
        super(HDLSPIMaster, self).__init__(identifier)
        # outputs
        self.ce = self.output('ce', initial=0)
        self.clk = self.output('clk', initial=0)
        self.do = self.output('do', initial=0)

        # data buffer
        self.queue = deque()

        # internal states
        self.tx_size = tx_size
        self.clk_period = clk_period
        self._state = 'idle'
        self._data = None
        self._size = None
        self._stop = False
        self._last_clk = 0

    def transmit(self, data, size=None, stop=True):
        """Transmit one block."""
        # put into queue for transmitting
        if size is None:
            size = self.tx_size
        sys.stderr.write('{} : stop = {}\n'.format(hex(data), stop))
        self.queue.appendleft([data, size, stop])

    def transmit_blocks(self, *data, block_size=None, stop=True):
        """Transmit a few blocks of same size."""
        if block_size is None:
            block_size = self.tx_size
        for index, block in enumerate(data):
            if stop is True:
                _stop = bool(index == len(data) - 1)
            else:
                _stop = False
            self.transmit(block, size=block_size, stop=_stop)

    def logic(self, input_states, **kwargs):
        """Perform internal logic."""
        if self._state == 'idle':
            if len(self.queue) > 0:
                self._state = 'transmit'
                # LSB first
                self._pos = 0
                self._data, self._size, stop = self.queue.pop()
                self.clk = False
                if self._stop is True:
                    self.ce = False
                self._stop = stop
            else:
                self.ce = False
                self.do = False
                self.clk = False
                self._data = None
        elif self._state == 'transmit':
            # chip enable
            self.ce = True
            if self._last_clk >= self.clk_period - 1:
                # CPOL = 0
                self.clk = not self.clk
                self._last_clk = 0

                # data output
                if self.clk is True:
                    self.do = bool(self._data & (1 << self._pos))

                    self._pos += 1
                    if self._pos > self._size - 1:
                        self._state = 'idle'
                        #self.ce = False
            else:
                # wait
                self._last_clk += 1


if __name__ == '__main__':

    sim = HDLSimulation()
    spi = HDLSPIMaster('spi')

    sim.add_stimulus(spi)

    spi.transmit_blocks(0x10, 0xAA)
    spi.transmit_blocks(0x80)
    dump = sim.simulate(100)

    vcd_dump = VCDDump('spi')
    vcd_dump.add_variables(**sim.report_signals())
    vcd_dump.load_dump(dump)
    vcd = VCDGenerator()

    print(vcd.dump_element(vcd_dump))

@@ -372,18 +372,51 @@
 d=1,
- tx_size=8
+%0A                 tx_size=8, lsb_first=True
 ):%0A 
@@ -723,23 +723,30 @@
   # 
-internal states
+default logic behavior
 %0A   
@@ -810,16 +810,78 @@
 _period%0A
+        self.lsb_first = lsb_first%0A%0A        # internal states%0A
         
@@ -2077,32 +2077,74 @@
 elf.clk = False%0A
+                # check last block's stop%0A
                 
@@ -2194,32 +2194,82 @@
 self.ce = False%0A
+                # store stop state for next block%0A
                 
@@ -2744,32 +2744,83 @@
 lf.clk is True:%0A
+                    if self.lsb_first is True:%0A    
                 
@@ -2868,16 +2868,170 @@
 f._pos))
+%0A                    else:%0A                        self.do = bool(self._data &%0A                                       (1 %3C%3C (self._size - self._pos - 1)))
 %0A%0A      
@@ -3106,24 +3106,24 @@
 ._size - 1:%0A
+
             
@@ -3159,49 +3159,8 @@
 le'%0A
-                        #self.ce = False%0A
     

add lsb first or msb first option