The literal 0x8000 is of type unsigned int. On your 16-bit machine, the int and therefore unsigned int is of the natural size of 16 bits, the smallest accepted by the C standard. The integer promotion rules say that the smaller width types are widened to int or unsigned int, but no further (C11 n1570 6.3.1.1p2):
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. 58) All other types are unchanged by the integer promotions. 
An operand is widened from int or unsigned int only if the other operand has a greater rank.
Here, 0x8000 + 0x8000 is calculated using unsigned int which will wrap to 0, because the maximum value that can be represented in unsigned int is 0xFFFF.
You should force at least one of the operands to unsigned long using either the suffix UL, or by adding an explicit cast:
int main() {
    unsigned long int x=0;
    /* unsigned long int * int */
    x = 0x8000UL * 0x2;
    /* unsigned long + unsigned int */
    x = (unsigned long)0x8000 + 0x8000;
    return 0;
}
See also In a C expression where unsigned int and signed int are present, which type will be promoted to what type? for general discussion.