#------------------------------------------------------------------------------
#
# LoongArch ASM CSR operation functions
#
# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#------------------------------------------------------------------------------

#include <Register/LoongArch64/Csr.h>

ASM_GLOBAL ASM_PFX (AsmCsrRead)
ASM_GLOBAL ASM_PFX (AsmCsrWrite)
ASM_GLOBAL ASM_PFX (AsmCsrXChg)

.macro AsmCsrRd Sel
  csrrd   $a0, \Sel
  jirl    $zero, $ra, 0
.endm

.macro AsmCsrWr Sel
  csrwr   $a0, \Sel
  jirl    $zero, $ra, 0
.endm

.macro AsmCsrXChange Sel
  csrxchg $a0, $a1, \Sel
  jirl    $zero, $ra, 0
.endm

ASM_PFX(AsmCsrRead):
  blt      $a0, $zero, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_EBASE
  bltu     $t0, $a0, TlbCsrRd

BasicCsrRd:
  la.pcrel $t0, BasicCsrRead
  alsl.d   $t0, $a0, $t0, 3
  jirl     $zero, $t0, 0

TlbCsrRd:
  li.w     $t0, LOONGARCH_CSR_TLBIDX
  bltu     $a0, $t0, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_RVACFG
  bltu     $t0, $a0, CfgCsrRd
  la.pcrel $t0, TlbCsrRead
  addi.w   $t1, $a0, -LOONGARCH_CSR_TLBIDX
  alsl.d   $t0, $t1, $t0, 3
  jirl     $zero, $t0, 0

CfgCsrRd:
  li.w     $t0, LOONGARCH_CSR_CPUNUM
  bltu     $a0, $t0, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_PRCFG3
  bltu     $t0, $a0, KcsCsrRd
  la.pcrel $t0, CfgCsrRead
  addi.w   $t1, $a0, -LOONGARCH_CSR_CPUNUM
  alsl.d   $t0, $t1, $t0, 3
  jirl     $zero, $t0, 0

KcsCsrRd:
  li.w     $t0, LOONGARCH_CSR_KS0
  bltu     $a0, $t0, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_KS8
  bltu     $t0, $a0, StableTimerCsrRd
  la.pcrel $t0, KcsCsrRead
  addi.w   $t1, $a0, -LOONGARCH_CSR_KS0
  alsl.d   $t0, $t1, $t0, 3
  jirl     $zero, $t0, 0

StableTimerCsrRd:
  li.w     $t0, LOONGARCH_CSR_TMID
  bltu     $a0, $t0, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_TINTCLR
  bltu     $t0, $a0, TlbRefillCsrRd
  la.pcrel $t0, StableTimerCsrRead
  addi.w   $t1, $a0, -LOONGARCH_CSR_TMID
  alsl.d   $t0, $t1, $t0, 3
  jirl     $zero, $t0, 0

TlbRefillCsrRd:
  li.w     $t0, LOONGARCH_CSR_TLBREBASE
  bltu     $a0, $t0, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_TLBREHI
  bltu     $t0, $a0, DirMapCsrRd
  la.pcrel $t0, TlbRefillCsrRead
  addi.w   $t1, $a0, -LOONGARCH_CSR_TLBREBASE
  alsl.d   $t0, $t1, $t0, 3
  jirl     $zero, $t0, 0

DirMapCsrRd:
  li.w     $t0, LOONGARCH_CSR_DMWIN0
  bltu     $a0, $t0, ReadSelNumErr
  li.w     $t0, LOONGARCH_CSR_DMWIN3
  bltu     $t0, $a0, ReadSelNumErr
  la.pcrel $t0, DirMapCsrRead
  addi.w   $t1, $a0, -LOONGARCH_CSR_DMWIN0
  alsl.d   $t0, $t1, $t0, 3
  jirl     $zero, $t0, 0

ReadSelNumErr:
  break    0

BasicCsrRead:
  CsrSel = LOONGARCH_CSR_CRMD
  .rept LOONGARCH_CSR_EBASE - LOONGARCH_CSR_CRMD + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

TlbCsrRead:
  CsrSel = LOONGARCH_CSR_TLBIDX
  .rept LOONGARCH_CSR_RVACFG - LOONGARCH_CSR_TLBIDX + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

CfgCsrRead:
  CsrSel = LOONGARCH_CSR_CPUNUM
  .rept LOONGARCH_CSR_PRCFG3 - LOONGARCH_CSR_CPUNUM + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

