X86 Light Sensor and Counter

X86 Light Sensor and Counter

Assembly code
The purpose of this project is to show understanding of the x86 processor. This project is about the automatic room light controller with visitor counter. It is to be implemented on 2 doors. One for entrance and one for the exit. Since the complete circuit or sensors is not used to count the number of the objects, so it requires the processor to randomly pick the number of the object and based on that, it turns on the lights and counts the number of the objects. It is very important to have the comments on all the codes. The comments have to be complete. 

Solution 

lights.asm 

.586

.model flat

EXTRN   _printf:PROC

EXTRN   _getchar:PROC

EXTRN   _rand:PROC

.data

door1msg    BYTE  ‘Enter door has opened.’,10,10,0

door2msg    BYTE  ‘Exit door has opened.’,10,10,0

nodoormsg   BYTE  ‘The doors remain closed.’,10,10,0

lightmsg    BYTE  ‘Number of lights on: %d’,10,0

prompt            BYTE  ‘Press enter to open a random door, x to exit…’,10,0

format            BYTE  ‘%d’,0

cformat           BYTE  ‘%c’,0

val               BYTE  0

.code

_main PROC

mov ebx,0                     ; number of lights on will be saved in ebx, initialize to zero

mainloop:

push ebx                      ; push the current count of lights on the stack for printing

push OFFSET lightmsg    ; get the address of the message to print and push it in the stack

call _printf                  ; print the number of lights on message

add esp, 8                    ; remove pushed elements from stack

push OFFSET prompt            ; get the address of the message to print and push it in the stack

call _printf                  ; print a prompt message

add esp, 4                    ; remove pushed elements from stack

call _getchar                 ; read a character from the user

cmp  al,’x’                   ; see if the user pressed x

je   endprog                  ; if so, end program

cmp  al,’X’                   ; see if the user pressed X

je   endprog                  ; if so, end program

call _rand                    ; else, generate a random number

and  eax,1                    ; see if the generated number was odd

je   door2open                ; if it was even, assume door 2 (exit) was open

door1open:                          ; else, door 1 (enter) was open

push OFFSET door1msg    ; else, get the address of the message to print and push it in the stack

call _printf                  ; indicate that the enter door was open by printing the enter door message

add esp, 4                    ; remove pushed elements from stack

inc  ebx                      ; increment the number of lights by one

jmp  mainloop                 ; repeat the cycle

door2open:

cmp ebx,0                     ; if there was no people inside, ignore

je nodoor                     ; go to no door

push OFFSET door2msg    ; else, get the address of the message to print and push it in the stack

call _printf                  ; indicate that the exit door was open by printing the exit door message

add esp, 4                    ; remove pushed elements from stack

dec ebx                             ; decrement the number of lights on

jmp mainloop                  ; repeat the cycle

nodoor:

push OFFSET nodoormsg   ; get the address of the message to print and push it in the stack

call _printf                  ; print the message to indicate that no door was open

add esp, 4                    ; remove pushed elements from stack

jmp mainloop                  ; repeat the cycle

endprog:

ret                                 ; exit the program

_main ENDP                          ; end of main procedure

END _main                           ; end of program, set main as the start 

lights_emu8086.asm 

org 100h                    ; program start address

mov bx,0   ; bx is a register what will hold the number of lights that have been turned on

mainloop:                   ; this is a label

mov ah, 9                   ; load in ah the number 9 to select the function of print string on the system interrupt 21h

mov dx, offset lightmsg     ; load the address (offset) of the light message to be printed in the register dx

int 21h         ; make the DOS interrupt to print the string in the screen

mov ax,bx           ; load the register ax with the contents of the register bx in order to pass it as a parameter for the subroutine printint, which will print the number

call printint       ; call the subroutine print int to print the number in ax which is the number of lights on which was previously saved in the register bx

mov ah, 9   ; load in ah the number 9 to select the function of print string on the system interrupt 21h

mov dx, offset prompt   ; load the address (offset) of the prompt message to be printed in the register dx

int 21h     ; make the DOS interrupt to print the string in the screen

mov ah,7    ; load in ah the number 7 to select the function of read a character using the system interrupt 21h

int 21h     ; make the DOS interrupt to read a character from the keyboard, the character is returned in al

cmp  al,’x’ ; compare the read character with x to set the condition flags

je   endprog    ; if the z flag is set (the values are equal) jump to the end of the program, since that would imply that the user pressed x, which we have set as the exit character for the program

cmp  al,’X’     ; compare the read character with X uppercase to set the condition flags

je   endprog            ; if the z flag is set (the values are equal) jump to the end of the program, since that would imply that the user pressed X, which we have set as the exit character for the program

mov ah,00h  ; load in ah the number 0 to select the function of read the current time in clock ticks using the system interrupt 1ah

int 1ah     ; make the DOS interrupt to read the current clock tick, the low part of the clock ticks is returned in dx

and  dx,1               ; make a boolean and operation with the number of ticks, this will isolate the first bit in the number and will result in either 0 or 1 depending onthe number of ticks, the operation affects the flags, this part is the random generator of opens and closes, since the lowest bit of the clock tick will vary randomly between keypresses

je   door2open  ; if the z flag is set (the and result was zero), jump to door2open to indicate that the second door will be opened

door1open:                ; if the previous jump was not taken, we will  open door 1

mov ah, 9       ; load in ah the number 9 to select the function of print string on the system interrupt 21h

mov dx, offset door1msg ; load the address (offset) of the door1msg message to be printed in the register dx

int 21h     ; make the DOS interrupt to print the string in the screen

inc  bx                 ; increment the register bx, which is the number of lights on, since the door 1 is the enter door so someone has entered the room and the number of lights corresponds to the number of things in the room

