News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Devilmarkus

How to set screen ram?

Started by Devilmarkus, 13:40, 24 November 12

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Devilmarkus

Hi folks,
I want to do a little experiment for what I need to load 3 screens into RAM.

1) &2000, 2) &6000 and 3) &C000

How can I toggle the screen ram now between these screens that every frame appears a different image?

It needs to be as fast as possible... 3 frames = 3 images.
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

IanS

From the firmware guide:-

QuoteIt is possible to change the location of the screen memory to any of the 4 16K
memory blocks on 16K boundaries (see SCR SET BASE). However, only #C000
and #4000 are useful; #0000 and #8000 both overlap firmware jumpblocks or other
system areas. The descriptions below all assume the default screen location at
#C000.
http://www.cpcwiki.eu/imgs/d/db/S968se06.pdf


Devilmarkus

So it seems its impossible? Damn!!! :(
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

tastefulmrship


IanS

QuoteOn the CPC6128 the base address sets which block will be used for the screen
memory. Base addresses of #0000, #4000, #8000 and #C000 correspond to blocks
0, 1, 2, and 3. It is not possible for the screen memory to be located in blocks 4 ... 7.
Where the block being used for screen memory actually appears in the memory
map depends on the bank switching (see section 2.5)

Devilmarkus

Is there a copy-method which is fast enough to copy a screen from &2000 for example to &C000? (Need to be very fast! LDI or LDIR is way to slow)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

Reason:
I saw a few demos on Thomson TO-8 which use a "flipscreen" technic with 3 screens:
[attach=2][attach=3][attach=4]

They change every frame.
So I want to do similar on a CPC.
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

This copy method is way too slow:
SCRPaste:
        XOR        A,A
        LD        HL,&4000
        LD        DE,&C000

LOOP
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI

        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI
        LDI

        DEC        A
        JP        NZ,LOOP
        RET

When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

Test video:
Flipscreen test with 3 screens

First example uses the ASM routine I posted before.
2nd uses a trick (Just reads the files and shows them, thats fast enough thanks to internal filesystem)

2nd shows properly (framerate in the video maybe is too bad to show it accurate)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Marq

Dunno much about CPC coding, but: if you're going to take over the system anyway then is there any need to preserve the system area?

Overflow

Hi!
Obviously LDI are too slow to copy a full 16Kb screen in 1 frame.
Here's an idea: switch basic+os in the upper 64Kb ("7FC2" mode), and let's have the full lower 64Kb as videoram only.
Remember backtro 2nd part? it uses such 3 screen flipping, to smooth the colorcycling.

---

Attached is a full example.

It first sets the screen at &4000, in order to let the code at &C000 on &7FC1 &7FC2 or &7FC3 mode.

Then it switch basic+os in the upper 64Kb: nothing at screen since os pokes in non-vram (= upper 64Kb), but basic is still available.

4 screens are loaded (from basic) then copied (from asm) to adresses 0000 4000 8000 C000 within lower 64Kb vram.

Last, still in basic: loop with the 4 screens.

Hope it helps!
Unregistered from CPCwiki forum.

arnoldemu

Quote from: Devilmarkus on 13:40, 24 November 12
Hi folks,
I want to do a little experiment for what I need to load 3 screens into RAM.

1) &2000, 2) &6000 and 3) &C000

How can I toggle the screen ram now between these screens that every frame appears a different image?

It needs to be as fast as possible... 3 frames = 3 images.
those locations are not good.
ok for loading to, and then relocating to their final positions.

if you turn off firmware, you can move them to any suitable position, have an interrupt active, and switch them.


org &a100

;; one screen to &0000
ld hl,&1000
ld de,&0000
ld bc,&4000
ldir
;; one screen to &4000
ld hl,&5000
ld de,&4000
ld bc,&4000
ldir
;; other screen remains at &c000

;; space at &8000-&c000 effectively.
;; with firmware present we'll try and go below &a700 so it can work fine on 64k machines

