; Это вот... Чтобы понимать всю глубину наших глубин...
; Остановился я в своем самокопании на процедуре DrawSegH... Все-таки
; как-то надо "слить" ее в одну с DrawSegV. Может и макросом.

;===========================================================================vp=

SepTimeM macro Time             ; Макрос для разделения времени на 
                                ; десятки и единицы

        mov     al,Time         ;- пихаем в ax время
        mov     ah,0            ;/
        mov     bl,10           ; 
        div     bl              ; Получаем в al десятки, в ah единицы 
endm

;---------------------------------------------------------------------------vp-

DrawSqrM macro X,Y,col          ; Макрос для рисования разделителя в
                                ; указанном месте указанным цветом.
        push    ax
        push    bx
        push    cx
        push    dx

        ; координаты очередного разделителя
        mov     cx,X            ; X
        mov     dx,Y            ; Y
        mov     bl,col
        mov     colour,bl       ; цвет
        call    DrawSqrP        ; Вызываем функцию рисования разделителя

        pop     dx
        pop     cx
        pop     bx
        pop     ax
endm

;---------------------------------------------------------------------------vp-
                                
DrawIndM macro massX,massY,X,Y,col ; Макрос рисования конкретного индикатора 
local startm, nulm, vertm          ; в конкретном месте конкретным цветом.
        push    ax                 ; Конкретно. 
        push    bx
        push    cx
        push    dx

        mov     dl,col
        mov     colour,dl       ; Определяем цвет
        
        xor     si,si           ; Обнуляем индекс
        xor     cx,cx           ; и координаты
        xor     dx,dx

 startm: 
        ; проверка на 'нерисование'
        cmp     massX[si],255
        je      nulm

        add     cl,massX[si]    ; координата X очередного сегмента
        add     dl,massY[si]    ; координата Y очередного сегмента

        mov     ax,si           ;
        mov     bl,2            ;                             /~2~\
        div     bl              ;                             1   3
        cmp     ah,0            ; какой сегмент рисуем?       >-4-<
        je      vertm           ; вертикальный! (нечетный)    5   7
        call    DrawHSegP       ; горизонтальный! (четный)    \_6_/
        jmp     nulm            ;
 vertm: call    DrawVSegP       ;
 nulm:
        inc     si

        cmp     si,7            ; 7 проходов, ибо семь сегментов в индикаторе
        jne     startm          ; Loop не используем, ибо CX...

        pop     dx
        pop     cx
        pop     bx
        pop     ax
endm

;===========================================================================vp=

sseg    segment stack
        db 256 dup(?)           ; ...и нафига мне такой здоровый стек?
sseg    ends

;===========================================================================vp=

dseg    segment
        temp dw ?               ; рабочая переменная
                                ; 
        ; Изменив эти координаты, можно получить изображение часов
        ; в любом месте экрана. Зачатки универсальности :-)
        TheX dw 42              ; координата X первого индикатора
        TheY dw 75              ; координата Y первого индикатора

        X dw ?                  ; координата X чего бы то ни было
        Y dw ?                  ; координата Y чего бы то ни было

        ; Некоторые уточнения относительно индикаторов
        ;
        ; (X,Y)∙  ██20        |26|   
        ;        ███22        ▄██▄~~~
        ;       █ ██20        █  █   
        ;      ███            ▐██▌ 49                        
        ;      222            █  █                            
        ;      020            ▀██▀___

        temp_sec  db ?          ; для проверки на изменение секунд

        colour    db ?          ; рабочая "цветовая" переменная
        colourIND db 10         ; цвет активного индикатора
        colourBKG db 8          ; цвет пассивного индикатора
        figure       db ?          ; цифра для рисования

        massX db 7 dup (?)      ; для временного хранения массива X-координат
        massY db 7 dup (?)      ; для временного хранения массива Y-координат

        ; Ниже представены массивы относительных координат 
        ; (X и Y соответственно) сегментов цифровых индикаторов.
        ; Если рисовать сегмент не нужно, то на соответствующей позиции
        ; в массиве координат имеем '255'.
        zeroX  db +00,+03,+21,255,-24,+03,+21
        zeroY  db +03,-03,+03,255,+24,+21,-21

        oneX   db 255,255,+24,255,255,255,+00
        oneY   db 255,255,+03,255,255,255,+24

        twoX   db 255,+03,+21,-21,-03,+03,255 
        twoY   db 255,-00,+03,+21,+03,+21,255

        threeX db 255,+03,+21,-21,255,+00,+21
        threeY db 255,-00,+03,+21,255,+24,-21
                         
        fourX  db +00,255,+24,-21,255,255,+21
        fourY  db +03,255,+00,+21,255,255,+03

        fiveX  db +00,+03,255,+00,255,+00,+21
        fiveY  db +03,-03,255,+24,255,+24,-21        

        sixX   db +00,+03,255,+00,-03,+03,+21
        sixY   db +03,-03,255,+24,+03,+21,-21

        sevenX db 255,+03,+21,255,255,255,+00
        sevenY db 255,-00,+03,255,255,255,+24        

        eightX db +00,+03,+21,-21,-03,+03,+21
        eightY db +03,-03,+03,+21,+03,+21,-21

        nineX  db +00,+03,+21,-21,255,+00,+21
        nineY  db +03,-03,+03,+21,255,+24,-21
dseg    ends

;===========================================================================vp=

cseg    segment
StartP  proc far
        assume cs:cseg,ds:dseg,ss:sseg

        ; Заносим нач. значения в стек, чтобы програма
        ; могла возвратить управление отладчику
        push    ds
        xor     ax,ax
        push    ax
        ; Инициируем адрес сегмента данных
        mov     bx,dseg
        mov     ds,bx

        call    MainP

        ret                     ; Возвратить управление отладчику
StartP  EndP

; Начало реализации задачи
;---------------------------------------------------------------------------vp-

MainP proc near                  

        mov     ah,00           ; Выбор режима
        mov     al,0Dh          ; 320x200x16
;        mov     al,12h          ; 640x480x16. Прикольно.
        int     10h

        xor     di,di            
        xor     dh,dh
 Beg:   

        mov     ah,01h          ; Выход из программы при нажатии
        int     16h             ; на любую клавишу.
        jz      NEnd
        ; Выход из графического режима
        mov     ah,00h          
        mov     al,02h 
        int     10h  
                  
        ret       

        ;============================================
        ; Координаты индикаторов на экране:
        ; X1 = X + 000 = 042       X4 = X + 124 = 166
        ; X2 = X + 036 = 078       X5 = X + 176 = 218
        ; X3 = X + 088 = 130       X6 = X + 212 = 254
        ;============================================
 NEnd:
        mov     temp_sec,dh
        call    TimeP           ; ch-час, cl-мин, dh-сек, dl-100д/сек
                                ; Доли секунды нам, в прочем, не нужны.
        cmp     dh,temp_sec     ; Изменилось ли время с прошлого прохода?
        je      Beg

        mov     bp,TheX         ; Определяем начальные условия -
        mov     X,bp            ; основная точка отсчета для рисования
        mov     bp,TheY         ; чего бы то ни было.
        mov     Y,bp

        cmp     di,0            ; А не в первый ли мы раз проходим цикл?
        je      hrs             ; Если в первый - рисуем все.

        ; ======= Начало блока "немигания" =======
        mov     dl,cl           
        add     dl,dh
        cmp     dl,0            ; Если минуты и секунды равны 00,
        jne     next1               
        jmp     hrs             ; то рисуем все, начиная с часов.
 next1:                         ; Если минуты не равны 00,
        cmp     dh,0            ; а секунды равны 00,
        jne     next2
        add     X,88
        jmp     min             ; то рисуем начиная с минут.

 next2: SepTimeM dh             ; al - десятки, ah - единицы
        cmp     ah,0            ; Если только единицы секунд не равны 0
        jne     trns_jmp0;=lsec ; то рисуем только единицы секунд,
        add     X,176           ; иначе рисуем и десятки и единицы секунд
        jmp     sec
        ; =======  Конец блока "немигания" =======
        
 hrs:   SepTimeM ch
        ; Рисование десятков часов
        mov     figure,al       ; 
        DrawIndM eightX,eightY,X,Y,colourBKG ; Погасим все индикаторы
        call    WhatFigP        ; Определяем что за цифра и рисуем 
        add     X,36            ; 26 + 10 (ширина индикатора + пропуск)
        jmp     across_trns
 trns_jmp0:                     ; Транзит
        add     X,212
        jmp     lsec
 across_trns:
        ; Рисование единиц часов
        mov     figure,ah
        DrawIndM eightX,eightY,X,Y,colourBKG
        call    WhatFigP        ; Определяем что за цифра и рисуем
        add     X,52            ; 26 + 26

 min:   SepTimeM cl             ; al - десятки, ah - единицы
        ; Рисование десятков минут
        mov     figure,al
        DrawIndM eightX,eightY,X,Y,colourBKG 
        call    WhatFigP        ; Определяем что за цифра и рисуем
        add     X,36            ; 26 + 10 (ширина индикатора + пропуск)
        ; рисование единиц минут
        mov     figure,ah
        DrawIndM eightX,eightY,X,Y,colourBKG 
        call    WhatFigP        ; Определяем что за цифра и рисуем
        add     X,52

 sec:   SepTimeM dh             ; al - десятки, ah - единицы
        ; рисование десятков секунд
        mov     figure,al
        DrawIndM eightX,eightY,X,Y,colourBKG 
        call    WhatFigP        ; Определяем что за цифра и рисуем
        add     X,36            ; 26 + 10 (ширина индикатора + пропуск)
 lsec:  ; рисование единиц секунд
        mov     figure,ah
        DrawIndM eightX,eightY,X,Y,colourBKG 
        call    WhatFigP        ; Определяем что за цифра и рисуем
        sub     X,212
        
        ; ======= Начало "блока разделителей" =======
        ; (X,Y)∙█    Разделители имеются в количестве 4 шт.
        ;      ███   по два между часами-минутами и минутами-мекундами
        ;      ███   ┌┐┌┐∙(1)┌┐┌┐∙(3)┌┐┌┐
        ;       █    └┘└┘∙(2)└┘└┘∙(4)└┘└┘
        ; Для начала рисуем разделители в негорящем состоянии
        add     X,74
        add     Y,12
        DrawSqrM X,Y,colourBKG  ; 116,87  (1)
        add     Y,23
        DrawSqrM X,Y,colourBKG  ; 116,110 (2)     
        add     X,88
        DrawSqrM X,Y,colourBKG  ; 204,110 (4)
        sub     Y,23
        DrawSqrM X,Y,colourBKG  ; 204,87  (3)
        ; Пусть разделители мигают в зависимости от четности секунд.
        ; Пусть по четным секундам горят (1) и (3), а по нечетным (2) и (4).
        mov     al,dh           
        xor     ah,ah
        mov     bl,2
        div     bl
        cmp     ah,0            ; Если секунды четные,
        jne     b_sep           ; то рисуем верхние разделители,
        DrawSqrM X,Y,colourIND  ; 204,87  (3)
        sub     X,88
        DrawSqrM X,Y,colourIND  ; 116,87  (1)
        jmp     w1
 b_sep: add     Y,23            ; иначе - нижние
        DrawSqrM X,Y,10         ; 116,110 (2)
        sub     X,88
        DrawSqrM X,Y,10         ; 204,110 (4)
 w1:    ; ======= Конец  "блока разделителей" =======

        mov     di,1 
        jmp     Beg

        ret
