#
#    Mecrisp-Quintus - A native code Forth implementation for RISC-V
#    Copyright (C) 2018  Matthias Koch
#
#    This program 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.
#
#    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#

# Logikfunktionen
# Logic.

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "and" # ( x1 x2 -- x1&x2 )
                        # Combines the top two stack elements using bitwise AND.
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  and x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:
opcodiereinsprung_and:
  push x1

  # Probe, ob sich die Konstante in einen einzigen Opcode passt:

  .ifdef mipscore
  li x5, 0xFFFF0000
  and x6, x3, x5
  bne x6, zero, 2f

  # Kurze Variante mit nur einem Opcode.

  li x5, 0x30630000
  or  x3, x3, x5
  j 3f

  .else

  li x5, 0xFFFFF800
  and x6, x3, x5
  beq x6, x5, 1f
  bne x6, zero, 2f

1:# Kurze Variante mit nur einem Opcode.

  sll x3, x3, 20
  li x5, 0x0001F193  # andi x3, x3, ...
  or  x3, x3, x5
  j 3f
  .endif

2:# Lange Variante mit zwei Opcodes.

  pushdaconst 5
  call registerliteralkomma

  .ifdef mipscore
  pushdaconst 0x00651824
  .else
  pushdaconst 0x0051F1B3 # and x3, x3, x5
  .endif
3:call komma

  pop x1
  ret

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "bic" # ( x1 x2 -- x1&~x2 )
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  inv x3
  and x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:

  inv x3
  j opcodiereinsprung_and

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "or" # ( x1 x2 -- x1|x2 )
                       # Combines the top two stack elements using bitwise OR.
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  or x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:

  push x1

  # Probe, ob sich die Konstante in einen einzigen Opcode passt:

  .ifdef mipscore
  li x5, 0xFFFF0000
  and x6, x3, x5
  bne x6, zero, 2f

  # Kurze Variante mit nur einem Opcode.

  li x5, 0x34630000
  or  x3, x3, x5
  j 3f

  .else

  li x5, 0xFFFFF800
  and x6, x3, x5
  beq x6, x5, 1f
  bne x6, zero, 2f

1:# Kurze Variante mit nur einem Opcode.

  sll x3, x3, 20
  li x5, 0x0001E193  # ori x3, x3, ...
  or  x3, x3, x5
  j 3f
  .endif

2:# Lange Variante mit zwei Opcodes.

  pushdaconst 5
  call registerliteralkomma

  .ifdef mipscore
  pushdaconst 0x00651825
  .else
  pushdaconst 0x0051E1B3 # or x3, x3, x5
  .endif
3:call komma

  pop x1
  ret

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "xor" # ( x1 x2 -- x1|x2 )
                        # Combines the top two stack elements using bitwise exclusive-OR.
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  xor x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:

  push x1

  # Probe, ob sich die Konstante in einen einzigen Opcode passt:

  .ifdef mipscore
  li x5, 0xFFFF0000
  and x6, x3, x5
  bne x6, zero, 2f

  # Kurze Variante mit nur einem Opcode.

  li x5, 0x38630000
  or  x3, x3, x5
  j 3f

  .else

  li x5, 0xFFFFF800
  and x6, x3, x5
  beq x6, x5, 1f
  bne x6, zero, 2f

1:# Kurze Variante mit nur einem Opcode.

  sll x3, x3, 20
  li x5, 0x0001C193  # xori x3, x3, ...
  or  x3, x3, x5
  j 3f
  .endif

2:# Lange Variante mit zwei Opcodes.

  pushdaconst 5
  call registerliteralkomma

  .ifdef mipscore
  pushdaconst 0x00651826
  .else
  pushdaconst 0x0051C1B3 # xor x3, x3, x5
  .endif
3:call komma

  pop x1
  ret

# -----------------------------------------------------------------------------
  Definition Flag_foldable_1, "clz" # ( x -- u )
                        # Counts leading zeroes in x.
# -----------------------------------------------------------------------------
  li x5, 32
  beq x3, zero, 2f # If TOS contains 0 we have 32 leading zeros.
  li x5, 0         # No zeros counted yet.

1:blt x3, zero, 2f # Stop if an one will be shifted out.
  sll x3, x3, 1    # Shift TOS one place
  # beq x3, zero, 2f # Stop if register is zero.
  addi x5, x5, 1
  j 1b

2:mv x3, x5
  ret

# -----------------------------------------------------------------------------
  Definition Flag_foldable_1|Flag_inline, "ror" # ( x -- x' ) # Um eine Stelle rechts rotieren
# -----------------------------------------------------------------------------
  # Rotate right by one bit place
  slli x5, x3, 31
  srli x3, x3, 1
  or x3, x3, x5
  ret
  
# -----------------------------------------------------------------------------
  Definition Flag_foldable_1|Flag_inline, "rol" # ( x -- x' ) # Um eine Stelle links rotieren
# -----------------------------------------------------------------------------
  # Rotate left by one bit place
  srli x5, x3, 31
  slli x3, x3, 1
  or x3, x3, x5
  ret

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "arshift" # ( x n -- x' )
                            # Shifts 'x' right by 'n' bits, shifting in x's MSB.
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  sra x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:

  # Die Schübe nehmen alle nur 5 Bit Schubweite auf. Alles andere wird mit $1F and wegmaskiert.
  andi x3, x3, 0x1F
  .ifdef mipscore
  slli x3, x3, 6
  li x5, 0x00031803
  .else
  slli x3, x3, 20
  li x5, 0x4001D193 # srai x3, x3, 0
  .endif
  or x3, x3, x5
  j komma

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "rshift" # ( x n -- x' )
                           # Shifts 'x' right by 'n' bits.
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  srl x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:

  # Die Schübe nehmen alle nur 5 Bit Schubweite auf. Alles andere wird mit $1F and wegmaskiert.
  andi x3, x3, 0x1F
  .ifdef mipscore
  slli x3, x3, 6
  li x5, 0x00031802
  .else
  slli x3, x3, 20
  li x5, 0x0001D193 # srli x3, x3, 0
  .endif
  or x3, x3, x5
  j komma

# -----------------------------------------------------------------------------
  Definition Flag_foldable_2|Flag_inline|Flag_opcodierbar, "lshift" # ( x n -- x' )
                           # Shifts 'x' left by 'n' bits.
# -----------------------------------------------------------------------------
  lw x5, 0(x4)
  addi x4, x4, 4
  sll x3, x5, x3
  ret

  # ---------------------------------------------
  #  Opcodier-Einsprung:

  # Die Schübe nehmen alle nur 5 Bit Schubweite auf. Alles andere wird mit $1F and wegmaskiert.
  andi x3, x3, 0x1F
  .ifdef mipscore
  slli x3, x3, 6
  li x5, 0x00031800
  .else
  slli x3, x3, 20
  li x5, 0x00019193 # slli x3, x3, 0
  .endif
  or x3, x3, x5
  j komma

# -----------------------------------------------------------------------------
  Definition Flag_foldable_1|Flag_inline, "not" # ( x -- ~x )
# -----------------------------------------------------------------------------
  inv x3
  ret

# -----------------------------------------------------------------------------
  Definition Flag_foldable_1|Flag_inline, "invert" # ( x -- ~x )
# -----------------------------------------------------------------------------
  inv x3
  ret
