I am trying to add the first 3 digits and last 3 digits of the series of numbers and subtracting the second result with the first. I will have to use the load byte and store byte commands. But when I use sb, I get the wrong answer.
My code is as follows (in MIPS assembly language):
.data
D1: .byte 1,7,2,0,0,3
D2: .byte 0
.text
.globl main
main: la $t0,D1
la $t9,D2
lb $t1,0($t0)
lb $t2,4($t0)
add $t3,$t1,$t2
lb $t4,8($t0)
add $t3,$t3,$t4
lb $t5,16($t0)
lb $t6,20($t0)
lb $t7,24($t0)
add $t8,$t5,$t6
add $t8,$t8,$t7
sub $t8,$t8,$t3
sb $t8,0($t9)
li $v0,10
syscall
Until sub $t8,$t8,$t3 I get the correct answer -7 that is stored in $t8 but when I use sb, the answer is 249. I am unable to figure out why that is.
The number -7(signed) in binary is :
11111111 11111111 11111111 11111001
And number 249(signed) is :
00000000 00000000 00000000 11111001
sb (save byte) , saves just one byte(8LS bits). This is why you'r getting 249 instead of -7.
After sb you can do :
lui $t8, 65535 # this will change the first 16 bits from 0 to 1
then add the correct number to $t8 to take the wished output.
However i do not know what you're trying to accomplish.
Related
I am a begginer with assembly i just started learning it and i don't get how the instruction IMUL really works
For example i'm working on this piece of code on visual studio:
Mat = 0A2A(hexadecimal)
__asm {
MOV AX, Mat
AND AL,7Ch
OR AL,83h
XOR BL,BL
SUB BL,2
IMUL BL
MOV Ris5,AX
}
the result in Ris5 should be 00AA (in hexadecimal), for the first couple lines i'm all good, from the first line to 'SUB BL,2'
the results are AL = AB (AX =0AAB)
but then starting from IMUL i'm stuck.
I know that IMUL executes a signed multiply of AL by a register or a byte or a word .. and stores the result in AX (here) but i can't find the same result (00AA)
MOV AX, Mat AX = 0x0A2A (...00101010)
AND AL,7Ch AX = 0x0A28 (...00101000)
OR AL,83h AX = 0x0AAB (...10101011)
XOR BL,BL BL = 0x00
SUB BL,2 BL = 0xFE
IMUL BL AX = 0xFFAB * 0xFFFE = 0x00AA
MOV Ris5,AX Ris5 = 0x00AA
When you multiply two N bit numbers the lower N bits don't care about signed vs unsigned, but as you pad the numbers then you get into signed vs unsigned multiply instructions as you will see in some instruction sets. To not lose precision you desire a 2*N number of bits result, grade school math:
00000000aaaaaaaa
* 00000000bbbbbbbb
=====================
AAAAAAAAAAaaaaaa
* BBBBBBBBBBbbbbbb
====================
Signed vs unsigned with the Capital letter representing the sign extension
0xAB = 171 unsigned = -85 signed
0xFE = 254 unsigned = -2 signed
unsigned multiply 171 * 254 = 43434 = 0xA9AA
signed multiply -85 * -2 = 170 = 0x00AA
The lower byte is the same as they are 8 bit operands and the sign extension doesn't come into play:
bbbbbbbb *a[0]
bbbbbbbb *a[1]
bbbbbbbb *a[2]
bbbbbbbb *a[3]
bbbbbbbb *a[4]
bbbbbbbb *a[5]
bbbbbbbb *a[6]
+ bbbbbbbb *a[7]
==================
cyyyyyyyxxxxxxxx
If you look up the columns the x bits are not affected by the sign extension so are the same for unsigned and signed. y bits are affected as well as the carry out of the msbit c which makes up the 16th bit of the result.
Now the tool is not complaining about this syntax, is it?
Mat = 0A2A(hexadecimal)
Without an h at the end or 0x or $ up-front that looks like octal, but the A's would cause an error if octal (or if decimal). Assuming you start with 0x0A2A, I think your understanding is solid.
The first instruction is at ‘0’ location in instruction memory.
Label:
lw $t0,8($t1)
add $t3,$t2,$t0
beq $t3,$t4,Label
jump Label
Suppose values of reg $t3 and reg $t4 are equal and it will jump to Label address.
So, I want to ask what will the offset value of Label and what will be the address of beq instruction?
The beq instruction is 3 instructions after Label(which has address 0000). So the beq is at 4*3 = 12 + 0000 = 0012 address.
You say $t3 == $t4, so offset says to the assembler to go 4 instructions back, so:
PCnew = (PCold + 4) + Label * 4
PCold is 0016 and Label is -4 , so PCnew equals 0000 and goes back to Label:
In instruction j Label the Imm26 (26bits), has the address of Label divided by 4 ... so technically 0000. After jump instruction :
PCnew = (Label*4) = (0000)*4 = 0000
I am using DosBox and I have a string read in from the buffer using an interrupt. I know where the first character is stored in memory, how do I increment to the next character?
0100 mov ah, 0a
0102 mov dx, 111
0105 int 21
0107 mov dl, [113] ;first character here
010b mov ah, 02
010d int 21
010f int 20
0111 db 0f
The question is how do I increment to the next character in the string? If I input the string "Hello" and then use inc dl it simply gives me the letter "I" instead of "e".
You need to pick a register to point at the current character. Once you have this there are instructions to advance your pointer as well as instructions to read the byte the pointer is pointing to.
Since you don't know how many characters will be read by the user input function, and you want this function to work with any input value, you'll need some sort of loop so you only print as many characters as have been read, although if you wanted to make it simple, you could make it only print the first 3 characters regardless of what was typed in. I'm going to assume you want to print out exactly what was typed by the user.
A good way to tackle this is to use the LOOP instruction which repeats (jumps into) the loop body by the count that has been placed into the CX register. Since the user input function gives us the character count, all we have to do is read that into the lower portion of the CX register (CL) for loop initialization. We'll also need a pointer to point to the current character. Once in the loop body, we'll just read whatever character is at our "current character" pointer and then call the DOS character-print function to output it to the console. Then we can advance the pointer and LOOP until all characters have been done. Note that each time the LOOP instruction is encountered, CX is decremented until it reaches zero. Once it is zero, LOOP no longer jumps back into the body and simply advances to the instruction following the LOOP.
NOTE: If you don't output a CRLF after reading the user input, there will be no line feed and the new output will overwrite where the input was read on the console. Effectively it will look like nothing happened.
Here's your modified sample:
0100 MOV AH,0A
0102 MOV DX,0123
0105 INT 21 ;input string using buffer at 0123
0107 MOV DX,0120
010A MOV AH,09
010C INT 21 ;output CRLF sequence first
010E MOV SI,0124 ;point SI at byte containing chars read
0111 XOR CX,CX ;CX = 0
0113 MOV CL,[SI] ;CX = chars_read
0115 INC SI ;mov SI to next char to display
0116 MOV DL,[SI] ;DL = character SI is pointing at
0118 MOV AH,02
011A INT 21 ;display character
011C LOOP 0115 ;loop back to INC instruction until no more chars left
011E INT 20 ;exit
0120 DB 0D ;CR
0121 DB 0A ;LF
0122 DB 24 ;"$" DOS string terminator
0123 DB 20 ;buffer start; max characters = 32
0124 DB 00 ; chars read goes here
0125 DB 00 ; input chars are read here
I want to implement a routine that calculates the sum of all natural numbers from 1 to n. n is a variable stored in RAM. The result has to be stored in a two-byte variable in RAM, too. I'm very new in assembly programming so I'm having a hard time trying to figure out the algorithm to achieve this. So far, I've done this:
.DSEG
.ORG 0x100
n: .BYTE l_n
result: .BYTE l_result
.CSEG
.ORG 0x100
SUM:
LDI XL, n ;the direction of n is stored in XL
LD R16, X ;now r16=n
LDI XL, LOW(result)
LDI XH, HIGH(result) ;X points to result
CLC ;in case C is full with trash
LDI R17, 0x0 ;R17 = 0
LDI R18, 0x1 ;R18 = 1
CALL LOOP
LDI R16,0
LDI R17,0
ADC R16, R17 ;if C is on when the loop finishes, then it has to be summed as well
ST X, R16
RET ;returns to the program that called the routine
I did the initialization of R17 and R18 because I thought that the subroutine LOOP should do something like increasing this numbers one by one until doing it n times. The thing that is complicating me the most is the fact that the result has two bytes, while each number being summed consists of just one byte. I don't know how to deal with this. Any help will be appreciated.
what you need is
ADD R18,R24 //sumL += nL
ADC R19,R25 //sumH += nH + Carry
and for 2 bytes variable the max sum will be 65535 so for
1+2+3+...+n=n*(n+1)/2 <= 65535 then N <= 361 = 0x0169
1+2+3+...+361=361*362/2=65341
and code will looks like this:
//CPU: ATmega128A
.include "m128Adef.inc"
.DSEG
//.ORG 0x100
n: .BYTE 2 // define 2 bytes var
result: .BYTE 2 // define 2 bytes var
.CSEG
.ORG 0
RJMP boot
n0: .DW 0x0169 //init value for n=361 (max value for 2 byte result)
//in: N=R24:R25
//out: Sum=R18:R19
//calc sum 1 to n (n >=1 and n <=361)
//1+2+3+...+n=n*(n+1)/2 <= 65535 => n<=361= 0x0169
Sum1toN:
LDI R18,0x00 //sumL=0
LDI R19,0x00 //sumH=0
Lsum:
ADD R18,R24 //sumL + = nL
ADC R19,R25 //sumH += nH + C
SBIW R24,0x01 //n--
BRNE Lsum // n >0 ?
RET
boot:
CLR R1
OUT SREG,R1 //Clear all
//init stack pointer
LDI R28,LOW(RAMEND) //LDI R28,0xFF
LDI R29,HIGH(RAMEND) //LDI R28,0x10
OUT SPH,R29
OUT SPL,R28
//init
LDI ZL,LOW(n0<<1)
LDI ZH,HIGH(n0<<1)
LDI XL,LOW(n)
LDI XH,HIGH(n)
LDI R24,2
LDI R25,0
init:
LPM R0,Z+
ST X+,R0
SBIW R24,1
BRNE init
//calc:
LDS R24,n // LDS R24,0x0100
LDS R25,n+1 // LDS R25,0x0101
RCALL Sum1toN
STS result,R18
STS result+1,R19
main:
RJMP main
I am trying to acces a specific bit and modify it.
I have moved 0x01ABCDEF (hex value) into ecx and want to be able to check bit values at specific position.
For example I must take byte 0 of 0x01ABCDEF (0xEF)
check if bit at position 7 is 1
set the middle 4 bits to 1 and the rest to 0.
Under x86 the most simple solution is using bit manipulation instructions like BT (bit test), BTC (bit test and complement), BTR (bit test and reset) and BTS (bit test and set).
Bit test example:
mov dl, 7 //test 7th bit
bt ecx, edx //test 7th bit in register ecx
Remember: only last 5 bits in register edx is used.
or
bt ecx, 7
In both cases the result is stored in carry flag.
It's been years since I've done asm, but you want to and your value with 0x80 and if the result is zero your bit is not set so you jump out, otherwise continue along and set your eax to the value you want (I assume the four bits you mean are the 00111100 in the fourth byte.
For example (treat this as pseudo code as it's been far too long):
and eax, 0x80
jz exit
mov eax, 0x3C
exit:
Most CPUs do not support bit-wise access, so you have to use OR to set and AND to clear bits.
As I'm not really familiar with assembly I will just give you C-ish pseudocode, but you should easily be able to transform that to assembly instructions.
value = 0x01ABCDEF;
last_byte = value & 0xFF; // = 0xEF
if (last_byte & 0x40) { // is the 7th bit set? (0x01 = 1st, 0x02 = 2nd, 0x04 = 3rd, 0x08 = 4th, 0x10 = 5th, 0x20 = 6th, 0x40 = 7th, 0x80 = 8th)
value = value & 0xFFFFFF00; // clear last byte
value = value | 0x3C; // set the byte with 00111100 bits (0x3C is the hex representation of these bits)
}
Not that you can remove the last_byte assignment and directly check value & 0x40. However, if you want to check something which is not the least significant part, you have to do shifting first. For example, to extract ABCD you would use the following:
middle_bytes = (value & 0xFFFF00) >> 8;
value & 0cFFFF00 gets rif og the more significant byte(s) (0x01) and >> 8 shifts the result left by one byte and thus gets rid of the last byte (0xEF).