使用字符GUI TASM组件打印到屏幕阵列中 [英] Print into screen array with character GUI TASM Assembly
问题描述
下午好,我试图用GUI Turbo Asembler TASM在屏幕上显示一个字符串数组,这个问题我不能只显示所有字符串.如果有人可以帮助我在屏幕上正确显示字符串并遍历该数组,非常感谢-
Good afternoon, I'm trying to show on screen an array of strings with GUI Turbo Asembler TASM, the problem that I can not show the all strings only the first. If someone can help me correctly display the strings on the screen and move through that array, very grateful-
这是Borland C ++中的一个例子
This an example in Borland C++
这实际上在TASM中:
This actually 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
推荐答案
嗯.我决定写一些高级版本的显示板...我知道纯代码答案不是很好,但是我添加了很多对代码进行注释,以使其更清楚地了解其工作原理.
Hmm.. I decided to write somewhat advanced version of the display board... I know the pure-code answers are not good ones, but I added many comments into the code to make it more clear, how it works.
关于所用概念的一些提示:
Some hints about concepts used:
我正在直接写入 VGA文本视频内存,避免使用BIOS/DOS服务(它们在绘制游戏棋盘的情况下使用起来既缓慢又麻烦.
I'm writing directly into VGA text video memory, avoiding BIOS/DOS services (they are slow and cumbersome to use in cases like drawing game board).
board
数据不仅包含字母,而且每个字母"的最高位(80h
值)都用作已用/未用标记.绘制例程将根据该位的值更改字母的颜色.
The board
data contain not only letters, but the top bit (80h
value) of each "letter" is used as used/unused marker. The drawing routine will change the colour of letter based on the value of this bit.
即板中的41h
值将用作未使用的A",而值41h + 80h = 0C1h
的值将用作已使用的A".
I.e. value 41h
in board will work as "unused A", and value 41h + 80h = 0C1h
will work as "used A".
未使用/已使用的字母为浅洋红色/白色,是根据已使用的位计算得出的,并且还利用字母ASCII值的40h位.
(数字将具有亮红色/黄色,如'0' = 30h
,因此数字的ASCII码不包含40h的位集=不同的颜色计算结果).
Unused/used letters have light_magenta/white colour, being calculated from the used bit and exploiting also the 40h bit of letter ASCII value.
(digits would have bright_red/yellow colours, as '0' = 30h
, so ASCII code of digits does not contain 40h bit set = different colour calculation result).
通过在原始字母颜色上添加/减去颜色来绘制" +隐藏"光标.
The cursor is "drawn" + "hidden" by adding/subtracting colour to the original letter colour.
代码墙(在dosbox
下使用TASM 4.1测试):
And the wall of code (tested with TASM 4.1 under dosbox
):
.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的命令:
Commands used to build exe:
REM source file has name: wordgame.asm
tasm /m5 /w2 /t /l wordgame
tlink wordgame.obj
使用Turbo调试器单步执行指令,并观察它们如何影响CPU状态以及如何修改内存(在选项"屏幕中将其设置为始终交换",以使直接视频RAM写入在用户屏幕上可见(Alt + F5)).尝试了解所有内容,以及您的旧代码,它如何工作以及在哪里出现问题.
Use Turbo debugger to single step over instructions, and watch how they affect CPU state and how they modify memory (set in Options the screen to "swap always", to make the direct video RAM writes visible on user screen (Alt+F5)). Try to understand everything, also your old code, how it works and where it had problems.
这篇关于使用字符GUI TASM组件打印到屏幕阵列中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!