;*****************************************************************************
;*
;*                            Open Watcom Project
;*
;*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;*  ========================================================================
;*
;*    This file contains Original Code and/or Modifications of Original
;*    Code as defined in and that are subject to the Sybase Open Watcom
;*    Public License version 1.0 (the 'License'). You may not use this file
;*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;*    provided with the Original Code and Modifications, and is also
;*    available at www.sybase.com/developer/opensource.
;*
;*    The Original Code and all software distributed under the License are
;*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;*    NON-INFRINGEMENT. Please see the License for the specific language
;*    governing rights and limitations under the License.
;*
;*  ========================================================================
;*
;* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
;*               DESCRIBE IT HERE!
;*
;*****************************************************************************


//
// CORTNS       : i/o co-routines (common to READ and WRITE)
//

#include "ppc_regs.h"
#include "ptypes.h"

// external symbols used by this module
.extern __ReleaseIOSys

.extern IORslt
.extern __ASTACKSIZ
.extern __ASTACKPTR
.extern __SwitchStkLow

.data
.align 4
SaveRegs: // assembler does not support .quad directive
        .long   0       // sp
        .long   0       // lk

.align 0
.text

// README !!!
// Setting the alternative stack (__ASTACKSIZ) size has been moved to a C file.

#define FRAME_SIZE      0xf0            // define stack frame to discard when restoring
                                        // state (20 registers*4 + 18 fp regs*8
                                        // + link*4 + cr*4) align 8 boundary

.globl  SwitchToGen
// .ent SwitchToGen
        b       j^SwitchToRT            // Use same routine as to switch in
// .end SwitchToGen

