root/sys/arch/mac68k/mac68k/macromasm.s
/*      $NetBSD: macromasm.s,v 1.23 2026/03/20 14:02:53 thorpej Exp $   */

/*-
 * Copyright (C) 1994   Bradley A. Grantham
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Mac ROM Glue assembly
 */


#include "opt_adb.h"
#include "assym.h"
#include <machine/asm.h>
#include <machine/trap.h>


        /* Define this symbol as global with (v) value */
#define loglob(g, v)    \
        .global _C_LABEL(g) ;\
        .set    _C_LABEL(g), v

        /* Return from a pascal function; pop (pbytes) number of bytes */
        /*  passed as parameters.  Should have picked up "pascal" extension */
        /*  to GCC... */
#ifdef __STDC__
#define IMMEDIATE       #
#define pascalret(pbytes)       \
        movl    %sp@+,%a1               /* get PC (I hate Pascal) */ ; \
        addl    IMMEDIATE pbytes,%sp    /* pop params (I hate Pascal) */ ; \
        jra     %a1@                    /* return (I hate Pascal) */
#else
#define pascalret(pbytes)       \
        movl    %sp@+,%a1               /* get PC (I hate Pascal) */ ; \
        addl    #pbytes,%sp             /* pop params (I hate Pascal) */ ; \
        jra     %a1@                    /* return (I hate Pascal) */
#endif


/*
 * MacOS low-memory global variables.
 */
        loglob(ADBBase, 0xcf8)          /* ptr to ADB driver variables */
        loglob(ADBYMM, 0xd18)           /* Yet more memory used by ADB/PM */
        loglob(ADBDelay, 0xcea)         /* 8s of dbras per ADB delay */
        loglob(ROMBase, 0x2ae)          /* ptr to ROM Base */
        loglob(Lvl1DT, 0x192)           /* VIA 1 interrupt table */
        loglob(Lvl2DT, 0x1b2)           /* VIA 2 interrupt table? */
        loglob(JADBProc, 0x6b8)         /* ADBReinit pre/post-processing */
        loglob(jADBOp, 0x5f0)           /* pointer to ADBOp */
        loglob(DeviceList, 0x8a8)       /* ptr to first device entry */
        loglob(KbdLast, 0x218)          /* ptr to first device entry */
        loglob(KbdType, 0x21E)          /* ptr to first device entry */
        loglob(JKybdTask, 0x21A)        /* keyboard task jump ptr? */
        loglob(Lo3Bytes, 0x31a)         /* contains 0x00ffffff */
        loglob(MinusOne, 0xa06)         /* contains 0xffffffff */
        loglob(MMU32Bit, 0xcb2)         /* MMU mode (uh-oh) 1 = 32 bit? */
        loglob(CPUFlag, 0x12f)          /* CPU type */
        loglob(MacJmp, 0x120)           /* ?? */
        loglob(Scratch8, 0x9fa)         /* 8-byte scratch area */
        loglob(Scratch20, 0x1e4)        /* 20-byte scratch area */
        loglob(Ticks, 0x16a)            /* ticks since system startup */
        loglob(Time, 0x20c)             /* Sec since midnight, 1-1-1904 */
        loglob(TimeDBRA, 0xd00)         /* dbra's per millisecond (short) */
        loglob(ToolScratch, 0x9ce)      /* another 8-byte scratch area */
        loglob(VIA, 0x1d4)              /* VIA1 base address */
        loglob(mrg_VIA2, 0xcec)         /* VIA2 base address */
        loglob(SCCRd, 0x1d8)            /* SCC read base address */
        loglob(FinderName, 0x2e0)       /* Name of finder */
        loglob(jSwapMMU, 0xdbc)         /* ptr to MMU swap routine */
        loglob(ADBState, 0xde0)         /* ptr to ADB state information? */
        loglob(jUnimplTrap, 0x61c)      /* ptr to UnimplTrap routine */
        loglob(jEgret, 0x648)           /* ptr to Egret trap routine */
        loglob(HwCfgFlags, 0xb22)       /* 2 bytes, h/w config flags */
        loglob(HwCfgFlags2, 0xdd0)      /* 4 bytes, more h/w config flags */
        loglob(HwCfgFlags3, 0xdd4)      /* 4 bytes, more h/w config flags */
        loglob(ADBReInit_JTBL, 0xdd8)   /* 4 bytes, pointer to patch table */
        loglob(jClkNoMem, 0x54c)        /* Pointer to ClkNoMem function */
        loglob(PramTransfer, 0x1e4)     /* Transfer buffer used with PRam */
        loglob(SysParam, 0x1f8)         /* Place where PRam data gets stored */
        loglob(ExpandMem, 0x2b6)        /* pointer to Expanded Memory used by */
                                        /*   newer ADB routines */
        loglob(VBLQueue, 0x160)         /* Vertical blanking Queue, unused ? */
        loglob(VBLQueue_head, 0x162)    /* Vertical blanking Queue, head */
        loglob(VBLQueue_tail, 0x166)    /* Vertical blanking Queue, tail */
        loglob(jDTInstall, 0xd9c)       /* Deferred task mgr trap handler */

        loglob(InitEgretJTVec, 0x2010)  /* pointer to a jump table for */
                                        /* InitEgret on AV machines */

#if 0
        /* I wish I knew what these things were */
        loglob(MMUFlags, 0xcb0)
        loglob(MMUFluff, 0xcb3)
        loglob(MMUTbl, 0xcb4)
        loglob(MMUTblSize, 0xcb8)
        loglob(MMUType, 0xcb1)
#endif

        .text
        .even
        .global _C_LABEL(panic)
        .global _C_LABEL(printf)

#ifdef MRG_ADB
/*
 * These functions are defined in adb_direct.c if we are not using
 * the MRG method of accessing the ADB/PRAM/RTC.
 */
/*
 * Most of the following glue just takes C function calls, converts
 * the parameters to the MacOS Trap parameters, and then tries to
 * return the result correctly.  About the only thing our C functions
 * and MacOS' traps have in common is returning numerical results in
 * %d0.
 *
 * If some code actually pulls down the a-trap line, we jump right
 * to the ROMs; none of this is called. 
 */

/* Initialize Utils, mainly XPRam */
        /*
         * void
         */
ENTRY(InitUtil)
        .word 0xa03f
        rts


/* Initialize the ADB ------------------------------------------------------*/
        /*
         * void
         */
ENTRY(ADBReInit)
        .word   0xa07b
        rts


/* Set the ADB device info for a device; routine handler and so on ---------*/
        /*
         * %sp@(4)      ADBSetInfoBlock *info
         * %sp@(8)      int             adbAddr
         */
ENTRY(SetADBInfo)
        movl    %sp@(4),%a0
        movl    %sp@(8),%d0
        .word   0xa07a
        rts


/* Find the number of ADB devices in the device table ----------------------*/
        /*
         * void
         */
ENTRY(CountADBs)
        .word 0xa077
        rts


/* Get ADB entry from index in table ---------------------------------------*/
        /*
         * sp@(4)       ADBDataBlock    *info
         * sp@(8)       u_short         devTableIndex
         */
ENTRY(GetIndADB)
        movl    %sp@(4),%a0
        movl    %sp@(8),%d0
        .word 0xa078
        rts


/* Get ADB device information ----------------------------------------------*/
        /*
         * sp@(4)       ADBSetInfoBlock *info
         * sp@(8)       int             adbAddr
         */
ENTRY(GetADBInfo)
        movl    %sp@(4),%a0
        movl    %sp@(8),%d0
        .word 0xa079
        rts


/* Perform an ADB transaction ----------------------------------------------*/
        /*
         * sp@(4)       Ptr     buffer
         * sp@(8)       Ptr     compRout
         * sp@(12)      Ptr     data
         * sp@(16)      short   commandNum
         */
ENTRY(ADBOp)
        lea     %sp@(4),%a0
        movl    %sp@(16),%d0
        .word 0xa07c
        rts
#endif /* MRG_ADB */


#if 0
/* My Own Trap (for testing.  returns 50.) ---------------------------------*/
        .global _MyOwnTrap
_MyOwnTrap:
        .word   0xa000
        rts


/* Known RTS (for testing) -------------------------------------------------*/
        .global _KnownRTS
_KnownRTS:
        .word   0xa001
        rts
#endif


/* Allocate memory ---------------------------------------------------------*/
ENTRY(NewPtr)
        /*
         * int size
         */
        movl    %sp@(4),%d0
        .word   0xa71e          /* clear and sys */
        rts


/* Free memory -------------------------------------------------------------*/
ENTRY(DisposPtr)
        /*
         * Ptr ptr
         */
        movl    %sp@(4),%a0
        .word   0xa01f
        rts


