; Entry point of kernel. Registers on entry:
rCI set r3 ; NKConfigurationInfo
rPI set r4 ; NKProcessorInfo
rSI set r5 ; NKSystemInfo
rDI set r6 ; NKDiagInfo

;   Other registers we use
rED set r8 ; Emulator Data Page

########################################################################

    li      r0, 0       ; Zero lots of fields

########################################################################

ClearSPRs
    mtsr    0, r0
    mtsr    1, r0
    mtsr    2, r0
    mtsr    3, r0
    mtsr    4, r0
    mtsr    5, r0
    mtsr    6, r0
    mtsr    7, r0
    mtsr    8, r0
    mtsr    9, r0
    mtsr    10, r0
    mtsr    11, r0
    mtsr    12, r0
    mtsr    13, r0
    mtsr    14, r0
    mtsr    15, r0

    mtspr   rtcl, r0
    mtspr   rtcu, r0

########################################################################

AlignFirstBankToPAR
    lwz     r12, NKConfigurationInfo.PA_RelocatedLowMemInit(rCI)    ; Scoop the ram before this ptr out of banks
                                                                    ; so that PAR starts at PA_RelocatedLowMemInit
    lwz     r11, NKSystemInfo.Bank0Start(rSI)
    add     r11, r11, r12
    stw     r11, NKSystemInfo.Bank0Start(rSI)

    lwz     r11, NKSystemInfo.Bank0Size(rSI)
    subf    r11, r12, r11
    stw     r11, NKSystemInfo.Bank0Size(rSI)

    lwz     r11, NKSystemInfo.PhysicalMemorySize(rSI)
    subf    r11, r12, r11
    stw     r11, NKSystemInfo.PhysicalMemorySize(rSI)

########################################################################

InitKernelMemory
    lwz     r15, NKSystemInfo.PhysicalMemorySize(rSI)   ; Size the HTAB for 2 entries per page
    subi    r15, r15, 1
    cntlzw  r12, r15
    lis     r14, 0x00ff                                 ; r14 = size-1
    srw     r14, r14, r12
    ori     r14, r14, 0xffff                            ; Obey architecture min and max size
    clrlwi  r14, r14, 9


    addis   r15, r15, 0x40                              ; Size the PageList
    rlwinm  r15, r15, 32-10, 10, 19                     ; (4b entry per page, total rounded to nearest page)


    add     r15, r15, r14                               ; Total = PageList + KDP/EDP (2 pages) + HTAB
    addi    r15, r15, 0x2001


    addi    r10, rSI, NKSystemInfo.EndOfBanks           ; Choose which bank of physical RAM to use
@nextbank                                               ; (no need to edit the bank table)
    lwz     r11, -4(r10)
    lwzu    r12, -8(r10)
    add     r11, r12, r11                               ; r12 = bank start, r11 = bank end

    andc    r13, r11, r14                               ; Check if HTAB fits in this bank,
    subf    r13, r15, r13                               ; while remaining aligned to its own size
    cmplw   r13, r12
    blt     @nextbank
    cmplw   r13, r11
    bgt     @nextbank


    add     r12, r13, r15                               ; base of address range we will use
    subf    r12, r14, r12                               ; r12 = ptr to HTAB (inside address range)
    inslwi  r12, r14, 16, 16                            ; SDR1 = HTABORG || HTABMASK (16b each)
    mtspr   sdr1, r12


    clrrwi  r11, r12, 16                                ; Init KDP, 2 pages below HTAB
    subi    r1, r11, 0x2000
    lwz     r11, KDP.CrashSDR1(r1)
    mtsprg  0, r1
    cmpw    r12, r11
    lis     r11, 0x7fff
    bne     @did_not_panic
    subf    r11, r13, r1
    addi    r11, r11, KDP.CrashTop
@did_not_panic

    subf    r12, r14, r15                               ; Erase all of kernel globals, except crash data
    subi    r12, r12, 1
@eraseloop
    subic.  r12, r12, 4
    subf    r10, r11, r12
    cmplwi  cr7, r10, KDP.CrashBtm - KDP.CrashTop
    ble     cr7, @skipwrite
    stwx    r0, r13, r12
@skipwrite
    bne     @eraseloop

########################################################################

CopyInfoRecords
    addi    r11, r1, KDP.ProcInfo
    li      r10, NKProcessorInfo.Size
