Info about assembly "variables"

Page 1/2
| 2

Par fpracek

Resident (51)

Portrait de fpracek

19-03-2023, 17:34

I'm using this method for to use "variables" in my code:

ld hl, myVariable ; read its value
ld (lh), 15            ; write its value


myVariable:         db 0

This way is perfect if I have a 1 byte value, but if I must use a 2 (ore more) bytes value I tryed much way to define a "db" but without success.
Can you help me please?

!login ou Inscrivez-vous pour poster

Par aoineko

Paladin (1002)

Portrait de aoineko

19-03-2023, 18:19

I don't know what assembler you are using but you should be able to use the ds directive to reserve some space.

For example to reseve 64 bytes:
ds 64

Par Accumulator

Champion (335)

Portrait de Accumulator

19-03-2023, 18:36

try:

LD HL,(MyVariable)
--> in HL is variable

LD HL,20
LD (MyVariable),HL

MyVariable: DEFW 0

Par fpracek

Resident (51)

Portrait de fpracek

19-03-2023, 19:20

Quote:

I don't know what assembler you are using but you should be able to use the ds directive to reserve some space.

For example to reseve 64 bytes:
ds 64

I'm using sjasmplus, but if I use ds 2 (2 bytes).
I tryed

MissilesRefreshPositionTime			ds 2

but here the compile say to me: Bytes lost.

    ld		hl, MissilesRefreshPositionTime
    ld		(hl),256  ; Bytes lost compile error

Par fpracek

Resident (51)

Portrait de fpracek

19-03-2023, 19:26

Quote:

LD HL,(MyVariable)
--> in HL is variable

LD HL,20
LD (MyVariable),HL

MyVariable: DEFW 0

This is ok for the compiler.
Tomorrow I'll try if all is ok.

THANKS

Par santiontanon

Paragon (1805)

Portrait de santiontanon

19-03-2023, 19:47

The "ld (hl), 256" instruction of the Z80 cpu interprets the second value to be an 8 bit constant. So, it will ONLY write 1 byte. Regardless of however you define your variable. In this case, the least-significant byte of 256, which is just a "0".

To write value "256" to your "MissilesRefreshPositionTime" 16 bit variable, you have other options, for example:

- Put the address in "hl", and write 1 byte at a time:

  ld hl, MissilesRefreshPositionTime
  ld (hl), 256 % 8  ; write the least-significant byte
  inc hl
  (ld (hl), 256 / 8  ; write the most-significant byte

- Put the 16bit value in a 16bit register (e.g., "hl"), and then write it in a single instruction using an immediate address:

  ld hl, 256
  ld (MissilesRefreshPositionTime), hl

Basically, the z80 has a limited instruction set. So, you need to be careful with the things that the z80 can or cannot do. I strongly advise you to learn the z80 instruction set very carefully. Otherwise, coding in assembler is going to be a big challenge Smile

Par fpracek

Resident (51)

Portrait de fpracek

20-03-2023, 06:56

Thanks for the explanation and the useful tips. It will be my care to know all the z80 instructions, even if only with experience I will be able to extricate myself at your levels.
Thanks again

Par Ped7g

Expert (67)

Portrait de Ped7g

20-03-2023, 14:19

fpracek wrote:

but here the compile say to me: Bytes lost.

    ld		hl, MissilesRefreshPositionTime
    ld		(hl),256  ; Bytes lost compile error

BTW maybe you can try latest version of z00m's fork of sjasmplus, I did update some of the error message in newer versions to make them hopefully more understandable:

$ sjasmplus --version
SjASMPlus Z80 Cross-Assembler v1.20.2 (<a href="https://github.com/z00m128/sjasmplus" title="https://github.com/z00m128/sjasmplus">https://github.com/z00m128/sjasmplus</a>)
$ sjasmplus --msg=lst -
 ld (hl),256
# file opened: 
(1): warning: value 0x100 is truncated to 8bit value: 0x00
1     0000 36 00         ld (hl),256
2     0002
# file closed: 

And in the listing the file there are line numbers, address the instruction is assembled for (0000) and machine code bytes `36 00` -> so you can sometimes reverse-check with instruction table what the assembler does produce, in this case it's `ld (hl),n` opcode and the `00` is the value, which is the truncated 256 to 8 bits. So this may be sometimes handy to figure out what happens during assembly.

Par ro

Scribe (4963)

Portrait de ro

20-03-2023, 16:04

Some basics: In ASM you can define RAM locations using the assembler with
DefB or DB (both are usually supported) - define 1 byte.
DefW or DW (idem) - define 1 word (= 2bytes)
DefS or DS (idem) - define space

So in your case, it would be DW instead of DB to house a 16-bit (is 2 bytes) value.
But, you can also define more than 1 values at one DB or DW line

Some examples;

DB 100 ;Define 1 byte with the value 100
DW 100 ;Define 1 word (2 bytes) with the value 100
DS 100 ;Reserver 100x1bytes (no values)
DB 1,2,100 ;Define 3 bytes each with its own value
DB 1,100,65535 ;Define 3 words, each with its own value

So

LD HL,myVariable ;Pointer to myVariable
LD (HL),100 ;Put 100 in myVariable
ret
myVariable DW 0 ;2 bytes of RAM to store myVariable

Par Micha

Expert (103)

Portrait de Micha

21-03-2023, 09:19

What I always do is something like this (assuming the program is in ROM and you want to use RAM for variables) in the beginning of my .asm file:

Xpos: equ &C000
Ypos: equ &C001
Score: equ &C002
Highscore: equ &C004
Level: equ &C006
etc

XPos and Ypos are bytes and Score and Highscore are words.
You can load the variables like this:

ld a,0   (or xor a...)
ld (Xpos),a
ld hl,8000
ld (Highscore),hl

It might look tricky, because if you make a mistake you can overwrite variables, but it makes it easier to do something like this:

Enemy1: equ &C010 ; this is not a variable itself, but a start address for Enemy1 variables
Enemy1X: equ &C010
Enemy1Y: equ &C011
Enemy1Power: equ &C012

Enemy2: equ &C020 ; this is not a variable itself, but a start address for Enemy2 variables
Enemy2X: equ &C020
Enemy2Y: equ &C021
Enemy2Power: equ &C022

dx: equ 0  ; these are not variables, but displacements
dy: equ 1
dpow: equ 2

start:
ld IX,Enemy1
ld (IX+dx),20   ; sets x variable
ld (IX+dy),10  ; sets y 
ld (IX+dpow),0   ; sets power
ld IX,Enemy2
ld (IX+dx),50       ... etc

Par ro

Scribe (4963)

Portrait de ro

21-03-2023, 09:48

One thing I don't like about these EQU thingies, is that they are permanent or absolute. If you need to change up the enemyTable for example, you'll need to redo a lot of work. I'd like to just tell the assembler with the ORG directive to reserve space with DS.

Example.

ORG #C000
Enemy1:
Enemy1.x DS 1
Enemy1.y DS 1
Enemy1.Pow DS 1

If I need to change the RAM location of this table, just change the ORG and be done.
If I later on decide to add a STATUS byte, and I want it to be the first byte, I'll just add it, like this:

ORG #C000
Enemy1:
Enemy1.stat DS 1
Enemy1.x DS 1
Enemy1.y DS 1
Enemy1.Pow DS 1

However, you still have the labels for the index register to work with. In that case, I'll use EQU as an offset indeed.

stat EQU 0
x EQU 1
y EQU 2
pow EQU 3

This is, again, kinda of static. meh.

I do this especially since my projects usually have more than one .asm source files which need to a link to each other WITHOUT using a linker for the whole project *(I like ASM in small parts). So having such spaces defines makes it easy to transfer between sources, for example, too.

just my thoughts Smile
I love discussing differnts ways to walk paths

Page 1/2
| 2