2016-10-31 13 views
0

У меня есть код, который записывает и считывает порты ввода-вывода для VGA. Я пытаюсь реализовать функциональность C-кода в встроенном ассемблере. Я использую Open Watcom 2.0 и компилирую для DOS 16 бит.Доступ к структурному элементу из указателя структуры с помощью встроенной сборки Open Watcom

Чтобы написать цветную палитру на VGA, я придумал это. Это работает неправильно.

EDIT: Код для setPaletteColor не совсем точен. Я обновил, чтобы отразить фактический код.

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 
    } 
} 

И для чтения у меня это есть. Это также не работает правильно.

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 
    } 
} 

Теперь вот чистые версии C, которые работают DO.

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); 
} 

И для чтения.

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); 
} 

ПРИМЕЧАНИЕ: Я не могу использовать '.' оператора или оператора '->' в встроенной сборке, потому что компилятор его не поддерживает.

Вот определение структуры rgbColor.

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

ли http://bos.asmhackers.net/docs/vga_without_bios/docs/palettesetting.pdf помочь? Похоже, он делает то же, что и ты. –

+0

* ПРИМЕЧАНИЕ. Я не могу использовать '.' оператора или оператора '->' в встроенной сборке, потому что компилятор не поддерживает его. * Поэтому присвойте данные локальной переменной на C и прочитайте или напишите, что в inline asm. Это может заставить компилятор сделать что-то глупое, например, на самом деле исправить дополнительные инструкции, чтобы скопировать его в стек. Что случилось с чистой версией C? Вызывает ли компилятор медленный код для этого?Почему, по-вашему, вы можете получить более быстрый код от его выполнения с помощью встроенного asm? Или это 'outp' фактическая функция, вызываемая, а не внутренняя? –

+1

@PeterCordes Посмотрите на мою сборку «getPaletteColor()« Я использую переменные локального указателя, чтобы получить смещения членов для цветовой структуры. Чистая версия C прекрасна, но я хочу знать, как все это делать. Вот почему я пишу программу DOS в первую очередь. Это все учебный опыт, и до сих пор я многому научился. 'outp' - это функция, предоставляемая компилятором для записи в порты ввода-вывода. То же самое с 'inp'. – SeanRamey

ответ

1

Хороший вопрос описал бы, как он не работает. Просто говорю, что это «не работает» заставило меня предположить, что это была синтаксическая ошибка, потому что я не знаю встроенный asm в стиле Watcom. Я просто предположил, что он похож на MSVC-стиль, и что использование оператора d-разметки C в asm является синтаксической ошибкой (например, в mov al,*p_color).

Видимо, это допустимый синтаксис для Open Watcom, но Вы загружаете один и тот же байт 3 раза. Может быть, попробуйте mov al, *(p_color+1) для второго байта? Хотя это может просто сделать C-указатель math и получить начало следующей структуры. Ознакомьтесь с руководством по компилятору для доступных вариантов синтаксиса.


Вы также можете просто загрузить указатель в регистр и использовать смещение от него самостоятельно (с режимами адресации, как mov al, [si+1]). Это зависит от того, как 3 элемента структуры будут выложены, чтобы не заполнить, но это должно быть безопасным предположением, я думаю. Вы всегда можете проверить выход asm компилятора, чтобы увидеть, как он описывает структуру.

Поскольку ваша структура выложена в правильном порядке, вы должны иметь возможность перебирать через нее 3 байта, используя OUTS. Или даже REP OUTS, поэтому вам не нужно писать цикл.

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) 

Аналогично, для чтения,

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++) 
+0

Собственно, мой код компилируется без ошибок или предупреждений и запускается. Он просто не делает то, что я ожидал. Спасибо за этот код. Я постараюсь адаптировать его и посмотреть, работает ли он! :) – SeanRamey

+0

@SeanRamey: О, хорошо, поэтому я думаю, что Watcom inline-asm отличается от MSVC. Это только усиливает мою мысль о том, что обучение asm таким образом означает, что вы потратили кучу инструментов и синтаксиса, которые не могут использоваться для чего-либо вне 16-битного кода, поэтому они не помогут вам взглянуть на выход asm из современного C++ кода, глядя на профили счетчиков производительности и другие вещи, которые полезно знать в asm в 2016 году. –

+0

Итак, я попробовал. Он работает, но он делает почти то же самое, что и раньше, с невероятно странным побочным эффектом написания нескольких случайных пикселей, которые никогда не должны были быть написаны. Кроме того, на самом деле это очень помогает мне в asm в современном C-коде. Снимать все лишнее дерьмо помогает мне видеть более ясно. Мне также нравится историческая часть этого материала. И я узнаю невероятную сумму о реальном оборудовании. Я узнаю, потому что я попадаю в эти действительно странные ситуации, и к тому времени, когда я их выясню, я определенно чему-то научился. – SeanRamey