Well, turns out a few people do read this blog after all! Cearn left a comment on my last post correcting my incorrect understanding of bit-shifts, which if you are interested, you can read for full detail, but the gist is that bit shifting WILL preserve the sign bit if it's declared as a signed integer and not an unsigned integer. So I stand corrected. Thanks Cearn!
Which means, looking back through my code, that the problem resulted less from my willy-nilly bit-shifting, and more from using an unsigned integer in one particular function. (which at the time was reasonable, because my engine never used negative screen positions until now).
I managed to scrape together 30 or 40 minutes this weekend to finish changing all of my screen setup and scrolling functions to be happy with signed numbers, and finished added some special cases to deal with rooms that are smaller than the screen size. And now all the backgrounds seem to be drawing and scrolling correctly! The first major task of porting is complete!
There's still plenty of issues to work though, even with backgrounds -- the priority of the foreground tiles isn't right...sprites still appear in front of them. And the overworld tiles aren't loading completely -- I'm probably just not copying enough tile data in that case. But I'm getting there!