Secondly, I've been doing some fiddling on BeebEm to try to make a new game and I've got some code here which creates a custom screen mode. It's based on MODE 1 but with a resolution of 256x160, taking only 10kb. I've managed to get the hardware text cursor scrolling playing nicely with it, too. I've seen various older posts talking about custom screen modes but I figured I'd include my code here in case it comes in handy for anyone else. I know that custom screen modes are essential for many of the larger games.
Firstly, run the following program which will create a new row multiplication table. The MOS uses these to speed up screen address calculations. The default in ROM is the 640 times table but with the resolution of this custom screen mode we need a 512 times table instead, otherwise the text cursor will be positioned incorrectly for every new line. Actually... I say 512... it really needs to be the 1024 times table. Why? Because the MOS factors its lookup index by the screen memory map type (stored at &0356), which is 2 in this case, denoting a size of 10kb. Fortunately, the MOS's flexibility is such that it stores in RAM a pointer to the row multiplication table to be used. The location of this pointer is &00E0-E1 (lo/hi bytes). So you just change that to point at the custom table. The table itself is stored at a convenient, seemingly-unused 64 bytes from &050-08F but you can put it anywhere you like if you're confident it won't be overwritten.
Code: Select all
10REM AM51220
20REM Arx
30REM To use as part of the Evolution build process
40REM Generate a *512*2 row multiplication table for the custom screen mode
50REM Then save as a data file for loading into &50-&8F spare region
60REM Memory Map Type 2 is for 10kb, however the MOS factors its row multiplication index by this value, so in fact we need a *1024 table to compensate
70:
80PRINT'"Generating x512x2 row lookup table..."
90r%=&50
100FOR I%=0 TO 31
110V%=I%*512*2
120r%?(I%*2)=V% DIV 256:REM HI byte
130r%?((I%*2)+1)=V% MOD 256:REM LO byte
140NEXT I%
150PRINT'"Done."
160PRINT'"Saving data file..."
170S$="SAVE DMUL512 0050 0090 0050"
180PRINT S$
190OSCLI S$
200PRINT'"Done."
210END
Code: Select all
10REM AMODE20
20REM Arx
30REM To use as part of the Evolution build process
40REM Assemble and save the routine that sets up the game's custom screen mode
50REM The routine will need only executing once as part of the game loading chain
60REM After which the space it occupies may be repurposed
70:
80REM The MODE 1 default 6845 register settings are held in &C46E - &C4A9
90REM If MODE 5 is needed instead, these are held in &C486 - &C491
100:
110exec%=&2F00
120PRINT';"Assembling XMODE routine..."
130:
140osbyte=&FFF4
150oswrch=&FFEE
160crtcr=&FE00:REM Write to this address the number of the CRTC register you want to update
170crtcv=&FE01:REM Then write to this address the new value of the register number specified just prior
180sviar=&FE40:REM Write to this address the value of the System VIA's Register B to update
190:
200DIM code% 255
210FOR opt%=4 TO 6 STEP 2
220P%=exec%
230O%=code%
240[
250OPT opt%
260:
270\Start with MODE 1
280LDA #&16
290JSR oswrch
300LDA #1
310JSR oswrch
320:
330\Set 6845 CRTC registers
340PHP
350SEI \Disable maskable interrupts while fiddling with the CRTC
360LDX #0 \From register R0
370.loop
380LDA crt,X \Load value
390STX crtcr \Tell the CRTC which register to write to
400STA crtcv \Tell the CRTC the value to be written to that register
410INX \Next register to update
420CPX #14 \If there is one
430BNE loop
440PLP \Restore interrupt flag
450:
460\Set MOS parameters as closely as the MOS itself does for an official mode
470LDA #3:STA &360 \Logical colours less 1
480LDA #16:STA &34F \Bytes per character
490LDA #3:STA &361 \Pixels per byte less 1
500LDA #17:STA &363 \Colour mask left
510LDA #136:STA &362 \Colour mask right
520LDA #2:STA &356 \Memory map type (2 -> 10kb)
530LDA #&28:STA &354 \Screen memory length (&5800 to &7FFF -> &28) (10kb)
540LDA #&58:STA &34E \High byte of screen memory start address (&5800)
550LDA #0:STA &352 \Bytes per row (LO)
560LDA #2:STA &353 \Bytes per row (HI) (00000010 00000000 -> 512)
570LDA #0:STA &34C \Text window width in bytes (LO)
580LDA #127:STA &34D \Text window width in bytes (HI)
590LDA #31:STA &30A \Text window right
600LDA #19:STA &309 \Text window bottom
610LDA #0:STA &304 \Y pixels (LO)
620LDA #1:STA &305 \Y pixels (HI) (00000001 00000000 -> 256)
630LDA #160:STA &306 \X pixels (LO)
640LDA #0:STA &307 \X pixels (HI) (00000000 10100000 -> 160)
650LDA #&0:STA &350 \Window area start address (LO)
660LDA #&58:STA &351 \Window area start address (HI)
670LDA #&58:STA &007 \HIMEM = &5800
680:
690\Configure System VIA for 10kb hardware scrolling
700LDA #12:STA sviar \Set System VIA Register B value C0=1
710LDA #13:STA sviar \Set System VIA Register B value C1=1
720:
730\Point MOS to the *512 row multiplication table
740\Must ensure this data file is loaded in to that location
750LDA #&50:STA &E0 \Row multiplication table pointer (LO)
760LDA #&0:STA &E1 \Row multiplication table pointer (HI)
770:
780RTS
790:
800.crt
810EQUB 127 \R0 Horiz. Total Reg.
820EQUB 64 \R1 Horiz. Displayed Reg. (80)
830EQUB 90 \R2 Horiz. Sync. Pos. Reg. (98)
840EQUB 40 \R3 Sync. Width Reg.
850EQUB 38 \R4 Vert. Tot. Reg.
860EQUB 0 \R5 Vert. Tot. Adj. Reg.
870EQUB 20 \R6 Vert. Disp. Reg. (32)
880EQUB 29 \R7 Vert. Sync. Pos. Reg. (34)
890EQUB 1 \R8 Interlace+Delay Reg.
900EQUB 7 \R9 Scan Lines per Char. Row
910EQUB 103 \R10 Cursor Start Reg.
920EQUB 8 \R11 Cursor End Reg.
930EQUB &B \R12 Start Address (HI)
940EQUB 0 \R13 Start Address (LO)
950:
960]
970NEXT
980:
990PRINT"Done."''"Assembled Base Address = ";~code%'"Assembled End Address = ";~(O%-1)'"Execution Base Address = ";~exec%'"Execution End Address = ";~(P%-1)
1000PRINT';"Saving executable..."
1010S$="SAVE XMODE "+STR$~code%+" "+STR$~O%+" "+STR$~exec%+" "+STR$~exec%
1020PRINT S$
1030OSCLI S$
1040PRINT"Done."
1050:
1060END
Code: Select all
10MODE7
20*LOAD DMUL512
30*RUN XMODE
40PRINTTAB(0,0);"HELLO WORLD"
50END
The MOS graphics routines don't work properly yet in this custom screen mode... I suspect at least in part due to lingering screen address calculation issues. I'll see if I can do anything about that, though I imagine most machine code games use their own routines.
P.S. Forgot to mention, I discovered courtesy of this forum that the Advanced User Guide gives incorrect values for C0 and C1 in the System VIA Register B for the different screen size types. I spent a good couple of hours trying to figure out where I was going wrong, until I went trawling online and found the answer here - thanks.