/* Get size of allocated memory --------------------------------------------*/
ENTRY(GetPtrSize)
        /*
         * Ptr ptr
         */
        movl    %sp@(4),%a0
        .word   0xa021
        rts


/* Extend allocated memory -------------------------------------------------*/
ENTRY(SetPtrSize)
        /*
         * Ptr ptr
         * int bytesdiff
         */
        movl    %sp@(4),%a0
        movl    %sp@(8),%d0
        .word   0xa020
        rts


/* Resource manager */
        .data
GLOBAL(mrg_ResErr)
        .word   0

        .text
/* Return the current Resource Manager Error -------------------------------*/
ENTRY(ResError)
        /*
         * void
         */
        movl    %d2,%sp@-               | Toolbox trap may alter %d0-%d2,%a0,%a1
                                        | but C caller would save %d1,%a0,%a1
        clrw    %sp@-                   | space for return arg (ugh)
        .word   0xa9af                  | ResError
        movw    %sp@+,%d0
        movl    %sp@+,%d2               | restore %d2
        rts     

ENTRY(mrg_ResError)
        /*
         * %sp@(4)      :short
         */
#if defined(MRG_SHOWTRAPS)
                movml   #0xc0c0,%sp@-
                pea     LRE_enter
                jbsr    _C_LABEL(printf)
                addql   #4,%sp
                movml   %sp@+,#0x0303
#endif
        movw    _C_LABEL(mrg_ResErr),%sp@(4)
        | movw  %d0,%sp@(4)
        pascalret(0)

LRE_enter:
        .asciz  "mrg: ResError()\n"
        .even

/* Find a resource in open resource files ----------------------------------*/
ENTRY(GetResource)
        /*
         * sp@(4)       u_int theType
         * sp@(8)       short theID
         */
        movl    %sp@(8),%a1
        movl    %sp@(4),%a0
        movl    %d2,%sp@-               | Toolbox trap may alter %d0-%d2,%a0,%a1
                                        | but C caller would save %d1,%a0,%a1
        clrl    %sp@-                   | space for :Handle
        movl    %a0,%sp@-
        movw    %a1,%sp@-               | pascal parameters upside down
        .word   0xa9a0                  | GetResource
        movl    %sp@+,%d0               | return Handle
        movl    %sp@+,%d2               | restore registers
        rts

ENTRY(mrg_GetResource)
        /*
         * sp@(10)      :Handle
         * sp@(6)       u_int   theType
         * sp@(4)       short   theID
         */
        /* For now, we return NIL, because, well, we have no resources. */
#if defined(MRG_SHOWTRAPS)
                movml   #0xc0c0,%sp@-
                movw    %sp@(20),%d0
                movl    %sp@(22),%d1
                movl    %d0,%sp@-
                movl    %d1,%sp@-
                pea     LGR_enter
                jbsr    _C_LABEL(printf)
                addl    #12,%sp
                movml   %sp@+,#0x0303
#endif
        clrl    %d0                     | okay to change %d0 ?
        movl    %d0,%sp@(10)            | return value is NIL
        movl    #-192,%d0               | resNotFound; that's pretty accurate.
        movw    %d0,_C_LABEL(mrg_ResErr)| set current ResMan error
        pascalret(6)                    | I hate Pascal.



ENTRY(mrg_CountResources)
/* Original from WRU: 960120
 * sp@(4)       u_int32_t  rsrc_type
 * sp@(8)       u_int16_t  nr_of_rsrcs
 */
        movl    %sp@(4),%d0
        movl    %d0,%sp@-
        jbsr    _C_LABEL(Count_Resources)
        addl    #4,%sp                  | pop C params
        movw    %d0,%sp@(8)             | store result
        pascalret(4)

ENTRY(mrg_GetIndResource)
/* Original from WRU: 960120
 * sp@(4)       u_int16_t  rsrc_index
 * sp@(6)       u_int32_t  rsrc_type
 * sp@(10)      void *  *rsrc_handle
 */
        movl    %sp@(6),%a0
        clrl    %d0
        movw    %sp@(4),%d0
        movl    %d0,%sp@-
        movl    %a0,%sp@-
        jbsr    _C_LABEL(Get_Ind_Resource)
        addl    #8,%sp          | pop C params
        movl    %d0,%sp@(10)    | store result
        pascalret(6)

