V4. Mode 2 is 320 by 200 with a byte a pixel: no tile to look up and no attribute to add, the byte IS the palette index. Programs/Examples/picture.asm fills a whole one in 127 bytes of program and 47,498 cycles. IT IS THE SAME MEMORY AS THE TILES AND THE MAP, which is what shared video memory has always been, and there is nowhere else it could be - 64,000 bytes of picture in a 65,536 byte bank leaves room for nothing beside it. Going to bitmap mode does not clear the text screen, it stops calling it one, and coming back finds the tiles holding whatever the picture put there. Taking the screen means taking it. The palette moves to 0xFC00, the top of video memory, because it is the one thing that has to mean the same in every mode and 64,000 bytes of picture leaves nowhere in the middle for it to hide. That is a documented address, so the example, the tests and the manual move with it. A BITMAP HAS NO COLUMNS AND NO ROWS, and both registers read zero rather than a leftover from the last mode. The console asks: told there is no character screen, it has nowhere to put a glyph and draws nothing, while still saying everything down the serial line. The honest alternative is what a machine with shared video memory really does, which is scribble marks nobody can read across somebody's picture - honest and useless, since a program that has taken the screen has not stopped wanting to print. Six checks in Tests/video.sh, to 55: that the mode is 320 by 200, that a byte is one pixel's colour and only that pixel, that printing leaves a picture alone while the letter still goes out, and that the columns register says nought and then forty again. The example is worth reading for one thing beyond the mode: Fill leaves its destination past what it touched, so two hundred rows are drawn from one address set once. Working out where row n begins would be n times 320, and this machine has no multiply. 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 sits at the top of video memory, 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
|