Difference between revisions of "NU32v2: Digital I/O Assembly Code"

From Mech
Jump to navigationJump to search
Line 22: Line 22:
The first number in each row is the address of the instruction relative to the start of the program at 000. (Note that the instructions are each 4 bytes long, or 32 bits, so the address of each successive instruction is 4 bytes greater than the previous one.) The second number is the 32-bit instruction written in hexadecimal; the first several bits are for the instruction type, or "opcode," and the remaining bits are to specify registers, memory locations, values, etc., used by the instruction. The next column is the opcode in human-readable form, and the last column contains the human-readable form of the registers, memory locations, values, etc., used by the instruction.
The first number in each row is the address of the instruction relative to the start of the program at 000. (Note that the instructions are each 4 bytes long, or 32 bits, so the address of each successive instruction is 4 bytes greater than the previous one.) The second number is the 32-bit instruction written in hexadecimal; the first several bits are for the instruction type, or "opcode," and the remaining bits are to specify registers, memory locations, values, etc., used by the instruction. The next column is the opcode in human-readable form, and the last column contains the human-readable form of the registers, memory locations, values, etc., used by the instruction.


I see 11 instructions in the loop, just less than my estimated 12 instructions. Usually we have one assembly instruction per machine instruction (cycle), but sometimes an assembly instruction expands to more than one machine instruction. Is that what's happening here---there's an extra machine instruction we're not seeing? Or bad timing by me? Not sure.
I see 11 instructions in the loop, just less than my estimated 12 instructions.
<1-- Usually we have one assembly instruction per machine instruction (cycle), but sometimes an assembly instruction expands to more than one machine instruction. Is that what's happening here---there's an extra machine instruction we're not seeing? Or bad timing by me? Not sure. -->


Notice our use of the constant 10,000,000 in the code actually requires two assembly instructions to load the value into register v0: one for the most significant half-word (16 bits), and one for the least significant half-word. We have a limit of 32 bits total to specify the instruction (and some of them are used for the opcode and specifying the register). If we created a variable and assigned it the value 10,000,000, on the other hand, the entire word could be loaded with one lw instruction.
Notice our use of the constant 10,000,000 in the code actually requires two assembly instructions to load the value into register v0: one for the most significant half-word (16 bits), and one for the least significant half-word. We have a limit of 32 bits total to specify the instruction (and some of them are used for the opcode and specifying the register). If we created a variable and assigned it the value 10,000,000, on the other hand, the entire word could be loaded with one lw instruction.

Revision as of 07:09, 26 January 2011

Let's say we called our source code digio.c. When we compile it, we find an "object code" file digio.o somewhere. I can "disassemble" this object code to see an assembly language version of the code. (You can either do this directly in the MPLAB IDE, or run the command-line functions pic32-nm or pic32-objdump with your .o file as the argument. These can be found in your C32 directory under "bin." For example, to produce the output below, I used pic32-objdump -D digio.o.) When we look at our disassembled code, we see a lot of stuff, including the block of code below. I added the comments beginning with //, since we don't know assembly language.

 354:  afc00010  sw     zero,16(s8)         // "store word" (4 bytes) zero to i (memory location 16(s8))

// start loop

 358:  8fc30010  lw     v1,16(s8)           // load word i into register v1
 35c:  3c020098  lui    v0,0x98             // load 0x98 into upper 16 bits of v0
 360:  3442967f  ori    v0,v0,0x967f        // load 0x967f into lower 16, to give v0 = 9,999,999 in base 10
 364:  0043102a  slt    v0,v0,v1            // if v0 < v1, set v0 to 1, otherwise to 0
 368:  1440ffe4  bnez   v0,2fc <main+0x2fc> // if v0 is nonzero (i.e., 10 M <= i), exit "for" loop
 36c:  00000000  nop                        // no operation; finish branching
 370:  8fc20010  lw     v0,16(s8)           // load i into v0
 374:  24420001  addiu  v0,v0,1             // (unsigned integer) add 1 to v0
 378:  afc20010  sw     v0,16(s8)           // store v0 back to i
 37c:  1000fff6  b      358 <main+0x358>    // go back to start of loop, instruction 358
 380:  00000000  nop                        // no operation; finish branching

The first number in each row is the address of the instruction relative to the start of the program at 000. (Note that the instructions are each 4 bytes long, or 32 bits, so the address of each successive instruction is 4 bytes greater than the previous one.) The second number is the 32-bit instruction written in hexadecimal; the first several bits are for the instruction type, or "opcode," and the remaining bits are to specify registers, memory locations, values, etc., used by the instruction. The next column is the opcode in human-readable form, and the last column contains the human-readable form of the registers, memory locations, values, etc., used by the instruction.

I see 11 instructions in the loop, just less than my estimated 12 instructions. <1-- Usually we have one assembly instruction per machine instruction (cycle), but sometimes an assembly instruction expands to more than one machine instruction. Is that what's happening here---there's an extra machine instruction we're not seeing? Or bad timing by me? Not sure. -->

Notice our use of the constant 10,000,000 in the code actually requires two assembly instructions to load the value into register v0: one for the most significant half-word (16 bits), and one for the least significant half-word. We have a limit of 32 bits total to specify the instruction (and some of them are used for the opcode and specifying the register). If we created a variable and assigned it the value 10,000,000, on the other hand, the entire word could be loaded with one lw instruction.

If you're interested to learn more about assembly instruction sets, you can start with http://en.wikipedia.org/wiki/MIPS_architecture, or the MIPS Instruction Set Reference or MIPS32 M4K Core Software Reference. If you are writing C code that needs to be very time or memory efficient, you can include assembly commands directly in your C code using asm. As a simple example, the line asm("nop") will directly insert a nop in your compiled code. (Though that specific example may not help with efficiency!) We will not go into assembly in more detail.