jmp  mainloop   ; jump to the mainloop label which is the start in order to generate another random event

door2open:          ; this label indicates the place where the program will continue if the and in line 27 was zero, when it jumps here we will assume that the door 2 was opened

cmp bx,0          ; we compare the contents of register bx with zero and set the flags, this is to test if there were no things in the room, we can’t open the exit door if there are no things inside the room

je nodoor         ; if the comparison set the flag z, (the values are equal, that is bx is zero), then go to nodoor

mov ah, 9       ; otherwise, load in ah the number 9 to select the function of print string on the system interrupt

mov dx, offset door2msg ; load the address (offset) of the door2msg message to be printed in the register dx

int 21h     ; make the DOS interrupt to print the string in the screen

dec bx            ; decrement the register bx, which holds the number of lights on in order to indicate that one light has been turned off since something has opened the exit door and thus we assume that there is one thing less in the room

jmp mainloop    ; jump to the mainloop label which is the start in order to generate another random event

nodoor:         ; this label indicates the place where the program will continue if the comparison in line 36 was equal (z=1), when it jumps here we will assume that no door has been opened since we cannot open the exit door if there was nothing inside the room

mov ah, 9   ; load in ah the number 9 to select the function of print string on the system interrupt

mov dx, offset nodoormsg    ; load the address (offset) of the nodoormsg message to be printed in the register dx

int 21h     ; make the DOS interrupt to print the string in the screen

jmp mainloop    ; jump to the mainloop label which is the start in order to generate another random event

endprog:        ; this label indicates the place where the program will continue if either of the comparisons in line 19 or 21 are equal (z=1), when it jumps here we will assume that the user wanted to exit the program

ret           ; return to the calling function, which in the emulator it corresponds to giving the control to the OS, that is the same as exiting the program

; this is the definition of a subroutine called print int, the subroutine takes as input a value in the register ax, which

;is the number to be printed

; the process is done by dividing the number by 10 in a loop:

; to print 123 we divide: 123/10 = 12 remainder 3, then 12/10 = 1 remainder 2, then 1/10 = 0 remainder 1

; we end when te quotient is zero, the digits to print are given in reverse so we use the stack to put them in order

printint:   ; this is a label that indicates the start of the subroutine

push bx ;   push the value of the register bx on the stack in order to preserve its contents since they will be changed inside the subroutine

push dx ;   push the value of the register dx on the stack in order to preserve its contents since they will be changed inside the subroutine

mov  bx,10  ; load the value 10 inside the register bx in order to make divisions by 10 in the following lines

push bx ; push the value of bx (which is 10) into the stack, this will be used as a marker of the top of the stack since we will be pushing values on it

l1: mov dx,0    ; l1 is a label that indicates the start of a loop, start by moving the value of zero in dx, since the division that will be done next uses the combination of dx:ax to divide

div bx  ; make a division of the value dx:ax over the value in bx, which is 10, since dx is zero, we are dividing the current number by 10

add dx,’0′  ; the division result is saved as ax=quotient, dx=remainder, the remainder will be the lowest digit in the number, we convert it to ascii by adding the digit to the ascii value ‘0’

push dx     ; push the value of dx on the stack, we are saving the first digit we found there so we can print it in reverse later

cmp ax,0    ; compare the value in ax, which is the division quotient , with zero and set the flags, whis is to determine if we have divided the number enough times to reach zero,

jne l1      ; if we haven reached zero, repeat division by 10 with the current quotient, which is saved in ax

l2: pop dx      ; if the comparison in line 65 was equal (ax is zero) then we en here, the label l2 indicates the start of another loop, we start by popping a value from the stack and saving it in the register dx, the value will be the last digit from the number

cmp dx,10   ; we compare the value we popped with 10 in order to see if we have reached the mark we pushed at the start of the subroutine

je  e1      ; if the values are equal (dx=10), then we have popped all the digits we saved in the stack so we end the subroutine by going to label e1

mov ah,2    ; load in ah the number 2 to select the function of print character on the system interrupt

int 21h     ; make the DOS interrupt to print the character in dl on the screen

jmp l2      ; jump to the start of the second loop with the label l2, which will pop another digit from the stack and print it

e1: mov dl,10   ; if the comparison in line 69 was equal (dx is 10) then we end here, the label e1 indicates the end of the subroutine, we start by moving the value of 10 into dl in order to print a line feed, which will move the cursor in the screen to the next line

mov ah,2    ; load in ah the number 2 to select the function of print character on the system interrupt

int 21h     ; make the DOS interrupt to print the character in dl on the screen

mov dl,13   ; move the value of 13 into dl in order to print a carriage return, which will move the cursor in the screen to the leftmost part of the screen at the start of the line

mov ah,2    ; load in ah the number 2 to select the function of print character on the system interrupt

int 21h     ; make the DOS interrupt to print the character in dl on the screen

pop dx      ; pop back the value of dx we saved in the stack in order to restore the value it had before the subroutine started

pop bx      ; pop back the value of bx we saved in the stack in order to restore the value it had before the subroutine started

ret         ; return to the calling routine, it will return to the line just after the call was made

; this are the variables used to keep the data in the program, they are string and since they will be printed using int21h we need to end them with a dollar sign $ to indicate the end of the string

; the values 10 and 13 are used to insert a line jump at the end of the string, 10 is a line feed character in ascii,

;13 is a carriage return in ascii

door1msg    DB    ‘Enter door has opened.’,10,13,’$’

door2msg    DB  ‘Exit door has opened.’,10,13,’$’

nodoormsg   DB    ‘The doors remain closed.’,10,13,’$’

lightmsg    DB    ‘Number of lights on: $’

prompt          DB   ‘Press enter to open a random door, x to exit…’,10,13,’$’