A second screen, and one port to say which is shown
A screen drawn where it can be seen is seen half drawn. A program that moves forty things and rewrites the map underneath them is wrong for as long as it takes to put them all right, and at a megahertz that is long enough to look at. So the device brings a second screen bank, on port 0x3B, and port 0x3C says which of the two is displayed. Everything a program draws into the other one is invisible until one byte shows the whole of it at once. ONE REGISTER IS ENOUGH, where the hardware this imitates needed two. The other said which screen the CPU's window pointed at; there is no window here, because a program reaches a bank through the memory controller by its number. Writing to the screen that is not shown is a matter of naming its bank, and the device never has to be told. And a flip cannot tear: a frame is drawn from one bank in one go, so a flip either happened before that frame or happens before the next. There is nothing to race, where the real machines had to catch the few lines between frames to swap in. The console draws into whichever screen is displayed rather than one of its own, so a fault message lands where somebody can read it even if a game had flipped. And CosmOS puts the displayed screen back at exit, the way it already puts back the cursor and the ink: a program that faulted while flipped could not have, and a shell that only came out right for programs which remembered would come out wrong the day one crashed. Flip.asm is the worked example. It deliberately does NOT restore the display itself - that is the point of the paragraph above, and it is what makes the system's guarantee the thing under test rather than the program's good manners. Written the other way round first, where it passed with the guarantee deleted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
66e7b84272
commit
023362b05a
@@ -1304,7 +1304,7 @@ uint8_t *deviceMemory(uint8_t port, uint32_t *capacity) {
|
||||
*capacity = DISK_BLOCK_BYTES;
|
||||
return diskBuffer;
|
||||
}
|
||||
if (port == PORT_VIDEO || port == VIDEO_SCREEN) {
|
||||
if (port == PORT_VIDEO || port == VIDEO_SCREEN0 || port == VIDEO_SCREEN1) {
|
||||
// Two banks: the atlas of tiles and colours on the base port, and the map or the
|
||||
// bitmap on its own. A program blits the part that changed and the rest stays as it
|
||||
// was, which is the whole reason the screen is memory rather than a window onto a
|
||||
@@ -1378,10 +1378,14 @@ static const DeviceRecord *deviceOnPort(uint8_t port) {
|
||||
//
|
||||
// So the block answers honestly. The screen port says it brings memory because it
|
||||
// does, and the rest of the block says it does not.
|
||||
static const DeviceRecord videoScreenRecord =
|
||||
{ VIDEO_SCREEN, DEVICE_VIDEO, DEVICE_FLAG_HAS_MEMORY };
|
||||
static const DeviceRecord videoScreen0Record =
|
||||
{ VIDEO_SCREEN0, DEVICE_VIDEO, DEVICE_FLAG_HAS_MEMORY };
|
||||
static const DeviceRecord videoScreen1Record =
|
||||
{ VIDEO_SCREEN1, DEVICE_VIDEO, DEVICE_FLAG_HAS_MEMORY };
|
||||
static const DeviceRecord videoPlainRecord = { PORT_VIDEO, DEVICE_VIDEO, 0 };
|
||||
return (port == VIDEO_SCREEN) ? &videoScreenRecord : &videoPlainRecord;
|
||||
if (port == VIDEO_SCREEN0) { return &videoScreen0Record; }
|
||||
if (port == VIDEO_SCREEN1) { return &videoScreen1Record; }
|
||||
return &videoPlainRecord;
|
||||
}
|
||||
if (port > PORT_SOUND && port <= PORT_SOUND_TOP) {
|
||||
return deviceOnPort(PORT_SOUND);
|
||||
|
||||
Reference in New Issue
Block a user