News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Prototron

Advice on split screen code

Started by Prototron, 11:43, 21 August 24

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Prototron

I'm attempting to create a split screen effect so that I can house a HUD panel at the top of the view for scores and lives etc. (just a 320*16 strip). I'd like it with a different screen mode and at a different memory location to the main area. Having it on the same range as the main view port creates flicker issues when I double buffer, and I want to use different colours etc.

I made a little test program and downloaded some example code, but I must admit I'm really struggling to mentally grasp what's happening. The examples are either far too complicated for what I want to do, or the code has errors/compatibility issues which don't work in WinAPE.

Regardless, I patched together bits and bobs from the various examples, and I managed to change the background colour and screen mode at the point on the screen that I want (see link to image below).

https://drive.google.com/file/d/1Tgv6F8EOh17Bxn7hwi6weIWN52qvyzPJ/view?usp=drive_link

However, I can't get the displayed memory range to change, and that's really the important part.

The code below shows what I'm doing. There are some elements commented out with a ; because they were giving odd results, but I know they are somehow important to achieving what I want, so I left them in.

 I'd be very grateful if some kind people could show me what I need to change in the code to get what I want.

Thank you.

(Target system is just a stock 6128)

;-------------------------------
nolist
org &1000
;-------------------------------


;-------------------------------
di                      ; Disable interrupts
im 1                 ; Set interrupt mode (jump to interrupt handler at &0038)
ld hl,&C9FB             ; Poke EI,RET to interrupt handler.
ld (&0038),hl
ei                      ; Enable interrupts
;-------------------------------


;=================================================================================================================


LOOP:
;-------------------------------
; SYNC
;-------------------------------
ld b,&F5 ; Synchronise with the VSYNC
Vsync
in a,(c)
rra
jr nc,Vsync
;-------------------------------
ld b,16 ; Wait for VSYNC to finish
VsyncDelay
ds 60
djnz VsyncDelay
;-------------------------------


;-------------------------------
; MAKE CHANGES
;-------------------------------
; ld bc,&BC04 ; Vertical Total (VTOT)
; out (c),c
; ld bc,&BD00+2-1 ; Height of block -1
; out (c),c
;-------------------------------
ld bc,&7F8C+0 ; Change screen Mode to 0
out (c),c
;-------------------------------
ld bc,&BC0C
out (c),c
inc b
ld a,&30 ; Show range &C000
out (c),a
;-------------------------------
ld hl,PALETTE_MAIN
ld a,PAL_BRIGHTBLUE ; Background colour to Blue
ld (hl),a
call SET_PALETTE
;-------------------------------
; ld bc,&BC07 ; Vertical Sync position (VSYNC)
; out (c),c
; ld bc,&BDFF ; Disable VSYNC (Set to 255)
; out (c),c

;-------------------------------
; SPLIT 2
;-------------------------------

halt ; Wait x number of interrupts so we are close to the position we want.
; At this point we are synchronised to the monitor draw cycle.
;-------------------------------
; WAIT
;-------------------------------

ld b,255 ; Wait until desired point on screen after interrupt
WAIT1
djnz WAIT1

ld b,255
WAIT2
djnz WAIT2

ld b,15
WAIT3
djnz WAIT3 ; We are now at the exact point we want to make changes

;-------------------------------
; MAKE CHANGES
;-------------------------------
; ld bc,&BC04 ; Vertical Total (VTOT)
; out (c),c
; ld bc,&BD00+37-1 ; Height of block -1
; out (c),c
;-------------------------------
ld bc,&7F8C+1 ; Change screen Mode to 1
out (c),c
;-------------------------------
ld bc,&BC0C
out (c),c
inc b
ld a,&10 ; Show range &4000
out (c),a
;-------------------------------
ld hl,PALETTE_MAIN
ld a,PAL_BRIGHTRED ; Background colour to red
ld (hl),a
call SET_PALETTE
;-------------------------------
halt
halt
;-------------------------------
; ld bc,&BC07 ; Vertical Sync position (VSYNC)
; out (c),c
; ld bc,&BD00 ; Enable VSYNC (Set to 0)
; out (c),c
;-------------------------------

