Oh, absolutely.
First, they're more granular. Segment represents 16 byte blocks, most banking systems had 4K blocks.
Second, the segments can overlap. The most basic example is the Tiny model where CS and DS are identical. 64K of shared code and data. Separate them, and you can have 64K of code and 64K of data with almost no code changes. (The Small memory model).
Third, you can move memory between segments. With banks, the typical setup if you wanted to move data from Bank A to Bank B, you had to move it out of Bank A, enable Bank B, and then move it back in. Obviously with more sophisticated banking architecture, you can do whatever you want. Eventually you creep into more of a MMU logic than simple banking.
Finally, somewhat related to the previous, you have the ES, Extra Segment. While more limited than the CS/DS in terms of capability, it was enough to let you shove things around without having to clobber your CS/DS if you didn't want to. Saved a bit of juggling there.
Regarding the part about code spanning, yeah, that's an issue in terms of continuity. You simply couldn't have code that was larger than 64K, the PC will wrap on the CS.
But, you had direct support for "far pointers". You could "Jump" to SSSS:XXXX, storing the entirety of the pointer, and do a far jump directly. The jump resets the CS for you. You can't do that with a banked system. You're responsible for banking things in at the right time. So, if you commit to far pointers for all of your function calls, the code just links and it "just works" without you having to do anything manually.
More expensive of course, so folks would make internal little worlds of code and data and contextually bounce between them. But you have the option of not having to do that if you didn't want to.
First, they're more granular. Segment represents 16 byte blocks, most banking systems had 4K blocks.
Second, the segments can overlap. The most basic example is the Tiny model where CS and DS are identical. 64K of shared code and data. Separate them, and you can have 64K of code and 64K of data with almost no code changes. (The Small memory model).
Third, you can move memory between segments. With banks, the typical setup if you wanted to move data from Bank A to Bank B, you had to move it out of Bank A, enable Bank B, and then move it back in. Obviously with more sophisticated banking architecture, you can do whatever you want. Eventually you creep into more of a MMU logic than simple banking.
Finally, somewhat related to the previous, you have the ES, Extra Segment. While more limited than the CS/DS in terms of capability, it was enough to let you shove things around without having to clobber your CS/DS if you didn't want to. Saved a bit of juggling there.
Regarding the part about code spanning, yeah, that's an issue in terms of continuity. You simply couldn't have code that was larger than 64K, the PC will wrap on the CS.
But, you had direct support for "far pointers". You could "Jump" to SSSS:XXXX, storing the entirety of the pointer, and do a far jump directly. The jump resets the CS for you. You can't do that with a banked system. You're responsible for banking things in at the right time. So, if you commit to far pointers for all of your function calls, the code just links and it "just works" without you having to do anything manually.
More expensive of course, so folks would make internal little worlds of code and data and contextually bounce between them. But you have the option of not having to do that if you didn't want to.