简体   繁体   中英

Access struct member from a struct pointer with Open Watcom inline assembly

I have some code that writes to and reads the I/O ports for the VGA. I am trying to implement the working C code functionality in the inline assembler. I am using Open Watcom 2.0 and compiling for DOS 16bit.

To write to the color palette on the VGA, I have come up with this. This does not work correctly.

EDIT: The code for setPaletteColor is not entirely accurate. I have updated to reflect the actual code.

void setPaletteColor (unsigned char index, rgbColor *p_color)
{
    _asm
    {
        ; tell VGA card we are going to update a palette register
        mov dx,PALETTE_MASK
        mov al,0xff
        out dx,al

        ; tell VGA which register we will be updating
        mov dx,PALETTE_REGISTER_WR
        mov al,index
        out dx,al

        ; update the color in the register at index
        mov dx,PALETTE_DATA
        mov al,*p_color
        out dx,al
        mov al,*p_color // this is actually *(p_color+1) but this actually gets the next structure not the next data member, so I left it out of the code I typed for my question.
        out dx,al
        mov al,*p_color // same here, actually is *(p_color+2)
        out dx,al
    }
}

And for reading, I have this. This, also, doesn't work correctly.

void getPaletteColor (unsigned char index, rgbColor *p_color)
{
    unsigned char *p_red = &p_color->red;
    unsigned char *p_green = &p_color->green;
    unsigned char *p_blue = &p_color->blue;
    _asm
    {
        ; tell VGA card we are going to read a palette register
        mov dx,PALETTE_MASK
        mov al,0xff
        out dx,al

        ; tell VGA which register we will be reading
        mov dx,PALETTE_REGISTER_RD
        mov al,index
        out dx,al

        ; read the data into the color struct at 'p_color'
        mov dx,PALETTE_DATA
        in  al,dx
        mov *p_red,al
        in  al,dx
        mov *p_green,al
        in  al,dx
        mov *p_blue,al
     }   
}

Now here are the pure C versions that DO work.

void setPaletteColor (unsigned char index, rgbColor *p_color)
{
    outp(PALETTE_MASK,0xff);
    outp(PALETTE_REGISTER_WR, index);
    outp(PALETTE_DATA,p_color->red);
    outp(PALETTE_DATA,p_color->green);
    outp(PALETTE_DATA,p_color->blue); 
}

And for read.

void getPaletteColor (unsigned char index, rgbColor *p_color)
{
    outp(PALETTE_MASK,0xff);
    outp(PALETTE_REGISTER_RD, index);
    p_color->red   = inp(PALETTE_DATA);
    p_color->green = inp(PALETTE_DATA);
    p_color->blue  = inp(PALETTE_DATA); 
}

NOTE: I cannot use the '.' operator nor the '->' operator in the inline assembly because the compiler doesn't support it.

Here is the definition of the rgbColor struct.

typedef struct rgbColorTag
{
    unsigned char red;
    unsigned char green;
    unsigned char blue;
} rgbColor;

A good question would have described how it doesn't work. Just saying it "doesn't work" made me assume it was a syntax error, because I don't know Watcom-style inline asm. I just assumed it was similar to MSVC-style, and that using a C dereference operator in asm was a syntax error (eg in mov al,*p_color ).

Apparently that is valid syntax for Open Watcom, but you're loading the same byte 3 times . Maybe try mov al, *(p_color+1) for the second byte? Although that might just do C pointer math, and get the start of the next struct. Check your compiler manual for available syntax options.


You could also just load the pointer into a register and use offsets from it yourself (with addressing modes like mov al, [si+1] ). This depends on the 3 struct members being laid out in order with no padding, but that should be a safe assumption, I think. You could always check the compiler's asm output to see how it lays out the struct.

Since your struct is laid out in the right order, you should be able to loop over the 3 bytes in it using OUTS . Or even REP OUTS so you don't need to write a loop.

    cld
    mov   si, p_color        ; get the function arg in a register
    mov   dx, PALETTE_DATA
    mov   cx, 3
    rep outsb                ; OUT 3 times, to port DX, using data from DS:[SI] (and do SI++ post-increment)

Similarly, for reading,

    cld
    mov   di, p_color
    mov   dx, PALETTE_DATA
    mov   cx, 3
    rep insb              ; IN 3 times, to port DX, using data from DS:[DI] (and do DI++)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM