mirror of
https://github.com/Relintai/scons_gd.git
synced 2025-02-10 16:40:14 +01:00
317 lines
8.7 KiB
Python
317 lines
8.7 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# MIT License
|
|
#
|
|
# Copyright The SCons Foundation
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
import TestSCons
|
|
|
|
test = TestSCons.TestSCons()
|
|
|
|
if sys.platform != 'win32':
|
|
test.skip_test('PharLap is only available on Windows; skipping test.\n')
|
|
|
|
if not test.detect_tool('linkloc'):
|
|
test.skip_test("Could not find 'linkloc', skipping test.\n")
|
|
|
|
if not test.detect_tool('386asm'):
|
|
test.skip_test("Could not find '386asm', skipping test.\n")
|
|
|
|
# From the Phar Lap minasm example program...
|
|
test.write("minasm.asm", r"""
|
|
;
|
|
; MINASM.ASM - A minimal assembly language program which runs
|
|
; under ToolSuite. You can use this program as a framework
|
|
; for large assembly language programs.
|
|
;
|
|
.386
|
|
|
|
;
|
|
; Segmentation and segment ordering.
|
|
;
|
|
; First comes the code segment.
|
|
;
|
|
_TEXT segment use32 byte public 'CODE'
|
|
_TEXT ends
|
|
|
|
;
|
|
; The data segment contains initialized RAM based data. It will automatically
|
|
; be placed in the ROM at link time and unpacked into RAM at run-time
|
|
; by the __pl_unpackrom function.
|
|
;
|
|
; If you do not need any initialized data in your assembly language program,
|
|
; you can leave this segment empty and remove the call to __pl_unpackrom.
|
|
;
|
|
;
|
|
_DATA segment use32 dword public 'DATA'
|
|
|
|
loopcount dd 10d
|
|
rammessage db 'This message is in RAM memory',0dh,0ah,0
|
|
|
|
_DATA ends
|
|
|
|
;
|
|
; The BSS segment contains RAM based variables which
|
|
; are initialized to zero at run-time. Putting unitialized
|
|
; variables which should start at zero here saves space in
|
|
; the ROM.
|
|
;
|
|
; If you do not need any zero-initialized data in your assembly language
|
|
; program, you can leave this segment empty (and optionally remove the
|
|
; instructions below which initialize it).
|
|
;
|
|
; The segment name must be lower case for compatibility with the linker
|
|
;
|
|
_bss segment use32 dword public 'BSS'
|
|
dummy_bss db 32 dup(?) ; Use a little bit of BSS just to test it
|
|
_bss ends
|
|
|
|
;
|
|
; The const segment contains constants which will never
|
|
; change. It is put in the ROM and never copied to RAM.
|
|
;
|
|
; If you do not need any ROM based constants in your assembly language
|
|
; program, you can leave this segment empty.
|
|
;
|
|
_CONST segment use32 dword public 'CONST'
|
|
rommessage db 'This message is in ROM memory',0dh,0ah,0
|
|
_CONST ends
|
|
|
|
;
|
|
; We're in flat model, so we'll put all the read-only segments we know about
|
|
; in a code group, and the writeable segments in a data group, so that
|
|
; we can use assume to easily get addressability to the segments.
|
|
;
|
|
CGROUP group _TEXT, _CONST
|
|
DGROUP group _DATA, _bss
|
|
|
|
assume cs:CGROUP,ds:DGROUP
|
|
_TEXT segment
|
|
|
|
;
|
|
; _main - the main routine of this program.
|
|
;
|
|
; We will display the RAM and ROM messages the number of times
|
|
; specified in the loopcount variable. This proves that we can
|
|
; initialize RAM data out of ROM and the fact that we can
|
|
; modify the loop count in memory verifies that it actually ends
|
|
; up in RAM.
|
|
;
|
|
public _main
|
|
_main proc near
|
|
|
|
mov cl,0ah ; Skip a line before we start
|
|
call PutCharTarget ;
|
|
main_loop:
|
|
cmp loopcount,0 ; Are we at the end of our loop?
|
|
je short done_main ; yes.
|
|
lea edx,rommessage ; EDX -> ROM message
|
|
call WriteStringTarget ; Display it
|
|
lea edx,rammessage ; EDX -> RAM message
|
|
call WriteStringTarget ; Display it
|
|
dec loopcount ;
|
|
jmp main_loop ; Branch back for next loop iteration
|
|
done_main:
|
|
ret ; That's it!
|
|
|
|
_main endp
|
|
|
|
;
|
|
; WriteStringTarget - Display a string on the target console
|
|
;
|
|
; Inputs:
|
|
; EDX -> Null terminated ASCII string to display
|
|
;
|
|
; Outputs:
|
|
; All registers preserved
|
|
;
|
|
WriteStringTarget proc near
|
|
|
|
push ecx ; Save registers
|
|
push edx ;
|
|
|
|
write_loop:
|
|
movzx ecx,byte ptr [edx] ; Get a character
|
|
jecxz done_str ; Branch if end of string
|
|
call PutCharTarget ; Display this character
|
|
inc edx ; Bump scan pointer
|
|
jmp write_loop ; And loop back for next character
|
|
|
|
done_str:
|
|
pop edx ; Restore registers
|
|
pop ecx ;
|
|
ret ; and return
|
|
|
|
WriteStringTarget endp
|
|
|
|
;
|
|
; PutCharTarget - Write a character on the target console
|
|
;
|
|
; This routine displays a character on the target console by using
|
|
; the PutChar kernel service available through int 254.
|
|
;
|
|
; Inputs:
|
|
; CL = character to display
|
|
;
|
|
; Outputs:
|
|
; All registers preserved
|
|
;
|
|
PutCharTarget proc near
|
|
|
|
push eax ; Save registers
|
|
push ebx ;
|
|
push edx ;
|
|
|
|
mov ax,254Ah ; Request Kernel Service
|
|
mov bx,1 ; service code 1 = PutChar
|
|
movzx edx,cl ; EDX = character to display
|
|
int 0FEh ; Int 254 is for kernel services
|
|
|
|
pop edx ; Restore registers
|
|
pop ebx ;
|
|
pop eax ;
|
|
ret ; and return
|
|
|
|
PutCharTarget endp
|
|
|
|
;
|
|
; The __pl_unpackrom unpacks initialized RAM based data variables
|
|
; out of the ROMINIT segment into their RAM area. They are put
|
|
; in the ROMINIT segment with the -ROMINIT switch in the link file.
|
|
;
|
|
extrn __pl_unpackrom:near
|
|
|
|
;
|
|
; The _EtsExitProcess function is used to terminate our program
|
|
;
|
|
extrn _EtsExitProcess:near
|
|
|
|
;
|
|
; The linker will define symbols for the beginning and end of the
|
|
; BSS segment.
|
|
;
|
|
extrn __p_SEG__bss_BEGIN:dword
|
|
extrn __p_SEG__bss_END:dword
|
|
|
|
;
|
|
; __p_start -- The entry point for our assembly language program.
|
|
; We unpack the RAM based variables out of the ROM and clear the
|
|
; BSS to zero, then call _main where the real work happens. When
|
|
; _main returns, we call EtsExitProcess(0) to terminate.
|
|
;
|
|
public __p_start
|
|
__p_start proc near
|
|
pushad ; save initial regs
|
|
push es ;
|
|
call __pl_unpackrom ; Call the unpacker
|
|
cld ; Clear direction flag
|
|
|
|
lea eax,__p_SEG__bss_END ; load end address and
|
|
lea ebx,__p_SEG__bss_BEGIN ; subtract start to get size
|
|
sub eax,ebx
|
|
mov ecx,eax ; This is size
|
|
inc ecx
|
|
lea edi,__p_SEG__bss_BEGIN ; Zero from start address
|
|
mov al,0 ;Zero out BSS and C_COMMON
|
|
rep stosb
|
|
|
|
pop es ; restore initial regs
|
|
popad
|
|
call _main ; go do some work
|
|
stopme:
|
|
xor eax,eax ; Call _EtsExitProcess(0)
|
|
push eax ;
|
|
call _EtsExitProcess ;
|
|
pop eax ;
|
|
jmp stopme ; .. in a loop just in case it ever
|
|
; comes back
|
|
|
|
__p_start endp
|
|
|
|
TD_hack:
|
|
mov eax, __p_tdhack ; force reference to TD-hack symbol
|
|
|
|
_TEXT ends
|
|
|
|
;
|
|
; Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being
|
|
; debugged doesn't have an import table. (TD looks for the address of
|
|
; the table, then dereferences that address wihtout checking for NULL).
|
|
;
|
|
; This symbol, __p_tdhack, must be declared as an import in all the
|
|
; .emb files shipped. IE:
|
|
;
|
|
; -implib embkern.lib
|
|
; -import __p_tdhack
|
|
;
|
|
; This forces the creation of an import table within the .EXE.
|
|
_DATA segment
|
|
extrn __p_tdhack:dword
|
|
_DATA ends
|
|
end __p_start
|
|
""")
|
|
|
|
test.write("foo.lnk","""
|
|
@baz\\bar.lnk
|
|
""")
|
|
|
|
test.subdir("baz")
|
|
test.write([ "baz", "bar.lnk"],"""
|
|
@asm.emb
|
|
""")
|
|
|
|
test.write("SConstruct", """\
|
|
env = Environment(
|
|
tools=['linkloc', '386asm'], ASFLAGS='-twocase -cvsym', LINKFLAGS='@foo.lnk'
|
|
)
|
|
env.Program(target='minasm', source='minasm.asm')
|
|
""")
|
|
|
|
test.run(arguments='.')
|
|
|
|
# Assume .exe extension...this test is for Windows only.
|
|
test.fail_test(not os.path.exists('minasm.exe'))
|
|
test.up_to_date(arguments='.')
|
|
|
|
# Updating a linker command file should cause a rebuild!
|
|
test.write([ "baz", "bar.lnk"],"""
|
|
-cvsym
|
|
@asm.emb
|
|
""")
|
|
|
|
oldtime = os.path.getmtime(test.workpath('minasm.exe'))
|
|
test.sleep() # delay for timestamps
|
|
test.run(arguments='.')
|
|
test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))
|
|
|
|
test.pass_test()
|
|
|
|
# Local Variables:
|
|
# tab-width:4
|
|
# indent-tabs-mode:nil
|
|
# End:
|
|
# vim: set expandtab tabstop=4 shiftwidth=4:
|