di
im 2
ld hl,&a000
ld e,l
ld d,h
ld (hl),&a1
ld bc,&100
ldir
ld i,&a0
ld a,&c3
ld (&a1a1),a
ld hl,int
ld (&a1a2),hl
ei

loop:
ld b,&f5
l1:
in a,(c)
rra
jr nc,l1
halt
halt
halt
jp loop

int:
push hl
push af
push bc
ld a,(scr)
inc a
cp 3
jr nz,int2
xor a
ld (scr),a

int2:
ld bc,&bc0c
out (c),c
add  a,base_addr and 255
ld l,a
ld a,base_addr/256
adc a,0
ld h,a
ld a,(hl)
inc b
out (c),a

pop bc
pop af
pop hl
ei
ret

.scr
defb 0

.base_addr
defb &00
defb &10
defb &30



done.

3 screens, hardware switch, 1 per 50hz, fits in 64k. load the other screens a bit lower (&1000 and &5000) to fit them below &a700.
our code sits between &a000 and &c000).

Who needs 128K????

I've got some code somewhere that will switch 2 overscan screens (flipscreens) AND it loads and runs in 64k.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Devilmarkus

Thankyou all for your code examples!
I will take a closer look, ASAP :)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

db6128

I'd like to see that code if you can ever find it! What you just posted is very interesting.

Not to highjack Devilmarkus's interesting subject, but I'm coding (read: trying and probably failing horribly to code, still haven't produced anything testable) something at the moment for which I really need double-buffering, and I could use all optimisations possible.

I should have relatively little happening on the screen, but it seems that keeping the two synced leaves me no choice but to (1) plot everything to the shadow screen at &4000, (2) leave the displayed screen at &C000 completely alone until the end of rendering, (3) switch the CRTC to &4000 to show the new frame, (4) LDIR all of that to &C000, and then (5) switch the CRTC back to &C000 (to be displayed again while everything is plotted to &4000 again, and so on).

Or am I just being really dense in how I'm visualising this process?  Again, any advice anyone has is much appreciated, and probably a lot cleverer than my current thoughts. :D Obviously, it's calculating the frames itself that'll be the main bottleneck; I imagine everything there will be really slow regardless, even with attempted optimisations such as using all of the shadow registers, etc.
Quote from: Devilmarkus on 13:04, 27 February 12
Quote from: ukmarkh on 11:38, 27 February 12[The owner of one of the few existing cartridges of Chase HQ 2] mentioned to me that unless someone could find a way to guarantee the code wouldn't be duplicated to anyone else, he wouldn't be interested.
Did he also say things like "My treasureeeeee" and is he a little grey guy?

Bryce

Can you not render to &C000 while &4000 is being displayed, instead of all that LDIRing between frames?

Bryce.

db6128

Thanks; I thought about that, but I can't get it to work... only in my head, admittedly, which isn't always the most logical place  :-X

But here was my reasoning: At the beginning, let's say the CRTC is displaying the normal screen at &C000, and that's empty. I render some stuff on the shadow screen at &4000. Once done, I switch the CRTC to show the just-completed frame at &4000. Nice! Instant refresh, no drawing, flicker, or whatever.

But now if I want to render the next frame – by adding more stuff onto the last one – the screen &C000 is still blank. This isn't a context in which I can start from a blank frame every time and just plot a few sprites; perhaps some people do that, as it's presumably faster if the screen is sparsely populated. So, it seems I'd have to copy over all of the last frame before I can begin to plot the next one... again, unless I'm missing something stupidly obvious. :)
Quote from: Devilmarkus on 13:04, 27 February 12
Quote from: ukmarkh on 11:38, 27 February 12[The owner of one of the few existing cartridges of Chase HQ 2] mentioned to me that unless someone could find a way to guarantee the code wouldn't be duplicated to anyone else, he wouldn't be interested.
Did he also say things like "My treasureeeeee" and is he a little grey guy?

arnoldemu