MainP EndP

;---------------------------------------------------------------------------vp-

WhatFigP proc near              ; Пр-ра определения и рисования цифры

 zero:  cmp     figure,0
        jne     one    
        ; если считанная цифра равна '0'
        DrawIndM zeroX,zeroY,X,Y,colourIND
        jmp     endD

 one:   cmp     figure,1
        jne     two
        ; если считанная цифра равна '1'
        DrawIndM oneX,oneY,X,Y,colourIND
        jmp     endD

 two:   cmp     figure,2
        jne     three
        ; если считанная цифра равна '2'
        DrawIndM twoX,twoY,X,Y,colourIND
        jmp     endD

 three: cmp     figure,3
        jne     four
        ; если считанная цифра равна '3'
        DrawIndM threeX,threeY,X,Y,colourIND
        jmp     endD

 four:  cmp     figure,4
        jne     five
        ; если считанная цифра равна '4'
        DrawIndM fourX,fourY,X,Y,colourIND
        jmp     endD

 five:  cmp     figure,5
        jne     six
        ; если считанная цифра равна '5'
        DrawIndM fiveX,fiveY,X,Y,colourIND
        jmp     endD

 six:   cmp     figure,6
        jne     seven
        ; если считанная цифра равна '6'
        DrawIndM sixX,sixY,X,Y,colourIND
        jmp     endD

 seven: cmp     figure,7
        jne     eight
        ; если считанная цифра равна '7'
        DrawIndM sevenX,sevenY,X,Y,colourIND
        jmp     endD

 eight: cmp     figure,8
        jne     nine
        ; если считанная цифра равна '8'
        DrawIndM eightX,eightY,X,Y,colourIND
        jmp     endD

 nine:  cmp     figure,9
        jne     endD
        ; если считанная цифра равна '9'
        DrawIndM nineX,nineY,X,Y,colourIND

 endD:
        ret
