CPC Plotting pixels
-
- Posts: 10
- Joined: Wed Apr 24, 2019 11:59 pm
CPC Plotting pixels
Hi Keith,
I'd first like to say how glad I am you setup this forum. I think it's really going to help users out a lot. And also my personal thanks to you for giving up so much of your free time to teach assembly - greatly appreciated. It's a shame you weren't teaching 30 years ago when I was much younger. I would have loved to have created some games.
Now onto the query. I'm having quite a bit of trouble working our how to convert pixel x,y to screen address. I know you have covered this in one or two of your tutorials but, for some reason I still can't seem to find the logic pattern. I have a very simple asm program in which I move a pixel around the screen but, that's easy because I start at addrss &C000 and using some register logic and xpos and ypos variables I control it's movement. However, I want to be able to plot at certain areas of the screens and this is where I need some help.
Thanks in advance.
I'd first like to say how glad I am you setup this forum. I think it's really going to help users out a lot. And also my personal thanks to you for giving up so much of your free time to teach assembly - greatly appreciated. It's a shame you weren't teaching 30 years ago when I was much younger. I would have loved to have created some games.
Now onto the query. I'm having quite a bit of trouble working our how to convert pixel x,y to screen address. I know you have covered this in one or two of your tutorials but, for some reason I still can't seem to find the logic pattern. I have a very simple asm program in which I move a pixel around the screen but, that's easy because I start at addrss &C000 and using some register logic and xpos and ypos variables I control it's movement. However, I want to be able to plot at certain areas of the screens and this is where I need some help.
Thanks in advance.
Re: CPC Plotting pixels
well the reason I wasn't doing this 30 years ago is I was ten then!... but seriously, remember i only started learning Assembly 3 years ago... In a lot of ways I'm really documenting what I'm learning, and making it available to others...
Anyway, in my tutorial I used a lookup table to calculate addresses, but I've come up with something cleverer - and saving a lot of memory!
Try running this from Winape:
Effectively we're now using the 'rules' of calculating the start of a line in memory, and calculating the memory position... we effect multiplication via bit shifts, and repeated adds where necessary
This is an improved version of the code in the 1st chibiakumas game, which used parital lookup tables... the reason I didn't use this at that time, is I simply wasn't good enough at ASM maths to manage it...
That said... the lookup table IS faster if you can spare the 400 bytes
Maybe this will help you? if not, I'll try something else, and maybe make a video about this new 'lookup table-less' version
Anyway, in my tutorial I used a lookup table to calculate addresses, but I've come up with something cleverer - and saving a lot of memory!
Try running this from Winape:
Code: Select all
org &8000
ld c,199
ld b,0
Again:
call GetScreenPos
ld (hl),255
halt
dec c
jr nz,Again
ret
GetScreenPos:
; ; Input BC= XY (x=bytes - so 80 across)
; ; output HL= screen mem pos
; ; de is wiped
;
;Looking at Y line (in C) - we need to take each set of bits, and work with them separately:
;YYYYYYYY Y line number (0-200)
;-----YYY (0-7) - this part needs to be multiplied by &0800 and added to the total
;YYYYY--- (0-31) - This part needs to be multiplied by 80 (&50)
;YYYYY--- (0-31) - This part needs to be multiplied by 80 (&50)
;screen is 80 bytes wide = -------- %01010000
ld a,C ; 00000000 01010000
and %11111000 ; -------- YYYYY---
ld h,0
ld l,a
; 00000000 01010000
sla l ; -------Y YYYY----
rl h
ld d,h ;value is in first bit position -add it
ld e,l
; 00000000 01010000
sla e ; ------YY YYY-----
rl d ;
sla e ; -----YYY YY------
rl d
add hl,de ;value is in 2nd bit position - add it
;We've now effectively multiplied by 80 (&50)
;-----YYY (0-7) - this part needs to be multiplied by &0800 and added to the total
ld a,C
and %00000111
rlca ;X8
rlca
rlca
ld d,a ;Load into top byte, and add as 16 bit
ld e,0
add hl,de
;We've now effectively multiplied by 8
;Screen Base
ld a,&C0 ;Add the screen Base &C000
ld d,a
;X position
ld e,B ;Add the X pos
add hl,de
ret ;return memory location in hl
This is an improved version of the code in the 1st chibiakumas game, which used parital lookup tables... the reason I didn't use this at that time, is I simply wasn't good enough at ASM maths to manage it...
That said... the lookup table IS faster if you can spare the 400 bytes
Maybe this will help you? if not, I'll try something else, and maybe make a video about this new 'lookup table-less' version
Chibi Akuma(s) Comedy-Horror 8-bit Bullet Hell shooter! // 「チビ悪魔」可笑しいゴシックSTG ! // Work in Progress: ChibiAliens
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
-
- Posts: 10
- Joined: Wed Apr 24, 2019 11:59 pm
Re: CPC Plotting pixels
Hi Keith,
Thanks for the example code. I've been looking through it and have started to understand how you are doing things. It's really puzzling why the Amstrad screen (and Spectrum) RAM was never designed to be linear. Using C on the PC I used to find it much easier to work with the screen memory. I used to use a formula to calculate the screen position by entering the x,y into it and I would get the screen RAM position. I suppose I was naive to think that all system would use a simple screen layout.
BTW - I noticed in your sample code you used the "HALT" command. Was that to slow it down or is that another trick of a quick less memory expensive method of V-SYNC?
I've got another quick query for you. Using your pixel plotting code, do you think it could be re-used to plot sprites considering sprites are plotted pixels at a time?
Thanks.
Thanks for the example code. I've been looking through it and have started to understand how you are doing things. It's really puzzling why the Amstrad screen (and Spectrum) RAM was never designed to be linear. Using C on the PC I used to find it much easier to work with the screen memory. I used to use a formula to calculate the screen position by entering the x,y into it and I would get the screen RAM position. I suppose I was naive to think that all system would use a simple screen layout.
BTW - I noticed in your sample code you used the "HALT" command. Was that to slow it down or is that another trick of a quick less memory expensive method of V-SYNC?
I've got another quick query for you. Using your pixel plotting code, do you think it could be re-used to plot sprites considering sprites are plotted pixels at a time?
Thanks.
Re: CPC Plotting pixels
The halt command was just to slow things down enough to see what was going on,
If the code was working correctly the lines should fill in order, but without the halt it would be hard to see what order they were filling.
The GetNextLine and GetScreenPos functions here were taken from ChibiAkumas, and used in GrimeZ80 and ChibiAliens, they definately can be used as the starting point for Sprites!
Now you may need to do some clipping or transparency, but these functions can be the first stage in that, working out what address in memory you need to write to (or read for transparency)
If the code was working correctly the lines should fill in order, but without the halt it would be hard to see what order they were filling.
The GetNextLine and GetScreenPos functions here were taken from ChibiAkumas, and used in GrimeZ80 and ChibiAliens, they definately can be used as the starting point for Sprites!
Now you may need to do some clipping or transparency, but these functions can be the first stage in that, working out what address in memory you need to write to (or read for transparency)
Chibi Akuma(s) Comedy-Horror 8-bit Bullet Hell shooter! // 「チビ悪魔」可笑しいゴシックSTG ! // Work in Progress: ChibiAliens
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
Re: CPC Plotting pixels
A youtube user has left the following comment:
It's a fair comment, so I've made the following example using the same functions above, this should just paste into Winape and run with Call &8000, and it should show an 8x8 sprite onscreenI've been trying to follow this, but the example code is just way too complicated in the way it branches off to so many external files and functions. I get that it's efficient to use prewritten code with these techniques but for a beginner just trying to get a grip on what's happening it's far too confusing and it makes it very hard to visualise what's meant to be going on. All I want to do is draw a simple 8x8 sprite to the screen.
Code: Select all
ORG &8000
ld b,2 ;Xpos in bytes
ld c,4 ;Ypos in lines
call getScreenPos
ex hl,de
ld hl,sourceBitmap ;Source Bitmap
ld b,8 ;height
NextLine:
ld c,2 ;width (in bytes)
push de
NextByte:
ld a,(hl) ;Move a byte to screen
ld (de),a
inc hl
inc de
dec c
jr nz,NextByte ;repeat for next byte
pop de
ex de,hl
call GetNextLine ;Move down a line
ex de,hl
djnz NextLine ;repeat for next line
ret
sourceBitmap:
db &FF,&FF
db 0,0
db &F0,&F0
db &F0,&F0
db &0F,&0F
db &0F,&0F
db 0,0
db &FF,&FF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetScreenPos: ;return memory pos in HL of screen co-ord B,C (X,Y)
; ; Input BC= XY (x=bytes - so 80 across)
; ; output HL= screen mem pos
; ; de is wiped
;
;Looking at Y line (in C) - we need to take each set of bits, and work with them separately:
;YYYYYYYY Y line number (0-200)
;-----YYY (0-7) - this part needs to be multiplied by &0800 and added to the total
;YYYYY--- (0-31) - This part needs to be multiplied by 80 (&50)
;YYYYY--- (0-31) - This part needs to be multiplied by 80 (&50)
push de
;screen is 80 bytes wide = -------- %01010000
ld a,C ; 00000000 01010000
and %11111000 ; -------- -YYYY---
ld h,0
ld l,a
; 00000000 01010000
sla l ; -------- YYYY----
rl h
ld d,h ;value is in first bit position -add it
ld e,l
; 00000000 01010000
sla e ; -------Y YYY-----
rl d ;
sla e ; ------YY YY------
rl d
add hl,de ;value is in 2nd bit position - add it
;We've now effectively multiplied by 80 (&50)
;-----YYY (0-7) - this part needs to be multiplied by &0800 and added to the total
ld a,C
and %00000111
rlca ;X8
rlca
rlca
ld d,a ;Load into top byte, and add as 16 bit
ld e,0
add hl,de
;We've now effectively multiplied by 8
;Screen Base
ld a,&C0 ;Add the screen Base &C000
ld d,a
;X position
ld e,B ;Add the X pos
add hl,de
pop de
ret ;return memory location in hl
GetNextLine:
push af
ld a,h ;Add &08 to H (each CPC line is &0800 bytes below the last
add &08
ld h,a
;Every 8 lines we need to jump back to the top of the memory range to get the correct line
;The code below will check if we need to do this - yes it's annoying but that's just the way the CPC screen is!
bit 7,h ;Change this to bit 6,h if your screen is at &8000!
jp nz,GetNextLineDone
push bc
ld bc,&c050 ;if we got here we need to jump back to the top of the screen - the command here will do that
add hl,bc
pop bc
GetNextLineDone:
pop af
ret
Chibi Akuma(s) Comedy-Horror 8-bit Bullet Hell shooter! // 「チビ悪魔」可笑しいゴシックSTG ! // Work in Progress: ChibiAliens
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
-
- Posts: 10
- Joined: Wed Apr 24, 2019 11:59 pm
Re: CPC Plotting pixels
Hi Keith
I was browsing through the CPCWiki forum the other day and came across a post in which someone showed a firmware function which calculated the screen address based on x/y coordinates. The call was to &BC1D – Have you ever come across this? I immediately looked it up in the firmware documentation to see how it can be used. Knocked up some basic assembler code to see how it worked and I was quite impressed. I then immediately thought, hold on, this is probably going to be slow because it uses the firmware but, to my surprise it wasn’t at all.
I put together some code which mimicked your example and ran a very crude benchmark (using a stopwatch app) and I was very impressed how fast it was. In fact it I couldn’t really see any speed difference between your version and the firmware one.
Here’s the code I used;
In your experience where would you think the firmware version will be lacking?
I was browsing through the CPCWiki forum the other day and came across a post in which someone showed a firmware function which calculated the screen address based on x/y coordinates. The call was to &BC1D – Have you ever come across this? I immediately looked it up in the firmware documentation to see how it can be used. Knocked up some basic assembler code to see how it worked and I was quite impressed. I then immediately thought, hold on, this is probably going to be slow because it uses the firmware but, to my surprise it wasn’t at all.
I put together some code which mimicked your example and ran a very crude benchmark (using a stopwatch app) and I was very impressed how fast it was. In fact it I couldn’t really see any speed difference between your version and the firmware one.
Here’s the code I used;
Code: Select all
org &8000
ld de,100 ;xpos start
ld hl,199 ;ypos start
Again:
push de ;save xpos
push hl ;save ypos
call &bc1d ;convert x/y to screen address and put destination address in HL
ld (hl),255 ;plot pixel to screen address
call &BD19 ;wait for v-sync
pop hl ;get current ypos
pop de ;get current xpos
dec l ;decrease ypos (by one)
jr nz,Again ;check if zero set. if not repeat..
ret ;..else return to BASIC
Re: CPC Plotting pixels
I've not used that particular function, so I will have to talk more generally
1. Chibi Akumas used to use the firmware text functions to get the 'highscore' onscreen... they were slow... horrendously so - I moved to my unoptimized sprite routines and the speedup was amazing - that's not to say they won't be OK for a simple game, but for an arcade game like ChibiAkumas it was a no-go... with Chibiakumas I had to do a lot of optimization, and every single command counted, so if not using the firmware saved just a few ticks, then that was what I did - that's not the case for other projects
2. if you use any firmware functions, then you have to play by the firmaware rules - ChibiAkumas uses ALL the registers and a custom interrupt handler - the firmware requires the shadow BC to be unaltered, otherwise it will crash in most cases - the firware also uses ram from around &A500-BFFF for various system variables - ChibiAkumas uses that area for the second screen buffer.
What I'm trying to say is, You should certainly use the firmware functions if they help you, but once you do then you have to work within the firmware limits... not that that's a problem, as you can always write your own replacement routines if you find the firmware is too limited later on... that's what I did with ChibiAkumas.
1. Chibi Akumas used to use the firmware text functions to get the 'highscore' onscreen... they were slow... horrendously so - I moved to my unoptimized sprite routines and the speedup was amazing - that's not to say they won't be OK for a simple game, but for an arcade game like ChibiAkumas it was a no-go... with Chibiakumas I had to do a lot of optimization, and every single command counted, so if not using the firmware saved just a few ticks, then that was what I did - that's not the case for other projects
2. if you use any firmware functions, then you have to play by the firmaware rules - ChibiAkumas uses ALL the registers and a custom interrupt handler - the firmware requires the shadow BC to be unaltered, otherwise it will crash in most cases - the firware also uses ram from around &A500-BFFF for various system variables - ChibiAkumas uses that area for the second screen buffer.
What I'm trying to say is, You should certainly use the firmware functions if they help you, but once you do then you have to work within the firmware limits... not that that's a problem, as you can always write your own replacement routines if you find the firmware is too limited later on... that's what I did with ChibiAkumas.
Chibi Akuma(s) Comedy-Horror 8-bit Bullet Hell shooter! // 「チビ悪魔」可笑しいゴシックSTG ! // Work in Progress: ChibiAliens
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809
Interested in CPU's :Z80,6502,68000,6809,ARM,8086,RISC-V
Learning: 65816,ARM,8086,6809