程序集8086中的图形模式 [英] Graphics mode in assembly 8086

查看:295
本文介绍了程序集8086中的图形模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 average 的变量,并且在我的 DATASEG 中,它每次都会变化,因为用户输入每次都有不同的输入。我想要做的是去图形模式(VGA),然后在那里打印你的平均水平是:然后平均我知道如何改变到像这样的图形模式:

  mov ax,13h 
int 10h

如果平均值高于75 ,我打印下面的平均值后打印出来。你是一个好学生,保持良好的工作,如果不是的话。不要担心,你会变得更好!
在此先感谢。

解决方案

我假设: PC VGA x86 MS DOS 平台

真正的或者模拟的真的不重要,除非你想要低级别的 IO 访问,它可能无法在模拟上正常工作,如 DOSBOX ...


  1. 视频/文字模式 b

    因此,要在视频和文本模式之间切换,您需要使用VGA BIOS:

      mov ax,模式;这里选择你想要的模式
    int 16;这叫EGA / VGA / VESA BIOS

    有很多您可以将端口它到 CPU / VGA / asm,但是在 CPU 上打印要简单得多,不需要像 GLSL 片段。



    因此,您只需从 ASCII 代码计算图像位置并将其像素复制到 VRAM 。在asm中使用粗略的位图并不容易,更容易的是直接以二进制形式(如 db )设置它,这样就可以编写一些简单的 C ++ (或其他)脚本加载图像并将其转换为asm源...

    这是一些古老的 320x200x256颜色打印lib我以前在 NASM 中写过(直接使用 EGA / VGA 字体):

      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
    ; GFX模式13h打印librrary版本:1.0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; txti init字体地址
    ; char cx = color,al = ASCII,scr:di< = al; cl = ch =>无背景
    ;打印scr:di <= ds:si,cx = color cl = ch =>无后台
    ; printl scr:调用后的文本,cx = color ...
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;
    txti:pusha; init字体地址
    push es
    mov ax,1130h; VGA BIOS - 字体信息
    mov bh,3;字体8 x 8像素
    int 10h; ES:BP返回字体地址
    mov [cs:fonts],es;获取字体adr
    mov [cs:fonto],bp
    pop es
    popa
    ret
    fonts dw 0;打印的字体地址...
    fonto dw 0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    char:pusha; cx = color,al = ASCII,scr:di< = al; cl = ch =>无背景
    推ds
    推es
    推单词0A000h
    pop es
    sub ah,ah
    shl ax,3
    mov ds, [cs:fonts]
    mov si,[cs:fonto]
    add si,ax
    mov dh,8
    .char0:mov dl,8
    lodsb
    mov ah,al
    .char1:mov al,cl
    rcl ah,1
    jc .char2
    mov al,ch
    .char2:cmp cl ,ch
    jz .char3
    mov [es:di],al
    .char3:inc di
    dec dl
    jnz .char1
    add di, 320-8
    dec dh
    jnz .char0
    pop es
    pop ds
    popa
    ret
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;
    print:pusha; scr:di <= ds:si,cx = color cl = ch =>没有背景
    .l0:lodsb
    或al,al
    jz .esc
    call char
    add di,8
    jmp short .l0
    .esc:popa
    ret
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    printl:mov [cs:.dat],si; scr:调用后的文本,cx = color ...
    pop si
    推斧
    推di
    推ds
    推cs
    pop ds
    .l0:lodsb
    或al,al
    jz .esc
    call char
    add di ,8
    jmp short .l0
    .esc:pop ds
    pop di
    pop ax
    push si
    add di,9 * 320
    mov si,[cs:.dat]
    ret
    .dat:dw 0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;
    ;;;结束。 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    因此,使用它的程序应该是这样的:

     开始:
    call txti;只在程序启动时一次

    mov di,50 + 320 * 10
    mov cx,127
    call printl
    db'SPEKTRA software&硬件',0

    mov di,50 + 320 * 30
    mov cx,127
    call printl
    db'print test',0

    print 用于设置 ds ,si 所以它指向你的空终止字符串。正如你所看到的, printl 不需要它,因为它使用直接位于 printl 调用之后的字符串,程序继续...这种方式你不需要指针设置指令或任何额外的实验......颜色在 cl,ch 一个是墨水,另一个是纸。如果 cl == ch 那么没有纸张会被渲染,只有在文本后面有图像或gfx背景时才有用的墨水像素...颜色的值可能不会可见的我从我的一个游戏设置了自己的调色板,所以如果没有任何可见的颜色尝试设置不同的 cl,ch mov cx ,0305h 看看这个:


  2. 打印号码



    打印非负整数值是将数字除以基数(10)并打印余数+'0' code>以相反的顺序作为字符...

    hex 中,每个数字对应于半字节< 0-15> ,因此对于16位,您可以通过 xlat 表或添加'0''A'取决于值是否低于 10 ...所以没有分区只是位移/掩码...打印char和shift将值保留4位以处理下一个数字...

    在gfx模式下,btw通常更好,并且用户友好,而不是将数值打印为数字进度条等东西,而不是更容易...崩溃到单循环呈现H或V线...像 REP STOSB :) ...



