Hi All,
I've been learning some assembly recently and to do this I write a simple app that draws filled rectangles in a test card-like pattern with a bitmap logo over it and accepts some keyboard input. I started on the neo-retro systems like the Agon, Neo6502 and Commander X16, but I'd now like to attempt it on my first computer - the Amstrad CPC! It doesn't do anything, but it's something familiar I can work on and gives me a nice foundation for more development later. Here's a video of the Neo version so you get an idea of what I'm trying to do.
Through some heavy use of AI to kickstart my CPC learning, I've got this assembly that draws two squares. One should be red and the other should be yellow. The shapes are drawn correctly, but this code causes them to flash black/red and for the life of me I can't work out why! I've tried different ink, pens and fill mode, but I can't get it and I've gone as far as I can do with AI too. This is what it looks like at the moment, but the squares flash red/black.
(https://i.imgur.com/RlNf3e5.png)
Here's the code:
; =============================================
; Amstrad CPC Drawing Functions
; Draws two rectangles using reusable functions.
; Assembler: sjasmplus
; =============================================
DEVICE AMSTRADCPC6128
ORG 0x8000 ; Let's place our code at 0x8000, safely away from BASIC
; --- Constants
screen_base EQU 0xC000 ; Base address of the screen memory
screen_size EQU 0x4000 ; Size of the screen memory (16k)
amstrad_red EQU 6 ; The hardware pen number for Red
amstrad_yellow EQU 22 ; The hardware pen number for Yellow
; --- Firmware Call Addresses
fw_scr_set_mode EQU 0xBC0E ; Set screen mode (a=mode)
fw_gra_set_ink EQU 0xBC32 ; Set an ink to a hardware pen (a=ink, b=pen)
fw_key_wait EQU 0xBB06 ; Wait for a key to be pressed
fw_txt_set_mode EQU 0xBB9C ; Set text screen mode (for restoring)
; ====================================================================
; --- MAIN PROGRAM START
; ====================================================================
start:
; Set up the screen
ld a, 1
call set_screen_mode
call clear_screen
; --- Draw the first rectangle (RED) ---
; We use Ink 2 because its fill pattern (0x0F) is stable and avoids video contention.
ld a, 2 ; Use Ink 2
ld b, amstrad_red ; Set Ink 2 to be the color Red
call set_pen_color
ld b, 20 ; X position in bytes (80 / 4)
ld c, 60 ; Y position
ld d, 20 ; Width in bytes (80 / 4)
ld e, 80 ; Height
ld a, 0x0F ; Use the stable fill pattern for Ink 2
call draw_rect
; --- Draw the second rectangle (YELLOW) ---
; We use Ink 3 because its fill pattern (0xFF) is stable and avoids video contention.
ld a, 3 ; Use Ink 3
ld b, amstrad_yellow ; Set Ink 3 to be the color Yellow
call set_pen_color
ld b, 45 ; X position in bytes (180 / 4)
ld c, 80 ; Y position
ld d, 10 ; Width in bytes (40 / 4)
ld e, 40 ; Height
ld a, 0xFF ; Use the stable fill pattern for Ink 3
call draw_rect
; Wait and exit
call wait_for_key_press
call restore_screen_mode
ret
; ====================================================================
; --- DATA STORAGE FOR DRAW_RECT
; ====================================================================
rect_params:
.x db 0
.y db 0
.width db 0
.height db 0
.fill db 0
; ====================================================================
; --- REUSABLE FUNCTIONS
; ====================================================================
; --------------------------------------------------------------------
; FUNCTION: clear_screen
; Clears the entire screen to the background color (Ink 0).
; Uses fast LDIR block copy.
; Corrupts: AF, BC, DE, HL
; --------------------------------------------------------------------
clear_screen:
ld hl, screen_base ; Start of screen memory
ld de, screen_base + 1 ; Destination is one byte after start
ld (hl), 0 ; Set first byte to 0 (background color)
ld bc, screen_size - 1 ; Number of bytes to copy
ldir ; Copy (hl) to (de), inc hl, inc de, dec bc. GO!
ret
; --------------------------------------------------------------------
; FUNCTION: set_screen_mode
; Sets the CPC's screen mode.
; IN: A = Mode number (0, 1, or 2)
; --------------------------------------------------------------------
set_screen_mode:
call fw_scr_set_mode
ret
; --------------------------------------------------------------------
; FUNCTION: set_pen_color
; Sets a given ink to a specific hardware color.
; IN: A = Ink number (0-3 in Mode 1)
; B = Hardware color number (0-26)
; --------------------------------------------------------------------
set_pen_color:
call fw_gra_set_ink
ret
; --------------------------------------------------------------------
; FUNCTION: draw_rect
; Draws a filled rectangle using a robust, simplified logic.
; IN: B = X position (in bytes, so X_coord / 4)
; C = Y position
; D = Width (in bytes, so width / 4)
; E = Height
; A = Fill pattern
; Corrupts: AF, BC, DE, HL
; --------------------------------------------------------------------
draw_rect:
; Save all parameters into our data structure
ld (rect_params.fill), a
ld a, b
ld (rect_params.x), a
ld a, c
ld (rect_params.y), a
ld a, d
ld (rect_params.width), a
ld a, e
ld (rect_params.height), a
y_loop:
; Calculate screen address for the current Y
ld a, (rect_params.y)
call calculate_screen_address
; Add X offset
ld a, (rect_params.x)
ld e, a
ld d, 0
add hl, de
; Draw the horizontal line
ld a, (rect_params.width)
ld b, a
x_loop:
ld a, (rect_params.fill)
ld (hl), a
inc hl
djnz x_loop
; Update Y and height for next iteration
ld a, (rect_params.y)
inc a
ld (rect_params.y), a
ld a, (rect_params.height)
dec a
ld (rect_params.height), a
cp 0
jp nz, y_loop
ret
; --------------------------------------------------------------------
; FUNCTION: calculate_screen_address
; Calculates screen address for a given Y coordinate.
; IN: A = Y coordinate
; OUT: HL = screen memory address for start of that line (X=0)
; USES: AF, BC, DE, HL
; --------------------------------------------------------------------
calculate_screen_address:
ld b, a ; Store Y in b
srl a
srl a
srl a ; a = Y / 8 (character line number)
ld l, a
ld h, 0 ; hl = character line number
add hl, hl ; *2
add hl, hl ; *4
add hl, hl ; *8
add hl, hl ; *16
ld de, hl ; Store val*16 in de
add hl, hl ; *32
add hl, hl ; *64
add hl, de ; hl = (val * 64) + (val * 16) = val * 80.
ld a, b ; Restore original Y
and 7 ; a = Y % 8
ld e, a
ld d, 0 ; de = pixel row number
ld b, 11
shift_loop:
add de, de
djnz shift_loop
add hl, de ; Add the pixel row offset
ld de, screen_base
add hl, de ; Add the screen base address
ret
; --------------------------------------------------------------------
; FUNCTION: wait_for_key_press
; Halts execution until a key is pressed.
; --------------------------------------------------------------------
wait_for_key_press:
call fw_key_wait
ret
; --------------------------------------------------------------------
; FUNCTION: restore_screen_mode
; Restores the screen mode to the one active before the program started.
; --------------------------------------------------------------------
restore_screen_mode:
ld a, 255
call fw_txt_set_mode
ret
; --------------------------------------------------------------------
; Creates a CPC file that can be run directly from AMSDOS
; --------------------------------------------------------------------
SAVEAMSDOS "rect.cpc", start, $-start, start
Would anyone be able to explain what I'm doing wrong please?
When using call &BC32, you must input the same color value both in B and C registers.ex:
ld bc,&0606call &BC32&BC32 SCR SET INK
Action: Sets the colours of a PEN - if the two values supplied
are different then the colours will alternate (flash)
Entry: contains the PEN number, B contains the first colour,
and C holds the second colour
Exit: AF, BC, DE and HL are corrupt, and all others are
preserved
Thank you so much
@Jean-Marie !
Can I ask - where did you get that info from? I'm mostly scraping around various websites like Chibi Akumas' site for resources on the CPC. Is there a definitive source I should be looking at?
You're welcome. On this very website you can find some useful info on the Firmware :
https://www.cpcwiki.eu/imgs/e/e1/The_Amstrad_CPC_Firmware_Guide.txt
BTW there are 2 functions that draw rectangles (or boxes as they call'em):
108 &BC44 SCR FILL BOX
Action: Fills an area of the screen with an ink - this only
works for 'character-sized' blocks of screen
Entry: A contains the mask for the ink that is to be used, H
contains the left hand colurnn of the area to fill, D
contains the right hand column, L holds the top line,
and E holds the bottom line of the area (using physical
coordinates)
Exit: AF, BC, DE and HL are corrupt, and all others are
preserved
109 &BC17 SCR FLOOD BOX
Action: Fills an area of the screen with an ink - this only
works for 'byte-sized' blocks of screen
Entry: C contains the encoded PEN that is to be used, HL
contains the screen address of the top left hand corner
of the area to fill, D contains the width of the area
to be filled in bytes, and E contains the height of the
area to be filled in screen lines
Exit: AF, BC, DE and HL are corrupt, and all other registers
are preserved
Notes: The whole of the area to be filled must lie on the
screen otherwise unpredictable results may occur
Look also here:
https://www.cpcwiki.eu/index.php/Soft968:_CPC_464/664/6128_Firmware
Quote from: andymccall on 12:51, 28 June 25Thank you so much @Jean-Marie !
Can I ask - where did you get that info from? I'm mostly scraping around various websites like Chibi Akumas' site for resources on the CPC. Is there a definitive source I should be looking at?
I like them in PDF. For example: "FW System Vectors 6128", "The Amstrad CPC FW Guide" by Bob Taylor, and "CPC464 FW (1984)" by Amsoft. Downloadable in the next link. Keep the link, and explore it, this is a mine of gold :D :
https://acpc.me/?language=eng#ACME/DOCUMENTS_TECHNIQUES/FIRMWARES
A good source to learn about how the firmware / the OS behaves is to look at its implementation in ROM. For this, there exist commented ROM listings that show the assembler sources and a lot of comments and explanations. This helps to understand how parameters are transferred from the caller via registers, how they are processed, and how a whole OS can be build up from a bunch of small assembler routines.
Usually I have a look in this ROM listing (https://www.cpcwiki.eu/index.php/ROM-Listing_CPC_464/664/6128) from the German publisher Markt&Technik, presented in our Wiki. Maybe somebody else can recommend another one in another language.
One drawback has to be mentioned: The developers of the CPC firmware did know the predecessing processor 8080 well, but not the newer Z80 processor. For this reason, some routines in the 464 ROM are more complex then they needed to be. The most famous example: Using "DEC B : JR NZ" instead of "DJNZ".
Another thing one should keep in mind: An OS needs to provide common services that can be used by a broad group of clients. E.g. screen managment should support a text editor as well as a spread sheet. This means that the used routines cannot be optimized to one purpose, because the purpose is not known in advance. Always be sure: Whatever you find in an OS can be optimized somehow to get faster or smaller or both, if the use case is restricted somehow.
for Firmware stuff I normally use this one, it has PDF format and HTML for specific parts of the firmware, such as keyboard, jumpblocks, text, graphics, memory sections on 464 & 6128, you name it
https://www.cantrell.org.uk/david/tech/cpc/cpc-firmware.html (https://www.cantrell.org.uk/david/tech/cpc/cpc-firmware.html)
First - thank you to all that replied! I really do appreciate everyone taking time out of their day to answer questions that I should be able to answer myself (but can't!) read from the documents! I'm very much a do-er when it comes to learning, I need to implement something, then go and look at the references and after a few attempts I generally start to understand what it means. I've always struggled reading a technical reference first, then implementing it.
I've read all the replies and looked a the the technical docs, and I'm still not getting it. I was hoping someone could help me understand what I'm doing wrong.
I set the colour:
ld a, 1 ; Pen 1
ld b, 25 ; 25 = yellow
ld c, b
call 0xBC32
The bit I'm getting stuck on is the fill pattern. This code here should draw a box using my routing, but also a box using the firmware routine.
ld b, 0 ; X position in bytes (180 / 4)
ld c, 0 ; Y position
ld d, 10 ; Width in bytes (40 / 4)
ld e, 60 ; Height
ld a, #11 ; Use the stable fill pattern for Ink 1
call draw_rect
ld c, #11
ld hl, #C000 + 1000
ld d, 20
ld e, 50
call #BC17
The code to draw it using my routine draws a box, but I can't work out the fill pattern at all, it seems random!
The code to draw a box using the firmware call doesn't draw anything at all.
Can anyone tell me what I'm doing wrong on both the fill pattern and the firmware call? I think if I can work out the firmware call I should be able to then make sense of the rest of the Amstrad CPC docs.
Your fill patterns must be incorrect.
To fill a byte in mode 1 (4 pixels), you must follow this rule :
bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 |
pixel 0 (bit 0) | pixel 1 (bit 0) | pixel 2 (bit 0) | pixel 3 (bit 0) | pixel 0 (bit 1) | pixel 1(bit 1) | pixel 2 (bit 1) | pixel 3 (bit 1) |
Yeah, pixels are interleaved within a byte. How fun!
Try with Fill patterns 0, &0F, &F0, &FF
Here is some good documentation, but you'll have to translate it: CPCRULEZ > AMSTRAD CPC > > CODING > ANTIBUG > STRUCTURE DE LA M�MOIRE �CRAN DE L'AMSTRAD CPC PAR ANTIBUG (https://cpcrulez.fr/coding_antibug-01-struct_memoire_ecran.htm)
Alan Sugar, when he ordered designed CPC, was afraid that other companies would clone it without a license, so he ordered make display more complicated. Unfortunately, this also made life difficult for programmers.
I don't know which of these links will seem more understandable to you, but each one explains which pixels fit into which bits in different MODEs.
https://cpcrulez.fr/codingBOOK_soft968-CPC464-664-6128_firmware_006.htm
http://www.cpcmania.com/docs/programming/painting_pixels_introduction_to_video_memory.htm
https://cpctech.cpcwiki.de/docs/graphics.html
I just noticed there is a typo in the Firmware doc ! There are 2 calls to BC17.
The correct value for SCR_FLOOD BOX is actually &BC47.
&BC17 SCR CHAR LIMITS
Action: Gets the size of the whole screen in terms of the
numbers of characters that can be displayed
Entry: No entry conditions
Exit: B contains the number of characters across the screen,
C contains the number of characters down the screen, AF
is corrupt, and all other registers are preserved
Okay, I kinda got there....
(https://i.imgur.com/7OTKAYW.png)
Honestly... I still don't really understand it, but I split the byte up into two 4 bits, then worked out the values for each colour when they were placed into both bits and came up with a table like this:
; 3 = Cyan
; 12 = Bright Cyan
; 15 = Pastel Blue
; 48 = White
; 51 = Bright Green
; 60 = Light Blue
; 192 = Bright Yellow
; 195 = Yellow (Mustard)
; 204 = Red
; 207 = Pink (Salmon)
; 240 = Black
; 243 = Pastel Green
; 252 = Bright Magenta
I still missing some colours, as there's only 13 colours there, but for now I've been able to move on.
I wish I could display the text at the lower resolution though, that fat font sucks!
Using Mode 0, the layout is different : There are 2 pixels of 4 bits per byte:
bit 7: pixel 1 (bit 0)
bit 6: pixel 2 (bit 0)
bit 5: pixel 1 (bit 2)
bit 4: pixel 2 (bit 2)
bit 3: pixel 1 (bit 1)
bit 2: pixel 2 (bit 1)
bit 1: pixel 1 (bit 3)
bit 0: pixel 2 (bit 3)
You can change the display mode to another one after the 4th interrupt after Vsync.
Quote from: andymccall on 18:34, 04 July 25I wish I could display the text at the lower resolution though, that fat font sucks!
It is something complex, but it can be done through interruptions. In each frame the Gate Array generates a rate of interruptions of 300Hz = 6 IRQ/frame, with 52 scanlines each one.
Approximately in the 5th interruption, the raster passes through the area where you have the text. When your program detects that IRQ you just have to change from mode 0 to Mode 1 or 2, and print the text (if it has time). And once the 6th interruption begins, already by the border of the screen, or at VSYNC, change again to mode 0.
@andymccall - I have no idea where you got the numbers for the colors you listed.
And as for the width of the text, you can use a narrow font, like this:
https://www.cpcwiki.eu/forum/programming/basic-programming-tips/msg117620/#msg117620
You're over complicating things. Since you're using the firmware to do the drawing, you might as well let it deal with the complexity of byte encoding too.
100 &BC2C SCR INK ENCODE
Action: Converts a PEN to provide a mask which, if applied to a screen byte, will convert all of the pixels in the byte to the appropriate PEN
Entry: A contains a PEN number
Exit: A contains the encoded value of the PEN, the flags are corrupt, and all other registers are preserved
Notes: The mask returned is different in each of the screen modes
So all you need is something like:
LD A,(current_pen)
CALL SCR_INK_ENCODE
1 SPEED INK 1,1 : BORDER 12
3 ON BREAK GOSUB 100
5 m(0)=-0.424773783:m(1)=-0.394236058 : REM asm code in Real table
6 CALL @m(0),0 : REM set video hardware Mode 0 - for FW only.
10 FRAME:POKE &B8BF,5
16 CALL @m(0),0
20 OUT &7F10,&10
30 WHILE PEEK(&B8BF)<>3:WEND:CALL @m(0),2:OUT &7F10,&5F
40 GOTO 10
100 CALL @m(0),2
Quote from: andycadley on 07:47, 05 July 25You're over complicating things. Since you're using the firmware to do the drawing, you might as well let it deal with the complexity of byte encoding too.
100 &BC2C SCR INK ENCODE
Action: Converts a PEN to provide a mask which, if applied to a screen byte, will convert all of the pixels in the byte to the appropriate PEN
Entry: A contains a PEN number
Exit: A contains the encoded value of the PEN, the flags are corrupt, and all other registers are preserved
Notes: The mask returned is different in each of the screen modes
So all you need is something like:
LD A,(current_pen)
CALL SCR_INK_ENCODE
Okay, this was useful! (Not saying the other posts weren't - I've learned a lot from my mistakes!). I think this is more like what I should be doing:
; Is this now correct?
; Set the pen
ld a, 2 ; Select Pen 2
call #BB90 ; Call TXT SET PEN
; Set the pen ink
ld a, 2 ; Use pen 2
ld b, 10 ; Set Ink 2 to be the color
ld c, b ; Copy same color to c to ensure a solid, non-flashing color
call #BC32 ; Call SCR SET INK
; Convert to code suitable for mode 0
ld a, 2 ; Use the current value of Pen 2
call #BC2C ; Call SCR INK ENCODE
; Copy the converted color code left in a to c
ld c, a ; Color of rectangle
ld hl, screen_base ; Start of screen memory
ld d, 10 ; Width of the rectangle, accounting for double width
ld e, 120 ; Height of the rectangle
call #BC47 ; Call the graphics function to draw the rectangle
Is this better?
If it is, one renaming question I do have is about the colours. The pallet here: https://www.cpcwiki.eu/index.php/CPC_Palette lists all the colours available, but how do I know which colours from that pallet are part of the default 16 when I switch to mode 0? (I'm hoping that question hasn't just triggered a load of seasoned developers and shown I *still* don't know what I'm doing!)
I'm going to try the interrupt technique to see if I can get the menu written using mode 1. I'll create a new project and write double width text at the top, and normal text at the bottom. If I can do this, I'll try and incorporate it to my project.
One thing this little project has shown me is how much quality of life the neo-retro systems like the Agon Light, Neo6502 and Commander X16 have added to them. Even though those systems are supposed to be "retro" systems, there's still a lot of stuff their firmware, API's and systems give you that you simply don't have on the original retro systems.
I'm having fun (if being fun can be defined as constantly confused nad frustrated!) learning the CPC so far, and I'd have *loved* to have seen a world where developers knew how to take 100% advantage of the CPC on the day it was launched - and it being launched a year earlier. I think it would have really changed the industry, with C64 and Spectrum owners looking on in envy. It's a shame it tended to get the Spectrum's poorly ported hand-me-downs. It amazes me that I had this system 30 years ago, and I never new the power it had.
Thank you!
Quote from: ZorrO on 00:05, 05 July 25@andymccall - I have no idea where you got the numbers for the colors you listed.
And as for the width of the text, you can use a narrow font, like this:
https://www.cpcwiki.eu/forum/programming/basic-programming-tips/msg117620/#msg117620
Yes, I still didn't understand it really. I think I can make do with &BC2C SCR INK ENCODE for my project, but what I might do afterwards is put together an small program that uses &BC2C SCR INK ENCODE and outputs the encoded colours to the screen so I can see what they are and how they change.
https://www.cpcwiki.eu/imgs/e/ef/S968ap05.pdf
This lists the default colours.
You can always change them with SCR SET INK and SCR SET BORDER as you have done already.
https://www.cpcwiki.eu/imgs/e/e1/The_Amstrad_CPC_Firmware_Guide.txt
6128 ł 464 ł Size ł Comments on the memory locations
ÄÄÄÄÄÄĹÄÄÄÄÄÄÄĹÄÄÄÄÄÄĹÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
&B7D4 ł &B1D9 ł 1+16 ł Border and Pens' First Inks (as hardware numbers):
ł ł ł
&B7D4 ł &B1D9 ł 1 ł hw &04 = sw 1 (blue) border
&B7D5 ł &B1DA ł 1 ł hw &04 = sw 1 (blue) pen 0
&B7D6 ł &B1DB ł 1 ł hw &0A = sw 24 (bright yellow) pen 1
&B7D7 ł &B1DC ł 1 ł hw &13 = sw 20 (bright cyan) pen 2
&B7D8 ł &B1DD ł 1 ł hw &0C = sw 6 (bright red) pen 3
&B7D9 ł &B1DE ł 1 ł hw &0B = sw 26 (bright white) pen 4
&B7DA ł &B1DF ł 1 ł hw &14 = sw 0 (black) pen 5
&B7DB ł &B1E0 ł 1 ł hw &15 = sw 2 (bright blue) pen 6
&B7DC ł &B1E1 ł 1 ł hw &0D = sw 8 (bright magenta) pen 7
&B7DD ł &B1E2 ł 1 ł hw &06 = sw 10 (cyan) pen 8
&B7DE ł &B1E3 ł 1 ł hw &1E = sw 12 (yellow) pen 9
&B7DF ł &B1E4 ł 1 ł hw &1F = sw 14 (pale blue) pen 10
&B7E0 ł &B1E5 ł 1 ł hw &07 = sw 16 (pink) pen 11
&B7E1 ł &B1E6 ł 1 ł hw &12 = sw 18 (bright green) pen 12
&B7E2 ł &B1E7 ł 1 ł hw &19 = sw 22 (pale green) pen 13
&B7E3 ł &B1E8 ł 1 ł hw &04 = sw 1 (blue) pen 14
&B7E4 ł &B1E9 ł 1 ł hw &17 = sw 11 (sky blue) pen 15
ÄÄÄÄÄÄĹÄÄÄÄÄÄÄĹÄÄÄÄÄÄĹÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
&B7E5 ł &B1EA ł 1+16 ł Border and Pens' Second Inks (as hardware numbers):
ł ł ł
&B7E5 ł &B1EA ł 1 ł hw &04 = sw 1 (blue) border
&B7E6 ł &B1EB ł 1 ł hw &04 = sw 1 (blue) pen 0
&B7E7 ł &B1EC ł 1 ł hw &0A = sw 24 (bright yellow) pen 1
&B7E8 ł &B1ED ł 1 ł hw &13 = sw 20 (bright cyan) pen 2
&B7E9 ł &B1EE ł 1 ł hw &0C = sw 6 (bright red) pen 3
&B7EA ł &B1FF ł 1 ł hw &0B = sw 26 (bright white) pen 4
&B7EB ł &B1F0 ł 1 ł hw &14 = sw 0 (black) pen 5
&B7EC ł &B1F1 ł 1 ł hw &15 = sw 2 (bright blue) pen 6
&B7ED ł &B1F2 ł 1 ł hw &0D = sw 8 (bright magenta) pen 7
&B7EE ł &B1F3 ł 1 ł hw &06 = sw 10 (cyan) pen 8
&B7EF ł &B1F4 ł 1 ł hw &1E = sw 12 (yellow) pen 9
&B7F0 ł &B1F5 ł 1 ł hw &1F = sw 14 (pale blue) pen 10
&B7F1 ł &B1F6 ł 1 ł hw &07 = sw 16 (pink) pen 11
&B7F2 ł &B1F7 ł 1 ł hw &12 = sw 18 (bright green) pen 12
&B7F3 ł &B1F8 ł 1 ł hw &19 = sw 22 (pale green) pen 13
&B7F4 ł &B1F9 ł 1 ł hw &04 = sw 1 (bright yellow) pen 14
&B7F5 ł &B1FA ł 1 ł hw &17 = sw 11 (pink) pen 15
If you want to change modes the firmware friendly way is to setup a fast ticker interrupt (see the relevant sections in the soft 968 documentation on cpcwiki), and to to use MC SET MODE to set the mode without clearing the screen and MC SET INKS to change the palette in each section. This would give the same results McArti0 posted.
The thing to be aware of doing this is the firmware may draw as if it was in the mode set at the time of SCR SET MODE but it seems Soft968 might have the answer:
Soft968 says: 'On V1.1 firmware all that is necessary is to patch a RET instruction into the first byte of the SCR MODE CLEAR indirection. On V1.0 firmware this would result in all the inks being set to the background colour!' but if you are changing inks anyway this last point doesn't matter.
Then use SCR SET MODE, put text/draw lines, and then SCR SET MODE for another area of the screen might work. :)
Quote from: arnoldemu on 13:08, 05 July 25https://www.cpcwiki.eu/imgs/e/ef/S968ap05.pdf
This lists the default colours.
You can always change them with SCR SET INK and SCR SET BORDER as you have done already.
Ahhhh!!!!
I didn't realise the pen's were already assigned a colour. I thought the pens were all empty and I had to set the ink's I wanted to them.
This makes much more sense! ;D
Quote from: andymccall on 13:37, 05 July 25Quote from: arnoldemu on 13:08, 05 July 25https://www.cpcwiki.eu/imgs/e/ef/S968ap05.pdf
This lists the default colours.
You can always change them with SCR SET INK and SCR SET BORDER as you have done already.
Ahhhh!!!!
I didn't realise the pen's were already assigned a colour. I thought the pens were all empty and I had to set the ink's I wanted to them.
This makes much more sense! ;D
The relationship between PENs and INKs is one of those things that's a lot more intuitive if you've played around with BASIC a lot. I think the firmware guide sort of assumes that you're familiar with BASIC in many ways, so it's worth skimming through the BASIC manual to be honest.
I wanted to see if my theory worked (using MC SET MODE) to change mode on screen, stopping MC SCREEN CLEAR from doing anything and then using SCR SET MODE to setup firmware to use correct text drawing.
The result is attached.
Thanks for all the help.
Here's a video of what I've learned and managed to do so far:
https://youtu.be/eHGWneF2ydo
I tried to do the mixed mode, but it was beyond me at the moment :-/ The next bit I need to do is take a png, export it into a format the CPC can understand, then load the .bin in my project and display it over the black stripe. I think because of the complexity of the Amstrad CPC's graphics system, this is going to be much harder than on the other systems I've written this demo for. If anyone has any tutorials or tips for doing this then I'd appreciate the links. I have managed to display a full screen image, but that was a bit easier as I could conver the whole image into a format for the whole graphics memory, displaying a smaller image over the top of another one seem to be much harder.
Source code is here - https://github.com/andymccall/bitriotdev-cpc for those experienced dev's that fancy a laugh at a newbie ;D
Quote from: andymccall on 18:05, 06 July 25... The next bit I need to do is take a png, export it into a format the CPC can understand, then load the .bin in my project and display it over the black stripe. ... If anyone has any tutorials or tips for doing this then I'd appreciate the links. I have managed to display a full screen image, but that was a bit easier as I could conver the whole image into a format for the whole graphics memory, displaying a smaller image over the top of another one seem to be much harder.
Here I would like to do some advertising for the existing Wiki page (https://www.cpcwiki.eu/index.php/Creating_images_for_the_Amstrad) about this topic as well as for my small plugin for the GIMP graphics software (link (https://codeberg.org/lightforce6128/gimp-file-cpp-bin-save) at the end of the Wiki page, discussion on this forum page (https://www.cpcwiki.eu/forum/gfx-tunes/gimp-plug-in-to-export-cpc-binary-data/)). The plugin provides a small BASIC program that in turn installs a small assembler program to copy the graphics data to the screen - currently always at the upper left corner, but this can be changed.
I'm looking at your video to see what effect you want to achieve. And on Amstrad you don't need machine code for this. You can do it in a few lines of Basic or even display such a screen as a text file with a few control codes. For the address text you can use characters with codes from 128 to 143, and for option font use narrow font with a 4x8 pixels matrix in MODE 0, or switch bottom of screen to MODE 1. Last one thing can't be done in text file. The only difficulty is to get a lighter gray color that is not in palette, there are 3 ways to do this but each has a certain drawback.
Quote from: ZorrO on 19:57, 06 July 25I'm looking at your video to see what effect you want to achieve. And on Amstrad you don't need machine code for this.
Oh, I get this. This is an exercise purely to learn asm on a few different platforms. In fact the absolute easiest way would be to have a script to display two full screen images - but that's not why I'm writing this.
I started programming when I was about 14/15 when I got DevPac 3 for the Amiga for my birthday, and I just couldn't understand it. I tried a number of times throughout the years to go back and learn it and it's been a bit of a mental block for me. About 18 months ago I started getting into retro systems and decided to finally learn how to code in asm. I've been exploring different modern 8-bit systems like the Commander X16, Neo6502 and Agon Light, and I thought I'd go back to the very first system I ever had - the Amstrad CPC 6128 and see if I could write it for that.
The demo/app isn't
for anything, it doesn't really do anything - it's a few loops, keyboard input, shapes, screen mode changes, displaying an image tile or a sprite etc. but it's enough for me to learn a few common skills across a number of platforms. I'll expand on it to try new things as I learn more. One thing I've already thought of is having a data structure for all my rects that loop through to display them. Right now I could do that in C/C++ or Java, but I've got no idea about this in asm so it will be fun learning.
It's cool, have fun as you wish. Just knowing assembler without knowing properties of specialized chips and contents of kernel doesn't give you feeling that you know what and how to do it. Many coders, when switching to another platform with the same processor they know, are unable to do as effective things on new machine as on the previous one. Accustomed to being better than those who write only in Basic, on new one they see that those who don't know assembler can do better things because they know machine. At least at the beginning it is like that. :)
Quote from: andymccall on 18:05, 06 July 25I tried to do the mixed mode, but it was beyond me at the moment :-/
Start:
Call #bd19 ;wait to vsync
Ld hl,#b8bf ; FW interrupt counter
Ld a,0
Call #bd1c ; set hw video mode in A.
Ld a,5
Ld (hl),a ; set FW interrupt counter
Ld a,3 ; or 2 or 1
To3:
Cp (hl)
Jr nz,To3 ; wait to int number for exp. 3
Ld a,1
Call #bd1c ; set hw video mode in A.
Call #bb1b ; read key
Jr nc,start
; A holds the char.