THE CURSOR DID NOT BLINK, and the reason is worth stating: it blinks on the machine's clock, and the machine's clock had stopped. A console waiting on a key stops the CPU, so no cycles passed, so the phase never moved - and the one moment somebody is looking at a cursor is the moment they are being asked to type. Waiting is now charged as IDLE CYCLES, which is what they were built for: a machine stopped on a device is not using memory, the same distinction WAIT makes, arrived at from the other direction. And the devices are told as it happens rather than when the instruction finally finishes, because a display controller does not stop blinking because the processor is waiting on a keyboard, any more than a disk stops turning. A keyboard file can now say NOTHING happened. A zero is a byte no keyboard sends, so it is free to mean "a moment went by with nobody typing" - which is the commonest thing behind a window and the only thing a file otherwise could not express. That unlocked the whole waiting path: three checks that the cursor is lit, then dark half a second later, then lit again, which is what blinking is. And Programs/Examples/colours.asm, because the palette had nowhere a newcomer could read it. It prints the sixteen pairs, prints each one again turned inside out, and then CHANGES ONE by writing three bytes into the palette - so the difference between using the colours a machine wakes up with and choosing your own is visible in one program. Its header explains what a cell is, what the attribute nibble does, why palette entries are four bytes rather than three, and why video memory has to be reached through the controller. The manual now says where the palette lives and points at it. SplitLint found a redundant RSTA in the example, which was worth acting on rather than suppressing: the zero was already in A from the mode write two lines up, and saying so in a comment teaches that SETD does not touch A, which is a thing worth knowing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
143 lines
4.2 KiB
NASM
143 lines
4.2 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 answers on port 0x30, and 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 starts at 0xC000, 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 0xC084.
|
|
INIA 0xC0
|
|
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
|