/*
 * I'd like to take a moment here to talk about the calling convention
 * for ToolBox routines.  Inside Mac "Operating System Utilities,"
 * page 8-16, "About the Trap Manager," states that ToolBox routines
 * may alter %D0-%D2 and %A0-%A1.  However, a crucial bit of code in
 * ADBReInit on the Mac II, 0x40807834, does not save its own %D1 or %A1
 * before calling GetResource.  Therefore, it is imperative that our
 * MacBSD ToolBox trap handler save at least %D1, %D2, %A0, and %A1.  I
 * believe that the system uses %D0 in most places to hold the function's
 * return value, as in "movl    %sp@+,%d0", and so I don't think it's
 * that necessary to save %d0 unless we find a specific case of ugliness.
 *
 * It surprises me during every moment that I deal with the Macintosh
 * architecture how wonderful and ugly it really is.  I continue to find
 * pieces of beautiful, elegant code, reduced to crap by another following
 * piece of code which uses global offsets, doesn't save registers, and
 * makes assumptions.  If only it was consistent, Mac ROMs would be a
 * true example to programmers everywhere.  As it stands, it is an example
 * of a different kind.         -Brad Grantham, September 5th, 1994
 */

LGR_enter:
        .asciz  "GetResource('0x%x', %d)\n"
        .even


/*
 * 1010 line emulator; A-line trap
 * (we fake MacOS traps from here)
 */
        .global _C_LABEL(mrg_aline_super)
        .global _C_LABEL(mrg_ToolBoxtraps)
ENTRY_NOPROFILE(alinetrap)
        clrl    %sp@-           | pad %SR to longword (I still don't know
                                | why we do this.)
        moveml  #0xffff,%sp@-   | save registers
        movl    %sp,%sp@-       | save pointer to frame
        movw    %sp@(FR_HW + 4),%d0     | retrieve status register
        andw    #PSL_S,%d0      | supervisor state?
        bne     Lalnosup        | branch if supervisor
        addql   #4,%sp          | pop frame ptr
        movql   #T_ILLINST,%d0  | user-mode fault
        jra     _ASM_LABEL(fault)
Lalnosup:
        movl    %sp@(FR_PC + 4),%a0     | retrieve PC
        movw    %a0@,%d0        | retrieve trap word
        btst    #11,%d0         | ToolBox trap?
        bne     Laltoolbox      | branch if ToolBox
        jbsr    _C_LABEL(mrg_aline_super) | supervisor a-line trap
Lalrts:
        addql   #4,%sp          | pop frame ptr
        movw    %sp@(FR_HW),%sr | restore status register (I hate MacOS traps)
        movl    %sp@(FR_PC),%a0 | move PC to correct location
        movl    %a0,%sp@(FR_PC+2)
        moveml  %sp@+,#0xffff   | restore registers (some of which may have
                                | been magically changed)
        addql   #8,%sp          | pop alignment long, make stack look like
                                | ordinary jbsr
        tstw    %d0             | Gotta do this because call might depend on it
        rts                     | Go home (God, this is ugly.)
Laltoolbox:
        addql   #4,%sp          | pop frame ptr
#if defined(MRG_DEBUG)
                movml   #0xC0C0,%sp@-   | better save
                pea     LalP1           
                jbsr    _C_LABEL(printf)
                        | printf ("Toolbox trap\n"); 
                lea     %sp@(4),%sp     | pop
                movml   %sp@+,#0x0303   | restore
#endif
        movl    %a0,%a1         | save PC
        movw    %sp@(FR_HW),%sr | restore status register
#if defined(MRG_DEBUG)
                movml   #0xC0C0,%sp@-   | better save
                movw    %sr,%sp@-
                clrw    %sp@-           | coerce to int
                pea     LalP2
                jbsr    _C_LABEL(printf)
                        | printf ("Status register 0x%x\n", sr);
                lea     %sp@(8),%sp     | pop
                movml   %sp@+,#0x0303   | restore
#endif
        btst    #10,%d0         | auto-pop the jump address?
        beq     Lalnoauto       | branch if no auto-pop
        pea     Lalautopanic    | I really don't know how to handle this
        jbsr    _C_LABEL(panic)
Lalnoauto:
        addl    #2,%a1          | add 2 to PC
#if defined(MRG_DEBUG)
                movml   #0xC0C0,%sp@-   | better save
                movl    %a1,%sp@-
                pea     LalP4
                jbsr    _C_LABEL(printf)
                        | printf ("return address is 0x%x\n", new pc);
                lea     %sp@(8),%sp     | pop
                movml   %sp@+,#0x0303   | restore
