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

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

问题描述

我有一个名为 average 的变量,在我的 DATASEG 中,它每次都会改变,因为用户每次输入不同的输入.我想要做的是转到图形模式(VGA),然后在那里打印您的平​​均值是:然后平均值我知道如何更改为这样的图形模式:

mov ax, 13h整数 10 小时

打印平均值后,如果平均值高于 75,我想打印在下面 你是个好学生,继续努力,如果不是.别担心,你会好起来的!提前致谢.

解决方案

我假设:PC VGA x86 MS DOS平台

除非您想要低级别的 IO 访问权限,否则它可能无法在 DOSBOX 之类的仿真中正常工作...

  1. 视频/文本模式

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

    mov ax,mode ;在这里选择你想要的模式整数 16 ;这称为 EGA/VGA/VESA BIOS

    有许多您可以将其移植到CPU/VGA/asm 但在 CPU 上的打印要简单得多,不需要像 GLSL 片段那样可怕的东西.

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

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

     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GFX 模式 13h 打印库 ver:1.0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;txti 初始化字体地址;char cx=color,al=ASCII,scr:di<=al ;cl=ch =>没有背景;打印 scr:di <= ds:si ,cx=color cl=ch =>没有背景;printl scr:di 调用后的文本,cx=color ...;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;txti: pusha ;init 字体地址推esmov ax,1130h ;VGA BIOS - 字体信息mov bh,3 ;字体 8 x 8 像素整数 10 小时;ES:BP 返回字体地址mov [cs:fonts],es ;获取字体地址mov [cs:fonto],bp教皇波帕退字体 dw 0 ;打印字体地址...丰托 dw 0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;字符:pusha ;cx=color,al=ASCII,scr:di<=al ;cl=ch =>没有背景推ds推es推字 0A000h教皇子啊,啊shl 斧头,3mov ds,[cs:fonts]mov si,[cs:fonto]添加 si,axmov dh,8.char0: mov dl,8lodsb移动啊,阿尔.char1: 移动 al,clrcl 啊,1jc .char2移动.char2: cmp cl,chjz .char3mov [es:di],al.char3: 包括 di十二月jnz .char1添加 di,320-8十二月jnz .char0教皇流行音乐波帕退;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;打印:pusha ;scr:di <= ds:si ,cx=color cl=ch =>没有背景.l0: lodsb或 al,aljz.esc调用字符添加 di,8jmp 短.l0.esc:popa退;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;printl: mov [cs:.dat],si ;scr:di text after call ,cx=color ...流行音乐推斧推地推ds推CS流行音乐.l0: lodsb或 al,aljz.esc调用字符添加 di,8jmp 短.l0.esc:流行音乐流行音乐流行斧推si添加di,9*320mov si,[cs:.dat]退.dat:dw 0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;结尾.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    所以要使用它,程序应该是这样的:

     开始:调用 txti ;仅在程序启动时一次mov di,50+320*10mov cx,127调用printldb 'SPEKTRA 软件 &硬件',0mov di,50+320*30mov cx,127调用printldb '打印测试',0

    print 通过设置 ds,si 使用,因此它指向您的空终止字符串.正如你所看到的 printl 不需要它,因为它使用位于 printl 调用之后的字符串,程序在它之后继续......这样你就不需要指针设置指令也没有任何额外的标签......颜色在 cl,ch 中,一种是墨水,另一种是纸.如果 cl==ch 则不会渲染任何纸张,只是在文本后面有图像或 gfx 背景时有用的墨水像素......颜色的值可能不可见我取了颜色来自我的一个游戏,它设置了自己的调色板,因此如果没有任何可见的内容,请尝试设置不同的 cl,ch,例如 mov cx,0305h 看看这个:

  2. 打印数字

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

    hex 中更容易,因为每个数字对应于半字节 <0-15> 所以对于 16 位,您可以通过以下方式将最高 4 位转换为字符xlat 表或添加 '0''A' 取决于值是否低于 10 ... 所以没有除法只是位移/掩码...打印字符并将值左移4位以处理下一个数字...

    顺便说一句,gfx 模式中的值通常更好且用户友好,而不是将值打印为数字呈现进度条之类的东西,而不是更容易...折叠为单循环呈现 H 或 V 线... 就像 REP STOSB :) ...

  3. VESA

    对于 320x200x8bpp 以上的 Super VGA 视频模式,我们需要添加数据的页面交叉,因为 VRAM 不再适合 64KByte 段.我强烈建议为此使用 VESA (VBE) api.这个想法是将 A000:0000 段映射到我们可以随时更改的 VRAM 的某个段.有关如何查看这些内容的更多信息:

    如果您的 gfx 卡没有适用于大多数卡的 VESA/VBE,可以使用 添加它UniVBE 5.3 或 MS-DOS 下更新的实用程序.

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 :) ...

  4. VESA

    For Super VGA video modes above 320x200x8bpp we need to add page crossings of data as VRAM does not fit 64KByte segment anymore. I strongly suggest to use VESA (VBE) api for this. The idea is to have the A000:0000 segment be mapped to certain segment of the VRAM which we can change at any time. For more info on how see these:

    In case your gfx card does not have VESA/VBE for most cards its possible to add it by using UniVBE 5.3 or newer utility under MS-DOS.

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

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