This is the mail archive of the crossgcc@cygnus.com mailing list for the crossgcc project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Dony wrote: > Hii all, > Right now, I'm trying to porting 80x86 code to M68K. > In Intel, there is a function: pokeb(base_addr,offset,data) > and using Borland C Compiler will translated like this : > > /* Assembly Routine to do a pokeb */ > /* bp points at stack */ > /* stack + 0xc = data */ > /* stack + 0xa = register offset from base addr. */ > /* es - set to be segment value (CS) */ > /* si - set to be register offset */ > /* al - data */ > > mov ax,[base_addr] > mov es,ax > mov al,[bp+0x0C] > mov si,[bp+0x0A] > mov es:[si],al > > I'm a high level programmer, and I don't really understand > where this 0x0c and 0x0a come from, and how could in 0x0c > is data, and in 0x0a is register offset?? > Can somebody explain step by step what the assembler > trying to do?? > Is there anybody M68K programmer know any C function to replace > pokeb, peekb function in M68K?? > > -- > Dony > Email : dony@willowglen.com.sg Hi Dony, Equivalent C functions would be: void pokeb( unsigned char data, volatile unsigned char *base_addr, unsigned short offset ) { *(base_addr + offset) = data; } unsigned char peekb( unsigned char *base_addr, unsigned short offset ) { return *(base_addr + offset); } I'm not sure why you want to understand the assembler, but: When your Borland C compiler compiles the code to invoke pokeb, it generates the following instructions: sub ax,ax mov al,data push ax mov ax,offset push ax mov ax,SEG base_addr push ax sub ax,ax push ax or something similar. At this point, your stack looks like this: sp+0: base_addr (seg:offset form -- length 4 bytes) sp+4: offset (length 2 bytes) sp+6: data (length 2 bytes) the actual data item is one byte, stored in the least significant byte of the word on the stack. 2 bytes are pushed so that the stack pointer will always point to an even adress. In some of the simpler 80x6 processors, writing or reading a 16-bit value to/from an odd-addressed word would cause an exception fault) Next, the compiler generates this: call pokeb Now, your stack looks like this: sp+0: return address (length 4 bytes -- 2 bytes for the cs segment register, and 2 bytes for the offset within the cs segment of the first byte of code followinging the call instruction sp+4: base_addr (length 4 bytes) sp+8: offset (length 2 bytes) sp+10: data (length 2 bytes) Next, in generating code for the pokeb instruction itself, your compiler will generate the following: push bp move bp,sp This is part of the prolog code generated for all standard C functions. It saves the frame pointer of the calling routine, so it can be restored later on exit. Then, it sets up bp to point to the parameters which are currently on the stack, so that the called function code can access them easily The prolog code also saves other registers used within the called function (e.g., es, si, whatever), and also decrements the stack pointer by an amount equal to the size of any automatic data used within the function itself. The function parameters are accessed as a positive offset from the new bp (frame pointer) register, and the automatic data (pokeb doesn't have any) are accessed as a negative offset from the new bp register. At this point, your stack looks like this: sp+0: old bp register (length 2 bytes) sp+2: return address (length 4 bytes) sp+6: base address (length 4 bytes) sp+10: offset (length 2 bytes) sp+12: data (length 2 bytes) The generated code you provided is: /* Assembly Routine to do a pokeb */ /* bp points at stack */ /* stack + 0xc = data */ /* stack + 0xa = register offset from base addr. */ /* es - set to be segment value (CS) */ /* si - set to be register offset */ /* al - data */ mov ax,[base_addr] mov es,ax mov al,[bp+0x0C] mov si,[bp+0x0A] mov es:[si],al The first instruction: mov ax,[base_addr] loads the segment portion of the segment:offset base address into the ax register The offset part is assumed to be zero, and is never used. The second instruction: mov es,ax loads the segment portion of the base address from the ax register into the es register so that it can be used to access that segment of memory The third instruction: mov al,[bp+0x0c] loads the data byte into al. Remember, that at this point, bp and sp both have the same value, and bp is normally used to access the function's calling parameters. 0x0c is the same as decimal 12, which is the offset of the data byte on the stack. The data byte itself is it offset 12, rather than 13 because all Intel machines are little-endian, and so the least significant byte is at the smallest offset within the word. The fourth instruction: mov si,[bp+0x0a] loads the si register with the offset value The fourth instruction: mov es:[si],al does the real poking. The es (segment) register, and the si (offset) register are combined within the alu of the cpu to form a memory address, and the data byte is stored at that address. Exactly how they are combined depends on the mode of the machine. In real mode, the memory address is calculated as ( es << 4 ) + si. In protected mode, es is used to index into a mapping table (most likely the ldt) and retrieve a memory address (24 bit for the 80286, I forget how many for the 80[3,4,5]86). The contents of the si register are then added to this value. If virtual memory is active, this address is a virtual address which is then converted to an equivalent physical address using the normal memory mapping mechanisms before it is placed on the bus. This last translation is invisible to the application itself. Hope I didn't bore you to death, but remember -- you asked the question. Have a nice day. Dennis dnewbold@ivs.com