#endif
        movl    %a1,%sp@(FR_PC+2)       | push new return address
        movl    %d0,%d1         | just in case of panic
        andl    #0x3ff,%d0      | %d0 = trap number
#if defined(MRG_DEBUG)
                movml   #0xC0C0,%sp@-   | better save
                movl    %d0,%sp@-
                pea     LalP5
                jbsr    _C_LABEL(printf)
                        | printf ("trap number is 0x%x\n", trapnum);
                lea     %sp@(8),%sp     | pop
                movml   %sp@+,#0x0303   | restore
#endif
        lsll    #2,%d0          | ptr = 4 bytes
        lea     _C_LABEL(mrg_ToolBoxtraps),%a0
        addl    %d0,%a0         | get trap address
        movl    %a0@,%a0
        bne     Laltbok         | branch on trap addr non-zero
        movl    %d1,%sp@+       | trap word
        pea     Laltbnotrap
        jbsr    _C_LABEL(printf)
        pea     Laltbnogo
        jbsr    _C_LABEL(panic)
Laltbok:
#if defined(MRG_DEBUG)
                movml   #0xC0C0,%sp@-   | better save
                movl    %a0,%sp@-
                pea     LalP6
                jbsr    _C_LABEL(printf)
                        | printf ("trap address is 0x%x\n", trapaddr);
                lea     %sp@(8),%sp     | pop
                movml   %sp@+,#0x0303   | restore
#endif
        movl    %a0,%sp@(FR_HW) | we will RTS to trap routine (ick)
        moveml  %sp@+,#0xffff   | restore registers
        addql   #4,%sp          | pop alignment long
        rts                     | go for it

Lalautopanic:
        .asciz  "mrg: A-line ToolBox trap wanted auto-pop; I don't know how"
Laltbnotrap:
        .asciz  "mrg: Don't know how to handle this trap: 0x%x\n"
Laltbnogo:
        .asciz  "mrg: can't go on"
LalP1:
        .asciz  "mrg: TB!"
LalP2:
        .asciz  " sr 0x%x"
LalP4:
        .asciz  " ret 0x%x"
LalP5:
        .asciz  " #%d"
LalP6:
        .asciz  " addr 0x%x\n"
        .even


        .data

GLOBAL(traceloopstart)
        .space  20 * 4          | save last 20 program counters on trace trap
GLOBAL(traceloopend)
GLOBAL(traceloopptr)
        .long   _C_LABEL(traceloopstart)

        .text
ENTRY_NOPROFILE(mrg_tracetrap)
        movl    %d0,%sp@-               | save %d0
        movl    %a0,%sp@-               | save %a0
        movl    %sp@(0x10),%d0          | address of instruction
                |%sp@    old %a0
                |%sp@(4) old %d0
                |%sp@(8) old %sr
                |%sp@(10) old %PC
                |%sp@(14) exception vector
                |%sp@(16) address of instruction
#if defined(MRG_FOLLOW)
                movml   #0xc0c0,%sp@-
                movl    %d0,%sp@-
                pea     Ltraceprint
                jbsr    _C_LABEL(printf) | printf("PC is %x\n", pc);
                addql   #8,%sp
                movml   %sp@+,#0x0303
                tstl    %d0
#endif
        beq     LPCiszero               | if PC goes to zero, freak!
        movl    _C_LABEL(traceloopptr),%a0      | ptr = traceloopptr;
        movl    %d0,%a0@+               | *ptr++ = PC;
        cmpl    #_C_LABEL(traceloopend),%a0     | if(ptr == traceloopend)
        bne     Lnotpast                |  {
        movl    #_C_LABEL(traceloopstart),%a0   |   ptr = traceloopstart;
Lnotpast:                               |  }
        movl    %a0,_C_LABEL(traceloopptr)      | traceloopptr = ptr;
        movl    %sp@+,%a0               | restore %a0
        movl    %sp@+,%d0               | restore %d0
        rte                             | everything cool, return.
LPCiszero:
        movl    %sp@+,%a0               | restore %a0
        movl    %sp@+,%d0               | restore %d0
        movml   #0xc0c0,%sp@-
        pea     LtracePCzero
        jbsr    _C_LABEL(panic)         | panic("PC is zero!", pc);
        addql   #4,%sp
        movml   %sp@+,#0x0303

Ltraceprint:
        .asciz  "tracing, pc at 0x%08x\n"
LtracePCzero:
        .asciz  "PC went to zero!\n"
        .even