使用字符 GUI TASM 组件打印到屏幕阵列
Print into screen array with character GUI TASM Assembly
下午好,我正在尝试使用 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
嗯..我决定写一些高级版本的显示板...我知道纯代码的答案不是很好,但我在代码中添加了很多注释以使其更清晰,如何有效。
关于所用概念的一些提示:
我正在直接写入 VGA text video memory,避免使用 BIOS/DOS 服务(它们在绘制游戏板等情况下使用起来既慢又麻烦)。
board
数据不仅包含字母,而且每个"letter"的最高位(80h
值)用作used/unused标记。绘图例程将根据此位的值更改字母的颜色。
即board 中的值 41h
将作为 "unused A",值 41h + 80h = 0C1h
将作为 "used A".
Unused/used 字母具有 light_magenta/white 颜色,从使用的位计算并利用字母 ASCII 值的 40h 位。
(数字会有 bright_red/yellow 颜色,如 '0' = 30h
,因此数字的 ASCII 码不包含 40h 位设置 = 不同颜色计算结果)。
光标是"drawn" + "hidden"由adding/subtracting颜色到原来的字母颜色。
还有代码墙(在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 状态以及它们如何修改内存(在选项中将屏幕设置为 "swap always",使直接视频 RAM 写入在用户屏幕上可见 (Alt+F5))。尝试了解所有内容,包括您的旧代码,它是如何工作的以及哪里有问题。
下午好,我正在尝试使用 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
嗯..我决定写一些高级版本的显示板...我知道纯代码的答案不是很好,但我在代码中添加了很多注释以使其更清晰,如何有效。
关于所用概念的一些提示:
我正在直接写入 VGA text video memory,避免使用 BIOS/DOS 服务(它们在绘制游戏板等情况下使用起来既慢又麻烦)。
board
数据不仅包含字母,而且每个"letter"的最高位(80h
值)用作used/unused标记。绘图例程将根据此位的值更改字母的颜色。
即board 中的值 41h
将作为 "unused A",值 41h + 80h = 0C1h
将作为 "used A".
Unused/used 字母具有 light_magenta/white 颜色,从使用的位计算并利用字母 ASCII 值的 40h 位。
(数字会有 bright_red/yellow 颜色,如 '0' = 30h
,因此数字的 ASCII 码不包含 40h 位设置 = 不同颜色计算结果)。
光标是"drawn" + "hidden"由adding/subtracting颜色到原来的字母颜色。
还有代码墙(在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 状态以及它们如何修改内存(在选项中将屏幕设置为 "swap always",使直接视频 RAM 写入在用户屏幕上可见 (Alt+F5))。尝试了解所有内容,包括您的旧代码,它是如何工作的以及哪里有问题。