0

I was given a task to write numbers from the relative address 10h numbers 0-255 in ascending order if the address is even and numbers from 0-255 in descending order if the adress is not even

then we had to sum up all the numbers from address 10h to 210h This is my code, I don't know why it doesn't work:

;Write into Address
MOV SI,10h
MOV AL,0d
MOV BX,255
MOV CX,255     

LOOP1:

TEST SI,00000001b   
jnz notzero
jz zero      

notzero: 
MOV [SI],BX
DEC BX
INC SI
LOOP LOOP1

zero:
MOV [SI],AL
INC SI 
INC AL
LOOP LOOP1

;Sum up address from 10h to 210h
MOV AL,0
MOV SI,10h
MOV cx,200  

Loop1:

ADD AL,[SI]
INC SI
LOOP Loop1  
Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • 5
    "It doesn't work": what does it do instead? What have you been able to find out, eg. using a **debugger**? – Marcus Müller Oct 12 '16 at 13:52
  • If you write numbers from 0 to 255, or from 255 to 0, you will cover 256 bytes only. But range 10h-210h is 512 bytes, so the task description leaves a lot to be desired... should you sum uninitialized memory or what? – Ped7g Oct 12 '16 at 17:20

2 Answers2

1

I would use just AX for all your math.

MOV SI,10h
MOV AX,FF00h  ;Or mov ax,0xff00 or however it is written
MOV CX,255    ;One memory write before the loop, 255 writes from the loop

WRITE_512_BYTES:
MOV [SI],AX
DEC AH
INC AL
ADD SI,2
LOOP WRITE_512_BYES

;Sum up address from 10h to 210h
MOV AX,0
MOV BX,0
MOV SI,10h
MOV CX,511  ;One iteration before the loop, 511 loops, 512 bytes summed.

SUM_LOOP:
MOV BL, [SI]  ;populate lower byte of bx from memory
ADD AX, BX    ;BH guaranteed to still be 0 from earlier MOV
INC SI
LOOP SUM_LOOP  

Bugs that have been discussed in other comments: 1- BX versus BL. Even if you have the correct value in BX (say, 0005h), when you write BX to memory, you'll be writing both the 00 and the 05. In your code, you only want to write one byte. The code I have writes two bytes, but also adds two to SI.

2- Was pointed out, but it is unclear what memory "from 10h to 210h" is referring to. If you were told to check the values of the bytes "from 10h to 10h", you would assume you were checking one byte- an inclusive range, so 10h-10h+1=1. Likewise, 210h-10h+1 = 201h = 513 bytes. Since you are only writing 512 bytes, that's probably not correct. Your algorithm will populate bytes from 10h to 20Fh.

3- Was pointed out, but as you sum the numbers with

ADD AL,[SI]   

You will overflow your 8 bit register AL, because the sum of the numbers is too big for the 0-255 range.

4- As was pointed out, when LOOP runs out of cx to count with, it will continue with the next instruction underneath it. This means that your notzero case will begin executing the zero case. You could solve this with an unconditional jump, placed directly underneath the LOOP, to the sum section, which you'll need to label as such.

5- I don't know why you are getting an error with mov [si],bl. Are you sure it is typed correctly? That is a valid instruction.

Nits:

TEST SI,00000001b

This does in fact AND SI with 1 and set flags, but it is odd to specify 1 as the 8 bit value "00000001b". The actual comparison is done as 16 bits, 32 bits, or 64 bits, depending on what mode you are running in. Consider just comparing it to 1 (and letting the assembler zero extend the value) instead of writing it out partially as an 8 bit value.

2- When you are doing a compare for one of two exclusive branches, you could get away with just testing one of the cases. For instance, if you do the test and then do the

jz zero

You will conditionally jump to the zero case, and then you can just have the non-zero case without any further redirection: just eliminate the jnz instruction.