KcsCsrRead:
  CsrSel = LOONGARCH_CSR_KS0
  .rept LOONGARCH_CSR_KS8 - LOONGARCH_CSR_KS0 + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

StableTimerCsrRead:
  CsrSel = LOONGARCH_CSR_TMID
  .rept LOONGARCH_CSR_TINTCLR - LOONGARCH_CSR_TMID + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

TlbRefillCsrRead:
  CsrSel = LOONGARCH_CSR_TLBREBASE
  .rept LOONGARCH_CSR_TLBREHI - LOONGARCH_CSR_TLBREBASE + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

DirMapCsrRead:
  CsrSel = LOONGARCH_CSR_DMWIN0
  .rept LOONGARCH_CSR_DMWIN3 - LOONGARCH_CSR_DMWIN0 + 1
    AsmCsrRd CsrSel
    CsrSel = CsrSel + 1
  .endr

ASM_PFX(AsmCsrWrite):
  blt      $a0, $zero, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_EBASE
  bltu     $t0, $a0, TlbCsrWr

BasicCsrWr:
  la.pcrel $t0, BasicCsrWrite
  alsl.d   $t0, $a0, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

TlbCsrWr:
  li.w     $t0, LOONGARCH_CSR_TLBIDX
  bltu     $a0, $t0, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_RVACFG
  bltu     $t0, $a0, CfgCsrWr
  la.pcrel $t0, TlbCsrWrite
  addi.w   $t1, $a0, -LOONGARCH_CSR_TLBIDX
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

CfgCsrWr:
  li.w     $t0, LOONGARCH_CSR_CPUNUM
  bltu     $a0, $t0, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_PRCFG3
  bltu     $t0, $a0, KcsCsrWr
  la.pcrel $t0, CfgCsrWrite
  addi.w   $t1, $a0, -LOONGARCH_CSR_CPUNUM
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

KcsCsrWr:
  li.w     $t0, LOONGARCH_CSR_KS0
  bltu     $a0, $t0, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_KS8
  bltu     $t0, $a0, StableTimerCsrWr
  la.pcrel $t0, KcsCsrWrite
  addi.w   $t1, $a0, -LOONGARCH_CSR_KS0
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

StableTimerCsrWr:
  li.w     $t0, LOONGARCH_CSR_TMID
  bltu     $a0, $t0, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_TINTCLR
  bltu     $t0, $a0, TlbRefillCsrWr
  la.pcrel $t0, StableTimerCsrWrite
  addi.w   $t1, $a0, -LOONGARCH_CSR_TMID
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

TlbRefillCsrWr:
  li.w     $t0, LOONGARCH_CSR_TLBREBASE
  bltu     $a0, $t0, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_TLBREHI
  bltu     $t0, $a0, DirMapCsrWr
  la.pcrel $t0, TlbRefillCsrWrite
  addi.w   $t1, $a0, -LOONGARCH_CSR_TLBREBASE
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

DirMapCsrWr:
  li.w     $t0, LOONGARCH_CSR_DMWIN0
  bltu     $a0, $t0, WriteSelNumErr
  li.w     $t0, LOONGARCH_CSR_DMWIN3
  bltu     $t0, $a0, WriteSelNumErr
  la.pcrel $t0, DirMapCsrWrite
  addi.w   $t1, $a0, -LOONGARCH_CSR_DMWIN0
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  jirl     $zero, $t0, 0

WriteSelNumErr:
  break    0

BasicCsrWrite:
  CsrSel = LOONGARCH_CSR_CRMD
  .rept LOONGARCH_CSR_EBASE - LOONGARCH_CSR_CRMD + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr

TlbCsrWrite:
  CsrSel = LOONGARCH_CSR_TLBIDX
  .rept LOONGARCH_CSR_RVACFG - LOONGARCH_CSR_TLBIDX + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr

CfgCsrWrite:
  CsrSel = LOONGARCH_CSR_CPUNUM
  .rept LOONGARCH_CSR_PRCFG3 - LOONGARCH_CSR_CPUNUM + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr

KcsCsrWrite:
  CsrSel = LOONGARCH_CSR_KS0
  .rept LOONGARCH_CSR_KS8 - LOONGARCH_CSR_KS0 + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr

StableTimerCsrWrite:
  CsrSel = LOONGARCH_CSR_TMID
  .rept LOONGARCH_CSR_TINTCLR - LOONGARCH_CSR_TMID + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr

TlbRefillCsrWrite:
  CsrSel = LOONGARCH_CSR_TLBREBASE
  .rept LOONGARCH_CSR_TLBREHI - LOONGARCH_CSR_TLBREBASE + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr

DirMapCsrWrite:
  CsrSel = LOONGARCH_CSR_DMWIN0
  .rept LOONGARCH_CSR_DMWIN3 - LOONGARCH_CSR_DMWIN0 + 1
    AsmCsrWr CsrSel
    CsrSel = CsrSel + 1
  .endr


ASM_PFX(AsmCsrXChg):
  blt      $a0, $zero, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_EBASE
  bltu     $t0, $a0, TlbCsrXchg

BasicCsrXchg:
  la.pcrel $t0, BasicCsrXchange
  alsl.d   $t0, $a0, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

TlbCsrXchg:
  li.w     $t0, LOONGARCH_CSR_TLBIDX
  bltu     $a0, $t0, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_RVACFG
  bltu     $t0, $a0, CfgCsrXchg
  la.pcrel $t0, TlbCsrXchange
  addi.w   $t1, $a0, -LOONGARCH_CSR_TLBIDX
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

CfgCsrXchg:
  li.w     $t0, LOONGARCH_CSR_CPUNUM
  bltu     $a0, $t0, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_PRCFG3
  bltu     $t0, $a0, KcsCsrXchg
  la.pcrel $t0, CfgCsrXchange
  addi.w   $t1, $a0, -LOONGARCH_CSR_CPUNUM
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

KcsCsrXchg:
  li.w     $t0, LOONGARCH_CSR_KS0
  bltu     $a0, $t0, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_KS8
  bltu     $t0, $a0, StableTimerCsrXchg
  la.pcrel $t0, KcsCsrXchange
  addi.w   $t1, $a0, -LOONGARCH_CSR_KS0
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

StableTimerCsrXchg:
  li.w     $t0, LOONGARCH_CSR_TMID
  bltu     $a0, $t0, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_TINTCLR
  bltu     $t0, $a0, TlbRefillCsrXchg
  la.pcrel $t0, StableTimerCsrXchange
  addi.w   $t1, $a0, -LOONGARCH_CSR_TMID
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

TlbRefillCsrXchg:
  li.w     $t0, LOONGARCH_CSR_TLBREBASE
  bltu     $a0, $t0, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_TLBREHI
  bltu     $t0, $a0, DirMapCsrXchg
  la.pcrel $t0, TlbRefillCsrXchange
  addi.w   $t1, $a0, -LOONGARCH_CSR_TLBREBASE
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

DirMapCsrXchg:
  li.w     $t0, LOONGARCH_CSR_DMWIN0
  bltu     $a0, $t0, XchgSelNumErr
  li.w     $t0, LOONGARCH_CSR_DMWIN3
  bltu     $t0, $a0, XchgSelNumErr
  la.pcrel $t0, DirMapCsrXchange
  addi.w   $t1, $a0, -LOONGARCH_CSR_DMWIN0
  alsl.d   $t0, $t1, $t0, 3
  move     $a0, $a1
  move     $a1, $a2
  jirl     $zero, $t0, 0

XchgSelNumErr:
  break    0

BasicCsrXchange:
  CsrSel = LOONGARCH_CSR_CRMD
  .rept LOONGARCH_CSR_EBASE - LOONGARCH_CSR_CRMD + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr

TlbCsrXchange:
  CsrSel = LOONGARCH_CSR_TLBIDX
  .rept LOONGARCH_CSR_RVACFG - LOONGARCH_CSR_TLBIDX + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr

CfgCsrXchange:
  CsrSel = LOONGARCH_CSR_CPUNUM
  .rept LOONGARCH_CSR_PRCFG3 - LOONGARCH_CSR_CPUNUM + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr

KcsCsrXchange:
  CsrSel = LOONGARCH_CSR_KS0
  .rept LOONGARCH_CSR_KS8 - LOONGARCH_CSR_KS0 + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr

StableTimerCsrXchange:
  CsrSel = LOONGARCH_CSR_TMID
  .rept LOONGARCH_CSR_TINTCLR - LOONGARCH_CSR_TMID + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr

TlbRefillCsrXchange:
  CsrSel = LOONGARCH_CSR_TLBREBASE
  .rept LOONGARCH_CSR_TLBREHI - LOONGARCH_CSR_TLBREBASE + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr

DirMapCsrXchange:
  CsrSel = LOONGARCH_CSR_DMWIN0
  .rept LOONGARCH_CSR_DMWIN3 - LOONGARCH_CSR_DMWIN0 + 1
    AsmCsrXChange CsrSel
    CsrSel = CsrSel + 1
  .endr
.end
