/*

  Zerocat Chipflasher --- Flash free firmware, kick the Management Engine.

  Copyright (C) 2016, 2017, 2018, 2020, 2021, 2022  Kai Mertens <kmx@posteo.net>

  This file is part of Zerocat Chipflasher.

  Zerocat Chipflasher is free software: you can redistribute it and/or
  modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  Zerocat Chipflasher is distributed in the hope that it will be
  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Zerocat Chipflasher.
  If not, see <http://www.gnu.org/licenses/>.


***/


/*

  Documentation
  =============


  Brief
  -----


  Inline Code Macros with Assembler, that provide fast SPI Bus access.


  Note
  ----


  Assembler directives are using bits that are within 9-bit address
  space, thus resulting in propeller port pins 0..8!


***/


# ifndef __FAST_SPI_H__
#   define __FAST_SPI_H__


// No Operation Command. Execution Time is 50ns @ 80MHz (5MHz Crystal).
#   define NOP            __asm__ volatile (                    \
                            "nop            'delay 50ns"        \
                            : /* no outputs */                  \
                            : /* no inputs */                   \
                          )

// No extra delay.
#   define t_NONE

// t as short as possible.
#   define t_FAST         NOP

// t which is really slow.
#   define t_SLOW         NOP; NOP; NOP

// Clock Delay
#   define tSCLK          t_NONE

// CE# Low to Output valid.
#   define tCLQV          t_NONE

// Data In Setup Time.
#   define tDSU           t_NONE

// Chip Select Time.
#   define tCSL           t_NONE

// Chip Deselect Time.
#   define tCSH           NOP; NOP

// Write Protect Hold Time.
#   define tSHWL          NOP; NOP

// Write Protect Setup Time.
#   define tWHSL          NOP; NOP

// Hold To Output Low-Z Time.
#   define tHHQX          NOP

// Hold To Output High-Z Time.
#   define tHLQZ          NOP

#   define CHIP_ON        __asm__ volatile (                                    \
                            "or dira, %0    'activate output, CE# goes low"     \
                            : /* no outputs */                                  \
                            : "i" (CEn_AVAIL)                                   \
                          ); tCSL

#   define CHIP_OFF       __asm__ volatile (                                        \
                            "andn dira, %0  'tristate, CE# goes high via pull-up"   \
                            : /* no outputs */                                      \
                            : "i" (CEn_AVAIL)                                       \
                          ); tCSH

#   define WPn_HIGH       __asm__ volatile (                \
                            "or outa, %0    'WP# high"      \
                            : /* no outputs */              \
                            : "i" (BIT_WPn)                 \
                          ); tWHSL

#   define WPn_LOW        __asm__ volatile (                \
                            "andn outa, %0  'WP# low"       \
                            : /* no outputs */              \
                            : "i" (BIT_WPn)                 \
                          ); tSHWL

#   define CLOCK_HIGH     __asm__ volatile (                \
                            "or outa, %0    'clock high"    \
                            : /* no outputs */              \
                            : "i" (SCLK_AVAIL)              \
                          ); tSCLK

#   define CLOCK_LOW      __asm__ volatile (                \
                            "andn outa, %0  'clock low"     \
                            : /* no outputs */              \
                            : "i" (SCLK_AVAIL)              \
                          ); tSCLK

#   define SO_HIGH        __asm__ volatile (                \
                            "or outa, %0    'SO high"       \
                            : /* no outputs */              \
                            : "i" (BIT_MOSI)                \
                          ); tDSU

#   define SO_LOW         __asm__ volatile (                \
                            "andn outa, %0  'SO low"        \
                            : /* no outputs */              \
                            : "i" (BIT_MOSI)                \
                          ); tDSU

/*
#   define HOLDn_HIGH     __asm__ volatile (                \
                            "or outa, %0    'HOLD# high"    \
                            :                               \
                            : "i" (BIT_HOLDn)               \
                          ); tHLQZ

#   define HOLDn_LOW      __asm__ volatile (                \
                            "andn outa, %0  'HOLD# low"     \
                            :                               \
                            : "i" (BIT_HOLDn)               \
                          ); tHHQX
*/

// Pin PIN_HOLDn is not directly addressable, thus C code is used.
// TODO: How to write assembler code for indirect addressing?
#   define HOLDn_HIGH     OUTA |= BIT_HOLDn; tHLQZ

// Pin PIN_HOLDn is not directly addressable, thus C code is used.
// TODO: How to write assembler code for indirect addressing?
#   define HOLDn_LOW      OUTA &= ~BIT_HOLDn; tHHQX

# endif
/* __FAST_SPI_H__ */
