Dummy question on button handling

SGDK only sub forum

Moderator: Stef

Post Reply
matasiete
Interested
Posts: 10
Joined: Thu Jan 25, 2018 6:21 pm
Location: Spain
Contact:

Dummy question on button handling

Post by matasiete » Sat Apr 06, 2019 9:08 pm

This is my first message here in the community so first and foremost: Hi all!

I'm a total newbie with the SGDK and in addition it's more than 15 years I had not used C, so expect really dummy questions.

I'm at the beginning of the learning process, going through the tutorials and the included samples, and I've thought that the best way to put everything into practice was to port a ZX Spectrum gem to the Megadrive.

Enough introduction for the moment, let's go to my first question.

I've been trying to implement the transition from a screen to another simply by clicking a button, just an extremely simple button handling, but the thing hasn't worked as I expected. I've found a workaround but the truth is I do not understand why it works.

This is the code:

Code: Select all

static u16 pressed;

void IH_waitForPress(u16 joy, u16 button) {

	// joy ignored for the moment, only JOY_1 supported
	JOY_setEventHandler(&recordButtonEvents);

	while (!(pressed & button)) {
		VDP_drawText("", 0, 0); // without this line the handling does not work
		VDP_waitVSync();
	}

	resetButtonEvents();
}

static void recordButtonEvents(u16 joy, u16 changed, u16 state) {

	if (joy == JOY_1) {
		pressed |= (changed & state);
	}
}

static void resetButtonEvents() {
	pressed = 0;
}
As it is it works as expected, but if I get rid of the VDP_drawText statement then it stops working.
Anybody has an explanation?

The project here:
https://github.com/diegomtassis/md-jetp ... handling.c

Cheers!

matasiete
Interested
Posts: 10
Joined: Thu Jan 25, 2018 6:21 pm
Location: Spain
Contact:

Re: Dummy question on button handling

Post by matasiete » Sat Apr 06, 2019 11:06 pm

Ok, I've seen that joy.h JOY_waitPress function implements the exact same behavior, yet still I would like to understand why my implementation is not working (I mean without the workaround).

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Re: Dummy question on button handling

Post by tryphon » Sat Apr 06, 2019 11:14 pm

I may be wrong, but I noticed that loops with only VDP_waitVSync() inside seem to be "overoptimized" and the VDP_waitVSync() ignored.

Try to compile with debug mode (just add debug to the end of your make.exe -f ...).

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Dummy question on button handling

Post by Chilly Willy » Sun Apr 07, 2019 4:42 pm

It's because you aren't using volatile on pressed. It is set by the callback, which is changed by an interrupt, so the variable needs to be set as volatile to force the loop to reread the variable from memory each time the while loop occurs. The drawText makes it work because all the registers get clobbered, so after that it has to reread pressed from memory. Without it, pressed stays in a register so it isn't reread from memory since it's not marked volatile.

This is a common error for people not used to low-level hardware handling in C. Don't forget volatile!

matasiete
Interested
Posts: 10
Joined: Thu Jan 25, 2018 6:21 pm
Location: Spain
Contact:

Re: Dummy question on button handling

Post by matasiete » Sun Apr 07, 2019 8:20 pm

Thanks for the answers.

15 years that I've been exclusively working with JVM languages. I'm really enjoying to be back using C :D

I think the best will be to read some C manual in parallel with my SGDK go-through.

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Re: Dummy question on button handling

Post by tryphon » Sun Apr 07, 2019 8:46 pm

Chilly Willy wrote:
Sun Apr 07, 2019 4:42 pm
It's because you aren't using volatile on pressed. It is set by the callback, which is changed by an interrupt, so the variable needs to be set as volatile to force the loop to reread the variable from memory each time the while loop occurs. The drawText makes it work because all the registers get clobbered, so after that it has to reread pressed from memory. Without it, pressed stays in a register so it isn't reread from memory since it's not marked volatile.

This is a common error for people not used to low-level hardware handling in C. Don't forget volatile!
But why isn't the VDP_waitVSync() enough ?

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Dummy question on button handling

Post by Chilly Willy » Sun Apr 07, 2019 9:12 pm

It doesn't use all the registers. Look at the code

Code: Select all

void VDP_waitVSync()
{
    vu16 *pw;

    pw = (u16 *) GFX_CTRL_PORT;

    while (*pw & VDP_VBLANK_FLAG);
    while (!(*pw & VDP_VBLANK_FLAG));
}
That simply isn't going to clobber more than a couple registers. Also note the vu16 - that's a volatile unsigned 16 bit int. You want that for pressed rather than u16.

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Re: Dummy question on button handling

Post by tryphon » Sun Apr 07, 2019 9:31 pm

So it means a C compiler keep exactly track of which registers is used by a function ?

Concerning the VDP_waitVSync() code : yes the control port adress is stored in a volatile, but I don't understand why here. There's no call to any function in the loop, so there's no risk for the register used to be overwritten ?

(sorry for the questions and the digression, but I've always wondered what was the precise situation(s) chere you need volatile)

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Dummy question on button handling

Post by Chilly Willy » Mon Apr 08, 2019 1:05 am

The more the compiled code can keep commonly used variables in a cpu register, the faster the code will be. Small functions may only use a few registers, so the code that calls that function can leave common variables in registers not touched by the function and hence run faster. In the case of your loop, pressed is used every time through the loop, so unless it's marked as volatile, the compiler will try it's hardest to keep pressed in a register.

Volatile is used when a variable (or memory mapped hardware port) can be changed by something other than the currently executing thread of the cpu. Maybe it's changed by another thread. Maybe it's changed by interrupt handlers (that's the case for pressed). Or maybe it's a hardware register and said hardware can change on its own, like a vdp register, or an io register. Or maybe it's memory that's change by DMA. So in general, make anything referring to hardware volatile, and make anything changed by the cpu outside the running thread volatile.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Dummy question on button handling

Post by Stef » Mon Apr 08, 2019 8:38 am

tryphon wrote:
Sun Apr 07, 2019 9:31 pm
So it means a C compiler keep exactly track of which registers is used by a function ?

Concerning the VDP_waitVSync() code : yes the control port adress is stored in a volatile, but I don't understand why here. There's no call to any function in the loop, so there's no risk for the register used to be overwritten ?

(sorry for the questions and the digression, but I've always wondered what was the precise situation(s) chere you need volatile)
You will see the variable is declared as a volatile pointer so it means the pointed value is volatile, not the control port address value itself.
If you don't do that, the compiler assume the value to be stored in RAM and won't change (except by the CPU itself) so it can optimize the whole and remove the (as value need to be read once). Chilly Willy perfectly explained it =)

Post Reply