home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c100 / 3.ddi / STARTUP.ZIP / TCPP10.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-09-01  |  18.8 KB  |  663 lines

  1.     page    60, 132
  2.     name    tcpp10
  3.     title    Turbo C++ 1.0 ROMable Startup Code, Version 1.00
  4.  
  5. ;
  6. ;    Embedded System Startup Code for Turbo C++ 1.0
  7. ;    Copyright (C) 1989, 1990 Paradigm Systems.  All rights reserved.
  8. ;
  9. ;    Assemble with MASM/TASM as follows:
  10. ;
  11. ;        masm tcpp10 /mx /d__MDL__ [ /dTDREM ] ;
  12. ;        tasm tcpp10 /mx /d__MDL__ [ /dTDREM ]
  13. ;
  14. ;    where
  15. ;        __MDL__ is one of the following:
  16. ;
  17. ;        __s__    Small memory model
  18. ;        __c__    Compact memory model
  19. ;        __m__    Medium memory model
  20. ;        __l__    Large memory model
  21. ;        __h__    Huge memory model
  22. ;
  23. ;    If no memory model is specified, the small memory model is
  24. ;    assumed and a warning is issued.
  25. ;
  26. ;    TDREM should be defined if the application will be debugged with
  27. ;    the Paradigm Turbo Debugger Interface.
  28. ;
  29.     
  30.     INCLUDE    startup.inc        ; Macros and other assembly langauge defintions
  31.     INCLUDE    tcpp10.inc        ; Compiler-specific defintions
  32.  
  33. IFDEF    ??Version            ; Check for TASM
  34. NOWARN    PDC                ; Disable pass 1 warnings
  35. ENDIF    ; ??Version
  36. IF1
  37. IFDEF    TDREM
  38.     %out    Building TDREM-compatible startup code
  39. ENDIF    ; TDREM
  40. ENDIF    ; IF1
  41. IFDEF    ??Version            ; Check for TASM
  42. WARN    PDC                ; Turn warnings back on
  43. ENDIF    ; ??Version
  44.  
  45.     subttl    Segment ordering/alignment section
  46.     page
  47. ;
  48. ;    Segment and group declarations.  The order of these declarations is
  49. ;    used to control the order of segments in the .EXE file since the
  50. ;    Microsoft and Borland linkers copy segments in the same order they
  51. ;    are encountered in the object files.
  52. ;
  53. ;    Make sure that this startup module is specified first when linking
  54. ;    the application.  Requires MASM 5.10 or TASM 1.0 (or later) to
  55. ;    assemble.
  56. ;
  57. DefSeg    begtext,     para,  public,  CODE,       <>    ; Start of CODE class
  58. DefSeg    _text,       word,  public,  CODE,       <>
  59.  
  60. ;
  61. ;    The following segments are used to hold the linked initializers
  62. ;    and terminators.  These permit automatic initialization of code
  63. ;    without startup source modification and should be located in ROM.
  64. ;    Terminators are not implemented since an application will normally
  65. ;    not return to the startup code but are supported for run-time library
  66. ;    compatibility.
  67. ;
  68. DefSeg    BEGINIT,     para,  public,  INITDATA, IGROUP    ; Start of initializers
  69. DefSeg    _INIT_,      word,  public,  INITDATA, IGROUP    ; Initializers
  70. DefSeg    _INITEND_,   byte,  public,  INITDATA, IGROUP
  71. DefSeg    _EXIT_,      word,  public,  EXITDATA, IGROUP    ; Terminators
  72. DefSeg    _EXITEND_,   byte,  public,  EXITDATA, IGROUP
  73.  
  74. IFNDEF    TDREM                ; ROMable code
  75. ;
  76. ;    The following segments are used to mark the place for ROM copies
  77. ;    of initialized data for use by the startup code.
  78. ;
  79. DefSeg    romdata,     para,  public,  ROMDATA,    <>
  80. DefSeg    erdata,      para,  public,  ENDROMDATA, <>
  81. ENDIF    ; !TDREM
  82.  
  83. DefSeg    begdata,     para,  public,  DATA,       DGROUP
  84. DefSeg    _data,       word,  public,  DATA,       DGROUP
  85. IF    @DataSize NE MM_HUGE        ; BSS class definition
  86. DefSeg    _bss,        word,  public,  BSS,        DGROUP
  87. DefSeg    _bssend,     word,  public,  BSSEND,     DGROUP
  88. ELSE                    ; HUGE_BSS class definition
  89. DefSeg    hugebss,     para,  public,  HUGEBSS,    <>
  90. DefSeg    hbssend,     word,  public,  HUGEBSSEND, <>
  91. ENDIF    ; MM_HUGE
  92.  
  93. ;
  94. ;    Two stack segments are declared, one for emulators that expect
  95. ;    a segment called STACK and the TC++ _STACK segment.
  96. ;
  97. IF    @DataSize EQ MM_NEAR        ; Stack is part of DGROUP
  98. DefSeg    stack,       para,  public,  STACK,      DGROUP
  99. DefSeg    _stack,      para,  stack,   STACK,      DGROUP
  100. ELSE                    ; Stack is independent of DGROUP
  101. DefSeg    stack,       para,  public,  STACK,      <>
  102. DefSeg    _stack,      para,  stack,   STACK,      <>
  103. ENDIF    ; MM_NEAR
  104.  
  105. IFDEF    TDREM                ; TDREM code
  106. ;
  107. ;    This segment marks the start of the saved copy of initialized
  108. ;    data.  The copy of the initialized data will be copied here for
  109. ;    restoring on restarts.
  110. ;
  111. DefSeg    backup,         para,  public,  BACKUP,     <>    ; Initialized data copy
  112. ENDIF    ; TDREM
  113.  
  114. ;
  115. ;    The far heap is defined as a convienence and identifies the
  116. ;    start of RAM available for general purpose use.
  117. ;
  118. DefSeg    farheap,     para,  public,  FARHEAP,    <>
  119.  
  120. ;
  121. ;    Make up the correct external references that depend on the
  122. ;    memory model and inform the user which code and data memory
  123. ;    models have been selected.
  124. ;
  125. ExtProc    main                ; Turbo C language entry point
  126. IF    @CodeSize EQ MM_HUGE        ; Huge memory model support
  127.     extrn    PSBP@ : far        ; Huge pointer subtraction helper
  128. ENDIF    ; MM_HUGE
  129.  
  130.     subttl    Startup code section
  131.     page
  132. _text    segment
  133.     assume    cs:_text
  134.  
  135. BegProc    _startup, far            ; Turbo C 2.0 startup code entry point
  136.     cli                ; Disable interrupts
  137.     cld                ; Make sure the direction is forward
  138.  
  139. IFDEF    TDREM
  140. ;
  141. ;    Check if the segment registers have been setup by DOS
  142. ;
  143.     mov    ax, ds            ; See if DOS setup DS
  144.     or    ax, ax            ; Check if the PSP is zero
  145.     jz    embedded        ; Continue with the embedded code
  146.  
  147.     push    cs            ; Display a DOS error message
  148.     pop    ds
  149.     assume    ds:_text
  150.     mov    dx, offset errmsg
  151.     mov    ah, 09h
  152.     int    21h
  153.  
  154.     mov    ah, 04ch        ; Exit before doing something harmful
  155.     int    21h
  156.  
  157. errmsg    db    "Embedded application: DOS not supported", 0ah, 0dh, '$'
  158.  
  159. embedded:
  160. ENDIF    ; TDREM
  161.  
  162. ;
  163. ;    Set up the stack according to the memory model.  The default Borland
  164. ;    model is to have the stack after the heap in the small and medium
  165. ;    memory models.
  166. ;
  167. IF    @DataSize EQ MM_NEAR
  168.     mov    ax, dgroup        ; Get the frame number for the group
  169.     mov    ss, ax            ; Load in the stack segment register
  170.     mov    sp, offset dgroup:tos    ; And the offset within the group
  171.     assume    ss:dgroup
  172. ELSE
  173.     mov    ax, stack        ; Get the frame number for the segment
  174.     mov    ss, ax            ; Load in the stack segment register
  175.     mov    sp, offset tos        ; And the offset within the segment
  176.     assume    ss:stack
  177. ENDIF    ; @DataSize
  178.  
  179. IFNDEF    TDREM                ; ROM-based initialization code
  180.  
  181. IF    @DataSize NE MM_HUGE        ; Small, medium, compact and large models
  182. ;
  183. ;    Prepare the segment registers for initialization.  The initialized
  184. ;    data is assumed to have been located in the class ROMDATA with begins
  185. ;    with the segment of the same name.
  186. ;
  187.     mov    ax, dgroup        ; The destination segment for DGROUP
  188.     mov    es, ax
  189.     mov    ax, romdata        ; The source segment
  190.     mov    ds, ax
  191.     assume    ds:romdata, es:dgroup
  192.  
  193. ;
  194. ;    Copy DGROUP from its position in ROM to the target address in RAM
  195. ;
  196.     mov    si, offset dgroup:idata    ; Get the starting offset of the DATA segment
  197.     mov    di, si            ; Same offset, different segment
  198.     mov    cx, offset dgroup:bdata    ; Get the ending offset (start of BSS)
  199.     sub    cx, di            ; Subtract the two for a length
  200.     shr    cx, 1            ; Convert to words
  201.     jcxz    $$1            ; Skip if zero length
  202.     rep    movsw            ; Copy initialized data from ROM to RAM
  203. $$1:
  204.  
  205. ELSE                    ; Huge model initialized data
  206.  
  207. ;
  208. ;    Copy the DATA class.  This class can span multiple segments in the
  209. ;    huge model so the copying from ROM to RAM must be iterated as many
  210. ;    times as necessary.  We start by computing the class length with the
  211. ;    help of the Turbo C run-time library.
  212. ;
  213.     mov    cx, _data        ; Get the destination address
  214.     mov    bx, offset idata
  215.     mov    dx, hugebss        ; Get the end address
  216.     mov    ax, offset bhdata
  217.     call    PSBP@            ; Length returned in DX:AX
  218.  
  219.     mov    bx, _data        ; Get the destination address in RAM
  220.     mov    es, bx            ; Address via ES:DI
  221.     mov    di, offset idata
  222.  
  223.     mov    bx, romdata        ; Point to the copy in ROM
  224.     mov    ds, bx            ; Address via DS:SI
  225.     mov    si, di
  226.     assume    ds:nothing, es:nothing
  227.  
  228. ;
  229. ;    Get the size of the class and perform the copy
  230. ;
  231.     or    dx, dx            ; Test if less than a segment
  232.     jz    $$3            ; Skip if less than 64K
  233.  
  234. $$2:
  235.     mov    cx, 08000h        ; Move 64KB
  236.     rep    movsw            ; Copy initialized data from ROM to RAM
  237.     mov    cx, ds            ; Get the source segment
  238.     add    cx, 1000h        ; Adjust for the 64K just transfered
  239.     mov    ds, cx            ; Save it back
  240.     mov    cx, es            ; Get the destination segment
  241.     add    cx, 1000h        ; Adjust for the 64K just transfered
  242.     mov    es, cx            ; Save it back
  243.     dec    dx            ; Bump the count
  244.     jnz    $$2            ; Repeat for all complete segments
  245.  
  246. $$3:
  247.     mov    cx, ax            ; Get the remaining count
  248.     shr    cx, 1            ; Convert to words
  249.     jcxz    $$4            ; Skip if zero
  250.     rep    movsw            ; Copy the remaining data
  251. $$4:
  252. ENDIF    ; MM_HUGE
  253.  
  254. ELSE                    ; Initialization code for TDREM
  255. ;
  256. ;    Copy the initialized to safety if not done all ready
  257. ;
  258.     mov    ax, dgroup        ; Setup DGROUP addressability
  259.     mov    ds, ax
  260.     assume    ds:dgroup
  261.  
  262.     cmp    SAVEDATA, 0        ; Check if saved
  263.     jne    do_init            ; Skip to the initialization
  264.  
  265. ;
  266. ;    Come here the first time thru to save a copy of the initialized
  267. ;    data.
  268. ;
  269.     mov    SAVEDATA, 1        ; Prevent further saves to BACKUP
  270.  
  271. IF    @DataSize NE MM_HUGE        ; Small, medium, compact and large models
  272. ;
  273. ;    The first pass requires that a copy of the initialized data be made
  274. ;    and stored in the BACKUP class.
  275. ;
  276.     mov    ax, backup        ; Where to store the data
  277.     mov    es, ax
  278.     mov    di, 0            ; ES:DI for destination address
  279.     mov    si, offset dgroup:idata    ; DS:SI for the source address
  280.     mov    cx, offset dgroup:bdata
  281.     sub    cx, si            ; Compute the length of the initialized data
  282.     shr    cx, 1            ; Convert from bytes to words
  283.     jcxz    $$5            ; Skip if zero
  284.     rep    movsw            ; Copy the data to be restored later
  285.     jmp    short $$5
  286.  
  287. ;
  288. ;    Come here when the initialized data must be restored from the copy
  289. ;    stored in the BACKUP class.
  290. ;
  291. do_init:
  292.     mov    ax, backup        ; Source address is DS:SI
  293.     mov    ds, ax
  294.     xor    si, si
  295.  
  296.     mov    ax, dgroup        ; Desintation address is ES:DI
  297.     mov    es, ax
  298.     mov    di, offset dgroup:idata
  299.  
  300.     mov    cx, offset dgroup:bdata    ; Find the end of the initialized data
  301.     sub    cx, di            ; Compute the length
  302.     shr    cx, 1            ; Convert from bytes to words
  303.     jcxz    $$5            ; Skip if zero
  304.     rep    movsw            ; Restore the previously saved data
  305. $$5:
  306.  
  307. ELSE                    ; Huge memory model
  308. ;
  309. ;    Huge model initialized data save/restore from BACKUP.  This is more
  310. ;    complicated since the initialized data spans multiple segments.
  311. ;
  312.     mov    cx, _data        ; Get the class base address
  313.     mov    bx, offset idata
  314.     mov    dx, hugebss        ; Get the class end address
  315.     mov    ax, offset bhdata
  316.     call    PSBP@            ; Class length in DX:AX
  317.  
  318.     mov    bx, _data        ; Get the class base address
  319.     mov    ds, bx
  320.     mov    si, offset idata    ; DS:SI source address
  321.  
  322.     mov    bx, backup        ; Destination of the copy
  323.     mov    es, bx
  324.     xor    di, di
  325.     jmp    short do_copy        ; Do the copy
  326.  
  327. ;
  328. ;    Come here when initialized data must be restored from the copy
  329. ;    to the destination.
  330. ;
  331. do_init:
  332.     mov    cx, _data        ; Get the class base address
  333.     mov    bx, offset idata
  334.     mov    dx, hugebss        ; Get the class end address
  335.     mov    ax, offset bhdata
  336.     call    PSBP@            ; Class length in DX:AX
  337.  
  338.     mov    bx, _data        ; Get the class base address
  339.     mov    es, bx
  340.     mov    di, offset idata    ; ES:DI destination address
  341.  
  342.     mov    bx, backup        ; DS:SI source address in BACKUP
  343.     mov    ds, bx
  344.     xor    si, si
  345.     assume    ds:nothing, es:nothing
  346.  
  347. do_copy:
  348.     or    dx, dx            ; Test if less than a segment
  349.     jz    $$7            ; Skip if less than 64K
  350.  
  351. $$6:
  352.     mov    cx, 08000h        ; Move 64KB
  353.     rep    movsw            ; Copy initialized data
  354.     mov    cx, ds            ; Get the source segment
  355.     add    cx, 1000h        ; Adjust for the 64K just transfered
  356.     mov    ds, cx            ; Save it back
  357.     mov    cx, es            ; Get the destination segment
  358.     add    cx, 1000h        ; Adjust for the 64K just transfered
  359.     mov    es, cx            ; Save it back
  360.     dec    dx            ; Bump the count
  361.     jnz    $$6            ; Repeat for all complete segments
  362.  
  363. $$7:
  364.     mov    cx, ax            ; Get the remaining count
  365.     shr    cx, 1            ; Convert from bytes to words
  366.     jcxz    $$8            ; Skip the copy if zero
  367.     rep    movsw            ; Copy the remaining data
  368. $$8:
  369. ENDIF    ; MM_HUGE
  370. ENDIF    ; !TDREM
  371.  
  372. ;
  373. ;    Setup the segment registers for Turbo C
  374. ;
  375.     mov    ax, dgroup        ; Address DGROUP via DS
  376.     mov    ds, ax
  377.     mov    es, ax
  378.     assume    ds:dgroup, es:dgroup
  379.  
  380. IF    @DataSize NE MM_HUGE
  381. ;
  382. ;    Zero out the BSS area (not present in the huge memory model)
  383. ;
  384.     xor    ax, ax            ; Use a zero fill pattern
  385.     mov    di, offset dgroup:bdata    ; Get the start of the BSS class
  386.     mov    cx, offset dgroup:edata    ; Get the end address
  387.     sub    cx, di            ; Subtract the two for a length
  388.     shr    cx, 1            ; Convert to the number of words
  389.     jcxz    $$9            ; Skip if zero
  390.     rep    stosw            ; Zero out the BSS
  391. $$9:
  392. ELSE
  393. ;
  394. ;    Zero out the HUGEBSS class.  This class can span multiple segments so
  395. ;    the zeroing of memory must be iterated as many times as necessary.
  396. ;    Start by making a normalized pointer to the end of class.
  397. ;
  398.     mov    dx, hbssend        ; Get the ending adress
  399.     mov    ax, offset ehdata
  400.     mov    cx, hugebss        ; Get the starting address
  401.     mov    bx, offset bhdata
  402.     call    PSBP@            ; Compute the class size
  403.     mov    bx, ax            ; DX:BX is the length
  404.  
  405.     mov    ax, hugebss        ; Get the starting address of HUGEBSS
  406.     mov    es, ax
  407.     assume    es:nothing
  408.     mov    di, offset bhdata    ; Address via ES:DI
  409.  
  410.     xor    ax, ax            ; Use a zero fill pattern
  411.     or    dx, dx            ; Test if less than a segment
  412.     jz    $$11            ; Skip if less than 64K
  413. $$10:
  414.     mov    cx, 08000h        ; Max operation is 64KB bytes
  415.     rep    stosw            ; Zero out the far BSS
  416.     mov    cx, es            ; Get the destination segment
  417.     add    cx, 1000h        ; Adjust for the 64K just transfered
  418.     mov    es, cx            ; Save it back
  419.     dec    dx            ; Bump the count
  420.     jnz    $$10            ; Repeat for all complete segments
  421.  
  422. $$11:
  423.     mov    cx, bx            ; Get the remaining count
  424.     shr    cx, 1            ; Convert to words
  425.     jcxz    $$12            ; Skip if zero
  426.     rep    stosw            ; Zero out the remaining far BSS
  427. $$12:
  428. ENDIF    ; @DataSize
  429.  
  430. ;
  431. ;    Call all of the linked-in initializers in the _INIT_ segment.  These
  432. ;    are a series of pointers to routines which are guaranteed to
  433. ;    execute before main() is called.  The advantage of this approach is
  434. ;    that the initialization will be made by virtue of the code being
  435. ;    linked in, without any modification to the startup code.
  436. ;
  437. ;    This implementation permits the initializers to be kept in ROM,
  438. ;    even though there is no ordering of the initializers.  The register
  439. ;    use is as follows:
  440. ;        SI - initializers start
  441. ;        DI - initializers end
  442. ;        CX - number of initializers not processed
  443. ;        BX - current initializer
  444. ;        AH - current priority
  445. ;
  446.     mov    si, offset igroup:InitStart    ; Start of initializers
  447.     mov    di, offset igroup:InitEnd    ; End of initializers
  448.     mov    ax, igroup
  449.     mov    es, ax
  450.     assume    es:nothing
  451.  
  452.     mov    ax, di
  453.     sub    ax, si
  454.     sub    dx, dx
  455.     mov    cx, SIZE InitRec
  456.     idiv    cx
  457.     mov    cx, ax            ; Number of initializers in the table
  458.     jcxz    InitDone        ; Skip if nothing to process
  459.     sub    ah, ah            ; Start with the highest priority
  460.  
  461. PriTop:
  462.     mov    bx, si            ; Point to the start of the table
  463.  
  464. NextInit:
  465.     cmp    bx, di            ; Check if this pass is done
  466.     jae    PriBottom        ; Process the next priority level
  467.     cmp    es:[bx.pri], ah        ; Compare against the current priority
  468.     jne    TableBottom        ; Not our turn to execute
  469.  
  470.     push    es
  471.     push    ax
  472.     push    bx
  473.     push    cx
  474.     cmp    es:[bx.ctype], MM_NEAR    ; Is it near or far?
  475.     je    @@NearCall
  476.     call    dptr es:[bx.foff]    ; Call the initializer
  477.     jmp    short $$14
  478. @@NearCall:
  479.     call    wptr es:[bx.foff]    ; Call the initializer
  480. $$14:
  481.     pop    cx
  482.     pop    bx
  483.     pop    ax
  484.     pop    es
  485.     dec    cx            ; Decrement the initializer count
  486.     jz    InitDone        ; Exit if done
  487.  
  488. TableBottom:
  489.     add    bx, SIZE InitRec    ; Move to the next initializer
  490.     jmp    NextInit
  491.  
  492. PriBottom:
  493.     inc    ah            ; Process the next priority
  494.     jmp    PriTop
  495. InitDone:
  496.  
  497. ;
  498. ;    Call the C language entry point - initialization complete.
  499. ;
  500.     sti                ; Enable interrupts
  501.     call    main            ; Call the Turbo C main()
  502.  
  503. ;
  504. ;    Program terminate is simulated by using a breakpoint with a 
  505. ;    CS:IP being both zero for TDREM.  Also return the exit code in AX.
  506. ;    Most embedded applications should not return.
  507. ;
  508. IFNDEF    TDREM                ; ROMable code
  509.     jmp    _startup        ; Restart the application
  510. ELSE                    ; TDREM code
  511.     and    ax, 7fh            ; Mask for TDREM codes
  512.     push    ax
  513.     call    pptr exit        ; Call the TDREM exit handler
  514. ENDIF    ; TDREM
  515.  
  516. EndProc    _startup
  517.  
  518. ;
  519. ;    This routine handles getting the error code from the caller
  520. ;    and terminating the application.
  521. ;
  522. public    __exit
  523. __exit    proc
  524. IFNDEF    TDREM                ; ROMable code
  525.     jmp    _startup        ; Application dependent
  526. ELSE
  527.     mov    bp, sp            ; Prepare the stack frame
  528. IF    @CodeSize EQ MM_NEAR
  529.     mov    ax, [bp+2]        ; After IP
  530. ELSE
  531.     mov    ax, [bp+4]        ; After CS:IP
  532.     sub    ah, ah            ; Zero the upper byte of the exit code
  533. ENDIF    ; MM_NEAR
  534.  
  535.     xor    bx, bx            ; Make the interrupt vector table addressable
  536.     mov    es, bx
  537.  
  538.     pushf                ; Push the PSW
  539.     push    bx            ; IP
  540.     push    bx            ; CS
  541.     jmp    dptr es:[000ch]        ; Call the break handler
  542. ENDIF    ; TDREM
  543. __exit    endp
  544.  
  545. BegProc    exit                ; C language exit()
  546. IF    @CodeSize NE MM_NEAR
  547.     pop    cx            ; Get rid of CS
  548. ENDIF    ; MM_NEAR
  549.     pop    cx            ; Clear IP (leave the exit code)
  550. IF    @CodeSize NE MM_NEAR
  551.     call    fptr __exit        ; Call the exit routine
  552. ELSE
  553.     call    nptr __exit           ; Call the exit routine
  554. ENDIF    ; MM_NEAR
  555. EndProc    exit
  556.  
  557. BegProc    _exitclean
  558. IF    @CodeSize NE MM_NEAR
  559.     pop    cx            ; Get rid of CS
  560. ENDIF    ; MM_NEAR
  561.     pop    cx            ; Clear IP (leave the exit code)
  562. IF    @CodeSize NE MM_NEAR
  563.     call    fptr __exit        ; Call the exit routine
  564. ELSE
  565.     call    nptr __exit           ; Call the exit routine
  566. ENDIF    ; MM_NEAR
  567. EndProc    _exitclean
  568.  
  569. BegProc    abort                ; C language abort()
  570.     mov    ax, TDE_ABORT        ; Abort error code
  571.     push    ax
  572.     call    exit            ; Call the exit routine
  573. EndProc    abort
  574.  
  575. ;
  576. ;    This is code given control when Turbo C detects a stack overflow.
  577. ;    Stack overflow checking is enabled by the -N compiler option.
  578. ;
  579. public    OVERFLOW@
  580. OVERFLOW@    proc
  581.     mov    ax, TDE_STKOVL        ; TDREM stack overflow error code
  582.     push    ax
  583.     call    exit
  584. OVERFLOW@    endp
  585.  
  586. _text    ends
  587.  
  588.     subttl    Data declarations
  589.     page
  590. ;
  591. ;    Run-time libraries and other modules can insert initializers in this
  592. ;    segment.  Initializers are executed by priority, and by link order when
  593. ;    the same priority.
  594. ;
  595. _INIT_        segment
  596. InitStart    label    dword
  597. _INIT_        ends
  598. _INITEND_    segment
  599. InitEnd        label    dword
  600.         db    ?
  601. _INITEND_    ends
  602.  
  603. IFNDEF    TDREM
  604. romdata    segment                ; Segment placeholder for initialized data
  605. public    ridata
  606. ridata    label    byte            ; Mark the start of the ROM data area where
  607.                     ; the ROM copy of initialized data is stored
  608. romdata    ends
  609. erdata    segment                ; ROMDATA class end marker
  610.     db    16 dup (?)        ; Force the next segment to a new paragraph
  611. erdata    ends
  612. ENDIF    ; !TDREM
  613.  
  614. _data    segment
  615. public    idata
  616. idata    label    byte            ; Mark the start of the _DATA segment
  617. IFDEF    TDREM
  618. SAVEDATA    dw    0        ; Restart flag (1 if restarted)
  619. ENDIF    ; TDREM
  620. _data    ends
  621.  
  622. IF    @DataSize NE MM_HUGE        ; No BSS in the huge memory model
  623. _bss    segment
  624. public    bdata                ; Mark the start of the BSS class
  625. bdata    label    byte            ; and the end of the DATA class
  626. _bss    ends
  627. _bssend segment                ; BSS class end marker
  628. public    edata
  629.     dw    ?            ; Give a fixed size for alignment
  630. edata    label    byte            ; Mark the end of the BSS class
  631. _bssend ends
  632. ELSE                    ; Must be huge memory model
  633. hugebss segment                
  634. public    bhdata                ; Mark the start of the HUGEBSS class
  635. bhdata    label    byte            ; and the end of the DATA class
  636. hugebss ends
  637. hbssend    segment
  638. public    ehdata
  639. ehdata    label    byte            ; Mark the end of the HUGEBSS class
  640.     db    16 dup (?)        ; Force the next segment to a new paragraph
  641. hbssend    ends
  642. ENDIF    ; @DataSize
  643.  
  644. IFDEF    TDREM                ; TDREM code
  645. backup    segment                ; Copy of initialized data
  646.     db    ?
  647. backup    ends
  648. ENDIF    ; TDREM
  649.  
  650. _stack    segment
  651. public    tos                ; Make the TOS visible to debuggers and ICE
  652. IFDEF    STKSIZE
  653.     db    STKSIZE dup (?)        ; Setup the stack
  654. ELSE
  655.     db    2048 dup (?)         ; Declare the stack size (in words)
  656.     %out    No stack size specified: stack size set to 2KB
  657. ENDIF
  658.     even                ; Force word alignment
  659. tos    label    word            ; Define the top of stack (the initial SP value)
  660. _stack    ends
  661.  
  662.     end    _startup        ; Program entry point
  663.