@loop_procinfo
    subic.  r10, r10, 4
    lwzx    r12, rPI, r10
    stwx    r12, r11, r10
    bgt     @loop_procinfo

    addi    r11, r1, KDP.SysInfo
    li      r10, NKSystemInfo.Size
@loop_sysinfo
    subic.  r10, r10, 4
    lwzx    r12, rSI, r10
    stwx    r12, r11, r10
    bgt     @loop_sysinfo

    addi    r11, r1, KDP.DiagInfo
    li      r10, NKDiagInfo.Size
@loop_diaginfo
    subic.  r10, r10, 4
    lwzx    r12, rDI, r10
    stwx    r12, r11, r10
    bgt     @loop_diaginfo

########################################################################

InitKernelGlobals
    stw     rCI, KDP.ConfigInfoPtr(r1)

    addi    r12, r14, 1
    stw     r12, KDP.SysInfo.HashTableSize(r1)

    addi    rED, r1, 0x1000
    stw     rED, KDP.EDPPtr(r1)

    stw     r13, KDP.KernelMemoryBase(r1)
    add     r12, r13, r15
    stw     r12, KDP.KernelMemoryEnd(r1)

    lwz     r12, NKConfigurationInfo.PA_RelocatedLowMemInit(rCI)
    stw     r12, KDP.LowMemPtr(r1)

    lwz     r12, NKConfigurationInfo.SharedMemoryAddr(rCI)
    stw     r12, KDP.SharedMemoryAddr(r1)

    lwz     r12, NKConfigurationInfo.LA_EmulatorCode(rCI)
    lwz     r11, NKConfigurationInfo.KernelTrapTableOffset(rCI)
    add     r12, r12, r11
    stw     r12, KDP.EmuKCallTblPtrLogical(r1)

    bl      * + 4
    mflr    r12
    addi    r12, r12, 4 - *
    stw     r12, KDP.CodeBase(r1)

    _kaddr  r12, r12, MRBase
    stw     r12, KDP.MRBase(r1)

    lwz     r12, NKConfigurationInfo.LA_EmulatorData(rCI)
    lwz     r11, NKConfigurationInfo.ECBOffset(rCI)
    add     r12, r12, r11
    stw     r12, KDP.ECBPtrLogical(r1)

    add     r12, rED, r11
    stw     r12, KDP.ECBPtr(r1)
    stw     r12, KDP.ContextPtr(r1)

    lwz     r12, NKConfigurationInfo.TestIntMaskInit(rCI)
    stw     r12, KDP.TestIntMaskInit(r1)
    lwz     r12, NKConfigurationInfo.ClearIntMaskInit(rCI)
    stw     r12, KDP.ClearIntMaskInit(r1)
    lwz     r12, NKConfigurationInfo.PostIntMaskInit(rCI)
    stw     r12, KDP.PostIntMaskInit(r1)

    lwz     r12, NKConfigurationInfo.IplValueOffset(rCI)
    add     r12, rED, r12
    stw     r12, KDP.EmuIntLevelPtr(r1)

    lwz     r12, NKConfigurationInfo.SharedMemoryAddr(rCI)
    addi    r12, r12, 0x7c
    stw     r12, KDP.DebugIntPtr(r1)

    lwz     r12, NKConfigurationInfo.PageAttributeInit(rCI)
    stw     r12, KDP.PageAttributeInit(r1)

    addi    r13, r1, KDP.PageMap
    lwz     r12, NKConfigurationInfo.PageMapInitSize(rCI)
    stw     r13, KDP.PageMapStartPtr(r1)
    add     r13, r13, r12
    stw     r13, KDP.PageMapEndPtr(r1)

########################################################################

InitInfoRecords
    lwz     r11, NKConfigurationInfo.LA_InfoRecord(rCI)

    addi    r12, r11, 0xFC0
    stw     r12, 0xFC0(r1)
    stw     r0, 0xFC4(r1)

    addi    r12, r11, 0xFC8
    stw     r12, 0xFC8(r1)
    stw     r0, 0xFCC(r1)

    addi    r12, r11, 0xFD0
    stw     r12, 0xFD0(r1)
    stw     r0, 0xFD4(r1)

    addi    r12, r11, KDP.ProcInfo
    stw     r12, NKProcessorInfoPtr & 0xFFF(r1)
    li      r12, 0x100
    sth     r12, NKProcessorInfoVer & 0xFFF(r1)
    li      r12, NKProcessorInfo.Size
    sth     r12, NKProcessorInfoLen & 0xFFF(r1)

    addi    r12, r11, KDP.NKInfo
    stw     r12, NKNanoKernelInfoPtr & 0xFFF(r1)
    li      r12, kVersion
    sth     r12, NKNanoKernelInfoVer & 0xFFF(r1)
    li      r12, NKNanoKernelInfo.Size
    sth     r12, NKNanoKernelInfoLen & 0xFFF(r1)

    addi    r12, r11, KDP.DiagInfo
    stw     r12, NKDiagInfoPtr & 0xFFF(r1)
    li      r12, 0x100
    sth     r12, NKDiagInfoVer & 0xFFF(r1)
    li      r12, NKDiagInfo.Size
    sth     r12, NKDiagInfoLen & 0xFFF(r1)

    addi    r12, r11, KDP.SysInfo
    stw     r12, NKSystemInfoPtr & 0xFFF(r1)
    li      r12, 0x102
    sth     r12, NKSystemInfoVer & 0xFFF(r1)
    li      r12, NKSystemInfo.Size
    sth     r12, NKSystemInfoLen & 0xFFF(r1)

    addi    r12, r11, KDP.ProcInfo
    stw     r12, 0xFF8(r1)
    li      r12, 0x100
    sth     r12, 0xFFC(r1)
    li      r12, NKProcessorInfo.Size
    sth     r12, 0xFFE(r1)

########################################################################

InitProcessorInfo
    mfpvr   r12
    stw     r12, KDP.ProcInfo.ProcessorVersionReg(r1)
    srwi    r12, r12, 16
    lwz     r11, KDP.CodeBase(r1)
    addi    r10, r1, KDP.ProcInfo.Ovr
    li      r9, NKProcessorInfo.OvrEnd - NKProcessorInfo.Ovr

    cmpwi   r12, 1 ; 601
    _kaddr  r11, r11, ProcessorInfoTable
    beq     CopyProcessorInfo

    cmpwi   r12, 3 ; 603
    addi    r11, r11, NKProcessorInfo.OvrEnd - NKProcessorInfo.Ovr
    beq     CopyProcessorInfo

    cmpwi   r12, 4 ; 604
    addi    r11, r11, NKProcessorInfo.OvrEnd - NKProcessorInfo.Ovr
    beq     CopyProcessorInfo

    subi    r11, r11, NKProcessorInfo.OvrEnd - NKProcessorInfo.Ovr
    b       CopyProcessorInfo

ProcessorInfoTable
; 601
    dc.l    0x1000      ; PageSize
    dc.l    0x8000      ; DataCacheTotalSize
    dc.l    0x8000      ; InstCacheTotalSize
    dc.w    0x20        ; CoherencyBlockSize
    dc.w    0x20        ; ReservationGranuleSize
    dc.w    1           ; CombinedCaches
    dc.w    0x40        ; InstCacheLineSize
    dc.w    0x40        ; DataCacheLineSize
    dc.w    0x20        ; DataCacheBlockSizeTouch
    dc.w    0x20        ; InstCacheBlockSize
    dc.w    0x20        ; DataCacheBlockSize
    dc.w    8           ; InstCacheAssociativity
    dc.w    8           ; DataCacheAssociativity
    dc.w    0x100       ; TransCacheTotalSize
    dc.w    2           ; TransCacheAssociativity

; 603
    dc.l    0x1000      ; PageSize
    dc.l    0x2000      ; DataCacheTotalSize
    dc.l    0x2000      ; InstCacheTotalSize
    dc.w    0x20        ; CoherencyBlockSize
    dc.w    0x20        ; ReservationGranuleSize
    dc.w    0           ; CombinedCaches
    dc.w    0x20        ; InstCacheLineSize
    dc.w    0x20        ; DataCacheLineSize
    dc.w    0x20        ; DataCacheBlockSizeTouch
    dc.w    0x20        ; InstCacheBlockSize
    dc.w    0x20        ; DataCacheBlockSize
    dc.w    2           ; InstCacheAssociativity
    dc.w    2           ; DataCacheAssociativity
    dc.w    0x40        ; TransCacheTotalSize
    dc.w    2           ; TransCacheAssociativity