.globl  SwitchToRT
// .ent SwitchToRT
SwitchToRT:
        lis     t1, h^SaveRegs          // prepare loading register
        addi    t1, t1, l^SaveRegs      // ...
        subi    sp, sp, FRAME_SIZE      // Push current env onto stack

        stfd    f14, 0x00(sp)           // Push floats
        stfd    f15, 0x08(sp)           // ...
        stfd    f16, 0x10(sp)           // ...
        stfd    f17, 0x18(sp)           // ...
        stfd    f18, 0x20(sp)           // ...
        stfd    f19, 0x28(sp)           // ...
        stfd    f20, 0x30(sp)           // ...
        stfd    f21, 0x38(sp)           // ...
        stfd    f22, 0x40(sp)           // ...
        stfd    f23, 0x48(sp)           // ...
        stfd    f24, 0x50(sp)           // ...
        stfd    f25, 0x58(sp)           // ...
        stfd    f26, 0x60(sp)           // ...
        stfd    f27, 0x68(sp)           // ...
        stfd    f28, 0x70(sp)           // ...
        stfd    f29, 0x78(sp)           // ...
        stfd    f30, 0x80(sp)           // ...
        stfd    f31, 0x88(sp)           // ...

        stw     s0, 0x90(sp)            // push the gprs
        stw     s1, 0x94(sp)            // ...
        stw     s2, 0x98(sp)            // ...
        stw     s3, 0x9c(sp)            // ...
        stw     s4, 0xa0(sp)            // ...
        stw     s5, 0xa4(sp)            // ...
        stw     s6, 0xa8(sp)            // ...
        stw     s7, 0xac(sp)            // ...
        stw     s8, 0xb0(sp)            // ...
        stw     s9, 0xb4(sp)            // ...
        stw     s10, 0xb8(sp)           // ...
        stw     s11, 0xbc(sp)           // ...
        stw     s12, 0xc0(sp)           // ...
        stw     s13, 0xc4(sp)           // ...
        stw     s14, 0xc8(sp)           // ...
        stw     s15, 0xcc(sp)           // ...
        stw     s16, 0xd0(sp)           // ...
        stw     s17, 0xd4(sp)           // ...

        stw     rtoc, 0xd8(sp)          // save rtoc
        mflr    t0                      // save link register
        stw     t0, 0xdc(sp)            // ...
        mfcr    t0                      // save cr
        stw     t0, 0xe0(sp)            // ...


        addi    t0, sp, 0               // switch stacks
        lwz     sp, 0x00(t1)            // ...
        stw     t0, 0x00(t1)            // ...

        addi    s0, a0, 0               // save return value
        lis     t0, h^__SwitchStkLow    // Load address of stacklow switcher
        addi    t0, t0, l^__SwitchStkLow// ...
        lwz     t0, 0x00(t0)            // ...
        mtlr    t0                      // prepare to link
        subi    sp, sp, 0x30            // set up caller stack frame
        li      t0, 0                   // and nullify chain
        stw     t0, 0x00(sp)
        blrl                            // switch stack lows
        addi    sp, sp, 0x30            // destroy caller stack frame
        addi    a0, s0, 0               // restore return value

        lfd     f14, 0x00(sp)           // Pop floats
        lfd     f15, 0x08(sp)           // ...
        lfd     f16, 0x10(sp)           // ...
        lfd     f17, 0x18(sp)           // ...
        lfd     f18, 0x20(sp)           // ...
        lfd     f19, 0x28(sp)           // ...
        lfd     f20, 0x30(sp)           // ...
        lfd     f21, 0x38(sp)           // ...
        lfd     f22, 0x40(sp)           // ...
        lfd     f23, 0x48(sp)           // ...
        lfd     f24, 0x50(sp)           // ...
        lfd     f25, 0x58(sp)           // ...
        lfd     f26, 0x60(sp)           // ...
        lfd     f27, 0x68(sp)           // ...
        lfd     f28, 0x70(sp)           // ...
        lfd     f29, 0x78(sp)           // ...
        lfd     f30, 0x80(sp)           // ...
        lfd     f31, 0x88(sp)           // ...

        lwz     s0, 0x90(sp)            // pop the gprs
        lwz     s1, 0x94(sp)            // ...
        lwz     s2, 0x98(sp)            // ...
        lwz     s3, 0x9c(sp)            // ...
        lwz     s4, 0xa0(sp)            // ...
        lwz     s5, 0xa4(sp)            // ...
        lwz     s6, 0xa8(sp)            // ...
        lwz     s7, 0xac(sp)            // ...
        lwz     s8, 0xb0(sp)            // ...
        lwz     s9, 0xb4(sp)            // ...
        lwz     s10, 0xb8(sp)           // ...
        lwz     s11, 0xbc(sp)           // ...
        lwz     s12, 0xc0(sp)           // ...
        lwz     s13, 0xc4(sp)           // ...
        lwz     s14, 0xc8(sp)           // ...
        lwz     s15, 0xcc(sp)           // ...
        lwz     s16, 0xd0(sp)           // ...
        lwz     s17, 0xd4(sp)           // ...

        lwz     rtoc, 0xd8(sp)          // load rtoc
        lwz     t0, 0xdc(sp)            // restore link register
        mtlr    t0                      // ...
        lwz     t0, 0xe0(sp)            // restore cr
        mtcrf   0xff, t0                // ...

        addi    sp, sp, FRAME_SIZE      // destroy frame
        blr                             // return
// .end SwitchToRT


