I am learning programming with 8051 and 2051 using Assembly language. About the pound sign (#) I found that it should be used when I am considering an immediate data. Like I found here http://what-when-how.com/8051-microcontroller/inside-the-8051/

MOV A,#23H ;load 23H into A (A=23H)
MOV RO,#12H ;load 12H into RO (RO=12H)
MOV R1,#1FH ;load 1FH into Rl (R1=1FH)

But when using Indexed addressing mode, I found that I have to use # sign to indicate address. And I didn't find it anywhere. This is a simple program I wrote -

ORG 00h
MOV A, #00h

MOV A, #00h


Here: sjmp HERE

X: db 00h
Y: db 100
Z: db 50 

Is there any other way to get value from a variable which is in code memory? And is DPTR considering #Z as the address of Z? Should not it get data rather then address?

I searched for that pound sign thing but seems I am finding in wrong place. Thanks for helping me understand in advance.

  • \$\begingroup\$ what assembler are you using? \$\endgroup\$
    – tcrosley
    Commented May 24, 2015 at 6:05
  • \$\begingroup\$ I am testing it on Edsim51 simulator. \$\endgroup\$ Commented May 24, 2015 at 6:17

1 Answer 1


In assembly language, the term addressing mode doesn't mean taking the address of a variable; but rather how information is encoded into the instruction code. For example, instruction code 0xE8 0x4D is the mov A,0x4D instruction using direct addressing mode: acc A gets the contents of iram address 0x4D. But instruction code 0x74 0x4D is mov A,#0x4D: acc A gets the actual literal value 0x4D. Both instructions are the same length and use similar encoding, but the meaning of the 0x4D depends on which addressing mode was used.

Even if you define a symbol LetterM equ 0x4D, this makes no difference to the 8051 -- mov A,LetterM assembles as 0xE8 0x4D and mov A,#LetterM assembles as 0x74 0x4D. The 8051 itself never sees the assembly source code, only the object code. So the only reason punctuation like # or @ matters at all, is to ensure that the assembler uses the right addressing mode to encode each instruction.

For loading the 16-bit data pointer register, mov dptr,#data16 only supports immediate addressing mode. Usually you want to use dptr to point to the memory address of an object, so immediate addressing mode is what you need. To your question, mov dptr,#Z considers mov dptr,#data16 as the immediate addressing mode, and Z as the address of symbol Z -- which you're using to store a variable.

If you already understand C language pointers, the dptr register is a pointer to an 8-bit value in memory, and the movc A, @A+DPTR instruction is what de-references the pointer value that's in the dptr register. So dptr always gets the address where the variable lives, and the indirect addressing mode (@) uses the value currently in dptr to get the value that dptr is pointing at.

// some C pseudocode to help explain 8051
uint8* dptr_register;      // 8051 built-in DPTR register
uint8 acc_a;               // 8051 built-in accumulator register A
static uint8 myVarZ = 123; // myVarZ: db 123
dptr_register = &myVarZ;   // mov dptr,#myVarZ ; address of myVarZ
acc_a = *dptr_register;    // movc A,@A+DPTR  (assuming A is 0) ; get value of myVarZ

The 8051 is a little bit more complicated though, because it has more than one address space. Code address 0 is different than internal RAM address 0, which is also different than external RAM address 0. This is why there are several different instructions that use dptr (`movc', 'mov', 'movx'). Real C compilers for 8051 (like Keil C51 or SDCC) have a few extra, non-standard keywords to distinguish between these different address spaces.

Other microcontrollers have slightly different instruction sets and use slightly different punctuation, but they're all similar enough that one you learn one, you can easily pick up the others.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.