4

I'm working on a personal project, an emulator. Let's say there are two registers H and L, each one byte long. So we could write to H or L with one byte. However, some instructions require that you write two bytes to H and L, or HL. First byte goes to H, second goes to L. There are some things that are difficult to implement based on how mine is implemented.

So my idea was to have HL be a single two-byte word. However, there would still exist H and L variables, which share the same address as the first byte of HL and the second byte of HL respectively.

I could do pointers, but I really don't want to declare all my registers as pointers.

One thing I was thinking was a union, like this:

union {
    BYTE H;
    WORD HL;
}

But then I wouldn't know how to put L in there as a second byte.

Any ideas?

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
yhtrjdtryh
  • 73
  • 4

3 Answers3

6

You can do it like this :

union
{
    struct
    {
        BYTE L, H;
    } b;

    WORD HL;
} u;

Some compilers will allow you to do this, although it's non-standard :

union
{
    struct
    {
        BYTE L, H;
    };

    WORD HL;
} u;
Sid S
  • 6,037
  • 2
  • 18
  • 24
  • Yes perfect! Thank you, didn't think about a nameless struct. – yhtrjdtryh Dec 02 '18 at 01:56
  • See https://stackoverflow.com/a/11996970/2785528. "The confusion is that C explicitly permits type-punning through a union, whereas C++ (c++11) has no such permission." The conclusion there is: C++ does not allow type-punning. Even if it looks like it is working, do not rely on the undefined behavior. – 2785528 Dec 02 '18 at 02:19
  • @Locrian note that unnamed structs are not standard C++ (although almost all compilers support them). Apart from that I would like to stress that type punning through a union is undefined behavior in C++ and chances are that you will get bitten some day. And it won't be pretty. Unless you're using GCC which is about the only C++ compiler I'm aware of that guarantees you that this will work… – Michael Kenzel Dec 02 '18 at 02:21
0

How about a union like this one?

union {
 BYTE asBytes[2];
 WORD asWord; 
}

Then you can access H via asBytes[0], L via asBytes[1], or HL as asWord.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Could work, but I feel like it's a little too much to access every register with array indexes. There would have to be 4 unions: AF, BC, DE, and HL. So it kinda sucks to access every register as AF[0] or AF[1]. Thanks though. – yhtrjdtryh Dec 02 '18 at 01:44
  • I think the ABC80/ABC800 emulators are doing a pretty good job. The Z80 itself becomes a struct and the LSB/MSB is dealt with properly. – Ted Lyngmo Dec 02 '18 at 01:47
0

Is there a way to have two variables of different sizes share a memory address without declaring them as pointers?

I believe you can achieve the 'behavior' you desire, without pointers, without shared memory, and without type-punning.

Consider the following class. Note that a user-defined-type's behavior is defined in the functions.

class ML // msByte and lsByte
{
 private:
    BYTE m_bytes[2];    // this data will be 2 * sizeof(BYTE) 

 public:
    ML() = default; // does nothing. ?or do you need to initialize these?
    ~ML() = default; // does nothing unless you want it to

    // extract one or the other byte - consider 

    BYTE lsByte() { return m_bytes[0]; } // index 0/1 
    BYTE msByte() { return m_bytes[1]; } //    fix based on endianess


    // extract the two bytes by summing, 
    //    I prefer bit shifting and or'ing

    WORD ML() { return ( add m_bytes[0] and (256*m_bytes[1]) into WORD }

    // or maybe   ( m_bytes[0] | (m_bytes[1] << 8)); )// fix based on endianess

    void ML( BYTE ls, BYTE ms)
    {   // fix index based on endianess
        m_bytes[0] = ls;   
        m_bytes[1] = ms; 
    } 

    void ML( WORD w)
    {   // fix shifting based on endianess
        ML ( (w & 0xff), ((w >> 8) & 0xff) ) // invoke ML (BYTE, BYTE)
        //        lsbyte      msbyte     
    } 
};
2785528
  • 5,438
  • 2
  • 18
  • 20
  • In host-to-net (hton) and net-to-host (ntoh) I think you will find only function support ... no type-punning, no unions. [Sorry, not compiled.] – 2785528 Dec 03 '18 at 02:06