3

I've been mulling over this for the last couple of days, and i cant see what is wrong with my code. Really just looking to assign two memory addresses to two pointers. ROM at 0x0000 and RAM at 0x7000. The program compiles, but instead of writing 'mydata' to the RAM location 0x7000, it instead writes zeros to the 0x0000 location, the code is below:

    unsigned short *ROM = (unsigned char*)(0x0000);     //these have no effect, always accesses 0x0000, assignment fails
    unsigned short *RAM = (unsigned char*)(0x7000);     //these have no effect, always accesses 0x0000, assignment fails

    //__at (0x0000) unsigned char *ROM;     //these have no effect, always accesses 0x0000, assignment fails
   //__at (0x7000) unsigned char *RAM;      //these have no effect, always accesses 0x0000, assignment fails
    
    unsigned char mydata[]={0xFF, 0xFE,0xCE,0xD1,0xFF, 0x1E,0x2E,0x31,0x4F, 0x5E,0x6E,0xD7,0x8F, 0xF9,0xAE,0x11};
    int main(){
        
    unsigned char bytecount=0;
    int n=0;
    for(n=0;n<16;n++)RAM[n]=mydata[n];
            
    return 0;
    }

Wondering if anyone has experienced this or a similar problem and has any ideas what could be wrong. I considered the compiler options where the code is placed at 0x0100 and the data at 0xA000. However it shouldnt affect the outcome though. This is a z80 compile.

interestingly, note that i have unsigned short, the erasing with zeros happens in pairs then after a cycle, the next pair of bytes are erased, and so on.. changing this to unsigned char results in single bytes being erased.

within the assembled output, there is a load HL register pair with the address A003, which I can't seem to attribute to any kind of variable in my program. there is no definition at A003 yet the compiled program is accessing it.

  000000                        232 __xinit__ROM:
  000000 00 00                  233     .dw #0x0000
  000002                        234 __xinit__RAM:
  000002 00 70                  235     .dw #0x7000

  000004                        236 __xinit__mydata:
 

the result

ld hl, 0A003 (results in value 0x0000)
...
ld (hl),a (a is always 0, this is written to location 0x0000, 0x0001, and so on).

Thanks in advance.

10
  • try with volatile. Commented Aug 31, 2023 at 18:10
  • Thank you Kamil, I tried adding volatile but unfortunately same result. Commented Aug 31, 2023 at 19:08
  • 1
    Does *(volatile unsigned short *)(0x7000) = 0xFFu; work? Commented Aug 31, 2023 at 19:21
  • 2
    Your ROM and RAM variables presumably live in ... RAM. Are you overwriting them? Commented Aug 31, 2023 at 19:28
  • 2
    Please edit your question and add the linker map and the complete disassembly or listing. The snippets do not prove anything. (I understand Z80 assembler. ;-) Which system do you target? If it is not a commonly known system, please add links to its documentation. Commented Sep 1, 2023 at 6:56

2 Answers 2

1

I'd posted a follow up comment earlier this morning but it doesnt seem to appear. I've got the program working by moving the initialisation of the RAM and ROM pointers to within the main program, instead of globally. Also I'd changed the unsigned char mydata to a const (but this aspect wasnt the issue i'd posted about, but still necessary).

unsigned char *ROM;  //initialisation moved to main
unsigned char *RAM;  //initialisation moved to main

const unsigned char mydata[16]={0xFF, 0xFE,0xCE,0xD1,0xFF, 0x1E,0x2E,0x31,0x4F, 0x5E,0x6E,0xD7,0x8F, 0xF9,0xAE,0x11};
int main(){
    
    ROM = (unsigned char*)(0x0000);
    RAM = (unsigned char*)(0x7000);
    __asm
    DI
    ;;puts the stackpointer at the top of the 8k ram area (ram starts at 0xA000 and 8191 bytes later is 0xBFFF)
    ld  sp,#0xBFFF
    __endasm;
    
    
    unsigned char n=0;

    for(n=0;n<16;n++)RAM[n]=mydata[n];

    return 0;
}

looking at the compiled assembly code in each case here is the working based on above:

