Merge branch 'master' into jbrill-msvc-detect
[scons.git] / test / PharLap.py
blob0a541518fd6479f0c58c96f15ac3afe956d5171a
1 #!/usr/bin/env python
3 # MIT License
5 # Copyright The SCons Foundation
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be included
16 # in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 import os
27 import sys
28 import time
30 import TestSCons
32 test = TestSCons.TestSCons()
34 if sys.platform != 'win32':
35 test.skip_test('PharLap is only available on Windows; skipping test.\n')
37 if not test.detect_tool('linkloc'):
38 test.skip_test("Could not find 'linkloc', skipping test.\n")
40 if not test.detect_tool('386asm'):
41 test.skip_test("Could not find '386asm', skipping test.\n")
43 # From the Phar Lap minasm example program...
44 test.write("minasm.asm", r"""
46 ; MINASM.ASM - A minimal assembly language program which runs
47 ; under ToolSuite. You can use this program as a framework
48 ; for large assembly language programs.
50 .386
53 ; Segmentation and segment ordering.
55 ; First comes the code segment.
57 _TEXT segment use32 byte public 'CODE'
58 _TEXT ends
61 ; The data segment contains initialized RAM based data. It will automatically
62 ; be placed in the ROM at link time and unpacked into RAM at run-time
63 ; by the __pl_unpackrom function.
65 ; If you do not need any initialized data in your assembly language program,
66 ; you can leave this segment empty and remove the call to __pl_unpackrom.
69 _DATA segment use32 dword public 'DATA'
71 loopcount dd 10d
72 rammessage db 'This message is in RAM memory',0dh,0ah,0
74 _DATA ends
77 ; The BSS segment contains RAM based variables which
78 ; are initialized to zero at run-time. Putting unitialized
79 ; variables which should start at zero here saves space in
80 ; the ROM.
82 ; If you do not need any zero-initialized data in your assembly language
83 ; program, you can leave this segment empty (and optionally remove the
84 ; instructions below which initialize it).
86 ; The segment name must be lower case for compatibility with the linker
88 _bss segment use32 dword public 'BSS'
89 dummy_bss db 32 dup(?) ; Use a little bit of BSS just to test it
90 _bss ends
93 ; The const segment contains constants which will never
94 ; change. It is put in the ROM and never copied to RAM.
96 ; If you do not need any ROM based constants in your assembly language
97 ; program, you can leave this segment empty.
99 _CONST segment use32 dword public 'CONST'
100 rommessage db 'This message is in ROM memory',0dh,0ah,0
101 _CONST ends
104 ; We're in flat model, so we'll put all the read-only segments we know about
105 ; in a code group, and the writeable segments in a data group, so that
106 ; we can use assume to easily get addressability to the segments.
108 CGROUP group _TEXT, _CONST
109 DGROUP group _DATA, _bss
111 assume cs:CGROUP,ds:DGROUP
112 _TEXT segment
115 ; _main - the main routine of this program.
117 ; We will display the RAM and ROM messages the number of times
118 ; specified in the loopcount variable. This proves that we can
119 ; initialize RAM data out of ROM and the fact that we can
120 ; modify the loop count in memory verifies that it actually ends
121 ; up in RAM.
123 public _main
124 _main proc near
126 mov cl,0ah ; Skip a line before we start
127 call PutCharTarget ;
128 main_loop:
129 cmp loopcount,0 ; Are we at the end of our loop?
130 je short done_main ; yes.
131 lea edx,rommessage ; EDX -> ROM message
132 call WriteStringTarget ; Display it
133 lea edx,rammessage ; EDX -> RAM message
134 call WriteStringTarget ; Display it
135 dec loopcount ;
136 jmp main_loop ; Branch back for next loop iteration
137 done_main:
138 ret ; That's it!
140 _main endp
143 ; WriteStringTarget - Display a string on the target console
145 ; Inputs:
146 ; EDX -> Null terminated ASCII string to display
148 ; Outputs:
149 ; All registers preserved
151 WriteStringTarget proc near
153 push ecx ; Save registers
154 push edx ;
156 write_loop:
157 movzx ecx,byte ptr [edx] ; Get a character
158 jecxz done_str ; Branch if end of string
159 call PutCharTarget ; Display this character
160 inc edx ; Bump scan pointer
161 jmp write_loop ; And loop back for next character
163 done_str:
164 pop edx ; Restore registers
165 pop ecx ;
166 ret ; and return
168 WriteStringTarget endp
171 ; PutCharTarget - Write a character on the target console
173 ; This routine displays a character on the target console by using
174 ; the PutChar kernel service available through int 254.
176 ; Inputs:
177 ; CL = character to display
179 ; Outputs:
180 ; All registers preserved
182 PutCharTarget proc near
184 push eax ; Save registers
185 push ebx ;
186 push edx ;
188 mov ax,254Ah ; Request Kernel Service
189 mov bx,1 ; service code 1 = PutChar
190 movzx edx,cl ; EDX = character to display
191 int 0FEh ; Int 254 is for kernel services
193 pop edx ; Restore registers
194 pop ebx ;
195 pop eax ;
196 ret ; and return
198 PutCharTarget endp
201 ; The __pl_unpackrom unpacks initialized RAM based data variables
202 ; out of the ROMINIT segment into their RAM area. They are put
203 ; in the ROMINIT segment with the -ROMINIT switch in the link file.
205 extrn __pl_unpackrom:near
208 ; The _EtsExitProcess function is used to terminate our program
210 extrn _EtsExitProcess:near
213 ; The linker will define symbols for the beginning and end of the
214 ; BSS segment.
216 extrn __p_SEG__bss_BEGIN:dword
217 extrn __p_SEG__bss_END:dword
220 ; __p_start -- The entry point for our assembly language program.
221 ; We unpack the RAM based variables out of the ROM and clear the
222 ; BSS to zero, then call _main where the real work happens. When
223 ; _main returns, we call EtsExitProcess(0) to terminate.
225 public __p_start
226 __p_start proc near
227 pushad ; save initial regs
228 push es ;
229 call __pl_unpackrom ; Call the unpacker
230 cld ; Clear direction flag
232 lea eax,__p_SEG__bss_END ; load end address and
233 lea ebx,__p_SEG__bss_BEGIN ; subtract start to get size
234 sub eax,ebx
235 mov ecx,eax ; This is size
236 inc ecx
237 lea edi,__p_SEG__bss_BEGIN ; Zero from start address
238 mov al,0 ;Zero out BSS and C_COMMON
239 rep stosb
241 pop es ; restore initial regs
242 popad
243 call _main ; go do some work
244 stopme:
245 xor eax,eax ; Call _EtsExitProcess(0)
246 push eax ;
247 call _EtsExitProcess ;
248 pop eax ;
249 jmp stopme ; .. in a loop just in case it ever
250 ; comes back
252 __p_start endp
254 TD_hack:
255 mov eax, __p_tdhack ; force reference to TD-hack symbol
257 _TEXT ends
260 ; Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being
261 ; debugged doesn't have an import table. (TD looks for the address of
262 ; the table, then dereferences that address wihtout checking for NULL).
264 ; This symbol, __p_tdhack, must be declared as an import in all the
265 ; .emb files shipped. IE:
267 ; -implib embkern.lib
268 ; -import __p_tdhack
270 ; This forces the creation of an import table within the .EXE.
271 _DATA segment
272 extrn __p_tdhack:dword
273 _DATA ends
274 end __p_start
275 """)
277 test.write("foo.lnk","""
278 @baz\\bar.lnk
279 """)
281 test.subdir("baz")
282 test.write([ "baz", "bar.lnk"],"""
283 @asm.emb
284 """)
286 test.write("SConstruct", """\
287 env = Environment(
288 tools=['linkloc', '386asm'], ASFLAGS='-twocase -cvsym', LINKFLAGS='@foo.lnk'
290 env.Program(target='minasm', source='minasm.asm')
291 """)
293 test.run(arguments='.')
295 # Assume .exe extension...this test is for Windows only.
296 test.fail_test(not os.path.exists('minasm.exe'))
297 test.up_to_date(arguments='.')
299 # Updating a linker command file should cause a rebuild!
300 test.write([ "baz", "bar.lnk"],"""
301 -cvsym
302 @asm.emb
303 """)
305 oldtime = os.path.getmtime(test.workpath('minasm.exe'))
306 test.sleep() # delay for timestamps
307 test.run(arguments='.')
308 test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))
310 test.pass_test()
312 # Local Variables:
313 # tab-width:4
314 # indent-tabs-mode:nil
315 # End:
316 # vim: set expandtab tabstop=4 shiftwidth=4: