вторник, 11 апреля 2017 г.

Приложение для тестирования монитора, Assembler/DOS

Задание

Написать приложение для тестирования монитора на ассемблере для ОС DOS.

Реализация

Было решено написать приложение для самых младших моделей процессоров архитектуры x86, что сильно ограничивает нас в выборе команд и регистров.
Сильные ограничения в выборе команд и регистров являются хорошей "разминкой для ума".

Репозиторий проекта:

https://github.com/AnotherStudent/DOS/tree/master/Projects/DispTest

Структура приложения

1. Инициализация
2. Главный цикл
2.1. Вывод меню
2.2. Ожидание нажатия клавиши
2.3. В зависимости от нажатой клавиши: если "e" - переход к 3.
2.4. Запуск нужного теста
2.4. Ожидание нажатия клавиши
2.5. Если нажата клавиша "<-" или "->", то inc/dec номера теста и переход к 2.3
2.6. Переход к 2.1.
3. Выход в DOS

Таблица переходов

Переход на нужный тест по его номеру присходит с помощью команды CALL и таблицы перехода.

Доступ к видеопамяти

Для вывода графики был выбран видеорежим 13h.
Особенностью данного видеорежима является то, что в нем линейное расположение памяти.
Для удобной адресации я установил сегментный регистр es на адрес 0-й видео страницы:
    mov ax,0a000h
    mov es,ax

Исходный код


; 2017 error(c)
.model small
.stack 100h
locals

.const
    screenWidth = 320
    screenHeight = 200
    screenSize = (screenWidth*screenHeight)

.data
    sRedScreen equ 'Red screen'
    sGreenScreen equ 'Green screen'
    sBlueScreen equ 'Blue screen'
    sWhiteScreen equ 'White screen'
    sHorizontalLines equ 'Horizontal lines'
    sVerticalLines equ 'Vertical lines'
    sGrayGradient equ 'Gray gradient'
    sColorGradient equ 'Color gradient'

    menuText db\
'+----------------------+',13,10,\
'|      Screen Test     |',13,10,\
'|     2017 by Error    |',13,10,\
'+----------------------+',13,10,\
13,10,\
'Please select mode:',13,10,13,10,\
'1) ',sRedScreen,13,10,\
'2) ',sGreenScreen,13,10,\
'3) ',sBlueScreen,13,10,\
'4) ',sWhiteScreen,13,10,\
'5) ',sHorizontalLines,13,10,\
'6) ',sVerticalLines,13,10,\
'7) ',sGrayGradient,13,10,\
'8) ',sColorGradient,13,10,\
'E) Exit',13,10,'$'

    redScreenText db sRedScreen,13,10,'$'
    greenScreenText db sGreenScreen,13,10,'$'
    blueScreenText db sBlueScreen,13,10,'$'
    whiteScreenText db sWhiteScreen,13,10,'$'
    horizontalLinesText db sHorizontalLines,13,10,'$'
    verticalLinesText db sVerticalLines,13,10,'$'
    grayGradientText db sGrayGradient,13,10,'$'
    colorGradientText db sColorGradient,13,10,'$'

    exitText db 13,10,'Press [esc] to exit','$'

.code

; clear screen: [color]
cls:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2+2; ret + color arg
    ; save registers
    push ax
    push cx
    push di
    ; work
    mov ax,[bp]; load [color] to ax
    mov di,0; 0 to di
@@loop:
    mov es:byte ptr[di],al; save byte to video ram
    inc di
    cmp di,screenSize
    jnz @@loop; if di < screenSize then goto loop
    ; restore registers
    pop di
    pop cx
    pop ax
    ; return
    pop bp; load bp
    ret 2

; print test name on screen: [@text]
printName:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2+2; ret + text arg
    ; save registers
    push ax
    push bx
    push cx
    push dx
    ; clear screen (set videomode)
    mov ax,13h
    int 10h
    ; set cursor pos
    mov ah,2h
    mov bh,0h; x
    mov dh,25/2-2; y
    mov dl,13
    int 10h; bios int
    ; print text
    mov ah,9
    mov dx,[bp]; [@text]
    int 21h; dos int
    mov ah,9
    mov dx,offset exitText
    int 21h; dos int
    ; sleep 1 second
    mov ah,86h
    mov cx,10
    mov dx,00
    int 15h; dos int
    ; restore registers
    pop dx
    pop cx
    pop bx
    pop ax
    ; return
    pop bp; load bp
    ret 2
    
redScreen:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2; ret
    ; print name
    push offset redScreenText
    call printName
    ; test
    push 40; red color in std palette
    call cls
    ; return
    pop bp; load bp
    ret
    
greenScreen:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2; ret
    ; print name
    push offset greenScreenText
    call printName
    ; test
    push 48; green color in std palette
    call cls
    ; return
    pop bp; load bp
    ret
    
blueScreen:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2; ret
    ; print name
    push offset blueScreenText
    call printName
    ; test
    push 32; blue color in std palette
    call cls
    ; return
    pop bp; load bp
    ret
    
