Search code examples
memoryassemblyx86intelmasm

x86 Assembly: Writing a Program to Test Memory Functionality for Entire 1MB of Memory


Goal:
I need to write a program that tests the write functionality of an entire 1MB of memory on a byte by byte basis for a system using an Intel 80186 microprocessor. In other words, I need to write a 0 to every byte in memory and then check if a 0 was actually written. I need to then repeat the process using a value of 1. Finally, any memory locations that did not successfully have a 0 or 1 written to them during their respective write operation needs to be stored on the stack.

Discussion:
I am an Electrical Engineering student in college (Not Computer Science) and am relatively new to x86 assembly language and MASM611. I am not looking for a complete solution. However, I am going to need some guidance.

Earlier in the semester, I wrote a program that filled a portion of memory with 0's. I believe that this will be a good starting point for my current project.

Source Code For Early Program:

;****************************************************************************
;Program Name: Zeros
;File Name: PROJ01.ASM
;DATE: 09/16/14
;FUNCTION: FILL A MEMORY SEGMENT WITH ZEROS
;HISTORY:
;AUTHOR(S):
;****************************************************************************

NAME ZEROS

MYDATA SEGMENT
MYDATA ENDS

MYSTACK SEGMENT STACK
                DB              0FFH  DUP(?)
                End_Of_Stack    LABEL BYTE
MYSTACK ENDS



ASSUME  SS:MYSTACK, DS:MYDATA, CS:MYCODE
MYCODE SEGMENT
START:  MOV AX, MYSTACK
        MOV SS, AX
        MOV SP, OFFSET End_Of_Stack
        MOV AX, MYDATA
        MOV DS, AX

        MOV AX, 0FFFFh                  ;Moves a Hex value of 65535 into AX
        MOV BX, 0000h                   ;Moves a Hex value of 0 into BX

        CALL Zero_fill                  ;Calls procedure Zero_fill

        MOV AX, 4C00H                   ;Performs a clean exit
        INT 21H

Zero_fill   PROC NEAR                   ;Declares procedure Zero_fill with near directive
                MOV DX, 0000h           ;Moves 0H into DX
                MOV CX, 0000h           ;Moves 0H into CX. This will act as a counter.
Start_Repeat:   INC CX                  ;Increments CX by 1
                MOV [BX], DX            ;Moves the contents of DX to the memory address of BX
                INC BX                  ;Increments BX by 1
                CMP CX, 10000h          ;Compares the value of CX with 10000H. If equal, Z-flag set to one.
                JNE Start_Repeat        ;Jumps to Start_Repeat if CX does not equal 10000H.
                RET                     ;Removes 16-bit value from stack and puts it in IP
Zero_fill   ENDP                        ;Ends procedure Zero_fill

MYCODE ENDS
END START

Requirements:
1. Employ explicit segment structure.
2. Use the ES:DI register pair to address the test memory area.
3. Non destructive access: Before testing each memory location, I need to store the original contents of the byte. Which needs to be restored after testing is complete.
4. I need to store the addresses of any memory locations that fail the test on the stack.
5. I need to determine the highest RAM location.

Plan:
1. In a loop: Write 0000H to memory location, Check value at that mem location, PUSH values of ES and DI to the stack if check fails.
2. In a loop: Write FFFFH to memory location, Check value at that mem location, PUSH values of ES and DI to the stack if check fails.

Source Code Implementing Preliminary Plan:

;****************************************************************************
;Program Name: Memory Test
;File Name: M_TEST.ASM
;DATE: 10/7/14
;FUNCTION: Test operational status of each byte of memory between a starting
;          location and an ending location
;HISTORY: Template code from Assembly Project 1
;AUTHOR(S):
;****************************************************************************

NAME M_TEST

MYDATA SEGMENT
MYDATA ENDS

MYSTACK SEGMENT STACK
                DB              0FFH  DUP(?)
                End_Of_Stack    LABEL BYTE
MYSTACK ENDS

ESTACK SEGMENT COMMON
ESTACK ENDS

ASSUME  SS:MYSTACK, DS:MYDATA, CS:MYCODE, ES:ESTACK
MYCODE SEGMENT
START:          MOV AX, MYSTACK
                MOV SS, AX
                MOV SP, OFFSET End_Of_Stack
                MOV AX, MYDATA
                MOV DS, AX

                MOV AX, FFFFH           ;Moves a Hex value of 65535 into AX
                MOV BX, 0000H           ;Moves a Hex value of 0 into BX

                CALL M_TEST             ;Calls procedure M_TEST

                MOV AX, 4C00H           ;Performs a clean exit
                INT 21H

M_TEST      PROC NEAR                   ;Declares procedure M_TEST with near directive
                MOV DX, 0000H           ;Fill DX with 0's
                MOV AX, FFFFH           ;Fill AX with 1's
                MOV CX, 0000H           ;Moves 0H into CX. This will act as a counter.
Start_Repeat:   MOV [BX], DX            ;Moves the contents of DX to the memory address of BX
                CMP [BX], 0000H         ;Compare value at memory location [BX] with 0H. If equal, Z-flag set to one.
                JNE SAVE                ;IF Z-Flag NOT EQUAL TO 0, Jump TO SAVE
                MOV [BX], AX            ;Moves the contents of AX to the memory address of BX
                CMP [BX], FFFFH         ;Compare value at memory location [BX] with FFFFH. If equal, Z-flag set to one.
                JNE SAVE                ;IF Z-Flag NOT EQUAL TO 0, Jump TO SAVE
                INC CX                  ;Increments CX by 1
                INC BX                  ;Increments BX by 1
                CMP CX, 10000H          ;Compares the value of CX with 10000H. If equal, Z-flag set to one.
                JNE Start_Repeat        ;Jumps to Start_Repeat if CX does not equal 10000H.
SAVE:           PUSH ES
                PUSH DI
                RET                     ;Removes 16-bit value from stack and puts it in IP
M_TEST      ENDP                        ;Ends procedure Zero_fill

MYCODE ENDS
END START

My commenting might not be accurate.

Questions:
1. How do I use ES:DI to address the test memory area?
2. What is the best way to hold on to the initial memory value so that I can replace it when I'm done testing a specific memory location? I believe registers AX - DX are already in use.

Also, if I have updated code and questions, should I post it on this same thread, or should I create a new post with a link to this one?

Any other advice would be greatly appreciated.
Thanks in advance.


Solution

  • How do I use ES:DI to address the test memory area?

    E.g. mov al, es:[di]

    What is the best way to hold on to the initial memory value so that I can replace it when I'm done testing a specific memory location? I believe registers AX - DX are already in use.

    Right. You could use al to store the original value and have 0 and 1 pre-loaded in bl and cl and then do something like this (off the top of my head):

    mov al, es:[di] // load/save original value
    
    mov es:[di], bl // store zero
    cmp bl, es:[di] // check that it sticks
    jne @pushbad    // jump if it didn't
    
    mov es:[di], cl // same for 'one'
    cmp cl, es:[di]
    jne @pushbad
    
    mov es:[di], al // restore original value
    jmp @nextAddr
    
    @pushbad:
    mov es:[di], al // restore original value (may be redundant as the mem is bad)
    push es
    push di
    
    @nextAddr:
    ...