Tiles and colours are written when a program loads; the map is written whenever anything moves. Sharing one 64K bank made them compete for room neither needed all of, and had a worse consequence than being cramped: a bitmap covers the whole bank, so entering bitmap mode destroyed the font. A program could not draw a picture and then say anything about it. Split, each gets a whole bank. The atlas holds the tiles and the palette, the screen holds the map or a bitmap, and a picture now costs the map and nothing else. It also leaves 48K free in the atlas, which is where the sprite table and a second page of tiles are going. No new mechanism was needed. A bank is registered by naming the port that owns it, so a device with two banks needs two ports that own memory: the base port keeps the atlas, since tiles have been at 0x0000 since there was a screen at all, and 0x3A owns the screen. The registry now answers honestly about which ports in the block bring memory, where it used to say all sixteen did. CosmOS never addresses video memory except in one place - the screen save, which walks 196 pages of it. The page number already says which bank a page is in, so screenBankFor works it out rather than keeping a second list beside screenPageFor. Grid and picture.asm register both banks; colours.asm only touches the palette and needed none of it. Tests/video.sh names the memory every write is for, because an address cannot: tile 5 and bitmap pixel 5 are both 0x0005, and a helper that guessed would be right for the tiles and silently wrong for a picture. And picture.asm gained a check, because this change broke it and nothing noticed - registering the second bank leaves DestBank pointing at it, so the palette went into the wrong one and the picture came out black. It was the only thing here found by looking rather than by a test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
145 lines
4.3 KiB
NASM
145 lines
4.3 KiB
NASM
; colours.asm
|
|
; Every colour the machine wakes up with, and how to change one.
|
|
; Written by Anachronaut
|
|
;
|
|
; ---- What a colour is on this machine ----
|
|
;
|
|
; The screen draws CELLS, and a cell is two bytes: which tile, and an attribute. A tile is
|
|
; eight by eight pixels and every pixel is a byte - a number, not a colour. What colour that
|
|
; number means is looked up in the PALETTE, which is 256 entries of four bytes: red, green,
|
|
; blue, and one spare. Four rather than three so that entry n begins at n times four, which
|
|
; is a shift; three would need a multiply and this machine has none.
|
|
;
|
|
; A cell's attribute nibble is ADDED to every number in its tile, sixteen at a time. So the
|
|
; same tile drawn with attribute 0 reads palette entries 0 and 1, with attribute 1 it reads
|
|
; 16 and 17, and so on. Sixteen banks of sixteen.
|
|
;
|
|
; The console's glyphs are drawn in numbers 0 and 1 - paper and ink - so for text those
|
|
; sixteen banks are sixteen INK AND PAPER PAIRS. Writing the attribute register at port 0x06
|
|
; says which one to use.
|
|
;
|
|
; The palette a machine wakes up with is laid out so one bit inverts a pair:
|
|
;
|
|
; banks 0 to 7 a colour on black
|
|
; banks 8 to 15 the same colour AS the background, with black text on it
|
|
;
|
|
; So attribute XOR 8 highlights, which is all a cursor is.
|
|
;
|
|
; ---- Reaching the palette ----
|
|
;
|
|
; Video memory belongs to the screen, not to the program, so the CPU cannot write it with a
|
|
; store. It is reached the way every device's memory is reached: registered as a bank, and
|
|
; written through the memory controller. That is what the last part of this program does.
|
|
|
|
#Program
|
|
|
|
start:
|
|
; The console wants sixteen columns for the name and a bit more, so the wide screen is
|
|
; not needed. This is the mode the machine wakes up in and is here to be seen.
|
|
RSTA
|
|
OUTA 0x31
|
|
|
|
; ---- Sixteen pairs, one line each ----
|
|
;
|
|
; Counting in memory rather than in a register, because the loop below uses A and B for
|
|
; the arithmetic and there is nowhere else to keep it.
|
|
SETD.0 Bank
|
|
STA.0 ; Still the zero from the mode write above: SETD does not touch A
|
|
|
|
nextBank:
|
|
LDA.0
|
|
OUTA 0x06 ; Draw in this pair from now on
|
|
SETD.1 SampleText
|
|
RCAL say
|
|
|
|
; The same bank with bit 3 set, which is the same colour inside out.
|
|
LDA.0
|
|
INIB 0x08
|
|
XOR
|
|
MVQA
|
|
OUTA 0x06
|
|
SETD.1 HighlightText
|
|
RCAL say
|
|
|
|
RSTA
|
|
OUTA 0x06 ; Back to plain for the newline
|
|
INIA 0x0A
|
|
OUTA 0x00
|
|
|
|
LDA.0
|
|
INCA
|
|
STA.0
|
|
INIB 0d8 ; Eight banks; the other eight are their reverses
|
|
CCF
|
|
SUB
|
|
BNQ nextBank
|
|
|
|
; ---- And one written by hand ----
|
|
;
|
|
; Bank 2 is green when the machine starts. This makes its ink orange instead, by writing
|
|
; three bytes into the palette - which means reaching video memory, which means the
|
|
; controller.
|
|
|
|
; Give the screen's memory a bank number. The screen brings TWO banks and this only wants
|
|
; one of them: port 0x30 owns the atlas, where the tiles and the palette are, and the
|
|
; palette is all this touches. Bank 3 is the first number software is allowed to hand out:
|
|
; 0, 1 and 2 belong to the machine.
|
|
INIA 0d3
|
|
OUTA 0xE3 ; DestBank: the number being given
|
|
INIA 0x30
|
|
OUTA 0xE2 ; SourceLow: the port that owns the memory
|
|
INIA 0x03
|
|
OUTA 0xE8 ; Command: RegisterBank
|
|
|
|
; The palette sits at the top of the atlas, at 0xFC00, and entry n is at n times
|
|
; four. Bank 2's ink is entry 2 * 16 + 1, which is 33, and 33 * 4 is 132 - so 0xFC84.
|
|
INIA 0xFC
|
|
OUTA 0xE4 ; DestHigh
|
|
INIA 0x84
|
|
OUTA 0xE5 ; DestLow
|
|
|
|
; Writing the controller's Data port puts a byte at the destination and steps it on, so
|
|
; three writes are red, green and blue in order.
|
|
INIA 0xF0
|
|
OUTA 0xE9 ; red
|
|
INIA 0x80
|
|
OUTA 0xE9 ; green
|
|
INIA 0x20
|
|
OUTA 0xE9 ; blue
|
|
|
|
INIA 0x02
|
|
OUTA 0x06 ; That pair again, now that it has been changed
|
|
SETD.1 ChangedText
|
|
RCAL say
|
|
RSTA
|
|
OUTA 0x06
|
|
HALT
|
|
|
|
; DP1 names a string. Printing is one byte at a time out of port 0x00, which is the oldest
|
|
; thing on this machine and has never changed.
|
|
say:
|
|
LDA.1
|
|
BRA sayDone
|
|
OUTA 0x00
|
|
INCD.1
|
|
BRI say
|
|
sayDone:
|
|
RRET
|
|
|
|
#Data
|
|
|
|
Bank:
|
|
0x00
|
|
|
|
SampleText:
|
|
" ordinary "
|
|
HighlightText:
|
|
" highlighted "
|
|
ChangedText:
|
|
"
|
|
bank 2's ink is orange now, because this program said so
|
|
"
|
|
|
|
#Vectors
|
|
Boot start
|