Skip to content

Instantly share code, notes, and snippets.

@nitwhiz
Last active June 13, 2021 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nitwhiz/ba63eac81ba8dd11321df83ed26911e2 to your computer and use it in GitHub Desktop.
Save nitwhiz/ba63eac81ba8dd11321df83ed26911e2 to your computer and use it in GitHub Desktop.
; ---
; constants
pit_count: equ 18432 ; pit counter constant - 10ms
segm_setting: equ 7 ; digit to display seconds set
segm_time_seconds: equ 3 ; digit to display seconds of timer
segm_time_100th: equ 0 ; digit to display 100th seconds of timer
; segment display address
segm_addr: equ 90h
; determinate output offsets for display digits
segm_setting_offset: equ segm_setting * 2
segm_time_seconds_offset: equ segm_time_seconds * 2
segm_time_100th_offset: equ segm_time_100th * 2
org 100h
cli
call IVTABinit ; init vector table
call PICinit ; init IC
call PITinit ; init PIT
sti
call display_clear
main:
call read_switches
call display_timer
cmp [time_running], byte 0
je main ; s7 is off, don't run timer
;call cycle_timer
;call delay
jmp main
; ---
; init IC
PICinit:
in al, 0c2h
and al, 11111110b
out 0c2h, al
ret
; ---
; init pit
PITinit:
mov al, 01110110b
out 0a6h, al ; counter 1 mode 3
mov al, pit_count % 255
out 0a2h,al
mov al, pit_count / 256
out 0a2h,al
ret
; ---
; init vector 8 to our ISR
IVTABinit:
; set address of ISR in vektor 8
mov [8 * 4], word isr8
mov [8 * 4 + 2], cs
ret
; ---
; interrupt service routine (ISR)
isr8:
push ax
inc byte [tick_count]
cmp [tick_count], byte 5
jne under_100ms
call cycle_timer
mov [tick_count], byte 0
under_100ms:
mov al, 20h
out 0c0h, al ; unlock PIC
pop ax
iret
; ---
; get state of switches
read_switches:
push ax
push cx
in al, 0
mov ah, al
and al, 7fh ; mask lower 7 bit
cmp [time_setting], al
je switches_unchanged ; s6-s0 are the same as before, don't reset
; s6-s0 changed, reset timer
mov [time_setting], al
mov [time_seconds], al
mov [time_100th], byte 0
switches_unchanged:
mov cl, 7
shr ah, cl ; remove lower 7 bit
mov [time_running], ah
cmp ah, 1
jne interrupt_off
sti
jmp switches_end
interrupt_off:
cli
switches_end:
pop cx
pop ax
ret
; ---
; decrements timer and wraps milliseconds if necessary
cycle_timer:
cmp [time_100th], byte 0
je cycle_wrap ; time_100th == 0
; time_100th != 0
dec byte [time_100th]
jmp cycle_end
cycle_wrap:
cmp [time_seconds], byte 0
je cycle_end ; seconds == 0
; seconds != 0
mov [time_100th], byte 9
dec byte [time_seconds]
cycle_end:
ret
; ---
; converts AX to BCD
ax_as_bcd:
push bx
push cx
mov bl, al ; copy complete input
and bl, 00001111b ; mask to lower nibble
and al, 11110000b ; mask to upper nibble
mov cl, 4
shr al, cl ; remove lower nibble
cmp al, 0 ; check if there is an upper nibble
jz no_upper_nibble ; jump if upper nibble is 0
mov cl, al ; prepare loop counter (repeat upper-nibble times)
mov al, 0h ; clear al for upper nibble value
mov ah, 0h ; clear ah for carry
upper_nibble_to_bcd:
add al, 0fh ; add 15 to al
daa ; make valid BCD
adc ah, 0h ; add 1 to ah if carry
; --- necessary, because 10h is 10d with DAA
add al, 1h ; add 1 more to add 16 in total
daa ; make value BCD
adc ah, 0h ; add 1 to ah if carry
loop upper_nibble_to_bcd ; will happen 0 to 7 times
; used to skip loop if there is no upper nibble
no_upper_nibble:
mov bh, al ; copy current BCD (from upper nibble)
mov al, bl ; move lower nibble to al
daa ; turn lower nibble into BCD
add al, bh ; add BCDs
daa ; ensure BCD output
adc ah, 0h ; add 1 to ah if carry
pop cx
pop bx
ret
; ---
; display setting and current time
display_timer:
push ax
push dx
; setting
mov dl, segm_setting_offset
mov al, [time_setting]
mov ah, 0
call ax_as_bcd
call display_3
; seconds
mov dl, segm_time_seconds_offset
mov al, [time_seconds]
mov ah, 0
call ax_as_bcd
call display_3
; 100th
mov dl, segm_time_100th_offset
mov al, [time_100th]
call display_1
pop dx
pop ax
ret
; wait for 025000 cycles
delay:
push cx
mov cx, 025000d
delay_cycle:
loop delay_cycle
pop cx
ret
; ---
; display 3 hex numbers
; AX - number to display
; DL - digit to display value at
display_3:
push ax
push cx
push dx
xchg al, ah ; make sure al contains upper 8 bit
call display_1 ; display upper 4 bit
xchg al, ah ; make sure al contains lower 8 bit
sub dl, 2 ; move display digit 1 digit to right
call display_2 ; display lower 8 bit
pop dx
pop cx
pop ax
ret
; ---
; display 2 hex numbers
; AL - number to display
; DL - digit to display value at
display_2:
push cx
push dx
sub dl, 2 ; move display digit right by 1
call display_1 ; display lower 4 bit
mov cl, 4
shr al, cl ; cut off lower 4 bit
add dl, 2 ; move display digit left again
call display_1 ; display upper 4 bit
pop dx
pop cx
ret
; ---
; display 1 hex number
; AL - number to display
; DL - digit to display value at
display_1:
push ax
push bx
push dx
add dl, segm_addr ; add display port address to position
mov bx, codetab ; point to codetab
and ax, 0fh ; mask AX
add bx, ax ; add which number to display from codetab
mov al, [bx] ; copy codetab value
out dx, al ; output codetab value
pop dx
pop bx
pop ax
ret
; ---
; clear display
display_clear:
push ax
push cx
push dx
mov ax, 0
mov dx, segm_addr ; start at display digit 0
mov cx, 8 ; repeat for 7 digits
clear_step:
out dx, ax ; turn off digit
add dx, 2 ; next display digit
loop clear_step
pop dx
pop cx
pop ax
ret
tick_count:
db 0
time_running:
db 0
time_100th:
db 0
time_seconds:
db 0
time_setting:
db 0
codetab:
db 00111111b ; 0
db 00000110b ; 1
db 01011011b ; 2
db 01001111b ; 3
db 01100110b ; 4
db 01101101b ; 5
db 01111101b ; 6
db 00000111b ; 7
db 01111111b ; 8
db 01101111b ; 9
db 01110111b ; A
db 01111100b ; b
db 01011000b ; c
db 01011110b ; d
db 01111001b ; E
db 01110001b ; F
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment