I have been trying to write c code to overwrite the interrupt vectors on the DS80c400 ( to do the same as the following asm code) EXTRN CODE (com_isr) MOV DPTR, #000023H MOV A, #02H; MOVX @DPTR, A; INC DPTR; MOV A, #BYTE2 com_isr; MOVX @DPTR, A; INC DPTR; MOV A, #HIGH com_isr; MOVX @DPTR, A; INC DPTR; MOV A, #LOW com_isr; MOVX @DPTR, A; i would like to do the same in 'c' but when I get a pointer to the com_isr fuction it is in the "generic pointer" format which is not much use. So any suggestion on how to do this in C?
Two issues: 1) Your assembly code, as given, won't typicall overwrite the interrupt vector table at all --- not unless you have von-Neumann address decoding in the lowermost address range. 2) To get a pointer to xdata instead of generic pointer, cast it to a pointer to xdata. Details in the manual.
"cast it to a pointer to xdata" Or define it as a pointer to xdata in the first place.
Thanks for the feeback... 1) The original code snipet I included does work. The DS80C400 is normally used in von-Neumann mode...required by its boot rom. 2) casting it with xdata converts the address to a 16 bit address, i need the 24 bit address (the ds80c400 has a linear 16M - 24 bit address map). thus the byte 2 in the asm code. I have also tried casting the pointers with "const far" and "far" but they still give me the generic pointers to my function rather than a linear 24 bit address.
The question here seems to be how to extort that highest byte of address location from the linker. The generic pointer format uses the high byte to indicate a type tag. For code pointers, that tag is 0xff. Xdata is 0x01. "Far" pointers use tags 0x02..0x7F. So in the case of xdata access, it's almost as though it's a flat 24-bit address with 0x10000 added. (This addition is exactly what the FVAR macros in absacc.h do.) The manual notes that you can use the ROM(512K) and ROM(D16M) directives for the compiler to generate code for the 24-bit contiguous mode of the 80c400, in which case the hardware has a 24-bit program counter. However, the linker manual says (under "Extended 8051 Variants") "The memory classes HDATA and HCONST are used for constants or variables only. Program code is located into the expanded program memory with the same code banking mechanism as described above under "Classic 8051 with Code Banking"." This hints to me that you should be sure the interrupt routine in always located in the common area. In that case, the high byte of the address would be 0. This question: http://www.keil.com/support/docs/2226.htm is a bit out of data (v6.23), but it seems to imply that the generic pointer tag formats are different when the compiler is used in D390 continuous mode. In this case, you'd subtract 0x81 from the high byte of the pointer to get the address in code space. (It's the opposite of the FCVAR macro in absacc.h) This would seem to correspond to the HCONST type of a generic pointer. This also seems to match the description in the 390 code examples (C:\Keil\C51\EXAMPLES\Dallas 390\readme.txt). Does that chain of reasoning match what you see in your debugger? That is, a pointer to a function has a value equal to the actual address (in the PC or LCALL instruction), plus 0x81 in the high byte? If so, I'd just write a SetIntVector routine that takes a generic pointer, mungs the high byte appropriately, and puts the jump into the vector table. Maybe even in assembler :)
Thanks that seems to do the trick void _isrInstall (unsigned char vector, void *pointer) { long unkludgedPointer; unkludgedPointer= (((long)pointer) & 0x7fffff) - 0x010000; FVAR (char,vector) = 0x02; FVAR (char,vector+1) = (unkludgedPointer >> 16) & 0xff; FVAR (char,vector+2) = (unkludgedPointer >> 8) & 0xff; FVAR (char,vector+3) = unkludgedPointer & 0xff; return; }