3- It would be kinda good to know where you are running this. In 16 bit DOS COM files, for instance, you would end up overwriting your own code when you wrote to bytes at 100h and above. I'm assuming that the memory addresses are safe for wherever you are writing this, because that was in your instructions.

XorMalice
  • 154
  • 3
  • Another common convention for ranges is `[start, end)` (inclusive start, exclusive end). C++ STL does this with `for(auto it = v.begin() ; it != v.end() ; ++it)`, and it's natural for looping over an array in asm, too: given a start and length, `end = start + len` using LEA or something, and loop with `add rsi, 2` / `cmp rsi, rdx` / `jb .not_at_end_yet`. – Peter Cordes Oct 13 '16 at 01:42
  • Your loop interleaves ascending and descending counts, and isn't conditional on the low bit of SI. IDK exactly what the OP needs, since the description is weird, but I don't think it's that. Anyway, welcome to SO, thanks for helping out answering x86 asm question. There are some links to some canonical-answers to common questions in the [x86 tag wiki](http://stackoverflow.com/tags/x86/info) (plus lots of other good stuff), in case you're ever looking for that. – Peter Cordes Oct 13 '16 at 01:46
  • "add rsi, 2 / cmp rsi, rdx" -> Without a lot of info, you never really know what the goal of something is in asm. I assumed he wanted to use LOOP, and tried to keep that. – XorMalice Oct 13 '16 at 01:48
  • [LOOP is slow](http://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently), so it's not a useful habit to learn, IMO. You won't find it in compiler-generated code, so learning the modern way to write loops is more useful. But anyway, I was just pointing out that one-past-the-end pointers are a useful way to describe loops. – Peter Cordes Oct 13 '16 at 01:51
  • " IDK exactly what the OP needs, since the description is weird, but I don't think it's that." I'm not sure either, but he gave a high level description about writing the bytes in a specific order, so I went for that. Another way would be to just write two byte loops, one for the odd addresses and one for the evens. I wanted to give him something that would avoid the "bl" issue he was having for some reason, and also show writing two bytes in one loop. I don't know if it is ideal for him. – XorMalice Oct 13 '16 at 01:51
  • Well, the description is ambiguous, but I don't think it's compatible with an interleaved FF 00 FE 01 ... Upvoted anyway because there's enough other stuff wrong that you point out that this is definitely a useful answer, even though I'm not sure it answers the title question. – Peter Cordes Oct 13 '16 at 01:53
  • " I don't think it's compatible with an interleaved FF 00 FE 01" -> I think he wants the first address to contain 00, the second to contain FF, the third to contain 01, the fourth to contain FE, the fifth to contain 02, the sixth to contain FD, etc. Doesn't his code intend to do that, and doesn't mine do that? With FF00 in AX, 00 and FF should be written to +0 and +1. With FE01 in AX, 01 and FE should be written to +2 and +3, etc. – XorMalice Oct 13 '16 at 02:16
  • The OP's code does either 00 01 02 ... or FF FE FD ..., depending on the low bit of SI (but falls through from notzero into zero). Oh, I just figured out how the text description is compatible with yours, if the OP just totally mangled it. i.e. put an ascending count in even addresses and a descending count in the odd addresses. That actually makes a lot *more* sense, because it will fill 512 bytes. Probably you're right and the OP was misinterpreting it, since the starting address is apparently supposed to be a known constant, so testing its low bit is weird. – Peter Cordes Oct 13 '16 at 03:22
  • Anyway, yes, your code correctly does what you intended, and I think it's actually the right answer to the OP's assignment. The OP misled me, and Ped7g. Nice job decoding that description. – Peter Cordes Oct 13 '16 at 03:23
  • As I read all of those comments, I can understand that this task is so unclear. Either way, i learned alot from it . Thanks alot ! – user6219654 Oct 23 '16 at 13:39
0

Problems found in your code are commented with arrows ◄■■■ :

.model small
.stack 100h
.data
arr db 1024 dup (0)   ;◄■■■ BUFFER FOR THE NUMBERS.
.code
  mov ax, @data
  mov ds, ax

;Write into Address
MOV SI,10h
MOV AL,0d
MOV BL,255            ;◄■■■ BL, NOT BX, BECAUSE BX IS TWO BYTES.
MOV CX,255     

LOOP1:

TEST SI,00000001b   
jnz notzero
jz zero      

notzero: 
MOV [SI],BL          ;◄■■■ BX IS TWO BYTES, SO WE USE BL INSTEAD.
DEC BL               ;◄■■■ BL, NOT BX.
INC SI
LOOP LOOP1

zero:
MOV [SI],AL
INC SI 
INC AL
LOOP LOOP1

;Sum up address from 10h to 210h
MOV AX,0              ;◄■■■ AL IS TOO SMALL FOR THE SUM.
MOV SI,10h
MOV cx,200h           ;◄■■■ 200H, NOT 200.  
MOV BH,0              ;◄■■■ CLEAR BH TO USE BX.

Loop2:                ;◄■■■ "LOOP1" WAS ALREADY USED.
MOV BL,[SI]           ;◄■■■ EXTRACT ONE BYTE ONLY.
ADD AX,BX             ;◄■■■ BH WAS CLEARED, SO BX=BL.
INC SI
LOOP Loop2            ;◄■■■ "LOOP1" WAS ALREADY USED.
  • I have a few question about ur correction. First, does it metter whether it's BX and not BL? is it because every memory is 8 bytes? – user6219654 Oct 12 '16 at 15:27
  • and can't I add content of address to register? i have to first mov it to register and then add both registers? – user6219654 Oct 12 '16 at 15:28
  • And when im running this program I get this message: FE /3 - no such opcode in 8086 instruction set. – user6219654 Oct 12 '16 at 15:36
  • @user6219654, about your first comment : BX is 2 bytes, BL is 1 byte. Your algorithm stores numbers 0-255 from AL (one byte), in order to be consistent, you have to store numbers 255-0 from BL, if you don't do it, your final sum will be wrong. – Jose Manuel Abarca Rodríguez Oct 12 '16 at 15:37
  • @user6219654, about your second comment : yes, you can add the content of address to register, but it is unnecessary. – Jose Manuel Abarca Rodríguez Oct 12 '16 at 15:39
  • @user6219654, about your third comment : what line gives you that error? – Jose Manuel Abarca Rodríguez Oct 12 '16 at 15:39
  • line 14 `mov [SI],BL` – user6219654 Oct 12 '16 at 15:43
  • @user6219654, what compiler do you use? Also try lowercase. If you have AL then you should have BL, both are basic x86 assembly registers. – Jose Manuel Abarca Rodríguez Oct 12 '16 at 15:56
  • The "notzero" loop will continue into "zero" loop. And he doesn't need to allocate buffer, if he was told that he really can overwrite memory at 10h. I just don't get it completely, as 10h is always even, and relative to what? To start of code segment? That's always aligned as well, so even too, no way to get odd address this way. Should the task be like "to address" instead of 10h, and 10h being example. – Ped7g Oct 12 '16 at 17:18
  • oh, I see, you wrote it in such complex way, I didn't understand it correctly at first. But it still contains few bugs IMO. (cx has to be 513 then to finish the loop with two sets of 0-255 values written (plus some overwrite after that)). Would be simpler to do for example `mov cx,256 mov si,10h mov bx,0FF00h loop1: mov [si],bx add si,2 add bx,0FF01h loop loop1` .. then again I wonder if the OP would be capable to explain to lector how this works. :D – Ped7g Oct 12 '16 at 19:06
  • 1
    As I read all of those comments, I can understand that this task is so unclear. Either way, i learned alot from it . Thanks alot ! – user6219654 Oct 23 '16 at 13:39