whiteScreen:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2; ret
    ; print name
    push offset whiteScreenText
    call printName
    ; test
    push 15; white color in std palette
    call cls
    ; return
    pop bp; load bp
    ret
   
horizontalLines:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2
    ; save registers
    push ax
    push bx
    push cx
    push di
    push dx
    ; print name
    push offset horizontalLinesText
    call printName
    ; clear screen
    push 0; black color
    call cls
    ; draw
    ; y loop
    mov cx,0
@@LoopY:
    ; get offset for y -> di
    mov ax,cx
    mov dx,screenWidth
    mul dx
    mov di,ax
    ; x loop
    mov bx,0
@@LoopX:
    ; draw point
    mov es:byte ptr[di+bx],15
    inc bx
    cmp bx,screenWidth
    jnz @@LoopX
    ; end x loop
    add cx,8
    cmp cx,screenHeight
    jl @@LoopY
    ; end y loop
    ; load registers
    pop dx
    pop di
    pop cx
    pop bx
    pop ax
    ; return
    pop bp; load bp
    ret
    
vertiacalLines:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2
    ; save registers
    push di
    ; print name
    push offset verticalLinesText
    call printName
    ; clear screen
    push 0; black color
    call cls
    ; draw
    mov di,0
@@Loop:
    ; draw point
    mov es:byte ptr[di],15
    add di,8
    cmp di,screenSize
    jbe @@Loop
    ; load registers
    pop di
    ; return
    pop bp; load bp
    ret
    
grayGradient:
 ; enter
    push bp; save bp
    mov bp,sp
    add bp,2
    ; save registers
    push ax
    push bx
    push cx
    push dx
    push di
    ; print name
    push offset grayGradientText
    call printName
    ; draw
    mov di,0
    ; y loop
    mov di,0
@@LoopY:
    ; x loop
    mov bx,0
@@LoopX:
    ; get offset [0..15] -> al
    mov ax,bx
    mov dx,20
    div dl
    ; al + 16 -> al - gray colors offset in std color table
    add al,16
    ; draw point
    mov es:byte ptr[di+bx],al
    inc bx
    cmp bx,screenWidth
    jnz @@LoopX
    ; end x loop
    add di,screenWidth
    cmp di,screenSize
    jbe @@LoopY
    ; end y loop
    ; load registers
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    ; return
    pop bp; load bp
    ret
    
colorGradient:
    ; enter
    push bp; save bp
    mov bp,sp
    add bp,2
    ; save registers
    push ax
    push bx
    push cx
    push dx
    push di
    ; print name
    push offset colorGradientText
    call printName
    ; draw
    mov di,0
    ; y loop
    mov di,0
@@LoopY:
    ; x loop
    mov bx,0
@@LoopX:
    ; get offset [0..15] -> al
    mov ax,bx
    mov dx,20
    div dl
    ; draw point
    mov es:byte ptr[di+bx],al
    inc bx
    cmp bx,screenWidth
    jnz @@LoopX
    ; end x loop
    add di,screenWidth
    cmp di,screenSize
    jbe @@LoopY
    ; end y loop
    ; load registers
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    ; return
    pop bp; load bp
    ret
        
.data
    testProc dw redScreen, greenScreen, blueScreen, whiteScreen,\
    horizontalLines, vertiacalLines, grayGradient, colorGradient

.code

; enter point
.startup
    ; std setup
    mov ax,@data
    mov ds,ax

    ; screen ram -> es
    mov ax,0a000h
    mov es,ax

    ; set video mode 10
    mov ax, 13h
    int 10h    
    
@@loop:
    ; clear screen
    mov ax,13h
    int 10h
    ; print menu
    mov ah,9
    mov dx,offset menuText
    int 21h
    ; getkey
    mov ah,08h
    int 21h
    
    ; exit
    cmp al,'e'
    jz @@exit
    
    ; select screen test proc
    cmp al,'1'
    jl @@endCase
    cmp al,'8'
    jg @@endCase
    ; al - '0' -> ax
    mov ah,'1'
    sub al,ah
    mov ah,0
    mov cx,ax
@@run:
    ; ax * 2 -> bx
    mov dl,2
    mul dl
    mov bx,ax
    ; []
    mov bx,[bx+testProc]
    ; call
    call bx

@@getKey:
    ; getkey
    mov ah,08h
    int 21h
    ; ex keys
    cmp al,0
    jnz @@endCase
    mov ah,08h
    int 21h
    ; ->
    cmp al,77
    jnz @@test2
    cmp cx,7
    jz @@getKey 
    inc cx
    mov ax,cx
    jmp @@run
@@test2:
    ; <-
    cmp al,75
    jnz @@endCase
    cmp cx,0
    jz @@getKey 
    dec cx
    mov ax,cx
    jmp @@run

@@endCase:
    jmp @@loop
    
@@exit:
    ;set text mode
    mov ax, 2h;
    int 10h 
    ; exit 
    mov ah,4ch
    int 21h
end

Название эффекта

Перед выводом непосредственно теста выводиться его название и подсказка по клавишам.

Вид главного меню

Некоторые тесты






Комментариев нет:

Отправить комментарий