Page 1 of 1

Why is my ROM writable code not working?

Posted: Wed Jul 27, 2022 6:17 pm
by derekfountain
I have this piece of code which checks to see if the Spectrum's ROM is writable (which on an emulator it might be):

Code: Select all

uint8_t is_rom_writable(void)
{
  uint8_t byte0 = z80_bpeek(0);

  z80_bpoke( 0, ~byte0 );
  if( z80_bpeek(0) == byte0 )
    return 0;

  z80_bpoke( 0, byte0 );

  return 1;
}
So peek the byte at 0000, poke it with the inversion, then check whether it has changed. If not, ROM isn't writable. Otherwise, put it back and return 1.

But it doesn't work. Looking at the code generated:

Code: Select all

   498                          ;	---------------------------------
   499                          ; Function is_rom_writable
   500                          ; ---------------------------------
   501                          _is_rom_writable:
   502                          ;tracetable.c:58: uint8_t byte0 = z80_bpeek(0);
   503   00004e 210000          	ld	hl,0x0000
   504   000051 4e              	ld	c, (hl)
   505                          ;tracetable.c:60: z80_bpoke( 0, ~byte0 );
   506   000052 79              	ld	a, c
   507   000053 2f              	cpl
   508                          ;tracetable.c:61: if( z80_bpeek(0) == byte0 )
   509   000054 320000          	ld	(0x0000),a
   510                          ;tracetable.c:62: return 0;
   511   000057 91              	sub	a,c
   512   000058 2003            	jr	NZ,l_is_rom_writable_00102
   513   00005a 6f              	ld	l,a
   514   00005b 1806            	jr	l_is_rom_writable_00103
   515                          l_is_rom_writable_00102:
   516                          ;tracetable.c:64: z80_bpoke( 0, byte0 );
   517   00005d 210000          	ld	hl,0x0000
   518   000060 71              	ld	(hl), c
   519                          ;tracetable.c:66: return 1;
   520   000061 2e01            	ld	l,0x01
   521                          l_is_rom_writable_00103:
   522                          ;tracetable.c:67: }
   523   000063 c9              	ret
I can't work that out. But it always returns 1 AFAICT.

This is with 2.2 and SDCC:

Code: Select all

>z88dk-zsdcc -v

ZSDCC IS A MODIFICATION OF SDCC FOR Z88DK
Build: 4.2.0 #13081 (Linux) Jul 24 2022

Re: Why is my ROM writable code not working?

Posted: Wed Jul 27, 2022 6:25 pm
by derekfountain
I just reverted to my 2.1 install which has

Code: Select all

>zsdcc -v

ZSDCC IS A MODIFICATION OF SDCC FOR Z88DK
Build: 4.0.7 #12036 (Linux) Nov 27 2021
That works. The generated code is

Code: Select all

491   004E              _is_rom_writable:
492   004E              ;tracetable.c:58: uint8_t byte0 = z80_bpeek(0);
493   004E  21 00 00    	ld	hl,0x0000
494   0051  4E          	ld	c, (hl)
495   0052              ;tracetable.c:60: z80_bpoke( 0, ~byte0 );
496   0052  79          	ld	a, c
497   0053  2F          	cpl
498   0054  21 00 00    	ld	hl,0x0000
499   0057  77          	ld	(hl), a
500   0058              ;tracetable.c:61: if( z80_bpeek(0) == byte0 )
501   0058  6C          	ld	l, h
502   0059  7E          	ld	a, (hl)
503   005A              ;tracetable.c:62: return 0;
504   005A  91          	sub	a,c
505   005B  20 03       	jr	NZ,l_is_rom_writable_00102
506   005D  6F          	ld	l,a
507   005E  18 06       	jr	l_is_rom_writable_00103
508   0060              l_is_rom_writable_00102:
509   0060              ;tracetable.c:64: z80_bpoke( 0, byte0 );
510   0060  21 00 00    	ld	hl,0x0000
511   0063  71          	ld	(hl), c
512   0064              ;tracetable.c:66: return 1;
513   0064  2E 01       	ld	l,0x01
514   0066              l_is_rom_writable_00103:
515   0066              ;tracetable.c:67: }
516   0066  C9          	ret
which looks more sensible.

Re: Why is my ROM writable code not working?

Posted: Wed Jul 27, 2022 6:57 pm
by dom
I suspect the z80_bpeek macro probably needs a volatile popping in there so that it refetches from memory.

Re: Why is my ROM writable code not working?

Posted: Wed Jul 27, 2022 7:24 pm
by derekfountain
Yes, making it my code:

Code: Select all

volatile uint8_t byte0 = z80_bpeek(0);
fixes it for 2.2.

So the compiler is assuming that it's already got a copy of the value at 0x0000 and thinks it doesn't need to reread it. So is what it's doing valid? I think it is, isn't it? I'm not sure what the rules are...