; 604
    dc.l    0x1000      ; PageSize
    dc.l    0x4000      ; DataCacheTotalSize
    dc.l    0x4000      ; InstCacheTotalSize
    dc.w    0x20        ; CoherencyBlockSize
    dc.w    0x20        ; ReservationGranuleSize
    dc.w    0           ; CombinedCaches
    dc.w    0x20        ; InstCacheLineSize
    dc.w    0x20        ; DataCacheLineSize
    dc.w    0x20        ; DataCacheBlockSizeTouch
    dc.w    0x20        ; InstCacheBlockSize
    dc.w    0x20        ; DataCacheBlockSize
    dc.w    4           ; InstCacheAssociativity
    dc.w    4           ; DataCacheAssociativity
    dc.w    0x40        ; TransCacheTotalSize
    dc.w    2           ; TransCacheAssociativity

CopyProcessorInfo
@loop
    subic.  r9, r9, 4
    lwzx    r12, r11, r9
    stwx    r12, r10, r9
    bgt     @loop

########################################################################

InitEmulator
    lwz     r11, NKConfigurationInfo.BootVersionOffset(rCI)     ; Copy 16b boot ver string
    lwz     r12, NKConfigurationInfo.BootstrapVersion(rCI)          ; ("Boot PDM 601 1.0")
    stwux   r12, r11, rED                                           ; into emulator data area
    lwz     r12, NKConfigurationInfo.BootstrapVersion + 4(rCI)
    stw     r12, 4(r11)
    lwz     r12, NKConfigurationInfo.BootstrapVersion + 8(rCI)
    stw     r12, 8(r11)
    lwz     r12, NKConfigurationInfo.BootstrapVersion + 12(rCI)
    stw     r12, 12(r11)


    lwz     r12, NKConfigurationInfo.LA_EmulatorCode(rCI)       ; Prepare the System ContextBlock:
    lwz     r11, NKConfigurationInfo.EmulatorEntryOffset(rCI)
    add     r12, r11, r12
    lwz     r11, NKConfigurationInfo.ECBOffset(rCI)                 ; address of declared Emu entry point
    add     r11, r11, rED
    stw     r12, CB.FaultSrcPC+4(r11)

    lwz     r12, NKConfigurationInfo.LA_EmulatorData(rCI)           ; address of Emu global page
    stw     r12, CB.FaultSrcR3+4(r11)

    lwz     r12, NKConfigurationInfo.LA_DispatchTable(rCI)          ; address of 512kb Emu dispatch table
    stw     r12, CB.FaultSrcR4+4(r11)

    lwz     r12, KDP.EmuKCallTblPtrLogical(r1)                      ; address of KCallReturnFromException trap
    stw     r12, CB.IntraState.HandlerReturn+4(r11)


    lwz     r10, KDP.LowMemPtr(r1)                              ; Zero out bottom 8k of Low Memory
    li      r9, 0x2000
@zeroloop
    subic.  r9, r9, 4
    stwx    r0, r10, r9
    bne     @zeroloop


    lwz     r11, NKConfigurationInfo.MacLowMemInitOffset(rCI)   ; Read address/value pairs from ConfigInfo
    lwz     r10, KDP.LowMemPtr(r1)                              ; and apply them to Low Memory
    lwzux   r9, r11, rCI
@setloop
    mr.     r9, r9
    beq     @donelm
    lwzu    r12, 4(r11)
    stwx    r12, r10, r9
    lwzu    r9, 4(r11)
    b       @setloop
@donelm


    mfpvr   r7                                                  ; Calculate Flags:
    srwi    r7, r7, 16
    cmpwi   r7, 1
    lis     r7, GlobalFlagSystem >> 16                          ; we will enter System Context (all CPUs)
    bne     @not_601
    _ori    r7, r7, GlobalFlagMQReg                             ; but only 601 has MQ register
@not_601
    stw     r7, KDP.Flags(r1)


    lwz     r10, KDP.EmuKCallTblPtrLogical(r1)                  ; Start at KCallReturnFromException trap


    mfmsr   r14                                                 ; Calculate the user space MSR
    andi.   r14, r14, MsrIP                                         ; (not sure why the dot)
    ori     r15, r14, MsrME | MsrDR | MsrRI                         ; does r15 even get used?
    ori     r11, r14, MsrEE | MsrPR | MsrME | MsrIR | MsrDR | MsrRI ; <- this is the real one


    li      r13, 0                                              ; Zero important registers (r13=CR, r12=LR)
    li      r12, 0
    li      r0, 0
    li      r2, 0
    li      r3, 0
    li      r4, 0

########################################################################

ResetContextClock
    lwz     r8, KDP.ProcInfo.DecClockRateHz(r1)
    stw     r8, KDP.OtherContextDEC(r1)
    mtdec   r8

########################################################################

    b       Reset