// on entry a0 contains address of read or write routine
//          lr contains the return address
//
.globl  RdWrCommon
// .ent RdWrCommon
RdWrCommon:
        lis     t1, h^SaveRegs          // prepare loading register
        addi    t1, t1, l^SaveRegs      // ..
        mflr    t0                      // save link register
        stw     t0, 0x04(t1)            // ...
        subi    sp, sp, FRAME_SIZE      // Create stack frame

        stfd    f14, 0x00(sp)           // Push floats
        stfd    f15, 0x08(sp)           // ...
        stfd    f16, 0x10(sp)           // ...
        stfd    f17, 0x18(sp)           // ...
        stfd    f18, 0x20(sp)           // ...
        stfd    f19, 0x28(sp)           // ...
        stfd    f20, 0x30(sp)           // ...
        stfd    f21, 0x38(sp)           // ...
        stfd    f22, 0x40(sp)           // ...
        stfd    f23, 0x48(sp)           // ...
        stfd    f24, 0x50(sp)           // ...
        stfd    f25, 0x58(sp)           // ...
        stfd    f26, 0x60(sp)           // ...
        stfd    f27, 0x68(sp)           // ...
        stfd    f28, 0x70(sp)           // ...
        stfd    f29, 0x78(sp)           // ...
        stfd    f30, 0x80(sp)           // ...
        stfd    f31, 0x88(sp)           // ...

        stw     s0, 0x90(sp)            // push the gprs
        stw     s1, 0x94(sp)            // ...
        stw     s2, 0x98(sp)            // ...
        stw     s3, 0x9c(sp)            // ...
        stw     s4, 0xa0(sp)            // ...
        stw     s5, 0xa4(sp)            // ...
        stw     s6, 0xa8(sp)            // ...
        stw     s7, 0xac(sp)            // ...
        stw     s8, 0xb0(sp)            // ...
        stw     s9, 0xb4(sp)            // ...
        stw     s10, 0xb8(sp)           // ...
        stw     s11, 0xbc(sp)           // ...
        stw     s12, 0xc0(sp)           // ...
        stw     s13, 0xc4(sp)           // ...
        stw     s14, 0xc8(sp)           // ...
        stw     s15, 0xcc(sp)           // ...
        stw     s16, 0xd0(sp)           // ...
        stw     s17, 0xd4(sp)           // ...

        stw     rtoc, 0xd8(sp)          // save rtoc
        mflr    t0                      // save link register
        stw     t0, 0xdc(sp)            // ...
        mfcr    t0                      // save cr
        stw     t0, 0xe0(sp)            // ...

        stw     sp, 0x00(t1)            // save stack pointer of executing code
        lis     sp, h^__ASTACKPTR       // get start of new stack
        addi    sp, sp, l^__ASTACKPTR   // ...
        lwz     sp, 0x00(sp)            // ...

        subi    sp, sp, 0x38            // create false caller stack frame
        li      t0, 0                   // and nullify chain
        stw     t0, 0x00(sp)

        // switch to new stacklow
        stw     a0, 0x30(sp)            // save return value
        lis     t0, h^__SwitchStkLow    // Load address of stacklow switcher
        addi    t0, t0, l^__SwitchStkLow// ...
        lwz     t0, 0x00(t0)            // ...
        mtlr    t0                      // prepare to link
        blrl                            // switch stack lows
        lwz     a0, 0x30(sp)            // restore return value

        // a0 still contains the io routine address
        mtlr    a0
        blrl                            // start i/o operation

        lis     t1, h^SaveRegs          // prepare loading register
        addi    t1, t1, l^SaveRegs      // ..
        lwz     sp, 0x00(t1)            // return sp
        lwz     t0, 0x04(t1)            // return lr
        mtlr    t0                      // ...

        cmpi    0, a0, 0                // check if i/o error then do not update
        bne     no_update               // ...
          lfd   f14, 0x00(sp)           // Pop floats
          lfd   f15, 0x08(sp)           // ...
          lfd   f16, 0x10(sp)           // ...
          lfd   f17, 0x18(sp)           // ...
          lfd   f18, 0x20(sp)           // ...
          lfd   f19, 0x28(sp)           // ...
          lfd   f20, 0x30(sp)           // ...
          lfd   f21, 0x38(sp)           // ...
          lfd   f22, 0x40(sp)           // ...
          lfd   f23, 0x48(sp)           // ...
          lfd   f24, 0x50(sp)           // ...
          lfd   f25, 0x58(sp)           // ...
          lfd   f26, 0x60(sp)           // ...
          lfd   f27, 0x68(sp)           // ...
          lfd   f28, 0x70(sp)           // ...
          lfd   f29, 0x78(sp)           // ...
          lfd   f30, 0x80(sp)           // ...
          lfd   f31, 0x88(sp)           // ...

          lwz   s0, 0x90(sp)            // pop the gprs
          lwz   s1, 0x94(sp)            // ...
          lwz   s2, 0x98(sp)            // ...
          lwz   s3, 0x9c(sp)            // ...
          lwz   s4, 0xa0(sp)            // ...
          lwz   s5, 0xa4(sp)            // ...
          lwz   s6, 0xa8(sp)            // ...
          lwz   s7, 0xac(sp)            // ...
          lwz   s8, 0xb0(sp)            // ...
          lwz   s9, 0xb4(sp)            // ...
          lwz   s10, 0xb8(sp)           // ...
          lwz   s11, 0xbc(sp)           // ...
          lwz   s12, 0xc0(sp)           // ...
          lwz   s13, 0xc4(sp)           // ...
          lwz   s14, 0xc8(sp)           // ...
          lwz   s15, 0xcc(sp)           // ...
          lwz   s16, 0xd0(sp)           // ...
          lwz   s17, 0xd4(sp)           // ...

          lwz   rtoc, 0xd8(sp)          // load rtoc
          lwz   t0, 0xdc(sp)            // restore link register
          mtlr  t0                      // ...
          lwz   t0, 0xe0(sp)            // restore cr
          mtcrf 0xff, t0                // ...

