Print into screen array with character GUI TASM Assembly

匆匆过客 提交于 2020-01-26 04:38:09

问题


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-

This an example in Borland C++

Example

This actually in TASM:

Program in tasm

the code is the following.

.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

回答1:


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:

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

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.

I.e. value 41h in board will work as "unused A", and value 41h + 80h = 0C1h will work as "used A".

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.


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

Commands used to build exe:

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

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.



来源:https://stackoverflow.com/questions/47445256/print-into-screen-array-with-character-gui-tasm-assembly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!