Assembly Code for part-number P89LPC933935 - c

I am working on translating assembly code to 'C', to which I came across a instruction which I am finding difficult to understand, here is the code
add a,#0-3
jc c_fail
I don't understand the line add a,#0-3

add a,#0-3 is same as add a,#-3 that will adds A with -3. -3 will be considered as 0xFD in 8051 MCU. So, if A value be equal or greater than 3 (a >= 3), program will goes to the c_fail address due to carry flag.
Also, you can replace it with subb a,#3, if use from the jnc instead of jc in its next line.

Related

Why compiler assembly C program into this?

I don't understand why the C51 compiler (in Keil) convert C source to this assembly language code: (As p is a pointer to unsigned char)
; p++;
; SOURCE LINE # 216
MOV R3,pDisplay?253
INC pDisplay?253+02H
MOV A,pDisplay?253+02H
MOV R2,pDisplay?253+01H
JNZ ?C0090
INC pDisplay?253+01H
As R3 and R2 wasn't used in the next lines of the program.
Why do compiler make these linesMOV R3,pDisplay?253, MOV R2,pDisplay?253+01H?
Welcome to 1980s "state of the art" code generation for 8-bit target processors. What the code is doing is "noting the value" of p before incrementing it. That's necessary when the postincrement operator is used in a surrounding expression; and not optimized away by subsequent passes of the compiler.
Try p += 1;, or even ++p; instead. Odds are that one or both of those will generate better code because there is no "note the value before" semantics to get in the code generator's way.
[This is how I got into the minority, by the way, using ++i in for () loops rather than the more common i++.]

Don't really understand how arrays work in Assembly

I've just started learning Assembly and I got stuck now...
%include 'io.inc'
global main
section .text
main:
; read a
mov eax, str_a
call io_writestr
call io_readint
mov [nb_array], eax
call io_writeln
; read b
mov eax, str_b
call io_writestr
call io_readint
mov [nb_array + 2], eax
call io_writeln
mov eax, [nb_array]
call io_writeint
call io_writeln
mov eax, [nb_array + 2]
call io_writeint
section .data
nb_array dw 0, 0
str_a db 'a = ', 0
str_b db 'b = ', 0
So, I have a 2 elem sized array and when I try to print the first element, it doesn't print the right value. Although I try to print the second element, it prints the right value. Could someone help me understand why is this happening?
The best answer is probably "because there are no arrays in Assembly". You have computer memory available, which is addressable by bytes. And you have several instructions to manipulate those bytes, either by single byte, or by groups of them forming "word" (two bytes) or "dword" (four bytes), or even more (depends on platform and extended instructions you use).
To use the memory in any "structured" way in Assembly: it's up to you to write piece of code like that, and it takes some practice to be accurate enough and to spot all bugs in debugger (as just running the code with correct output doesn't mean much, if you would do only single value input, your program would output correct number, but the "a = " would be destroyed anyway - you should rather every new piece of code walk instruction by instruction in debugger and verify everything works as expected).
Bugs in similar code were so common, that people rather used much worse machine code produced by C compiler, as the struct and C arrays were much easier to use, not having to guard by_size multiplication of every index, and allocating correct amount of memory for every element.
What you see as result is exactly what you did with the memory and particular bytes (fix depends whether you want it to work for 16b or 32b input numbers, you either have to fix instructions storing/reading the array to work with 16b only, or fix the array allocation and offsets to accompany two 32b values).

bne instruction in cpu simulator not working

I am trying to write a cpu simulator. But, it doesnt seem to function as expected when bne instruction is encountered. bne performs the same as bqe. bqe seems to be working fine though:
Mux2_32(mbranchAddress, pcPlus4, branchAddress, AND2_1(zero, branch));
Mux2_32(pc, mbranchAddress, jumpAddress, jump);
if(!strcmp(opcode, "000101")&& !strcmp(branch, "1")){ /*bne instruction, ("000101" is the opcode for bne)*/
Mux2_32(mbranchAddress, pcPlus4, branchAddress, AND2_1(NOT_1(zero), branch));
Mux2_32(pc, mbranchAddress, jumpAddress, jump);
}
"branch" is the flag raised when the instruction is a branch instruction. zero is the single bit alu output
MUX2_32(a, b, c, d) works as follows:
a=b if d=0
a=c if d=1
where a, b and c are 32 bits long and d is a single bit.
Could someone please point out why beq instruction works fine but bne doesn't. Thanks
C does not support binary number constants. 000101 is an octal number with value 65... and '000101' is a 64 bit wide multichar constant. You need to use hex numbers, that is opcode 000101 in hex is 0x5...