I have a variable that is called average and in my DATASEG, it changes every time because the user enters a different input every time. What I want to do is to go to the graphics mode (VGA) and then print there Your average is: and then the average I know how to change to the graphics mode like this:

mov ax, 13h  
int 10h

After printing the average I want to print below if the average is above 75 You are a good student, keep up the good work and if not. Don't worry you will get better! Thanks in advance.

解决方案

I am assuming: PC VGA x86 MS DOS platform

It does not really matter if real or emulated unless you want low level IO access which might not work properly on emulation like DOSBOX ...

  1. Video/Text modes

    So to switch between video and text modes you need to use VGA BIOS:

    mov ax,mode ; here select which mode you want
    int 16      ; this calls EGA/VGA/VESA BIOS
    

    There are many video modes here two very important ones:

    mode | type  | segment | resolution         | align
    ----------------------------------------------------
    03   | text  | B800h   | 80x25 chars        | 2 Byte
    19   | video | A000h   | 320x200x256 colors | 1 Byte
    

    In video mode 19 you print/peek pixel by accessing memory at segment A000h where offset is computed like this:

    offset = 320*y + x
    

    The 320x200 mode fits entirely into 64 KByte segment so you do not need to switch pages. This makes it ideal for simple asm gfx programs ....

    Mode 3 is text mode where each character has 2 BYTEs one is color and the other is extended ASCII code. Again print/peek is done by accessing WORD at segment B800h where offset is:

    offset = (80*y + x) * 2
    

    Not sure what order is the two bytes in anymore it was ages ago but you can easily test if writing A at 0B800:0000 will render A in top left corner or 0B800:0001 instead. IIRC colors in text modes are just first 16 colors from palette and the color byte encodes ink paper brightness and flash. This text mode is also the default mode your MS-DOS shell is working in so you should set it back before program exit.

    So your program should look like this:

    start:
        mov ax,19 ; set video mode
        int 16      
    
    mainloop:
        ; here your stuff
    
    exit:
        mov ax,3
        int 16
        ret
    

  2. Printing strings

    For starters you can combine text and video modes ... Like I do here:

    it is a simple game where menus are in text mode (where printing is easy and just matter of copying the string into VRAM) and the sprite graphics game is on 320x200x256c video mode.

    When you want to print in gfx mode you first need to have some Font in the memory. If you look at the EGA/VGA BIOS documentation you can obtain the font located in EGA/VGA ROM and use directly that. I also created this image (IIRC using Trident 9000 256/512KB VGA font) which I use as a mono-spaced font for OpenGL and other stuff (where accessing VGA BIOS is not possible or wanted)...

    Here GLSL example of using it for printing You can port it to CPU/VGA/asm but the printing on CPU is much more simpler no need for such horrible things like in GLSL fragment.

    So you just need to compute image position from ASCII code and copy its pixels into VRAM. Of coarse having bitmap in asm is not easy and much easier is to have it directly in binary form (as set of db) so you can write some simple C++ (or whatever) script which loads image and converts it to asm source ...

    Here is some ancient 320x200x256 colors printing lib I wrote in NASM ages ago (using EGA/VGA Font directly):

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;GFX mode 13h print librrary ver:1.0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;txti       init font adress
    ;char       cx=color,al=ASCII,scr:di<=al ;cl=ch => no background
    ;print      scr:di <= ds:si ,cx=color cl=ch => no background
    ;printl     scr:di text after call ,cx=color ...
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    txti:   pusha           ;init font adress
        push es
        mov ax,1130h    ; VGA BIOS - font info
        mov bh,3        ; font 8 x 8 pixels
        int 10h         ; ES:BP returns font address
        mov [cs:fonts],es   ;get font adr
        mov [cs:fonto],bp
        pop es
        popa
        ret
    fonts   dw 0        ; font address for printing ...
    fonto   dw 0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    char:   pusha       ;cx=color,al=ASCII,scr:di<=al ;cl=ch => no background
        push    ds
        push    es
        push    word 0A000h
        pop es
        sub     ah,ah
        shl     ax,3
        mov     ds,[cs:fonts]
        mov     si,[cs:fonto]
        add     si,ax
        mov     dh,8
    .char0: mov     dl,8
        lodsb
        mov     ah,al
    .char1: mov     al,cl
        rcl     ah,1
        jc  .char2
        mov     al,ch
    .char2: cmp     cl,ch
        jz  .char3
        mov     [es:di],al
    .char3: inc     di
        dec     dl
        jnz     .char1
        add     di,320-8
        dec     dh
        jnz     .char0
        pop es
        pop     ds
        popa
        ret
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    print:  pusha       ;scr:di <= ds:si ,cx=color cl=ch => no background
    .l0:    lodsb
        or  al,al
        jz  .esc
        call    char
        add     di,8
        jmp     short .l0
    .esc:   popa
        ret
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    printl: mov [cs:.dat],si    ;scr:di text after call ,cx=color ...
        pop si
        push    ax
        push    di
        push    ds
        push    cs
        pop ds
    .l0:    lodsb
        or  al,al
        jz  .esc
        call    char
        add     di,8
        jmp     short .l0
    .esc:   pop ds
        pop di
        pop ax
        push    si
        add di,9*320
        mov si,[cs:.dat]
        ret
    .dat:   dw  0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;; end. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    

    So to use it the program should be like:

    start:
        call txti ; just once at program startup
    
        mov di,50+320*10
        mov cx,127
        call printl
        db  'SPEKTRA software & hardware',0
    
        mov di,50+320*30
        mov cx,127
        call printl
        db  'print test',0
    

    The print is used by setting ds,si so it points to your null terminated string. As you can see printl does not need that as it uses string located directly after the printl call and program continues after it ... This way you do not need pointer setting instructions nor any additional labes ... The colors are in cl,ch one is ink and the other is paper. If cl==ch then no paper will be rendered just the ink pixels that is useful if you got image or gfx background behind the text ... The values for colors might not be visible I taken the colors from one of mine games which sets its own palette so if nothing is visible try to set different cl,ch like mov cx,0305h Take a look at this:

  3. Print numbers

    Printing non negative integer number value is a matter of dividing the number by base (10) and printing the remainder + '0' in reverse order as characters ...

    In hex it is even easier as each digit corresponds to nibble <0-15> so for 16 bit in you take highest 4 bits convert to char either by xlat table or by adding '0' or 'A' depending if value is below 10 ... so no divisions just bit shift/mask ... print the char and shift left the value by 4 bits to process next digit ...

    btw in gfx modes is often much nicer and user friendly to instead of printing a value as a number render a progress bar like stuff instead which is much much more easier ... collapses to single loop rendering H or V line ... like REP STOSB :) ...

这篇关于程序集8086中的图形模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