WhatFigP EndP

;---------------------------------------------------------------------------vp-

DrawSqrP proc near              ; Пр-ра рисования разделителя
                
        inc     cx              ;  █
        call    PointP          ; ···
        dec     cx              ; ···
                                ;  ·

        mov     temp,0          ;  █ 
 qw:    inc     dx              ; ███
        call    PointP          ; ███
        inc     cx              ;  · 
        call    PointP
        inc     cx      
        call    PointP
        dec     cx
        dec     cx
        inc     temp
        cmp     temp,2
        jb      qw

        inc     cx              ;  █ 
        inc     dx              ; ███
        call    PointP          ; ███
                                ;  █ 
        ret
DrawSqrP EndP

;---------------------------------------------------------------------------vp-

DrawHSegP proc near            ; Процедура рисования горизонтального сегмента        
                                ;   ----20----
                                ;  -----22-----
                                ;   ----20----
        push    cx
        push    dx

        add     cx,X
        add     dx,Y

        mov     temp,cx
        add     temp,20
 hl1:   call    PointP
        inc     cx
        cmp     cx,temp
        jbe     hl1
        
        sub     cx,22
        mov     temp,cx
        add     temp,22
        inc     dx
        
 hl2:   call    PointP
        inc     cx
        cmp     cx,temp
        jbe     hl2
        
        sub     cx,22
        mov     temp,cx
        add     temp,20
        inc     dx
        
 hl3:   call    PointP
        inc     cx
        cmp     cx,temp
        jbe     hl3
        
        pop     dx
        pop     cx
        
        ret
DrawHSegP EndP

;---------------------------------------------------------------------------vp-

DrawVSegP proc near            ; Пр-ра рисования вертикального сегмента

        push    cx
        push    dx

        add     cx,X
        add     dx,Y

        mov     temp,dx
        add     temp,20
 vl1:   call    PointP
        inc     dx
        cmp     dx,temp
        jbe     vl1

        sub     dx,22
        mov     temp,dx
        add     temp,22
        inc     cx

 vl2:   call    PointP
        inc     dx
        cmp     dx,temp
        jbe     vl2

        sub     dx,22
        mov     temp,dx
        add     temp,20
        inc     cx

 vl3:   call    PointP
        inc     dx
        cmp     dx,temp
        jbe     vl3

        pop     dx
        pop     cx

        ret
DrawVSegP EndP

;---------------------------------------------------------------------------vp-

PointP  proc near               ; Процедура рисования точки
                                ; Входные параметры: cx, dx, colour

        push    ax
        push    bx

        mov     ah,0Ch          ; Функция рисования точки
        mov     al,colour       ; Атрибуты точки (для стирания mov al,0)
        mov     bh,00
        int     10h

        pop     bx
        pop     ax

        ret
