【问题标题】:Print into screen array with character GUI TASM Assembly使用字符 GUI TASM 组件打印到屏幕阵列
【发布时间】:2017-11-22 23:12:37
【问题描述】:

下午好,我正在尝试使用 GUI Turbo Asembler TASM 在屏幕上显示字符串数组,问题是我无法仅显示第一个字符串。如果有人可以帮助我在屏幕上正确显示字符串并在该数组中移动,非常感谢-

这是 Borland C++ 中的一个示例

Example

这实际上在 TASM 中:

Program in tasm

代码如下。

.MODEL small

.STACK  100h ; reserves 256 bytes of uninitialized storage

.DATA
startX equ 35
startY equ 8
y db ?
x db ?
t1 db ?
t2 db ?
t3 db ?

zSprite db'M','M','L','E','E','N','A','E','V','E',
    db'E','R','H','O','N','G','O','S','T','R',
    db'X','X','O','T','I','R','R','A','C','A',
    db'I','S','A','P','P','O','T','A','P','S',
    db'C','C','M','L','A','A','I','Z','O','T',
    db'O','A','A','U','A','N','U','L','P','U',
    db'S','O','M','B','R','E','R','O','M','P',
    db'C','N','E','A','R','R','I','I','O','O',
    db'W','O','J','E','N','O','C','P','Z','E',
    db'A','A','Z','A','A','L','N','Y','T','D'


.386 ;enabled assembly of non privileged 80386 instructions
.CODE
start:
;set DS to point to the data segment
mov ax,@data
mov ds,ax

mov di,offset zSprite

mov y,0

l5:
cmp y,10
jl  l0
jmp l1

l0:
mov x,0

l4:
cmp x,10
jl  l2
jmp l3

l2:
mov al,startX
add al,x
mov t1,al

mov al,startY
add al,y
mov t2,al

; set cursor position at (x,y)
mov ah,02h ;set cursor position service
mov bh,00h ;page number
mov dh,t2 ;row
mov dl,t1 ;column
int 10h ;bios interrupt

mov ax,0 ;reset ax
mov al,y ;ax = y
mov bx,10
mul bx   ;ax = ax * 10
mov bx,0 ;reset bx
mov bl,x ;bx = x
add ax,bx ;ax = ax + x
mov bx,ax

; set color
mov ah,09h ;service
mov al, zSprite;character
mov bh,00h ;page number
mov bl,[bx+di] ;color
mov cx,01h ;number of times to print character
int 10h

;print symbol
mov ah, 02h  
mov dl,  zSprite
int 21h 

inc x
jmp l4

l3:
inc y
jmp l5

l1:
nop

exit:
;DOS: terminate the program
mov ah,4ch ; mov ax, 4c00h
mov al,0h
int 21h

delay PROC
pop bx

mov ax,1000d
mov dx,ax

delay1:
mov cx,ax

delay2:
dec cx
jnz delay2
dec dx
jnz delay1

push bx

ret
delay ENDP

END start

【问题讨论】:

  • 呃,你的自己的评论"mov al,0feh ;character" ...那你的“图片”。
  • 我很抱歉我的英语不好。我不知道如何显示字母而不是错误字符。感谢您的帮助。
  • 这不是“错误”,而是您告诉程序要做的事情。
  • 如何让它显示字符串?谢谢
  • 您必须在内存中从地址zSprite 开始的值之一加载AL 寄存器(您必须在该内存上进行+1 才能逐字符读取整个字符串和显示它们中的每一个)。值254 (0feh) 是填充的矩形字符。如果您将其修改为mov al,'x',您将获得全屏“x”字符...

标签: arrays string assembly tasm


【解决方案1】:

嗯..我决定写一些高级版的显示板...我知道纯代码答案不好,但我在代码中添加了许多 cmets 以使其更清楚,它是如何工作的。

关于所用概念的一些提示:

我直接写信给VGA text video memory,避免使用 BIOS/DOS 服务(它们在绘制游戏板等情况下使用起来既慢又麻烦)。

board 数据不仅包含字母,而且每个“字母”的最高位(80h 值)用作已使用/未使用的标记。绘图程序会根据这个位的值改变字母的颜色。

即板中的值41h 将作为“未使用的A”工作,而值41h + 80h = 0C1h 将作为“使用的A”工作。

未使用/已使用的字母具有浅品红色/白色,由已使用的位计算并利用字母 ASCII 值的 40h 位。 (数字会有亮红色/黄色,如'0' = 30h,因此数字的ASCII码不包含40h位设置=不同的颜色计算结果)。

光标是“绘制”+“隐藏”通过对原始字母颜色添加/减去颜色。


还有代码墙(用dosbox下的TASM 4.1测试):

.MODEL small

.STACK  100h ; reserves 256 bytes of uninitialized storage

.DATA

BOARD_SIZE_X    EQU     10
BOARD_SIZE_Y    EQU     10
START_X         EQU     35
START_Y         EQU     8
CURSOR_COLOR    EQU     0B0h     ; add "blink" + cyan background