#16
Double buffering... LONG post:

I'll try and cover as much as I can here.

We need 2 16k areas. Normally one is at &c000 the other can be at &4000 (best if you want to be friendly with the firmware) or &8000 if you are hitting the hardware directly (remember to relocate stack if you put it here).

Only one of these areas is visible at one time. The other is not visible and we can safely draw to it.

When drawing a sprite for example, we give it some coordinates. I like to use top-left as 0,0. Y increases down, X increases to the right.
Using sprite coordinates makes it easy to move it around and control it.

You can describe the coordinates in pixels if you want, but ultimately you need to convert to screen coordinates at some point.

If you do use pixel coordinates, part of the X coordinate can be used to determine the "shift" to display the sprite with, or if you use preshifted sprites, which of these to display. You could choose to work in "byte coordinates" for X, then you are limited to 2 pixel movement in mode 0 for example.

If you always work in sprite coordinates it makes it much easier, and then convert to screen coordinates with a calculation.

To convert to screen coordinates, I use an array which has the start "offset" of each line (address minus the  base of the screen) this array is precomputed.
(can be precomputed even if screen is hardware scrolled, but anyway that's another topic).

I use y to lookup into the array, fetch the offset, add the x byte coordinate (derived by dividing the pixel coordinate by the number of pixels in a byte - e.g. 2 for mode 0).
Then I OR on the screen base to the upper byte. I have my screen address for the top-left of the sprite.

If sprite moves over the sides of the border, I "clip" it and work out the visible part to draw. it's another detail I can describe in another topic.

Base will change between &40 and &c0 as we swap.

I have a sprite draw function that then reads a sprite pixel byte, looks up a mask, and combines the pixels with the screen. This assumes pen 0 is transparent. Sprite is then drawn correctly.
When calculating the next line, I use a universal routine that works when the screen is at &4000 or &c000, e.g. base independant.
Sprite routine becomes:

remember screen address
draw a line
get back remembered screen address and go to next line
repeat for number of lines

So to plot a sprite I need to know x,y coordinate, and the base address that I will be drawing to. Note I always draw to the invisible screen.

Using the hardware, specifically crtc r12 and r13, we can set the screen base at vsync time of the screen which is visible.

Example:
&c000 is visible. &4000 is invisible. To make &c000 visible: r12=&30, r13=0. My "draw" base is &40, my visible base is &c0.
Swap it.
&4000 is visible (we see the changes I made now). &c000 is now invisible (old changes from 2 frames ago, last frame is the one I started to show now). To make &4000 visible:
r12=&10, r13=0. My "draw" base is &c0, my visible base is &40.

Note both visible and draw base can be exchanged using XOR (old base XOR value = new base).

My code doesn't take 50hz, so how do I do the exchange?

I have two "flags" one says "I am ready to swap", other says "I've swapped".
"I am ready to swap" is read at vsync time, and if set is (set means value is not 0) acted upon.

At this point it tells the hardware of the new screen using r12 and r13 and exchanges my values.  It then sets the "I've swapped flag".

int code is like this:

in vsync?
no: quit interrupt

yes:
update keyboard
update music.

"I am ready to swap" not 0?
yes: swap values, set "swap done".
no: do nothing.
quit interrupt

my main code is this:

draw to invisible screen
set "ready to swap".
wait until "swap done"
... interrupt triggers swap here....
clear "swap done" and "ready to swap" for next time.
repeat.

This will do the double buffer, exchanging values and you can see a sprite move.

but any difference between the screen causes a flicker, including sprite trails.

So there is more.

I need to keep track of:

2 sets of sprite coordinates. One for each screen.

So when I swap the screen, I get the sprite coordinates remembered for that screen.

main code is this:

erase sprites using the coordinates that were used last time we draw to this screen
(could be done by redrawing the tiles behind them for example, by converting sprite coords to tilemap coords, and width and height in tiles).
update sprites (ai, player control)
draw sprites in new position and remember the coordinates for next time
loop

this works really well for sprites, they move, the background is restored and all is good.

only problem I've had is with things such as score.

so you make a movement that triggers a score update. you update the score and draw it on the invisible screen.
after the swap, the new invisible screen has the old graphics for the score. you need to update it.
I set a flag that says "score has been updated, it needs to be copied". And I simply copy from the visible screen to the invisible screen. I copy a rectangle from one to the other.
That works great for cases like this.

in terms of erasing sprites, there are various methods:
ghosts and goblins uses a special trick where you OR on the sprite data and then use AND to remove it.
Some games redraw tiles that are "dirty".
some, that use software scroll redraw the entire screen, tiles and then sprites.
some store the background and restore it from there.
the choice is yours depending on your game.

I've used dirty tiles method in my games.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

sprite clipping:

ok, I'll cover this now.

If we work in sprite coordinates it's a bit easier.

We have our area on the screen, it has an x,y origin, and a width, height. it could be the whole screen which makes it 0,0 and 160 wide and 200 tall (mode 0 here).

I will call these "area_x", "area_y", "area_width", "area_height".

We know our sprite coords, they can be negative too.

I will call these "sprite_x", "sprite_y", "sprite_width", "sprite_height".

clipping a sprite is working out which part is visible.
we then use this information with a special sprite drawing function to only draw what is visible on the screen.
We work in byte coordinates so we always draw a complete number of bytes.

we can either use pre-shifted sprites, or shift them as we draw.

consider left side only:

(sprite_x+sprite_width)<area_x
sprite is completely off the left edge, we don't need to draw it.

sprite_x<area_x
(sprite is cut on the left side of the area)

area_x-sprite_x is the number of bytes off the left side. we call this "offs_x".
sprite_width-(area_x-sprite_x) is the number of bytes to draw in the width. we call this "draw_x"

the x position of the clipped sprite is "area_x".

so draw coordinates:
area_x, sprite_y
dimensions:
draw_x and sprite_height

we know the address of the sprites pixels in ram.

we add "offs_x" this is our starting memory address for sprite pixels, it points to the first visible sprite pixel byte.

remember sprite pixels
we draw "draw_x" for each line, we calc next screen address to move down the screen.
get what we remembered and add on sprite_width.
repeat.

we have just draw a sprite clipped on the left edge.

consider right edge only:

sprite_x>(area_x+area_width)
sprite is off the right side, it's not visible, don't draw.

(sprite_x+sprite_width)>(area_x+area_width)
sprite is cut on the right edge

so what is visible?

(area_x+area_width)-sprite_x = draw_x
offs_x = 0, because we are not clipped on the left side.

we add "offs_x" this is our starting memory address for sprite pixels, it points to the first visible sprite pixel byte.

remember sprite pixels
we draw "draw_x" for each line, we calc next screen address to move down the screen.
get what we remembered and add on sprite_width.
repeat.

top/bottom edges are the same but using y instead of x.

this is how you can draw a clipped sprite.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Quote from: db6128 on 14:17, 26 November 12
Thanks; I thought about that, but I can't get it to work... only in my head, admittedly, which isn't always the most logical place  :-X

But here was my reasoning: At the beginning, let's say the CRTC is displaying the normal screen at &C000, and that's empty. I render some stuff on the shadow screen at &4000. Once done, I switch the CRTC to show the just-completed frame at &4000. Nice! Instant refresh, no drawing, flicker, or whatever.
yes that's it.

for a game you don't start with a blank screen.
I would draw the tiles and the sprite in it's initial position.
I do this to an invisible screen, do a swap to show it, then go from there.

so what was visible before I drew my initial state? could have been the menu, could have been blank, that's ok.

So my code is like this:

draw tiles and sprites to invisible screen
swap

do game loop


the loop is then redrawing the dirty bits, updating and redrawing in new position.

any differences between the screen will result in flicker.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

db6128

#19
Wow, thanks a lot for the huge amount of detail! Much appreciated.

I completely see your point about not updating everything (if I'm reading that right) but it makes a bit of sense for this project: the changes are going to be numerous and small, often single pixels, and would probably require a lot of logic to copy only the altered bits. I definitely don't think LDIRing is ideal, but the alternative might be even slower in this case. For a game, I'm starting to see how having the 'past' screen be the next 'future' screen might not be bad, possibly even better – even for something simple like Breakout, which is probably still quite far away. : P

QuoteI like to use top-left as 0,0. Y increases down, X increases to the right.
I actually recently developed a spriting routine, with a few pointers from various things online. And yeah, this is ideal/optimal for calculating the address.

QuoteYou can describe the coordinates in pixels if you want, but ultimately you need to convert to screen coordinates at some point.
If you do use pixel coordinates, part of the X coordinate can be used to determine the "shift" to display the sprite with
I got this too. :) I do an SRL A to get (x/2) and branch depending on whether or not it carried; next, each routine gets the LSB, adds (x/2) to it, copies the full address to HL, and does either non-shifted or shifted plotting depending on the result of the branch. I shift the sprite's pixel 0 to the screen's pixel 1 by doing LD A, (HL);sprite : AND %10101010 : RRCA : LD C,A : LD A,(DE): RLCA: AND %10101010: OR C: RRCA: LD (DE),A or something very similar – and then do the converse to plot the sprite's pixel 1 to the screen's next byte's pixel 0.

QuoteTo convert to screen coordinates, I use an array which has the start "offset" of each line
Yep, and I have the LSB and then MSB page-aligned to make the lookup slightly faster... According to a certain discmag, Executioner would be proud ;) I did previously arrive at the same solution as you for this, too: have the sprite routine writing to a dynamically definable address by storing only relative offsets in the table, adding the base using self-modifying code, and XORing the base each frame. But then I made it write to &C000 only, for the same reasons that I outlined above – oh, and the added ease of detecting whether the next scanline is in the next character-row (LD A,D : ADD 8 : JR c,NEXTCHR). Of course, being able to plot to either screen may be best, in which case I'll go back to the old way.

