summaryrefslogtreecommitdiff
path: root/ext/systemc/src/sysc/qt/md/i386.s
blob: b5806cd27075650940e04ef9b7e02e1a3a030686 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* i386.s -- assembly support. */

/*
// QuickThreads -- Threads-building toolkit.
// Copyright (c) 1993 by David Keppel
//
// Permission to use, copy, modify and distribute this software and
// its documentation for any purpose and without fee is hereby
// granted, provided that the above copyright notice and this notice
// appear in all copies.  This software is provided as a
// proof-of-concept and for demonstration purposes; there is no
// representation about the suitability of this software for any
// purpose. */

/* NOTE: double-labeled `_name' and `name' for System V compatability.  */
/* NOTE: Mixed C/C++-style comments used. Sorry! */

/* Callee-save: %esi, %edi, %ebx, %ebp
// Caller-save: %eax, %ecx
// Can't tell: %edx (seems to work w/o saving it.)
//
// Assignment:
//
// See ``i386.h'' for the somewhat unconventional stack layout.  */


	.text
	.align 2

	.globl _qt_abort
	.globl qt_abort
	.globl _qt_block
	.globl qt_block
	.globl _qt_blocki
	.globl qt_blocki
	.globl _qt_align
	.globl qt_align

/* These all have the type signature
//
//	void *blocking (helper, arg0, arg1, new)
//
// On procedure entry, the helper is at 4(sp), args at 8(sp) and
// 12(sp) and the new thread's sp at 16(sp).  It *appears* that the
// calling convention for the 8X86 requires the caller to save all
// floating-point registers, this makes our life easy.  */

/* Halt the currently-running thread.  Save it's callee-save regs on
// to the stack, 32 bytes.  Switch to the new stack (next == 16+32(sp))
// and call the user function (f == 4+32(sp) with arguments: old sp
// arg1 (8+32(sp)) and arg2 (12+32(sp)).  When the user function is
// done, restore the new thread's state and return.
//
// `qt_abort' is (currently) an alias for `qt_block' because most of
// the work is shared.  We could save the insns up to `qt_common' by
// replicating, but w/o replicating we need an inital subtract (to
// offset the stack as if it had been a qt_block) and then a jump
// to qt_common.  For the cost of a jump, we might as well just do
// all the work.
//
// The helper function (4(sp)) can return a void* that is returned
// by the call to `qt_blockk{,i}'.  Since we don't touch %eax in
// between, we get that ``for free''.  */

_qt_abort:
qt_abort:
_qt_block:
qt_block:
_qt_blocki:
qt_blocki:
	pushl %ebp		/* Save callee-save, sp-=4. */
	pushl %esi		/* Save callee-save, sp-=4. */
	pushl %edi		/* Save callee-save, sp-=4. */
	pushl %ebx		/* Save callee-save, sp-=4. */
	movl %esp, %eax		/* Remember old stack pointer. */

qt_common:
	movl 32(%esp), %esp	/* Move to new thread. */
	pushl 28(%eax)		/* Push arg 2. */
	pushl 24(%eax)		/* Push arg 1. */
	pushl %eax		/* Push arg 0. */
	movl 20(%eax), %ebx	/* Get function to call. */
	call *%ebx		/* Call f. */
	addl $12, %esp		/* Pop args. */

	popl %ebx		/* Restore callee-save, sp+=4. */
	popl %edi		/* Restore callee-save, sp+=4. */
	popl %esi		/* Restore callee-save, sp+=4. */
	popl %ebp		/* Restore callee-save, sp+=4. */
_qt_align:
qt_align:
	ret			/* Resume the stopped function. */

	.globl _qt_tramp
	.globl qt_tramp
_qt_tramp:
qt_tramp:
	movl 12(%esp), %eax	/* Load 'qt_error' address */
	sub $4, %esp		/* Align stack pointer to 16-byte boundary */
	jmp *%eax		/* call 'qt_error' */
	hlt			/* 'qt_error' never returns */

/* Start a varargs thread. */

	.globl _qt_vstart
	.globl qt_vstart
_qt_vstart:
qt_vstart:
	pushl %edi		/* Push `pt' arg to `startup'. */
	call *%ebp		/* Call `startup'. */
	popl %eax		/* Clean up the stack. */

	call *%ebx		/* Call the user's function. */

	pushl %eax		/* Push return from user's. */
	pushl %edi		/* Push `pt' arg to `cleanup'. */
	call *%esi		/* Call `cleanup'. */

	hlt			/* `cleanup' never returns. */