News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Passing variable addresses with CALL

Started by zeebee, 22:24, 19 January 12

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

zeebee

Hi all,

I am trying to pass the address of a string variable from BASIC to a small machine code program. I am learning about IX and IY.

When I pass:

a%=42
CALL &4000,@a%

The address pointed to by IX contains the address of the 'a' variable in memory, where BASIC is keeping it, so I can read and modify it through IX.

But when I do:

a$="hobbits"
call &4000,@a$

The address pointed to by IX does not contain the address of this string variable in memory. I found the string somewhere else in memory, and I don't know how to get this variable's address in my assembly code.

I have tried on both WinAPE and WinCPC emulators, I don't have a real Amstrad (yet!).

Am I doing something obviously wrong?

Thanks.

ralferoo

#1
Try something like this:
ld e,(ix+0)
ld d,(ix+1)
push de
pop iy
ld a,(iy+0)    ; A=length
ld l,(iy+1)
ld h,(iy+2)    ; HL=address

The last parameter will be at (IX+0/1), the second to last at (IX+2/3) etc... A at entry holds the number of parameters.

The simplest way of thinking about it is that BASIC pushes each parameter onto the stack and then does LD IX,0:ADD IX,SP before calling your code.

zeebee

Yes, and this works as you describe for the a% case, but not for strings, i.e. a$

BASIC:

a$="hobbits"
call &4000,@a$

z80:

org &4000
limit &4fff
ld e,(ix+0)
ld d,(ix+1)
push de
pop iy
ld a,(iy+0)    ; A=length
ld l,(iy+1)
ld h,(iy+2)    ; HL=address
ret

A does contain the number of parameters, 1. ED is not loaded with the address of "hobbits" in memory, when I pass the address of a string (a $ var) - it only works when I pass numbers (% vars).

In your example, if it worked, I would expect to get the ASCII values for 'h', 'o', and 'b' loaded into A, L, and H respectively. This is not the case because the address pointed to by IX and pushed onto the stack does not point to "hobbits" where it is kept in memory by BASIC.

So, does this work on a real machine?

[I can't believe WinAPE and WinCPC would have this wrong so it must be me :D ]


zeebee

There seems to be an extra level of indirection when string variables are passed, and a strange offset of one byte.

This works for me (under WinAPE):

org &4000
limit &4fff
ld e,(ix+0)
ld d,(ix+1)
inc de
ld a,(de)
ld l,a
inc de
ld a,(de)
ld h,a
push hl
pop iy
ld a,(iy+0)
call &bb5a    ;'h'
ld a,(iy+1)
call &bb5a    ;'o'
ld a,(iy+2)
call &bb5a    ;'b'
ret

I have to INC the address in IX by one byte, and read the two bytes at that location as another address - the address of my string!? Contrast this with passing in numeic vars (%), where IX is the actual address of that variable in memory.

I know C, so the address of a string being a ptr to a ptr doesn't surpise me, but I do not understand IX being one byte out ...


arnoldemu

Quote from: zeebee on 22:24, 19 January 12
Hi all,

I am trying to pass the address of a string variable from BASIC to a small machine code program. I am learning about IX and IY.

When I pass:

a%=42
CALL &4000,@a%

The address pointed to by IX contains the address of the 'a' variable in memory, where BASIC is keeping it, so I can read and modify it through IX.

But when I do:

a$="hobbits"
call &4000,@a$

The address pointed to by IX does not contain the address of this string variable in memory. I found the string somewhere else in memory, and I don't know how to get this variable's address in my assembly code.

I have tried on both WinAPE and WinCPC emulators, I don't have a real Amstrad (yet!).

Am I doing something obviously wrong?

Thanks.
In this case, IX points to a "string descriptor". This is a 3-byte structure with string length (1 byte), string address (2 bytes).
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

zeebee

Thanks. That is exactly the case. :)

ralferoo

Quote from: zeebee on 23:23, 19 January 12
In your example, if it worked, I would expect to get the ASCII values for 'h', 'o', and 'b' loaded into A, L, and H respectively. This is not the case because the address pointed to by IX and pushed onto the stack does not point to "hobbits" where it is kept in memory by BASIC.
You clearly didn't read the comments in my Z80 code where I said that A is the length and HL is the address of the string. Here it is again:  ;)

ld a,(iy+0)    ; A=length
ld l,(iy+1)
ld h,(iy+2)    ; HL=address

Your example is just moving the address from HL to IY in order to read the characters. Alternatively, you could have done something like this at the end of my code to print the entire string:

or a
ret z       ; return if empty string
ld b,a
print_loop:
ld a,(hl)
call &bb5a
inc hl
djnz print_loop

zeebee

Sorry, I didn't understand your reply from the code alone. The other poster said it in just such a way that I got it.


As you can see form my code snippet, I am very new to assembly. :)


You example for printing out the string works perfectly and is much neater than my own. Thankyou.

ralferoo

Heh, not a problem. Good luck in learning Z80... if you have questions, feel free to ask as there are quite a few coders on here!

Also, one of the best ways of learning is to take a look at other people's code, preferably with some comments, and try to figure out how it works...

Powered by SMFPacks Menu Editor Mod