In things like this, I'm starting to really appreciate the 8-bit index registers, especially for counters as B and C seem to get swallowed up by more commonly accessed and/or 16-bit things very quickly! I can only imagine how horrendous this would all be if we were dealing with a vanilla 8080. :D

Clipping is something I haven't considered, but seeing as I'm probably still miles from programming even a simple Breakout or something, and that won't require clipping, I'll leave it for now. I will definitely refer to your guide when/if the time comes, though!

Thanks again, really interesting stuff. :)
Quote from: Devilmarkus on 13:04, 27 February 12
Quote from: ukmarkh on 11:38, 27 February 12[The owner of one of the few existing cartridges of Chase HQ 2] mentioned to me that unless someone could find a way to guarantee the code wouldn't be duplicated to anyone else, he wouldn't be interested.
Did he also say things like "My treasureeeeee" and is he a little grey guy?

Devilmarkus

I used Overflow's code and made a little test:

RUN"FROG"

(The result looks better on the Thomson TO-8)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

arnoldemu

#21
Quote from: db6128 on 15:12, 26 November 12
Wow, thanks a lot for the huge amount of detail! Much appreciated.
You're welcome.

I read from your posts that you're already well advanced. :)

it is true that what I outlined is not perfect for every game, and a lot of tweaking and trying things out is needed to achieve the correct balance for each game, but it is one method I have used in one of my cpc games.

