The completely general way to decode an address map is to use a bunch of comparators, one for each boundary in the address map. These comparators need to be the full width of the address bus. The "A" input is tied to the address bus and the "B" input is set to a constant representing the start of one of the memory regions. The output is high when A < B.
In your case, the first comparator would have the value 0x6050, and its output C1 will be high for all addresses prior to the start of RAM.
The second comparator would have the value 0x8050, and its output C2 will be high for all addresses prior to the start of ROM1. The chip select for the RAM is therefore !C1 && C2.
The third comparator would have the value 0xA050, and its output C3 will be high for all addresses prior to the start of ROM2. The chip select for ROM1 is therefore !C2 && C3.
And so forth and so on.
The reason we normally select "natural" boundaries for memory segments based on their size is that this general decoding scheme reduces to a very small number of gates, once you take into account all of the constant values and "don't cares".