Byte and Bit addressable 8051 - microcontroller

8051 SFRs
'P0,SP, DPL & DPH' have their byte addresses 80h,81h,82h,83h. Since P0 is bit addressable, P0.0 - P0.7 has bit addresses 80h - 87h. But, how it's gonna distinguish the addresses P0.1(81h) & SP(81h), P0.2(82h) & DPL(82h), P0.3(83h) & DPH(83h) …?

Byte addresses and bit addresses are never used in the same instruction.
So while
mov SP, #5 ; mov 81h, #5
mov P0.1, C ; setb 81h
both have the address 81h and both are written as mov, the first one is assembled as 0x75 0x81 0x5 and the second 0x91 0x81. To the processor, 0x75 and 0x91 mean entirely different things, namely, move the the value in the 3rd byte of this instruction to the address in the second byte of this instruction, and move the carry flag to the bit address in the second byte of this instruction. The assembler knows that mov addr, #imm and mov bit, C need to be encoded differently, and the processor really doesn't care how they're written because it doesn't see the source code at all.

Related

Understanding pointers in assembly language

Are we enclosing the variable or register in brackets to specify a pointer in assembly?
Example1;
MOV eax, array+4
LEA eax, [array+4]
Example2;
section .data
array DB 116,97
section .bss
variable RESB 0
section .text
global _start:
_start:
mov eax,[array]
;exit
mov eax,1
int 0x80
I am not getting any errors while compiling or running the above code. Is the address of the zero index of the array placed in the EAX register?
Example3;
INC [variable]
When compiling the above code, I am getting the "operation size not specified" error. And why can't the command be used as INC variable?
Example4;
section .data
array DB 116,97
section .bss
variable RESB 97
section .text
global _start:
_start:
mov eax,4
mov ebx,1
mov ecx,variable
mov edx,1
int 0x80
;exit
mov eax,1
int 0x80
And this code is not working.
Are we enclosing the variable or registrar in brackets to specify a
pointer in assembly?
Example1;
MOV eax, array+4
LEA eax, [array+4]
The brackets are like the dereference operator in C (*ptr). They get the value at the resulting address inside the square brackets. As for the example, both of these essentially do the same thing. The first moves the address of the array label + 4 into eax. The second uses lea, which loads the effective address of its source operand. So you get array + 4, dereference it, and get the address again with lea and load it into eax.
Example2;
section .data
array DB 116,97
section .bss
variable RESB 0
section .text
global _start:
_start:
mov eax,[array]
;exit
mov eax,1
int 0x80
I am not getting any errors while compiling or running the above code.
Is the address of the zero index of the array placed in the eax
register?
Kind of. Since you're moving it into eax, a 32-bit register, it is assumed that you want to move the first 4 bytes at the address array into eax. But there are only 2 bytes at array: 116 and 97. So this is probably not what you intended. To load the first byte at array into eax, do movzx eax, BYTE [array], which will move array[0] into the LSByte of eax and zero out the higher bytes. mov al, [array] will also work, though it won't zero out the upper bytes.
Example3;
INC [variable]
When compiling the above code, I am getting the "operation size not
specified" error. And why can't the command be used as INC variable.
The error says it all. variable is just an address. When you use [], how many bytes should it take? You need to specify a size. For example to get the first byte, you would do inc BYTE [variable]. However, from the previous example, it seems like you've reserved nothing at variable, so trying to access any bytes at it may cause some issue. As for "And why can't the command be used as INC variable", as I just said, variable is just a label which translates to some address. You can't change the address which variable translates to.
Example4;
section .data
array DB 116,97
section .bss
variable RESB 97
section .text
global _start:
_start:
mov eax,4
mov ebx,1
mov ecx,variable
mov edx,1
int 0x80
;exit
mov eax,1
int 0x80
And this code is not working.
It may seem to not be printing anything, but it actually is. .bss zero-initializes any memory that you reserve. That means when you print the first byte at variable, it just prints the NUL character. However, this doesn't seem to be visible for you when you print it, so it seems like nothing has been printed.
(By the way, are you certain that you know what resb does? In one example, you reserve 0 bytes, and in another, you reserve 97 bytes for no apparent reason. You might want to take another look at what resb actually does.)
array ; variable address
byte[array] ; value of first byte of array
word[array] ; value of first word of array
byte[array + 1] ; value of second byte of array
Think of the variable names as pointers, and using size[name] gets the value being pointed (similar to *name in C where name is a pointer)

x86 assembly, moving data from an array to a register

Ive been going over the book over and over again and cannot understand why this is giving me "improper operand type". It should work!
This is inline assembly in Visual Studio.
function(unsigned int* a){
unsigned int num;
_asm {
mov eax, a //This stores address (start of the array) in eax
mov num, dword ptr [eax*4] //This is the line I am having issues with.
That last line, I am trying to store the 4 byte value that is in the array. But I get error C2415: improper operand type
What am I doing wrong? How do I copy 4 byte value from an array into a 32 bit register?
In Visual C++'s inline assembly, all variables are accessed as memory operands1; in other words, wherever you write num you can think that the compiler will replace dword ptr[ebp - something].
Now, this means that in the last mov you are effectively trying to perform a memory-memory mov, which isn't provided on x86. Use a temporary register instead:
mov eax, dword ptr [a] ; load value of 'a' (which is an address) in eax
mov eax, dword ptr [eax] ; dereference address, and load contents in eax
mov dword ptr [num], eax ; store value in 'num'
Notice that I removed the *4, as it doesn't really make sense to multiply a pointer by four - maybe you meant to use a as base plus some other index?
1 Other compilers, such as gcc, provide means to control way more finely the interaction between inline assembly and compiler generated code, which provides great flexibility and power but has quite a steep learning curve and requires great care to get everything right.

PTR Directive in ASM, how does it work?

I have this block of ASM code with a few variables and 1 instruction:
.data
g BYTE 32h
a DWORD 11111111h
h BYTE 64h
.code
mov ebx, DWORD PTR g
Could anyone explain why the value of ebx is not 11 11 11 32 instead of 00 00 00 32 or at least how does PTR work?
I thought that the PTR directive would represent the operand as a 32-bit operand ?
Thanks in advance.
See #Jester's comment if your code really looks like what you've posted.
But judging by your question I'm guessing that your code actually contains this line instead:
mov ebx, DWORD PTR g
I thought that the PTR directive would represent the operand as a 32-bit operand ?
That depends on what you mean by that. DWORD PTR would be used as a size specifier when the size is ambiguous.
For example, the instruction mov [eax], 0 would be ambiguous because the assembler has no idea of knowing if you meant to write a byte, a word, a dword, etc. So in that case you could use DWORD PTR to state that you want to write a DWORD to memory: mov DWORD PTR [eax], 0.
If you want to read a byte from memory and convert it to a DWORD you need to use movzx or movsx:
movzx ebx, BYTE PTR g ; if g should be treated as unsigned
movsx ebx, BYTE PTR g ; if g should be treated as signed
Unfortunately the assembly language for x86 was too generic, using
mov ebx,a
If you look at the instruction encodings (if you are writing/learning assembly you should have a reference handy and open anyway) you find that that might mean read a byte at address 8, or a 16 bit word at address a or perhaps a 32 bit word at address a. And it may or may not go further and allow for sign extension or not. So in order to get the right instruction that you want you need to add more stuff.
Assembly language is not some standard it is defined by the assembler, the program reading the ASCII file, so one assembly language for the same instruction set does not dictate what another is. x86 in particular starting with intel vs AT&T and then gcc vs masm vs nasm and so on. And naturally with gcc and AT&T and everyone else that intentionally didnt want to go along with what was already out there, how you specify if this is a byte read or word read or dword read varies. Likewise the default instruction if any that is generated if you dont specify what you want.

Indirect Register Addressing

I am trying to figure out how register indirect addressing works. I have a variable that stores the value of 5 as follows:
section .data
number db 53 ; ascii code for 5
section .bss
number2 resb 1
section .text
global _start
_start:
mov eax,number
mov number2,[eax]
At the last two lines of the code what I am essentially trying to do is made eax act like a pointer to the data stored at number and then move this data into the number2 variable. I had though indirect register addressing was done via [register] but my code does not seem to work. Any help with regards to syntax would be much appreciated.
Labels work as addresses in nasm so your mov number2, [eax] would translate to something like mov 0x12345678, [eax] which is of course invalid because you cannot move data to immediate operand. So you would need mov [number2], [eax] but that's also invalid.
You can achieve this using some register to temporarily hold the value [eax]:
mov eax, number
mov dl, [eax]
mov [number2], dl
The problem here is, that number and number2 are not numbers, i.e. immediate literals. Instead they are interpreted as absolute memory addresses and the corresponding instructions, if they would exist would be e.g.
mov eax, [0x80000100] ;; vs
mov [0x80000104], [eax] ;; Invalid instruction
One has to pay attention to the instruction format as well, as answered by Mika Lammi -- is the instruction
mov src, dst ;; vs
mov dst, src
In addition, one should match the register size to the variable size; i.e
.data
number db 1; // this is a byte
.code
mov al, number

UART 3 Will Not Accept 5th Byte

The chip in question is PIC24FJ256GB210
It is a 100-Pin TQFP form factor
We have an embedded system with two microprocessors.
The two microprocessors use a UART to communicate Which is (according to me) mapped to UART #3 on the PIC24.
I place 4 bytes into UART #3. All goes well. The 5th byte will not go in.
I say FIFO backup.
My local hardware expert says that if I turn off flow control that the bytes will go out no matter what.
Is this true ? I've never heard that one before. I thought it was a hardware signal on the other side; i.e., a read signal has to occur on the other side before the FIFO buffer would allow room on this side.
His definition of "turn off flow control" is for me to not use PPS (Peripheral Pin Select) to map either the RTS (Request to Send) or CTS (Clear To Send) pins to their corresponding physical pin on the board.
I did that. Result: no change; the FIFO buffer still fills up. The "#UTXBF" bit never clears after the fourth byte goes in.
I have the schematic diagram with physical pins numbered and labeled.
I have the source code and MpLab showing the executable down at the register level, right at the assembly language instructions themselves.
I am mapping the pins of UART #3 exactly and identically to the manner that I am mapping UART #2 and UART #1, and both of those other two work perfectly.
While the numbers are different, the instruction sequences are identical. The numbers match the pins.
I am debugging this for the third time, watching each bit in each register and comparing them against the manual to make sure that I have the correct corresponding numbers in the correct bit positions in the correct special function registers.
This is from MpLab's disassembler window where the opcodes show exactly which bits are set and cleared.
206CC1 mov.w #0x6cc,0x0002 Mov #Uart_3_Tx_PPS_Output_Register, W1 ;This is the register we want
21C002 mov.w #0x1c00,0x0004 Mov #Uart_3_Tx_Or_In_Bit_Pattern, W2 ;These are the bits we want on
2C0FF3 mov.w #0xc0ff,0x0006 Mov #Uart_3_Tx_And_Off_Bit_Pattern, W3 ;These are the bits we want off
780211 mov.w [0x0002],0x0008 Mov [W1], W4 ;The existing pattern
618204 and.w 0x0006,0x0008,0x0008 And W3, W4, W4 ;Turn existing bits off
710204 ior.w 0x0004,0x0008,0x0008 Ior W2, W4, W4 ;Turn Desired bits on
780884 mov.w 0x0008,[0x0002] Mov W4, [W1] ;And that's all there is to it
After execution, RPOR6 (which is the Uart_3_Tx_PPS_Output_Register) contains 0x1C06
This is from the inc file that is used to create the masks and patterns. (I try to avoid hard coding numbers in the source files which have the actual instructions.)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; ;;
;; Map UART # 3 Tx Pin ;;
;; ;;
;; Docs for this are: Manual DS39975A ;;
;; ;;
;; Find "TABLE 2: COMPLETE PIN FUNCTION DESCRIPTIONS FOR 100-PIN DEVICES" ;;
;; in Manual DS39975A, Page 8, where We find the secret PIC Pin Names for ;;
;; the actual physical pin numbers ;;
;; ;;
;; TABLE 10-4: SELECTABLE OUTPUT SOURCES (MAPS FUNCTION TO OUTPUT) ;;
;; Page 160, We find the output function numbers ;;
;; ;;
;; ;;
;; ;;
;; PIC Associated Output ;;
;; Circuit Physical PIN Control Actual Func. ;;
;; Function Pin NAME Reg Bits Number ;;
;; ------------ ------ ----- ------- ---- ----- ;;
;; ;;
;; UART #3, TX Pin 23 RP13 RPOR6 3F00 28 Output ;;
;; ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I combined that knowledge with these notes from the family data sheet to create the constants with meaningful names.
.Equiv Uart_3_Tx_PPS_Output_Register, RPOR6 ;Register 10-35, Page 177
.Equiv Uart_3_Tx_Reg_Control_Bits, 0x3F00 ;Look for "RP13R" in the big include file ;;;DEBUG DEBUG Date: 2013-02-05 Time: 20:47:02
.Equiv Uart_3_Tx_Output_Func_Number, 28 ;From Table 10-4, P. 160
.Equiv Uart_3_Tx_And_Off_Bit_Pattern, ~(Uart_3_Tx_Reg_Control_Bits)
.Equiv Uart_3_Tx_Or_In_Bit_Pattern, ( Uart_3_Tx_Output_Func_Number << RP13R0 )
From the File: "p24FJ256GB210.inc" (no quotes)
;----- RPOR6 Bits -----------------------------------------------------
.equiv RP12R0, 0x0000
.equiv RP12R1, 0x0001
.equiv RP12R2, 0x0002
.equiv RP12R3, 0x0003
.equiv RP12R4, 0x0004
.equiv RP12R5, 0x0005
.equiv RP13R0, 0x0008 ;;; <<<<<----- RP13 is in the right place
.equiv RP13R1, 0x0009
.equiv RP13R2, 0x000A
.equiv RP13R3, 0x000B
.equiv RP13R4, 0x000C
.equiv RP13R5, 0x000D
After all is said and done, with or without RTS or CTS enabled, the PIC on the other side of the UART apparently never sees the first byte that I put in on this side.
Does anyone see anything where I put the wrong bit in the wrong place ?
At this moment, I cannot confidently answer yes or no to this question: Is the UART #3 TX function correctly connected to physical Pin 23 on a 100-Pin TQFP configured PIC24FJ256GB210 ?
Thanks a ton if you can identify what's going on here.
Here is where I found the error and the answer to the problem
Look at special function register U3STA
Look for the bit UTXEN
It must be set.
If not, you will fill the FIFO and clog it up after the 4th byte.
The UTXEN is bit #10. The assembler and compiler will probably change it to #2 in the next higher numbered byte.
There is a errata issued from MicroChip about this behaviour on PIC24 microcontroller.
refer: http://ww1.microchip.com/downloads/en/DeviceDoc/80522c.pdf.
Page 4 of the document indicates that:
Module: UART (TX Buffer)
If the transmit buffer is filled sequentially with
four characters, the characters may not be
transmitted in the correct order.
Work around
Do not completely fill the buffer before transmit-
ting data; send three characters or less at a
time.
Another work arround is suggested by a developer to use the TRMT flag instead, refer to: http://www.microchip.com/forums/m622420-print.aspx
Hope it helps.
My local hardware expert says that if I turn off flow control that the bytes will go out no matter what.
Yes, that's true. But that takes time, serial ports are very slow. Getting one byte transmitted from the fifo takes an eternity, about a millisecond at 9600 baud. Which is why UARTs are normally fed from a larger buffer by an interrupt handler.

Resources