If you want to have fun, then you could avoid double buffering completely.

the problem then is to draw your sprites either well ahead, or behind the current position of the raster beam on the monitor.
OR, draw them in a way where if it crosses your sprite, the flicker is minimised.

this way is quite hard to do, but some spectrum games do exactly this.

one way that may be useful to you:

- have a screen which is not visible, and never visible.
- the other is always visible.

draw to the invisible buffer, noting in another buffer where you drew. you could split the buffer into tiles and mark a tile as "dirty", or an entire row.

one buffer is new pixels, one is visible, another is "what was modified".

then, when you're done, only draw the modified bits to the visible buffer, from the top to the bottom, left to right. clear the "modified" state so you start fresh with the next frame after that.

the buffer that is always visible is the full representation, the invisible one, if viewed, is not 100% accurate, and in general shows differences between frames.

I've used this before on spectrum.

I am not a god of game programming and I don't know everything, and I'm learning all the time, but I have finished 3 games on cpc.
I also work in the games industry and know the more modern stuff too.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Quote from: Devilmarkus on 15:20, 26 November 12
I used Overflow's code and made a little test:

RUN"FROG"

(The result looks better on the Thomson TO-8)
is the difference down to the colour palette of the thomson?
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Devilmarkus

Indeed... I could make a 1:1 result when I would convert to CPC+ palette.
But I have no idea how to keep the palette. (The palette is stored in unseen image pixels incl. the necessary code to show the screen, but when you press space after viewing, it returns to regular CPC palette)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