PointP  EndP

;---------------------------------------------------------------------------vp-

TimeP   proc near               ; Процедура вычисления времени

        mov     ah,2ch          ; ch-час, cl-мин, dh-сек, dl-100д/сек
        int     21h   

        ret
TimeP   EndP

;---------------------------------------------------------------------------vp-
; Конец реализации задачи

cseg    EndS
End     StartP






;===========================================================================vp=

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; На все, что ниже не следует обращать никакого внимания, ибо это
; есть пережитки нашего (моего и программы) тяжелого прошлого.
;---------------------------------------------------------------------------vp-

DrawSqrP proc near

        push    ax
        push    bx
        push    cx
        push    dx

        mov     cx,116
        mov     dx,90
        
        mov     bl,colourIND
        mov     colour,bl

        inc     cx
        call    PointP
        dec     cx

        mov     temp,0
 qw:    inc     dx
        call    PointP
        inc     cx
        call    PointP
        inc     cx      
        call    PointP
        dec     cx
        dec     cx
        inc     temp
        cmp     temp,2
        jb      qw

        inc     cx
        inc     dx
        call    PointP        
        pop     dx
        pop     cx
        pop     bx
        pop     ax

        ret

DrawSqrP EndP        

; Пр-ра рисования индикатора. Вдруг пригодится? Сейчас за нее работает макрос
;---------------------------------------------------------------------------vp-

DrawIndP proc near              ; Процедура рисования сегмента 
                                ; Входные параметры massX и massY

        xor     si,si
        xor     cx,cx
        xor     dx,dx

        mov     cl,X
        mov     dl,Y

 start: 
        ; проверка на 'нерисование'
        cmp     massX[si],255
        je      nul

        add     cl,massX[si]
        add     dl,massY[si]

        mov     ax,si           ;
        mov     bl,2            ;                             /~2~\
        div     bl              ;                             1   3
        cmp     ah,0            ; какой сегмент рисуем?       >-4-<
        je      vert            ; вертикальный! (нечетный)    5   7
        call    DrawHSegP      ; горизонтальный! (четный)    \_6_/
        jmp     nul             ;
 vert:  call    DrawVSegP      ;
 nul:
        inc     si

        cmp     si,7
        jne     start

        ret
DrawIndP EndP

;---------------------------------------------------------------------------vp-


; На данный момент развития программы, эта процедура не нужна

Delay   proc near                       ; Пр-ра задержки
;---------------------------;
;  BIO's INTERRUPT METHOD.  ;
;                           ;
;  The value added to DX    ;
;  determines delay period. ;
;---------------------------;
bio_int_delay:
        mov     ah, 0                   ; clock count service
        int     1ah                     ; BIO's date time interrupt
        add     DX, 18                  ; roughly 1 second delay
        mov     bx, dx                  ; move it to BX for compare
delayit:
        int     1ah                     ; get another tick count
        cmp     dx, bx                  ; new tick in DX = BX yet?
        jne     delayit                 ; NO - get next tick count
                                        ; YES - DX = BX
        ret
Delay   EndP

;---------------------------------------------------------------------------vp-

; На данный момент развития программы, эта процедура не нужна

Clear_Screen  proc near         ; Пр-ра очищения экрана (прокруткой)

        push    ax
        push    bx
        push    cx
        push    dx
        mov     ah,6            ; Стереть экран в режиме прокрутки сверху
        mov     al,0            ; Заполнять пробелами X строк 
                                ;  (при 0 - весь экран)
                                ; Аналогично 'mov   ax,0600h'
        mov     cx,0000h        ; Левый верхний угол
        mov     dx,184Fh        ; Правый нижний угол
        mov     bh,0            ; Нормальный атрибут - ч/б
        int     10h
        pop     dx
        pop     cx
        pop     bx
        pop     ax

        ret
Clear_Screen  EndP

;---------------------------------------------------------------------------vp-