;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 4.1.0 #12072 (MINGW64)
;--------------------------------------------------------
    .module test
    .optsdcc -mz80
    
;--------------------------------------------------------
; Public variables in this module
;--------------------------------------------------------
    .globl _main
    .globl _RAM
    .globl _ROM
    .globl _mydata
;--------------------------------------------------------
; special function registers
;--------------------------------------------------------
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
    .area _DATA
                                                         
          
                                                         
                   
_ROM::
    .ds 2
_RAM::
    .ds 2
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
    .area _INITIALIZED
;--------------------------------------------------------
; absolute external ram data
;--------------------------------------------------------
    .area _DABS (ABS)
;--------------------------------------------------------
; global & static initialisations
;--------------------------------------------------------
    .area _HOME
    .area _GSINIT
    .area _GSFINAL
    .area _GSINIT
;--------------------------------------------------------
; Home
;--------------------------------------------------------
    .area _HOME
    .area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
    .area _CODE
;test.c:17: int main(){
;   ---------------------------------
; Function main
; ---------------------------------
_main::
;test.c:19: ROM = (unsigned char*)(0x0000);
    ld  hl, #0x0000
    ld  (_ROM), hl
;test.c:20: RAM = (unsigned char*)(0x7000);
    ld  h, #0x70
    ld  (_RAM), hl
;test.c:25: __endasm;
    DI
;;puts  the stackpointer at the top of the 8k ram area (ram starts at 0xA000 and 8191 bytes later is 0xBFFF)
    ld  sp,#0xBFFF
;test.c:43: for(n=0;n<16;n++)RAM[n]=mydata[n];
    ld  c, #0x00
00102$:
    ld  hl, (_RAM)
    ld  b, #0x00
    add hl, bc
    ld  a, #<(_mydata)
    add a, c
    ld  e, a
    ld  a, #>(_mydata)
    adc a, #0x00
    ld  d, a
    ld  a, (de)
    ld  (hl), a
    inc c
    ld  a, c
    sub a, #0x10
    jr  C, 00102$
;test.c:52: return 0;
    ld  hl, #0x0000
;test.c:53: }
    ret
_mydata:
    .db #0xff   ; 255
    .db #0xfe   ; 254
    .db #0xce   ; 206
    .db #0xd1   ; 209
    .db #0xff   ; 255
    .db #0x1e   ; 30
    .db #0x2e   ; 46
    .db #0x31   ; 49    '1'
    .db #0x4f   ; 79    'O'
    .db #0x5e   ; 94
    .db #0x6e   ; 110   'n'
    .db #0xd7   ; 215
    .db #0x8f   ; 143
    .db #0xf9   ; 249
    .db #0xae   ; 174
    .db #0x11   ; 17
    .area _CODE
    .area _INITIALIZER
             
            
             
            
    .area _CABS (ABS)

and here is the non-working assembly previously where attempted global initialize of pointers:

;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 4.1.0 #12072 (MINGW64)
;--------------------------------------------------------
    .module test
    .optsdcc -mz80
    
;--------------------------------------------------------
; Public variables in this module
;--------------------------------------------------------
    .globl _main
    .globl _RAM
    .globl _ROM
    .globl _mydata
;--------------------------------------------------------
; special function registers
;--------------------------------------------------------
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
    .area _DATA
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
    .area _INITIALIZED
_ROM::
    .ds 2
_RAM::
    .ds 2
;--------------------------------------------------------
; absolute external ram data
;--------------------------------------------------------
    .area _DABS (ABS)
;--------------------------------------------------------
; global & static initialisations
;--------------------------------------------------------
    .area _HOME
    .area _GSINIT
    .area _GSFINAL
    .area _GSINIT
;--------------------------------------------------------
; Home
;--------------------------------------------------------
    .area _HOME
    .area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
    .area _CODE