Quote from: arnoldemu on 15:25, 26 November 12
is the difference down to the colour palette of the thomson?

I looked into JavaCPC's emulation code, how I write the Plus routines:

            for (int i = 0; i < CodeP0.length; i++) {
                POKE(0xc7d0 + i, (byte) CodeP0[i]);
            }
            for (int i = 0; i < CodeP1.length; i++) {
                POKE(0xcfd0 + i, (byte) CodeP1[i]);
            }
            for (int i = 0; i < CodeP3.length; i++) {
                POKE(0xdfd0 + i, (byte) CodeP3[i]);
            }
            int mode = gateArray.getScreenMode();
            byte mo = (byte) 0x8c;
            if (mode == 1) {
                mo = (byte) 0x8d;
            }
            if (mode == 2) {
                mo = (byte) 0x8e;
            }
            POKE(0xd7d0, mo);
            byte[] pluspal = normalPaintBox.getPlusPalette();
            System.arraycopy(pluspal, 0, GateArray.screenmemory, 0xd7d1, 32);


The code which is "POKEd" to the unseen screen area is:

    static int CodeP0[] = {
        0xF3, 0x01, 0x11, 0xBC, 0x21, 0xD0, 0xDF, 0x7E,
        0xED, 0x79, 0x23, 0x0D, 0x20, 0xF9, 0x01, 0xA0,
        0x7F, 0x3A, 0xD0, 0xD7, 0xED, 0x79, 0xED, 0x49,
        0x01, 0xB8, 0x7F, 0xED, 0x49, 0x21, 0xD1, 0xD7,
        0x11, 0x00, 0x64, 0x01, 0x22, 0x00, 0xED, 0xB0,
        0xCD, 0xD0, 0xCF, 0x38, 0xFB, 0xFB, 0xC9
    };
    static int CodeP1[] = {
        0x01, 0x0E, 0xF4, 0xED, 0x49, 0x01, 0xC0, 0xF6,
        0xED, 0x49, 0xAF, 0xED, 0x79, 0x01, 0x92, 0xF7,
        0xED, 0x49, 0x01, 0x45, 0xF6, 0xED, 0x49, 0x06,
        0xF4, 0xED, 0x78, 0x01, 0x82, 0xF7, 0xED, 0x49,
        0x01, 0x00, 0xF6, 0xED, 0x49, 0x17, 0xC9
    };
    static int CodeP3[] = {
        0xFF, 0x00, 0xFF, 0x77, 0xB3, 0x51, 0xA8, 0xD4,
        0x62, 0x39, 0x9C, 0x46, 0x2B, 0x15, 0x8A, 0xCD,
        0xEE
    };


Perhaps someone has fun to disassemble it ;)

I load a plus screen to C000 and then do a CALL &C7D0 -> this shows the screen with proper palette
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Powered by SMFPacks Menu Editor Mod