board LABEL BYTE
    DB "MMLEENAEVE"
    DB "ERHONGOSTR"
    DB "XXOTIRRACA"
    DB "ISAPPOTAPS"
    DB "CCMLAAIZOT"
    DB "OAAUANULPU"
    DB "SOMBREROMP"
    DB "CNEARRIIOO"
    DB "WOJENOCPZE"
    DB "AAZAALNYTD"

cursor_x        db  5
cursor_y        db  7

.386
.CODE
start:
    ;set DS to point to the data segment
    mov     ax,@data
    mov     ds,ax   ; ds = data segment
    mov     ax,0B800h
    mov     es,ax   ; es = text VRAM segment for direct VRAM writes

    ; fake some characters being "used" to test drawing code
    or      BYTE PTR [board+34],80h     ; mark the "POT" word
    or      BYTE PTR [board+35],80h     ; on fourth line in middle
    or      BYTE PTR [board+36],80h

    call    clear_screen
    call    draw_board
    mov     dl,CURSOR_COLOR
    call    draw_cursor

    ; wait for keystroke
    xor     ah,ah
    int     16h

    ; fake "move cursor"
    mov     dl,-CURSOR_COLOR        ; hide cursor on old position
    call    draw_cursor
    inc     BYTE PTR [cursor_x]     ; move it up+right
    dec     BYTE PTR [cursor_y]
    mov     dl,CURSOR_COLOR         ; show cursor on new position
    call    draw_cursor
    ; (other option would be to redraw whole board)

    ; wait for keystroke before exit
    xor     ah,ah
    int     16h
    ; exit to DOS
    mov     ax,4C00h
    int     21h

; sets whole text video RAM to white "space" with red background
; modifies ax, cx, di, assumes es=B800
clear_screen PROC
    xor     di,di   ; B800:0000 target address
    mov     ax,' ' + 4Fh*256 ; white space on red background
    mov     cx,80*25
    rep stosw       ; fill up video RAM with that
    ret
ENDP

; redraws whole board to the video RAM, marks "used" characters too
; modifies ax, cx, dx, si, di, assumes ds=@DATA, es=B800
draw_board PROC
    mov     si,OFFSET board ; si = address of first letter of board
    ; di = offset of starting position in video RAM
    ; 2 bytes per char (char+color), 80 chars (160B) per line
    mov     di,(START_Y*80 + START_X)*2
    ; output BOARD_SIZE_Y lines
    mov     dx,BOARD_SIZE_Y
board_line_loop:
    ; output BOARD_SIZE_X coloured characters
    mov     cx,BOARD_SIZE_X
board_char_loop:
    lodsb           ; al = next character + used bit, advance si +1
    mov     ah,al   ; color of unused/used will be: 12 + 1 || 3 = 13 || 15
    and     al,7Fh  ; clear the top bit (used/unused): al = ASCII letter
    shr     ah,6    ; ah = 1 || 3 (80h "used" bit + 40h bit from letter code)
    add     ah,12   ; ah = 13 || 15 by "used" bit (magenda/white on black)
    stosw           ; write letter+color to VRAM es:di, advance di +2
    dec     cx
    jnz     board_char_loop ; loop till whole line is displayed
    ; move video ram pointer to start of next line
    add     di,(80-BOARD_SIZE_X)*2  ; advance to start of next line
    dec     dx
    jnz     board_line_loop ; loop till every line is displayed
    ret
ENDP

; Modifies letter color at current cursor position by adding DL
; modifies ax, di, assumes ds=@DATA, es=B800
draw_cursor PROC
    mov     al,[cursor_y]
    mov     ah,160
    mul     ah      ; ax = cursor_y * 160
    movzx   di,BYTE PTR [cursor_x] ; di = zero-extended cursor_x
    add     di,di   ; di *= 2 (cursor_x*2)
    add     di,ax   ; di += cursor_y * 160
    ; add initial board offset and +1 to address attribute only
    add     di,(START_Y*80 + START_X)*2 + 1
    add     es:[di],dl  ; modify letter color by adding DL
    ret
ENDP

END start

用于构建 exe 的命令:

REM source file has name: wordgame.asm
tasm /m5 /w2 /t /l wordgame
tlink wordgame.obj

使用 Turbo 调试器单步执行指令,并观察它们如何影响 CPU 状态以及它们如何修改内存(在选项中将屏幕设置为“始终交换”,以使直接视频 RAM 写入在用户屏幕上可见(Alt+ F5))。尝试了解所有内容,包括您的旧代码、它的工作原理以及问题所在。

【讨论】:

  • 非常感谢您的帮助。我将对其进行分析并检查我的错误以了解更多信息。
  • @raintrooper 不幸的是,这并不能解释你的代码中的问题,但这会是更多的聊天,我相信你很快就能自己识别出其中的几个,你会的获得更多经验。只需获取一些调试器(涡轮调试器曾经是 TASM 安装的一部分),并学习如何使用它来检查单个指令,然后尝试始终根据 CPU 的实际操作来验证您的期望(并使用参考指南来获取指令,如x86.renejeschke.de 或英特尔官方文档)。另外,如果您不了解我的代码中的特定内容,请询问。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 2012-12-08
  • 1970-01-01
相关资源
最近更新 更多