;test.c:17: int main(){
;   ---------------------------------
; Function main
; ---------------------------------
_main::
;test.c:25: __endasm;
    DI
;;puts  the stackpointer at the top of the 8k ram area (ram starts at 0xA000 and 8191 bytes later is 0xBFFF)
    ld  sp,#0xBFFF
;test.c:43: for(n=0;n<16;n++)RAM[n]=mydata[n];
    ld  c, #0x00
00102$:
    ld  hl, (_RAM)
    ld  b, #0x00
    add hl, bc
    ld  a, #<(_mydata)
    add a, c
    ld  e, a
    ld  a, #>(_mydata)
    adc a, #0x00
    ld  d, a
    ld  a, (de)
    ld  (hl), a
    inc c
    ld  a, c
    sub a, #0x10
    jr  C, 00102$
;test.c:52: return 0;
    ld  hl, #0x0000
;test.c:53: }
    ret
_mydata:
    .db #0xff   ; 255
    .db #0xfe   ; 254
    .db #0xce   ; 206
    .db #0xd1   ; 209
    .db #0xff   ; 255
    .db #0x1e   ; 30
    .db #0x2e   ; 46
    .db #0x31   ; 49    '1'
    .db #0x4f   ; 79    'O'
    .db #0x5e   ; 94
    .db #0x6e   ; 110   'n'
    .db #0xd7   ; 215
    .db #0x8f   ; 143
    .db #0xf9   ; 249
    .db #0xae   ; 174
    .db #0x11   ; 17
    .area _CODE
    .area _INITIALIZER
__xinit__ROM:
    .dw #0x0000
__xinit__RAM:
    .dw #0x7000
    .area _CABS (ABS)

Apologies for the lengthy code, but to highlight the differences between the two: in the 'working' version, the text .area _INITIALIZED is moved away from the .area_data where the _rom and _ram are defined as .ds 2.

line 59 shows these then being initialised which is within the main program:

main::
;test.c:19: ROM = (unsigned char*)(0x0000);
    ld  hl, #0x0000
    ld  (_ROM), hl
;test.c:20: RAM = (unsigned char*)(0x7000);
    ld  h, #0x70
    ld  (_RAM), hl

However if you look at the non working code, there is no such initialisation, as it is assumed globally. instead there is a bit of code in the .area _INITIALIZER which looks like

.area _INITIALIZER
__xinit__ROM:
    .dw #0x0000
__xinit__RAM:
    .dw #0x7000

This may not translate into any kind of binary, thus it doesnt initialise on the z80. Also for reference my compiler line is :

sdcc -mz80 --code-loc 0x0000 --no-std-crt0 --data-loc 0xA000 test.c

I'd wondered perhaps if the insertion of --no-std-crt0 might have prevented the init, but switching this out makes the program fail completely.

Regards

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @gregspears, I've always wanted to develop my own homebrew z80 machine with software, finally got there, but still learning more. Its such a simple yet powerful little device. to see it in operation is fascinating! i'd recommend it anyone.
0

It looks like a problem with your crt0.s (C runtime) or perhaps the order of segments. Can you share it with us? When creating a ROM program you usually make your _DATA segment point to RAM and the _INITIALIZED segment right after it (because your crt0.s may use initial part of data segment, otherwise they'll be the same). Then upon startup it is the job of the crt0.s to copy stuff from _INITIALIZER to _INITIALIZED.

This is the typical order of your segments.

    ;; (linker documentation) where specific ordering is desired -
    ;; the first linker input  file should  have  the area definitions
    ;; in the desired order
    .area   _HEADER
    .area   _CODE
    .area   _INITIALIZER
    .area   _INITFINAL
    .area   _GSINIT
    .area   _GSFINAL
    .area   _DATA
    .area   _INITIALIZED
    .area   _BSS
    .area   _HEAP

And this is the part that does the copying...

    gsinit:
    ;; initialize vars from initializer
    ld      de, #s__INITIALIZED ; could be s__DATA too...
    ld      hl, #s__INITIALIZER
    ld      bc, #l__INITIALIZER
    ld      a, b
    or      a, c
    jr      z, gsinit_none
    ldir
    gsinit_none:

And that should copy all your vars from ROM to RAM before calling your main. Which you now explicitly do later. So check the order of your segments and where does your _DATA point to (all is in the map file).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.