jp LOOP


;=================================================================================================================

;-------------------------------
; SET PALETTE
;-------------------------------
SET_PALETTE:
ld hl,PALETTE_MAIN
ld b,16 ; 16 pens for Mode 0
xor a ; Starting palette index number (0)
;-------------------------------
SET_COLOURS:
push bc
push af
;-------------------------------
push hl
ld bc,&7F00                ; Gate Array port
out (c),a                   ; Send pen number
ld a,(hl) ; Pen colour
or %01000000 ; or in Gate Array function
out (c),a                   ; Send
;-------------------------------
pop hl
pop af
pop bc
;-------------------------------
inc hl
inc a
;-------------------------------
djnz SET_COLOURS ; Loop
;-------------------------------
RET


PAL_BLACK EQU &54 ;00
PAL_BLUE EQU &44 ;01
PAL_BRIGHTBLUE EQU &55 ;02
PAL_DARKRED EQU &5C ;03
PAL_MAGENTA EQU &58 ;04
PAL_MAUVE EQU &5D ;05
PAL_BRIGHTRED EQU &4C ;06
PAL_PURPLE EQU &45 ;07
PAL_BRIGHTMAGENTA EQU &4D ;08
PAL_GREEN EQU &56 ;09
PAL_CYAN EQU &46 ;10
PAL_SKYBLUE EQU &57 ;11
PAL_YELLOW EQU &5E ;12
PAL_WHITE EQU &40 ;13
PAL_PASTELBLUE EQU &5F ;14
PAL_ORANGE EQU &4E ;15
PAL_PINK EQU &47 ;16
PAL_PASTELMAGENTA EQU &4F ;17
PAL_BRIGHTGREEN EQU &52 ;18
PAL_SEAGREEN EQU &42 ;19
PAL_BRIGHTCYAN EQU &53 ;20
PAL_LIME EQU &5A ;21
PAL_PASTELGREEN EQU &59 ;22
PAL_PASTELCYAN EQU &5B ;23
PAL_BRIGHTYELLOW EQU &4A ;24
PAL_PASTELYELLOW EQU &43 ;25
PAL_BRIGHTWHITE EQU &4B ;26

;------------------------------
PALETTE_MAIN:
db PAL_BRIGHTBLUE
db PAL_BLACK
db PAL_BLUE
db PAL_BRIGHTBLUE
db PAL_PASTELCYAN
db PAL_GREEN
db PAL_YELLOW
db PAL_BRIGHTGREEN
db PAL_DARKRED
db PAL_MAUVE
db PAL_BRIGHTRED
db PAL_ORANGE
db PAL_PINK
db PAL_BRIGHTYELLOW
db PAL_WHITE
db PAL_BRIGHTWHITE
;------------------------------
"For the money, for the glory, and for the fun!

Mostly for the money."

Prodatron

#1
Did you take into account, that
- changes to the screen address have to be done anywhere in the previous split
- changes to the height of the split have to be done inside the current split (after it has started, in the area of the size of the previous split)
- changes to screen mode and colours are happening immediately


Just found some old notes about CRTC registers and screen splitting:

;reg 0 (63) = x-screenwidth (usually always 63)
;reg 1 (50) = x-splitwidth (e.g.50)
;reg 2 (51) = x-splitstart (e.g. 51)
;reg 3 (08) = x-finestart (maybe use this for half-char scrolling)
;reg 4 (##) = y-splitheight-1 (set this inside the current split)
;reg 5 (00) = y-finestart
;reg 6 (25) = y-max visible splitpart (same like 4)
;reg 7 (##) = inside last split -> set to 0; inside first split, but after vblank -> set to 255
;reg 9 (07) = y-lines/char-1
set this inside the previous split:
;reg12 (##) = address high (char / 256 + block * 16)
;reg13 (##) = address low  (char mod 256)

Total height of all splits must be 39.

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

McArti0

#2
R12 and R13 are used and reload inside at one point in time. First screen line,after last hi border.

Kind people.  ;D

Ps. You must make 2 frame small f.ex. 5 chars R4 and big 38-5
CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
One chip drver for 512kB extRAM 6128
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

Nich

Going a bit off-topic, I got rather confused by the very similar usernames in the first two posts and thought @Prodatron was asking for some programming help - WTF?! Then I looked at the usernames more closely... :picard:

McArti0

I had exactly the same impression. I think to myself, well, everyone forgets something sometimes.  ::)

And then I started looking for the letter 'd'... :-X
CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
One chip drver for 512kB extRAM 6128
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

Prodatron

Quote from: Nich on 19:29, 21 August 24Going a bit off-topic, I got rather confused by the very similar usernames in the first two posts and thought @Prodatron was asking for some programming help - WTF?! Then I looked at the usernames more closely... :picard:
:D  like to welcome new people on the CPC and help them no matter which Nickname.

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

Prototron

Thanks for the info folks.

Just to say, I've been using this example as a base for what I'm trying to do, but I don't think it's working correctly. The JP at the end doesn't point to anything, and when I set it to go back to the start of the main loop all I get are some staggered horizontal lines on the screen. No indication that a split is happening, so I'm still quite confused? Tried on multiple settings in WinApe.

There's really not a lot of examples of this technique out there (that I could find), so is that example faulty? Or am I just running it wrong?

Thanks!
"For the money, for the glory, and for the fun!

Mostly for the money."

Prodatron

#7
Quote from: Prototron on 10:10, 22 August 24The JP at the end doesn't point to anything, and when I set it to go back to the start of the main loop all I get are some staggered horizontal lines on the screen.
Indeed, there is something missing at the end, it should be JP main_loop, that is the only issue.
It seems to work in WinApe (no matter which settings). Yes, the random pixel lines look like a bug, but it just shows the code starting at #4000.
In line 374 you can change HL from #1000 (which means vram start at #4000) to #3000 (which means vram start at #C000), when you now assemble and run it, you will see parts of the last screen.
Starting from line 420 it sets the address for the last split to #0000 (=vram #0000; here you see the first #100 bytes of the OS, including the RSTs etc.), and starting from line 440 it sets it again to #1000 (=#4000).
Try setting these as well to #3000 (=#C000) and you will see the current screen in all splits:

You cannot view this attachment.

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

Prototron

Ahh that's much clearer!

Cool, I'm getting somewhere with it now that I can see what's happening.

Thanks for pointing that out. It helped a lot.
"For the money, for the glory, and for the fun!

Mostly for the money."

McArti0

CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
One chip drver for 512kB extRAM 6128
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

Prototron

Quote from: McArti0 on 15:53, 22 August 24https://www.cpcwiki.eu/forum/programming/basic-programming-tips/msg221062/#msg221062

Split in basic use to overscan
Very cool. Thanks for the example!

So I have something sort of working now. Managing to get three strips with different memory locations, palettes, and screen modes.

I take it that since Vsync is essentially disabled, the top and bottom borders have to be simulated? I'm using the first block at both the top and the bottom to sort of make fake borders, and the other two are the visible "screens".

Is that right? Or am I on the wrong track?
"For the money, for the glory, and for the fun!

Mostly for the money."

McArti0

#11
The bottom border and then the top border belong to the lowest strip. The image starts and ends at the bottom of the top border. V-sync is also belong to the lowest strip.
CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
One chip drver for 512kB extRAM 6128
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

Prototron

Quote from: McArti0 on 08:48, 23 August 24The bottom border and then the top border belong to the lowest strip. The image starts and ends at the bottom of the top border. V-sync is also belong to the lowest strip.
So it wraps around?
"For the money, for the glory, and for the fun!

Mostly for the money."

McArti0

CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
One chip drver for 512kB extRAM 6128
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

lightforce6128




Move the blue image to the left. The same thing that applies to upper and lower border also applies to the left and right border. From the view of the CRTC the image comes first, then the border, split into two parts by HSYNC or VSYNC.

On the other hand, for a vertical split it does not matter.

lightforce6128

For working on this topic, I once got the valuable tip to use a spreadsheet for planning. Use one line per pixel row, 312 in all, numbered from 0 to 311. Then assign the character row to each by integer-dividing by eight, 39 in all, numbered from 0 to 38. Finally use a modulo operation to get the pixel row per character, continuously numbered from 0 to 7, then starting over. The image starts at the top at character 0. The border is at the bottom, divided into two parts (maybe of different size) by the sync signal. If you want to work with interrupts, then you can place interrrupt-0 two pixel rows after the sync signal starts. Every 52nd pixel row the next interrupt occurs up to interrupt-5.

The CRTC does not do any magic, it just counts and compares for equality (what does not mean that things are simple). If you set a value to late, it will not compare for greater than, but still only for equality and miss the change until the next image is built up. It will also do this comparison at special points in time. Also the transfer from a CRTC register to the corresponding counter register will only be done at special points in time. So, in the spreadsheet described above, think about where you want some value to be active, and in which range you can set this value. A common example for this: You have to set the screen memory address before image drawing starts (although this is not true for all CRTC versions).

Another trap I got into: If you want to use interrupts to set the registers at the right time points, and you think: I do not have to synchronize this, it will synchronize on its own after a few images, then this might be wrong. I had one example where the created images and the interrupts to set values steps through a few periodic states, but none of them was what I was expecting. It never synchronizes on its own.

Another thing with interrupts is that they cannot interrupt a command in between. For commands that take more than 4 cycles the interrupt will be delayed accordingly. For some CRTC tricks this might not be of importance, but for others it is.

Talking about this topic is not complete without a reference to the great Amstrad CPC CRTC Compendium (https://shaker.logonsystem.eu/ACCC1.8-EN.pdf). Information there goes into deep detail and maybe is too much for a simple screen split.

Ast

_____________________

Ast/iMP4CT. "By the power of Grayskull, i've the power"

http://amstradplus.forumforever.com/index.php
http://impdos.wikidot.com/
http://impdraw.wikidot.com/

All friends are welcome !

Prodatron

Quote from: Ast on 18:30, 26 August 24@Prodatron : you can try what i do here ->  *****Programmez vos ruptures facilement (forumforever.com)

or ->  *****Programmez vos Ruptures encore plus facilement (forumforever.com)

I hope it could help U ! See you, probably on BND Meeting 4 !
Hi @Ast , thanks, but please note, that Prototron, the one with the questions, is someone else :D
Yeah, looking forward! :)

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

Ast

#18
OMG ! Sorry @Prototron !

Hi @Prodatron !!!
_____________________

Ast/iMP4CT. "By the power of Grayskull, i've the power"

http://amstradplus.forumforever.com/index.php
http://impdos.wikidot.com/
http://impdraw.wikidot.com/

All friends are welcome !

Prototron

Quote from: Ast on 18:30, 26 August 24@Prodatron : you can try what i do here ->  *****Programmez vos ruptures facilement (forumforever.com)

or ->  *****Programmez vos Ruptures encore plus facilement (forumforever.com)

I hope it could help U ! See you, probably on BND Meeting 4 !
This was great! The diagram really helped me visualise what was happening.

I have it working now, though I had to hide the first rupture by setting vertical displayed to zero for that block, but the viewport now has two independent screens pointing at different memory locations (the light blue strip shows &8000)

https://drive.google.com/file/d/1Gc1J0V7MhRYa9gZs3JCkyRT_8Q1rjO1Y/view?usp=sharing

I'm wondering if I even need three ruptures, because I only require two sections to the screen?

Anyway, thanks for the help! I'll probably be back with more questions as I try different things with this.

"For the money, for the glory, and for the fun!

Mostly for the money."

Ast

Excellent news !

I am happy to read you fixed it !
_____________________

Ast/iMP4CT. "By the power of Grayskull, i've the power"

http://amstradplus.forumforever.com/index.php
http://impdos.wikidot.com/
http://impdraw.wikidot.com/

All friends are welcome !

Powered by SMFPacks Menu Editor Mod