Testing a status bit

I have been learning Assembly and I have a question. The textbook presents the following example:
Assume that the printer data port is memory-mapped to address 0FFE0h
and the printer status port is bit zero of memory-mapped port 0FFE2h.
The following code waits until the printer is ready to accept a byte
of data and then it writes the byte in the L.O. byte of ax to the
printer port:
0000: mov bx, [FFE2]
0003: and bx, 1
0006: cmp bx, 0
0009: je 0000
000C: mov [FFE0], ax
. .
. .
. .
The first instruction fetches the data at the status input port. The
second instruction logically ands this value with one to clear bits
one through fifteen and set bit zero to the current status of the
printer port. Note that this produces the value zero in bx if the
printer is busy, it produces the value one in bx if the printer is
ready to accept additional data. The third instruction checks bx to
see if it contains zero (i.e., the printer is busy). If the printer is
busy, this program jumps back to location zero and repeats this
process over and over again until the printer status bit is one.
Why must we perform the second instruction, and bx, 1? Can't we just go straight to cmp bx, 0?
Also, can you please clarify or reword "The second instruction logically ands this value with one to clear bits one through fifteen and set bit zero to the current status of the printer port"? I don't understand what it means right now because English isn't my first language.
Thank you for
The bit field of the status byte may contain other flags in other bits. You're only interested in the bit 0 (the least significant bit) in this case, so you ignore the rest of bits by anding the value with 1, and then testing the value against 0.
Let's say that memory address 0xFFE2 contains a byte with 8 bits, for instance something like this: 00010100.
Only the last bit contains information about printer status. All other bits don't matter for this purpose. How would you extract the last bit from this byte?
The solution given by the book (and one that is used overall) is to zero out all bits that don't matter by using bitwise and operator:
00010100 # content of the memory cell (0x14)
and 00000001 # 0x1
---------------
00000000
...or...
00010101 # content of the memory cell (0x15)
and 00000001 # 0x1
---------------
00000001
You see where this is going, don't you? By comparing the result of the operation with 0, you can get definite answer if the last bit was 0 or not and hence if the printer is ready or not. Thus, in this case, and operator is just a way of extracting single bit from a byte, nothing more.
Because, as the problem states, "the printer status port is bit zero". If you don't clear away the other bits with that AND instruction, these could cause you to not take the jump even when the bit of interest is zero.
Since you're a student, you probably need more than just a quick answer:
BX is a 16 bit register and only the first bit (bit 0) is of interest.
As an example, use a value of 10101111 00101000 (AF28h) for bx.
cmp bx, 0 would return false even though bit 0 has a value of zero because cmp compares the value of the whole register, not just bit 0.
In other words, cmp bx, 0 = false because AF28h <> 0
The line and bx, 1 changes the value of bx to 0 if the first bit is 0, or 1 if the first bit is 1
In my example, and bx, 1 sets bx = 0 because bit 0 has a value of zero

Empty array when printed

Im writing some C/asm program for the AVR MCU. Im still learning as I go so I hope I have made some sort of mistake in my code.
I have a buffer volatile unsigned char suart_0_rx_buffer[SUART_0_BUF_SIZE+1]; in my C code that I am accessing in my asm code as below. All I want to do is store a byte s0_Rxbyte in the buffer and increment the pointer s0_index every time. 's0_Rxbyte` is always a non zero value.
suart_0_wr_buf_2: ldi s0_z_low, lo8(suart_0_rx_buffer)
ldi s0_temp1, hi8(suart_0_rx_buffer)
add s0_z_low, s0_index
adc s0_z_high,s0_temp1
suart_0_wr_buf_3: st Z+, s0_Rxbyte
inc s0_index
clr s0_temp1
st Z, s0_temp1
If I try and print the contents in a loop in my C code I am getting absolutely nothing.
I didnt want to attach everything here because it will be cluttered.
So does anyone see any problems with the asm code above ?
Managed to figure it out in the end. It was a case of a simple error in the assembly code that caused it write an incorrect location in the SRAM.
suart_0_wr_buf_2: clr s0_temp1
ldi s0_z_low, lo8(suart_0_rx_buffer)
ldi s0_z_high, hi8(suart_0_rx_buffer)
add s0_z_low, s0_index
adc s0_z_high, s0_temp1
suart_0_wr_buf_3: st Z+, s0_Rxbyte
inc s0_index
st Z, s0_temp1

Resources