no_update:                              // Do not restore from stack because
                                        // regs are same as initial call
        stw     a0, 0x34(sp)            // save result of io operation
        mflr    t0                      // save return address
        stw     t0, 0x30(sp)            // ...
        li      t0, 0                   // nulify callback chain
        stw     t0, 0x00(sp)            // ...

        lis     t0, h^__SwitchStkLow    // Load address of stacklow switcher
        addi    t0, t0, l^__SwitchStkLow// ...
        lwz     t0, 0x00(t0)            // ...
        mtlr    t0                      // prepare to link
        blrl                            // switch stack lows

        bl      j^__ReleaseIOSys        // release i/o system
        lwz     t0, 0x30(sp)            // restore return address
        mtlr    t0                      // ...
        lwz     a0, 0x34(sp)            // restore return value
        addi    sp, sp, FRAME_SIZE      // clear stack frame
        blr                             // return
// .end RdWrCommon


.globl  IOType
// .ent IOType                          // return to generated code
IOType:
        li      a0, 0                   // indicate operation succeeded
        b       j^SwitchToRT            // Use same routine as to switch in
// .end IOType


.globl  IOChar
// .ent IOChar
IOChar:
        lis     t1, h^IORslt            // load IORslt pointer
        addi    t1, t1, l^IORslt        // ...
        lwz     a1, 0x04(a0)            // Load SCB (its only 8 bytes :)
        lwz     a0, 0x00(a0)            // ...
        stw     a0, 0x00(t1)            // Store SCB in IORslt
        stw     a1, 0x04(t1)            // ...
        li      a0, PT_CHAR             // return CHARACTER*n type
        b       j^SwitchToRT            // return to caller of IOType()
// .end IOChar


.globl  IOStr
// .ent IOStr
IOStr:
        lis     t1, h^IORslt            // load IORslt pointer
        addi    t1, t1, l^IORslt        // ...
        stw     a0, 0x00(t1)            // Store SCB in IORslt
        stw     a1, 0x04(t1)            // ...
        li      a0, PT_CHAR             // return CHARACTER*n type
        b       j^SwitchToRT            // return to caller of IOType()
// .end IOStr


.globl  IOArr
// .ent IOArr                           // put array descriptor in IORslt
IOArr:
        lis     t1, h^IORslt            // load IORslt pointer
        addi    t1, t1, l^IORslt        // ...
        stw     a0, 0x00(t1)            // Store array record in IORslt (address)
        stw     a1, 0x04(t1)            // number of elements
        stw     a2, 0x0c(t1)            // type
        li      a0, PT_ARRAY            // return ARRAY type
        b       j^SwitchToRT            // return to caller of IOType()
// .end IOArr


.globl  IOChArr
// .ent IOChArr                         // put array descriptor in IORslt
IOChArr:
        lis     t1, h^IORslt            // load IORslt pointer
        addi    t1, t1, l^IORslt        // ...
        stw     a0, 0x00(t1)            // Store array record in IORslt (address)
        stw     a1, 0x04(t1)            // number of elements
        stw     a2, 0x08(t1)            // element size
        li      a1, PT_CHAR             // set type
        stw     a1, 0x0c(t1)            // ...
        li      a0, PT_ARRAY            // return ARRAY type
        b       j^SwitchToRT            // return to caller of IOType()
// .end IOChArr


.globl  __RT_EndIO
// .ent __RT_EndIO
__RT_EndIO:
        li      a0, PT_NOTYPE           // return "no i/o items remaining"
        b       j^SwitchToRT            // return to caller of IOType()
// .end __RT_EndIO
