|
|
NASM Helper
Programming in Assembler can became difficult, when you want to pass parameters to a function and/or using local variables.
I wrote some macros, to have a simple solution for using arguments and local variables easily in the same way. The macros
are written for NASM.
Although NASM has the "%local" directive to declare local variables (see %local Directive)
and some Helper Macros for C Interface, I prefer my solution.
See sample.asm with a lot of examples and at
the bottom of this page you find a complex function as example.
I release my macros in hope that it helps other people. And make it easier to write programs in Assembler.
Download
nasm-helper-1.2.zip (08/01/2022), includes the macros, sample.asm and assembler.syntax.
nasm-helper-1.1.zip (07/01/2018), includes the macros, sample.asm and assembler.syntax.
nasm-helper-1.0.zip (29/12/2017), includes the macros, sample.asm and assembler.syntax.
How it works
Initialize a function:
When you want to use a function that should be called with parameters or use local variables, then initialize the function with "M_Vars".
MyFunction:
M_Vars
Declare arguments (function parameters):
To declare arguments use "M_Arg <name>, <size>". "Name" is the name of the variable and "size" is the variable size.
Valid size values are "S_WORD", "S_DWORD", "S_QWORD".
M_Arg var1, S_WORD
M_Arg var2, S_DWORD
Declare local variables:
To declare local variables use "M_Local <name>, <size>". "Name" is the name of the variable and "size" is the variable size.
Valid size values are "S_WORD", "S_DWORD", "S_QWORD" or for arrays multiple of 2 values.
M_Local foo , S_WORD
M_Local temp1 , S_DWORD
M_Local temp2 , S_WORD
M_Local array , S_WORD * 100
M_Local array2, S_DWORD * 20
End of declarations:
When you declared your variables use
"M_Code"
at the beginning of your function code.
M_Code
Note: M_Code is the same as
enter LOCAL_LEN, 0
Using the variables:
You can use arguments and local variables in the same way. The syntax is a dot and then the variable name. For example ".foo".
mov ax, [.foo]
mov [.temp1], edx
cmp word [.var1], 2001h
Function end:
At the end of your function use
M_Ret
Which is the same as
leave
ret ARG_LEN
M_VarsEnd
Function sample:
MyFunction:
; We are using arguments and/or local variables
M_Vars
; Declare arguments
M_Arg var1, S_WORD
M_Arg var2, S_DWORD
; Declare local variables
M_Local foo, S_WORD
; Function code
M_Code
; Do something
nop
nop
; Return
M_Ret
How to call the function with parameters:
You pass the parameters to the function with "push". You have to pass them in the opposite direction of your declaration. The first parameter is pushed at last and the
last parameter is pushed first.
push dword 6 ; This became .var2
push ax ; This became .var1
call MyFunction ; (word var1, dword var2)
sample.asm:
The sample.asm program is written for DOS. It is just for demonstration purpose and makes nothing useful, but it shows you
- how to use arguments and local variables.
- using a function return value.
- using the M_Printf macro.
- using the bit macro.
- declare and using an array.
- set all local variables of a function to 0.
- a recursive function sample.
Output of sample.asm:
Hello world.
Hello world with macro!
var2 is not 100.
Value is not 100.
Bit 4 is set.
RecursiveSample:
depth: 1 value1: 1 value2: 0
depth: 2 value1: 2 value2: 1
depth: 3 value1: 4 value2: 2
depth: 4 value1: 8 value2: 3
Back in depth 3
Back in depth 2
Back in depth 1
mc/assembler.syntax
I extended the assembler syntax highlighting file of the Midnight Commander for my needs. The syntax highlighting file is
usually stored in "/usr/share/mc/syntax/".
Sample files
sample.asm
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
|
;=========================================================
; Demonstration of NASM Helper by Elmar Hanlhofer
;=========================================================
[ORG 0x100]
%define STRING_END "$"
%include "sys/const.inc"
%include "sys/sys16.inc"
%include "macro/args.inc"
%include "macro/bit.inc"
%include "macro/printf.inc"
TESTBIT4 equ 4
OTHERBIT equ 7
start:
push cs
pop ds
push cs
pop ss
mov sp, 0FFFEh
;==============================
push word hello
call PrintString ; (word string)
M_PrintfNL "Hello world with macro!"
; Do an extra new line
M_PrintfNL ""
;==============================
push word 5
push word 200
call SimpleAdd ; (word value1, word value2)
push ax
push word 150
call SimpleAdd ; (word value1, word value2)
; ax has now the value 355 (136h)
;==============================
push ax
call LocalStuff ; (word value)
M_PrintfNL ""
;==============================
push word 20
call IsValue100 ; (word value)
jc .is_not_100
M_PrintfNL "Value is 100."
jmp .next
.is_not_100:
M_PrintfNL "Value is not 100."
.next:
M_PrintfNL ""
;==============================
mov ax, b(TESTBIT4) | b(OTHERBIT)
test ax, b(TESTBIT4)
jne .is_set
M_PrintfNL "Bit 4 is not set."
jmp .next2
.is_set:
M_PrintfNL "Bit 4 is set."
.next2:
M_PrintfNL ""
mov bx, ~b(OTHERBIT) ; Bitwise not sample
;==============================
push word TRUE
push dword 130
push word 20
call SampleClearLocalVars ; (word value1, dword value2, word bool)
;==============================
call LocalArraySample
M_PrintfNL ""
;==============================
push word 0
push word 1
call RecursiveSample ; (word value1, word value2)
;==============================
.exit:
mov ax, 0x4c00
int 21h
hello db "Hello world.", 0Dh, 0Ah, "$"
;======================================
;void PrintString (word string)
;======================================
PrintString:
M_Vars
M_Arg string, S_WORD
M_Code
push ax
push dx
mov ah, 9
mov dx, [.string]
int 21h
pop dx
pop ax
M_Ret
;======================================
;void PrintCharAL (ax)
;--------------------------------------
;Print a single char
;======================================
PrintCharAL:
push ax
push dx
mov dl, al
mov ah, 2
int 21h
pop dx
pop ax
ret
;======================================
;word SimpleAdd (word value1, word value2)
;======================================
SimpleAdd:
M_Vars
M_Arg value1, S_WORD
M_Arg value2, S_WORD
M_Code
mov ax, [.value1]
add ax, [.value2]
; ax is the return value
M_Ret
;======================================
;word LocalStuff (word value)
;--------------------------------------
;Just demonstrating how to work with arguments and local variables
;Return word
;======================================
LocalStuff:
M_Vars
M_Arg value, S_WORD
M_Local var1, S_WORD
M_Local var2, S_WORD
M_Code
push bx
mov ax, [.value]
mov [.var1], ax
mov word [.var2], 20
add word [.var2], ax
mov bx, [.var1]
cmp word [.var2], 100
je .result1
M_PrintfNL "var2 is not 100."
jmp .done
.result1:
M_PrintfNL "var2 is 100."
.done:
; ax is the return variable
mov ax, [.var2]
pop bx
M_Ret
;======================================
;bool IsValue100 (word value)
;======================================
IsValue100:
M_Vars
M_Arg value, S_WORD
M_Code
cmp word [.value], 100
je .is100
; Set carry flag for bool return (false, error)
stc
jmp .done
.is100:
; Clear carry flag for bool return (true, success)
clc
.done:
; Carry flag is the return value
M_Ret
;======================================
;void SampleClearLocalVars (word value1, dword value2, word bool)
;--------------------------------------
;Demonstrate how to init local variables with value 0
;======================================
SampleClearLocalVars:
M_Vars
M_Arg value1, S_WORD
M_Arg value2, S_DWORD
M_Arg bool , S_WORD
M_Local val1 , S_WORD
M_Local len , S_DWORD
M_Local buffer, S_WORD
M_Local absval, S_WORD
M_Code
push ax
push bx
M_LocalClear
mov ax, [.value1]
mov bx, [.value2]
cmp byte [.bool], TRUE
je .is_true
nop
nop
.is_true:
cmp ax, 200
je .result1
mov [.buffer], bx
.result1:
cmp word [.buffer], 0
je .not_set
nop
nop
jmp .done
.not_set:
nop
nop
.done:
pop bx
pop ax
M_Ret
;======================================
;void LocalArraySample ()
;======================================
LocalArraySample:
M_Vars
M_Local array, S_WORD * 100
M_Local dummy, S_DWORD
M_Code
; Clear array and any other local variables
M_LocalClear
push di
; Get array address
M_GetLocalAddress array, di
; Set 3rd field in array to 30
mov word [ss:di + 2 * S_WORD], 30
pop di
M_Ret
;======================================
;void RecursiveSample (word value1, word value2)
;======================================
RecursiveSample:
M_Vars
M_Arg value1, S_WORD
M_Arg value2, S_WORD
M_Local depth, S_WORD
M_Local temp , S_WORD
M_Code
push ax
mov ax, [.value2]
inc ax
mov [.depth], ax
cmp byte [.value2], 0
jne .skip_header
M_PrintfNL "RecursiveSample:"
.skip_header:
M_Printf " depth: "
mov al, [.depth]
add al, "0"
call PrintCharAL
M_Printf " value1: "
mov ax, [.value1]
add al, "0"
call PrintCharAL
M_Printf " value2: "
mov ax, [.value2]
add al, "0"
call PrintCharAL
M_PrintfNL ""
cmp byte [.depth], 4
je .break
shl word [.value1], 1
push word [.depth]
push word [.value1]
call RecursiveSample
M_Printf " Back in depth "
mov al, [.depth]
add al, "0"
call PrintCharAL
M_PrintfNL ""
.break:
pop ax
M_Ret
|
Arguments macro
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
;===========================================================
; Macros to simplify usage of arguments and local variables.
;
; Written by Elmar Hanlhofer, (C)2017-2022, https://www.plop.at
; Free to use, without warranty.
;===========================================================
%macro M_Vars 0
%push my_args
%ifdef SYS64
%assign %$arg_offset_macro S_QWORD + S_QWORD ; Keep rbp and call return save on stack
%elifdef SYS32
%assign %$arg_offset_macro S_DWORD + S_DWORD ; Keep ebp and call return save on stack
%else
%assign %$arg_offset_macro S_WORD + S_WORD ; Keep bp and call return save on stack
%endif
%define ARG_LEN ; Keep ARG_LEN empty until use of arguments, to have an empty return
; parameter if no arguments are used.
%assign %$local_offset_macro 0
%assign %$local_len_macro 0
%define LOCAL_LEN %$local_len_macro
%endmacro
%macro M_Local 2
.%{1}_base_macro equ %$local_offset_macro
.%{1}_offset_macro equ %$local_offset_macro + %2
%ifdef SYS64
%define .%1 (rbp - .%{1}_offset_macro)
%elifdef SYS32
%define .%1 (ebp - .%{1}_offset_macro)
%else
%define .%1 (bp - .%{1}_offset_macro)
%endif
%assign %$local_offset_macro %$local_offset_macro + %2
%assign %$local_len_macro %$local_len_macro + %2
%endmacro
%macro M_Arg 2
%ifndef ARGS ; Inititalize ARG_LEN
%define ARGS
%assign %$arg_len_macro 0
%define ARG_LEN %$arg_len_macro
%endif
.%{1}_offset_macro equ %$arg_offset_macro
%ifdef SYS64
%define .%1 (rbp + .%{1}_offset_macro)
%elifdef SYS32
%define .%1 (ebp + .%{1}_offset_macro)
%else
%define .%1 (bp + .%{1}_offset_macro)
%endif
%assign %$arg_offset_macro %$arg_offset_macro + %2
%assign %$arg_len_macro %$arg_len_macro + %2
%endmacro
%macro M_VarsEnd 0
%undef .arg_len_macro
%undef .local_len_macro
%undef LOCAL_LEN
%undef ARG_LEN
%undef ARGS
%pop ; Restore original context
%endmacro
%macro M_LocalClear 0 ; Set local variables to 0
%ifdef SYS64
push rcx
push rdi
mov rcx, LOCAL_LEN / 2
mov rdi, rbp
sub rdi, S_QWORD ; Dont touch rbp on stack
.local_clear_stack:
mov word [ss:rdi], 0
sub rdi, 2
loop .local_clear_stack
pop rdi
pop rcx
%elifdef SYS32
push ecx
push edi
mov ecx, LOCAL_LEN / 2
mov edi, ebp
sub edi, S_DWORD ; Dont touch ebp on stack
.local_clear_stack:
mov word [ss:edi], 0
sub edi, 2
loop .local_clear_stack
pop edi
pop ecx
%else
push cx
push di
mov cx, LOCAL_LEN / 2
mov di, bp
sub di, S_WORD ; Dont touch bp on stack
.local_clear_stack:
mov word [ss:di], 0
sub di, 2
loop .local_clear_stack
pop di
pop cx
%endif
%endmacro
%macro M_GetLocalAddress 2 ; Get stack address to register (local_variable, register)
%ifdef SYS64
mov %2, rbp
%elifdef SYS32
mov %2, ebp
%else
mov %2, bp
%endif
sub %2, .%{1}_offset_macro
%endmacro
%define M_Code enter LOCAL_LEN, 0
%macro M_Ret 0
leave
ret ARG_LEN
M_VarsEnd
%endmacro
%macro M_Retf 0
leave
retf ARG_LEN
M_VarsEnd
%endmacro
|
Sample 2
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
|
mov dword [.length], 8 ; At first, receive only 8 bytes of the device descriptor
; Setup Packet
push word [.length]
push word 0x0000
push word USB_DESCRIPTOR_TYPE_DEVICE << 8 ; 0x0100
push word USB_GET_DESCRIPTOR ; 0x06
push word 0x80
call CreateSetupPacket ; (word bmRequestType, word bRequest, word wValue, word wIndex, word wLength)
jc .error
mov [.setup], eax
; Allocate buffer for the descriptor
push dword 8
call MEM_Allocate
jc .error
mov [.buffer], eax
push dword 0
push dword Enumerate
push dword [.length]
push dword [.buffer]
push dword [.setup]
push dword [.device]
call QueueControlTransfer ; (dword device, dword setup, dword buffer,
; dword buffer_len, dword callback, dword callback_data)
jc .error
|
Complex function
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
|
;======================================
;bool QueueControlTransfer (dword device, dword setup,
; dword buffer, dword buffer_len,
; dword callback, dword callback_data)
;======================================
QueueControlTransfer:
M_Vars
M_Arg device , S_DWORD
M_Arg setup , S_DWORD
M_Arg buffer , S_DWORD
M_Arg buffer_len, S_DWORD
M_Arg callback , S_DWORD
M_Arg callback_data, S_DWORD
M_Local ed0 , S_DWORD
M_Local first_td , S_DWORD
M_Local current_td, S_DWORD
M_Local last_td , S_DWORD
M_Local new_td , S_DWORD
M_Local endpoint_max_packet_size, S_DWORD
M_Local request_direction, S_WORD
M_Local data_toggle , S_WORD
M_Local buffer_rounding , S_WORD
M_Local transfer, S_DWORD
M_Local transfer_td_list, S_DWORD
M_Local host, S_DWORD
M_Code
M_LocalClear
push eax
push ebx
push ecx
push edx
push esi
push edi
mov ebx, [.device]
;================================
; Setup direction
mov esi, [.setup]
mov al, [esi]
test al, 80h ; bit 7 0...Host to device
; bit 7 1...Device to host
je .host_to_device
mov word [.request_direction], OHCI_IN ; Device to host
jmp .direction_done
.host_to_device:
mov word [.request_direction], OHCI_OUT ; Host to device
.direction_done:
;================================
; Get device host
push dword [ebx + USB_DEVICE.dHost]
pop dword [.host]
;================================
; Get address of endpoint descriptor for EP0
mov esi, [ebx + USB_DEVICE.dEP0]
mov [.ed0], esi
;================================
; Create the transfer
;================================
push dword TRANSFER.size
call MEM_Allocate
jc .error_transfer
mov [.transfer], eax
;================================
; Get address for the td_list
mov eax, [.transfer]
add eax, TRANSFER.dTDList
mov [.transfer_td_list], eax
;================================
; Setup Transfer
push dword [.device]
push dword TRANSFER.dDevice
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
push dword [.ed0]
push dword TRANSFER.dED
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
push dword [.setup]
push dword TRANSFER.dSetup
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
push dword [.buffer]
push dword TRANSFER.dBuffer
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
push dword [.buffer_len]
push dword TRANSFER.dBufferLen
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
push dword [.callback]
push dword TRANSFER.dCallback
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
push dword [.callback_data]
push dword TRANSFER.dCallbackData
push dword [.transfer]
call SetValueDword ; (dword address, dword offset, dword value)
;================================
; Add Transfer to the host
push dword [.transfer]
mov edi, [.host]
add edi, OHCI_HOST.dTransferList
push edi
call LIST_AddEntry ; (dword list, dword entry)
jc .error_transfer
;================================
; Get Max Packet Size of EP0
movzx edx, word [ebx + USB_DEVICE.wEP0_MaxPacketSize]
mov [.endpoint_max_packet_size], edx
;================================
; Get Last TD of ED, which became the first td of the new transfer
mov edx, [esi + OHCI_ED.dTailP]
mov [.current_td], edx
mov [.first_td] , edx
mov [.last_td] , edx
;================================
; Allocate following TD
push dword OHCI_TD.size
call MEM_AllocateAligned16
jc .error
mov [.new_td], eax
;================================
; Update previous transfer descriptor with the SETUP
;================================
mov byte [.data_toggle], 2 ; Initial data toggle for SETUP PID
push dword [.new_td]
push word SETUP_PACKET.size
push dword [.setup]
push word OHCI_CC_NOT_ACCESSED
push word [.data_toggle]
push word OHCI_NO_DELAY_INTERRUPT
push word OHCI_SETUP
push word FALSE
push dword [.current_td]
call UpdateTransferDescriptor ; (dword td_addr, word buffer_rounding, word pid,
; word delay_interrupt, word data_toggle, word condition_code,
; dword buffer_addr, word buffer_len, dword next_td_addr)
;================================
; Add TD to the Transfer TD list
push dword [.current_td]
push dword [.transfer_td_list]
call LIST_NewEntry ; (dword list, dword value)
jc .error
;===================================
; Create TDs for data packets
;===================================
mov edi, [.buffer]
mov ecx, [.buffer_len]
.data_packets_loop:
; Use the latest created TD buffer
mov eax, [.new_td]
mov [.current_td], eax
mov [.last_td] , eax
or ecx, ecx
je .data_packets_done
; Allocate a new following TD
push dword OHCI_TD.size
call MEM_AllocateAligned16
jc .error
mov [.new_td], eax
; Check data packet size
mov edx, ecx
cmp edx, [.endpoint_max_packet_size]
jb .data_packet_small
; Data packet is too large, force to max packet size
mov edx, [.endpoint_max_packet_size]
; Disallow buffer rounding
mov word [.buffer_rounding], FALSE
jmp .update_td
.data_packet_small:
; Allow buffer rounding
mov word [.buffer_rounding], TRUE
.update_td:
xor byte [.data_toggle], 1
push dword [.new_td]
push dx ; This is in word size! Loop is using edx, but here it is at maximum word size.
; Max TD buffer len is word.
push edi
push word OHCI_CC_NOT_ACCESSED
push word [.data_toggle]
push word OHCI_NO_DELAY_INTERRUPT
push word [.request_direction]
push word [.buffer_rounding]
push dword [.current_td]
call UpdateTransferDescriptor ; (dword td_addr, word buffer_rounding, word pid,
; word delay_interrupt, word data_toggle, word condition_code,
; dword buffer_addr, word buffer_len, dword next_td_addr)
; Add TD to the Transfer TD list
push dword [.current_td]
push dword [.transfer_td_list]
call LIST_NewEntry ; (dword list, dword value)
jc .error
add edi, edx ; Set new destination buffer address for next TD
sub ecx, edx
jmp .data_packets_loop
.data_packets_done:
;=================================
; Create TD for SETUP status
;=================================
; Allocate a new following TD
push dword OHCI_TD.size
call MEM_AllocateAligned16
jc .error
mov [.new_td], eax
; Switch direction
cmp word [.request_direction], OHCI_IN
je .dir_out
mov word [.request_direction], OHCI_IN
jmp .dir_done
.dir_out:
mov word [.request_direction], OHCI_OUT
.dir_done:
mov word [.buffer_rounding], FALSE
xor byte [.data_toggle], 1
push dword [.new_td]
push word 0 ; buffer len
push dword 0 ; buffer addr
push word OHCI_CC_NOT_ACCESSED ; condition code
push word [.data_toggle]
push word 6 ; delay interrupt
push word [.request_direction]
push word [.buffer_rounding]
push dword [.current_td]
call UpdateTransferDescriptor ; (dword td_addr, word buffer_rounding, word pid,
; word delay_interrupt, word data_toggle, word condition_code,
; dword buffer_addr, word buffer_len, dword next_td_addr)
; Add TD to the Transfer TD list
push dword [.current_td]
push dword [.transfer_td_list]
call LIST_NewEntry ; (dword list, dword value)
jc .error
; Update Last TD value in transfer
push dword [.current_td]
push dword TRANSFER.dLastTD
push dword [.transfer]
call SetValueDword
;=================================
; Set Control List filled
push dword [.host]
call SetControlListFilled
clc
jmp .done
.error:
push dword [.transfer]
push dword [.host]
call FreeTransfer ; (dword host, dword transfer)
.error_transfer:
push dword [.transfer]
call MEM_Free
stc
.done:
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop eax
M_Ret
|
© 2026 by
Elmar Hanlhofer This page was last modified on 18/03/2022.
|