New source:
http://www.cpctech.org.uk/source/normals.asm (http://www.cpctech.org.uk/source/normals.asm)
Software scroll using LDI for copying the scroller.
Mode 1 font (2 bytes wide and 16 lines tall).
I will add to this thread as I release my example sources.
New source:
http://www.cpctech.org.uk/source/scrlrast.asm
A simple single line scrolling horizontal split raster.
New source:
http://www.cpctech.org.uk/source/multinst.asm
Example shows how to load your own code into the multiface 2 ram. When the Stop button is pressed your code is executed. The multiface 2 menu is not shown.
New source
http://www.cpctech.org.uk/source/hardmess.asm
Horizontal message scroller. Uses hardware scroll (crtc reg 12 and 13).
Note: Code is not optimised, it is meant for example for others to learn.
New source
http://www.cpctech.org.uk/source/rotospr.asm
Source shows the type of sprites used in Mission Genocide, Ghosts and Goblins, Bubble Bobble, Ghouls and Ghosts.
Sprites are 3 colours (pen 0 is transparent). Background is 4 colours.
Sprites drawn using logical-OR and erased using logical-AND.
These are also known as "bitplane" sprites.
Quote from: arnoldemu on 21:29, 19 April 10
Source shows the type of sprites used in Mission Genocide, Ghosts and Goblins, Bubble Bobble, Ghouls and Ghosts.
That's a really cool example, will have a play around with it.
Quote from: redbox on 18:05, 21 April 10
That's a really cool example, will have a play around with it.
:) remember it is not optimised!
The sprite drawing and erase loops could be unrolled to speed it up for example.
Also i use the firmware for checking keys pressed, this could be changed for direct hardware reading.
So there is scope to improve it.
New source:
http://www.cpctech.org.uk/source/maskspr.asm (http://www.cpctech.org.uk/source/maskspr.asm)
An example that shows a mode 0 sprite over a background. Pen 0 of sprite is transparent, leaving 15 pens for use with the sprite.
Background can use any of the 16 colours. Sprite is masked when it is drawn to screen.
Background behind sprite is stored in a buffer.
Sprite x movement is by the byte (so 2 pixels at a time in X).
Sprite y movement is by the line (1 pixel in Y).
Again, the code is not optimised.
Code also shows use of a 256-byte aligned mask table, how to create it and how to use it to mask the sprite.
NOTE: Background from internet at a site that claims that the picture is free for use.
Sprite is my own ;)
Cool...
Your asm codes really help me to improve JavaCPC's Z80 assembler ;)
The source for rotosprites compiles well after I found a missing command ;)
Quote from: Devilmarkus on 21:55, 21 April 10
Cool...
Your asm codes really help me to improve JavaCPC's Z80 assembler ;)
The source for rotosprites compiles well after I found a missing command ;)
:) helping everyone :)
Funny:
Also the roto sprite in example before and now this disappear in upper half of screen?
Quote from: Devilmarkus on 21:58, 21 April 10
Funny:
Also the roto sprite in example before and now this disappear in upper half of screen?
Indeed.
I wait for vsync and first erase the sprite, then I check for keyboard to decide where new sprite coords should be then I draw sprite in new position.
But by this time monitor refresh has gone too far, so either you see no sprite (so time when sprite has been erased and I am checking keyboard), or if you are lucky you see the sprite in time :P
For example code it works if you move the sprite into the correct place :P
Well there are ways to fix this: 1. use double buffer 2. erase and draw sprite in same routine, erase a line, draw the line, erase a line, draw the line etc.
New source:
http://www.cpctech.org.uk/source/shftspr.asm
This example is for Markus ;)
Shows:
1. ASM version of SPEED KEY 1,1 to speed up key presses (thanks Markus for suggesting it)
2. Only drawing sprite when it has moved (thanks again Markus for suggesting it). The sprite does flicker when moved.
3. Masked mode 1 sprites
4. Pre-shifted sprites. There are 4 sprites used here, each shifted by one more pixel than the other. This is done to move the sprite pixel by pixel.
5. 16-bit X coordinates for positioning sprite on screen
6. Nice background and nice smiley sprite with it's tongue sticking out (I am sure I read that Markus likes these smileys ;) )
Nice example.
Managed to fix another bug thanks your code ;)
But your code is bad!
Compile, run it and move sprite up! (Reset)
the disappearing sprite :P
Quote from: Devilmarkus on 22:46, 23 April 10
Nice example.
Managed to fix another bug thanks your code ;)
But your code is bad!
Compile, run it and move sprite up! (Reset)
possibly. I found a bug where pre-shifted sprites overrun the buffer.
Yeah it resets near the top.. so... ?
I'll fix it later ;)
EDIT: New version of code has been uploaded that fixes the bug that Markus reported.
Quote from: ynot.zer0 on 11:00, 24 April 10
the disappearing sprite :P
Proof. Of. Concept.
..and very nice PoCs these samples are too. I'm learning quite a lot from them at the moment.
With the latest code update
buffer_size equ sprite_height*(sprite_width+1)
;; a buffer to store screen behind sprite
sprite_background:
defs buffer_size <<<<<<<<<<<<<<<<Assemble error here
I found that for some reason it would not compile if referencing sprite_height; but if you replace it with the numeric value it works:
defs 64*sprite_width+1
I'm curious; can anyone explain why?
Quote from: ynot.zer0 on 11:03, 27 April 10
buffer_size equ sprite_height*(sprite_width+1)
;; a buffer to store screen behind sprite
sprite_background:
defs buffer_size <<<<<<<<<<<<<<<<Assemble error here
Which assembler did you use? (JavaCPC's assembler parses the mathematics correct here. (In progress...))
winape 2.0 alpha 17
Quote from: ynot.zer0 on 11:03, 27 April 10
..and very nice PoCs these samples are too. I'm learning quite a lot from them at the moment.
With the latest code update
buffer_size equ sprite_height*(sprite_width+1)
;; a buffer to store screen behind sprite
sprite_background:
defs buffer_size <<<<<<<<<<<<<<<<Assemble error here
I found that for some reason it would not compile if referencing sprite_height; but if you replace it with the numeric value it works:
defs 64*sprite_width+1
I'm curious; can anyone explain why?
Sorry I didn't check my update with winape.
I did check most of the others.
for winape you probably need to do this:
preshifted_width equ sprite_width+1
buffer_size equ sprite_height*preshifted_width
defs buffer_size
I normally use pasmo for my code because like javacpc it has an assembler that evaluates the mathematical expressions and allows you to bracket them.
If I have time, I'll correct it for winape.
You can try the mathparser I am using in JavaCPC's assembler here:
http://cpc-live.com/calc/ (http://cpc-live.com/calc/)
Simply enter what you want to calculate in the upper text window.
e.g. 20*(40+1)
It also accepts binary input like %10110111*15
Quote from: arnoldemu on 11:36, 27 April 10
I normally use pasmo for my code because like javacpc it has an assembler that evaluates the mathematical expressions and allows you to bracket them.
This was never done in WinAPE simply because it wouldn't be Maxam compatible any longer, and would break lots of existing assembler code. I might include it as an option in the next release though.
I have an option in my assembler.
You can select left-to-right calculation (default, like maxam) or exact math parsing (allows brackets etc...)
Updated source:
http://www.cpctech.org.uk/source/shftspr.asm
Now builds with Winape assembler.
New source:
http://www.cpctech.org.uk/source/tilemap.asm
Shows:
1. How to use KM_TEST_KEY to read keyboard (uses key numbers)
2. How to draw a tilemap to the screen (20 tiles wide and 12 tall). The tilemap is for a static screen (no scroll).
3. How to join tilemaps together to make a larger map (you can press up/down/left/right cursors to move to other screens).
Quick tile gfx by Markus. Thanks :)
Quote from: arnoldemu on 21:52, 28 April 10
New source:
http://www.cpctech.org.uk/source/tilemap.asm (http://www.cpctech.org.uk/source/tilemap.asm)
Shows:
1. How to use KM_TEST_KEY to read keyboard (uses key numbers)
2. How to draw a tilemap to the screen (20 tiles wide and 12 tall). The tilemap is for a static screen (no scroll).
3. How to join tilemaps together to make a larger map (you can press up/down/left/right cursors to move to other screens).
Quick tile gfx by Markus. Thanks :)
That sample is absolutely SUPERB! It is just what I was after knowing. Thank you so much for posting these samples they are a tremendous help to us newbie coders 8) keep 'em coming!
Quote from: ynot.zer0 on 13:18, 29 April 10
That sample is absolutely SUPERB! It is just what I was after knowing. Thank you so much for posting these samples they are a tremendous help to us newbie coders 8) keep 'em coming!
np. I have a few more ideas (hardware scrolling a tilemap, software scrolling a tilemap, reducing/stopping flicker in sprites, double buffering) and then I will ask for suggestions.
Quote from: arnoldemu on 11:36, 30 April 10
hardware scrolling a tilemap, software scrolling a tilemap, reducing/stopping flicker in sprites, double buffering
YES!
I have been slaving over a tilemap routine and it's been great to see how you've done it.
Would definitely like some pointers on quick double buffering (scrolling has been taken care of by the ASIC for me ;) ).
I also wrote a small assembler routine today.
I use it to load several screens into ram banks.
This routine provides 2 RSX commands for BASIC:
|BANK,bank
|COPY
You can load a screen to bank &C4 and copy it to screen:
10 MEMORY &3FFF
20 |BANK,&C4:LOAD"MYSCREEN.BIN",&4000
30 |COPY
Here's the source:
nolist
org #8000
LD HL,BufferRsx
LD BC,PtrRsx
JP #BCD1
PtrRsx:
DW RSX_TABLE
JP Bank
JP Copy
RSX_TABLE:
DB "BAN","K"+#80
DB "COP","Y"+#80
Bank:
LD A,(IX+0)
LD B,#7F
OUT (C),A
RET
Copy:
LD HL,#4000
LD BC,#4000
LD DE,#c000
LDIR
RET
BufferRsx:
DS 4
Quote from: Devilmarkus on 21:58, 23 June 10
I also wrote a small assembler routine today.
I use it to load several screens into ram banks.
This routine provides 2 RSX commands for BASIC:
|BANK,bank
|COPY
You can load a screen to bank &C4 and copy it to screen:
10 MEMORY &3FFF
20 |BANK,&C4:LOAD"MYSCREEN.BIN",&4000
30 |COPY
Here's the source:
nolist
org #8000
LD HL,BufferRsx
LD BC,PtrRsx
JP #BCD1
PtrRsx:
DW RSX_TABLE
JP Bank
JP Copy
RSX_TABLE:
DB "BAN","K"+#80
DB "COP","Y"+#80
Bank:
LD A,(IX+0)
LD B,#7F
OUT (C),A
RET
Copy:
LD HL,#4000
LD BC,#4000
LD DE,#c000
LDIR
RET
BufferRsx:
DS 4
A nice example of RSX commands.
The same code but modified with double buffering the screens:
nolist
org #8000
LD HL,BufferRsx
LD BC,PtrRsx
JP #BCD1
PtrRsx:
DW RSX_TABLE
JP Bank
JP Copy
RSX_TABLE:
DB "BAN","K"+#80
DB "COP","Y"+#80
Bank:
LD A,(IX+0)
LD B,#7F
OUT (C),A
RET
Copy:
LD BC,#BC0C
OUT (C),C
LD BC,#BD10
OUT (C),C ; switch display to #4000 bank #C0
LD HL,#4000
LD DE,#C000
LD BC,#4000
LDIR
LD BC,#BD30
OUT (C),C ; switch display to #C000
LD BC,#7FC0
OUT (C),C ; switch to bank #C0
LD HL,#C000
LD DE,#4000
LD BC,#4000
LDIR
RET
BufferRsx:
DS 4
New source:
http://www.cpctech.org.uk/source/newflip.asm
This code uses the firmware to show:
1. How to sync with the firmware colour. So if you do ink 1,2,3 you can know for definite when this ink is colour 2 and when it is colour 3 and to ensure it always happens when you want it to.
2. How to set the colours using MC_SET_INK
3. How to define the screen base using SCR_SET_BASE and how to toggle screen between starting at &4000 and &c000.
4. How to change the mode using MC_SET_MODE so that the mode is changed without CLS.
This example is good if you want to make video modes which give the illusion of higher resolution or more colours by "flicking"/swapping the screens, colours and modes.
New source:
http://www.cpctech.org.uk/source/sldldr.asm
This code shows:
1. How to get the current drive number
2. How to initialise the disc rom after loading this file (BASIC will disable all roms, effectively going to
cassette mode)
3. How to set the current drive back again
4. Using a list of files, and loading each file one-by-one. When we get to the end of the list
going back to the first file again. Good for slideshows ;)
Updated source:
http://www.cpctech.org.uk/source/overscan.asm
Updated overscan code so that it supports crtc type 2 (changed register 3 value).
Quote from: arnoldemu on 21:30, 20 July 10
Updated overscan code so that it supports crtc type 2 (changed register 3 value).
Your link is wrong: try http://www.cpctech.org.uk/source/overscn.asm (http://www.cpctech.org.uk/source/overscn.asm)
Quote from: Executioner on 01:05, 22 July 10
Your link is wrong: try http://www.cpctech.org.uk/source/overscn.asm (http://www.cpctech.org.uk/source/overscn.asm)
thanks :)
Thought I'd have a go at some commented source of a variation of the sprite code from the 64k version of Star Sabre. This example only uses one screen, runs with firmware and interrupts, and isn't well optimised. The source has been tested under Winape.
This demonstrates using a look up table to generate an address list for all the sprites, then using that list when printing, then clearing the sprites. The idea being that the more things the list is used for, the more useful it becomes to generate the addresses just the once as a separate process (for example, you might need to save & restore the background, or check for background collisions). It also shows how the look up table can be used for easy 'sprite clipping' on the top and bottom edges of the screen.
Thanks for sharing.
To let JavaCPC compile this piece of code, I have a question:
.ScoreText
text "Score:10000 Lives:3",0
when I replace it to:
.ScoreText
db "Score:10000 Lives:3",0
it compiles.
So what's the difference between 'text' and 'db'?
Quote from: Devilmarkus on 16:22, 23 July 10
So what's the difference between 'text' and 'db'?
Nothing at all, I guess 'text' must be specific to Maxam.
http://www.grimware.org/doku.php/documentations/software/winape/start#defb.db.defm.byte.and.text (http://www.grimware.org/doku.php/documentations/software/winape/start#defb.db.defm.byte.and.text)
http://www.cpctech.org.uk/source/sampplay.asm
New source:
- Shows how to play samples using digiblaster, amdrum and AY sound chip.
- All source sample data should be raw (e.g. no headers), 8-bit signed samples.
You can use Markus' tools to make this.
- shows how to create an RSX
Markus has been using similar code in his new productions.
Quote from: arnoldemu on 21:56, 17 September 10
Markus has been using similar code in his new productions.
Here's my tool I used to transform 8 bit mono WAV-files to RAW.
(http://cpc-live.com/rawtransformet.png)
How to use?
- Simple: Just keep the default settings. No changes needed here.
- Click "Transform" and select your WAV file.
- That's all.
- You will find up to 33 RAW files in your folder. (If WAV is larger, the rest is truncated)
- "Transform Folder" is not useful yet. It's just experimental.
- "Header" adds an AMSDOS header to each RAW file.
- "As ASM" also generates ASM source code for each RAW part.
- "Store sample" also saves the complete RAW file as 1 sample file (up to 524k). (My experimental JavaCPC can import this by drag & drop)
http://www.cpctech.org.uk/source/mltmde2.asm (http://www.cpctech.org.uk/source/mltmde2.asm)
New/Updated source
- This example shows multiple modes using the firmware. It is based on the code here:
http://www.cpctech.org.uk/source/multmode.asm (http://www.cpctech.org.uk/source/multmode.asm)
- However, sometimes one of the mode changes will not occur exactly at the time we expect, but is delayed by 8 lines.
This delay is caused by the keyboard scan.
The firmware doesn't scan the firmware always at the same time in a frame. It does scan the keyboard every 6 interrupts so that it is once per frame.
This example shows how to sync with the vsync (using firmware), and then use KL SCAN NEEDED to reset the keyboard scan so that it occurs when we want it to. Now our mode splits are accurate.
EDIT: Only works on 664/6128 because it uses firmware v1.1 functions.
Source updated with comment.
New source:
http://www.cpctech.org.uk/source/modesplt.asm
This shows how to do the most accurate mode-split with the firmware.
It uses an asynchronous express fast ticker event.
With this one, I can't even use MC SET MODE because the alternative register set is not setup for it, and also because it disables and then re-enables interrupts. So this time I had to look at the OS and work out where the information is stored.
Normally C' holds the byte we are interested in, but at this point A' actually stores it.
Also I must ensure the rom is paged in, but I mustn't remember this in A'.
Asynchronous express interrupts are the 2nd interrupt type to be processed. First is frame ticker (if vsync is active), otherwise these are the first interrupt type to be executed at other times. This function is about 8 or so scanlines ahead of the previous one and doesn't get altered by the keyboard scanning AND it works on 464, 664 and 6128.
But to make it work I have to hit the hardware direct and make sure I setup the alternative register set correct, otherwise the firmware will crash.
Enjoy my journey into the OS rom and the results ;)
New source:
http://www.cpctech.org.uk/source/sixpixfirm.asm
This shows how to draw a 6x8 pixel font in mode 1 using the firmware.
It can be slow, but it works.
Quote from: arnoldemu on 13:08, 20 November 10
New source:
http://www.cpctech.org.uk/source/sixpixfirm.asm (http://www.cpctech.org.uk/source/sixpixfirm.asm)
This shows how to draw a 6x8 pixel font in mode 1 using the firmware.
It can be slow, but it works.
And now the version without the firmware:
http://www.cpctech.org.uk/source/sixpix.asm
This does some manipulation of the screen pixels to draw and mask the chars.
This example also shows how you can write text to the screen *without* the firmware and using your own pixel data.
arnoldemu wrote:
And now the version without the firmware:
http://www.cpctech.org.uk/source/sixpix.asm (http://www.cpctech.org.uk/source/sixpix.asm)
This does some manipulation of the screen pixels to draw and mask the chars.
This example also shows how you can write text to the screen *without* the firmware and using your own pixel data.
Just wondering if this version of the program is supposed to return the user back to BASIC?
EDIT: Oh I see you're looping "l1" onto itself! ;) Change it to ret and your back in BASIC! :) Only the non-firmware version and firmware versions vary quite significantly cause the Firmware version alters the text so it still active once the program exits! I couldn't see a lot of difference speed wise between both of these program, though I presume it would become more apparent the more you throw more 'text' at these routines!
Quote from: CP/M User on 22:03, 20 November 10
arnoldemu wrote:
And now the version without the firmware:
http://www.cpctech.org.uk/source/sixpix.asm (http://www.cpctech.org.uk/source/sixpix.asm)
This does some manipulation of the screen pixels to draw and mask the chars.
This example also shows how you can write text to the screen *without* the firmware and using your own pixel data.
Just wondering if this version of the program is supposed to return the user back to BASIC?
EDIT: Oh I see you're looping "l1" onto itself! ;) Change it to ret and your back in BASIC! :) Only the non-firmware version and firmware versions vary quite significantly cause the Firmware version alters the text so it still active once the program exits! I couldn't see a lot of difference speed wise between both of these program, though I presume it would become more apparent the more you throw more 'text' at these routines!
Both pieces of code were actually made for another game which I am helping with.
Some other people are making it, but I offered some help. Not sure when this game will be released.
Quote from: arnoldemu on 10:47, 22 November 10
Both pieces of code were actually made for another game which I am helping with.
Some other people are making it, but I offered some help. Not sure when this game will be released.
A Spectrum conversion?
The font looks very Speccy and also you're converting 1-bit per pixel graphics ;)
arnoldemu wrote:
Both pieces of code were actually made for another game which I am helping with.
Some other people are making it, but I offered some help. Not sure when this game will be released.
Always good to have a different font when it comes to games! ;D
This article on Screen Squashing (which is older than my 6128 ;) ) always comes to mind when I think of articles on Character Sets:
http://cpcwiki.eu/imgs/7/78/Amstrad_Computer_User8504_020.jpg (http://cpcwiki.eu/imgs/7/78/Amstrad_Computer_User8504_020.jpg)
http://cpcwiki.eu/imgs/3/3b/Amstrad_Computer_User8504_021.jpg (http://cpcwiki.eu/imgs/3/3b/Amstrad_Computer_User8504_021.jpg)
http://cpcwiki.eu/imgs/4/4b/Amstrad_Computer_User8504_022.jpg (http://cpcwiki.eu/imgs/4/4b/Amstrad_Computer_User8504_022.jpg)
http://cpcwiki.eu/imgs/5/5e/Amstrad_Computer_User8504_025.jpg (http://cpcwiki.eu/imgs/5/5e/Amstrad_Computer_User8504_025.jpg)
Quote from: arnoldemu on 13:11, 20 November 10
And now the version without the firmware:
http://www.cpctech.org.uk/source/sixpix.asm (http://www.cpctech.org.uk/source/sixpix.asm)
This does some manipulation of the screen pixels to draw and mask the chars.
This example also shows how you can write text to the screen *without* the firmware and using your own pixel data.
The Y char position was not calculated correctly in this code. This has now been fixed.
Updated source:
http://www.cpctech.org.uk/source/6pixpatch.asm (http://www.cpctech.org.uk/source/6pixpatch.asm)
I mostly fixed cursor position.
But still some bugs here.
Why not 2 RSX commands?
|LOCATE,<1-53>,<1-lines>
|PRINT,"HELLO WORLD"
+ these:
|PEN,x
|PAPER,y
This is perhaps a bit beyond me, though I was playing around with txt_write_char and noticed you were only using "A" with the character byte, cause with that routine H contains the physical column number and L holds the physical line number. When I was trying it out as a standard writing routine with 65 in A it doesn't seem to obey writing outside the zone 0-39 and 0-24 seems to be it's range.
I didn't think it was possible to go beyond the bounds using text based Co-ordinates, hence the article from the early Amstrad CPC464 User (which became ACU) I posted was treating the text as graphically based characters. Interesting I "TAG"ged while your program was running and it wrote using the standard character set across the screen.
But there's a lot of stuff going on in that program that I don't know! ???
I remember having this whole fastwriting routine for the IBM which allowed me to write wherever onscreen using Text based co-ordinates. I don't recall there being anything standard about it, though it came in very useful because I was converting some 80x50 Text Mode games in TP for CP/M-86. In CP/M-86 while you could tell it to go into 80x50 Mode, CP/M-86 simply didn't know anything about 80x50 text mode and needed a separate routine which would allow it to happen. I'm guessing this is the sort of thing your trying out here.
Quote from: CP/M User on 08:52, 06 December 10
This is perhaps a bit beyond me, though I was playing around with txt_write_char and noticed you were only using "A" with the character byte, cause with that routine H contains the physical column number and L holds the physical line number. When I was trying it out as a standard writing routine with 65 in A it doesn't seem to obey writing outside the zone 0-39 and 0-24 seems to be it's range.
I didn't think it was possible to go beyond the bounds using text based Co-ordinates, hence the article from the early Amstrad CPC464 User (which became ACU) I posted was treating the text as graphically based characters. Interesting I "TAG"ged while your program was running and it wrote using the standard character set across the screen.
But there's a lot of stuff going on in that program that I don't know! ???
I remember having this whole fastwriting routine for the IBM which allowed me to write wherever onscreen using Text based co-ordinates. I don't recall there being anything standard about it, though it came in very useful because I was converting some 80x50 Text Mode games in TP for CP/M-86. In CP/M-86 while you could tell it to go into 80x50 Mode, CP/M-86 simply didn't know anything about 80x50 text mode and needed a separate routine which would allow it to happen. I'm guessing this is the sort of thing your trying out here.
I think tag makes it use the graphics drawing functions?
I was thinking about the char ranges and thought that perhaps I needed to redefine the window size, or perhaps also "WIDTH" or similar. Then it may work.
Well, the aim of this initially was to draw a 6 pixel wide font. Then I wanted to extend it so it could be used from BASIC without using any | commands. So you could use normal BASIC commands to use it.
Also, the size of the screen could be changed and this new charset used if you wanted.
I was interested in how much work I would need to do with patching the firmware jumpblock for it to work.
arnoldemu wrote:
I think tag makes it use the graphics drawing functions?
Yep, TAG allows the user to enter standard Text Character from a Graphic co-ordinates position.
I was thinking about the char ranges and thought that perhaps I needed to redefine the window size, or perhaps also "WIDTH" or similar. Then it may work.
I try some experimenting with WINDOW 1,53,1,25, perhaps the firmware equivalent may do something, though I dare say it's all based on that one WINDOW routine. WIDTH might do something though it appears to be. I had a look though the firmware guide which had some stuff re;ating to the cursor though didn't see anything relating to the size of the cursor, merely the ability of turning it on and switching it off and something relating to drawing and undrawing the cursor! :-[ There seems to be a few routines relating to the position of the cursor, though it may have to restrict itself to those standard position guidelines.
Anyhow I'm suprised to see how far it's developed into what you've created! :)
I hope no-one minds me posting this old dinosaur of a routine in here! ???
org &4000
.setup
LD A,1 ;; My crude routine for setting up Scr_Mode
CALL &BC0E
LD A,240 ;; Setup Symbol Table - A Holds Character value
LD HL,ship1 ;; HL points to Symbol Data to Define to
CALL &BBA8 ;; Firmware routine to Redefine Symbol Table.
LD A,241
LD HL,ship2
CALL &BBA8
LD A,242
LD HL,ship3
CALL &BBA8
LD A,243
LD HL,ship4
CALL &BBA8
.init
ld hl,&140C ;; Initial Position
LD A,0 ;; Initial Direction
.loop
PUSH HL ;; Start of Main Loop
PUSH AF
CALL &BB75 ;; TXT SET CURSOR
POP AF
PUSH AF
ADD A,240 ;; graphic code
CALL &BB5D ;; Print
LD BC,&0C00 ;; Start Short Delay
.shtdel
DEC BC
LD A,B
OR C
JR NZ,shtdel ;; loop back if Non Zero
POP AF
POP HL ;; only HL actually wanted
PUSH HL
PUSH AF ;; the next call corrupts AF & HL
CALL &BB75 ;; TXT SET CURSOR
LD A,32 ;; code for space
CALL &BB5D ;; Print
LD A,0 ;; code for up arrow
CALL &BB1E ;; KM TEST KEY
JR Z,proa ;; Jump if Key Up
POP AF ;; reclaim direction code
POP HL ;; ..and position
CP 0 ;; Compare A with 0 - up?
JR NZ,right ;; Jump to check Right if Not
DEC L ;; Up a row
JR newpos ;; Jump to the next position
.right
CP 1 ;; Compare with 1 - right?
JR NZ,down
INC H ;; Right one column
JR newpos
.down
CP 2 ;; Down?
JR NZ,left
INC L ;; Down a row
JR newpos
.left
DEC H ;; Left - no check needed here
.newpos
PUSH HL ;; Save new position
PUSH AF ;; Protect A from the TEST KEY call
.proa
LD A,1 ;; key code for right arrow
CALL &BB1E ;; KM TEST KEY
JR Z,lftar ;; Zero if not pressed
POP AF ;; old direction
ADD A,1 ;; clockwise move
CP 4 ;; check A value in range
JR NZ,newdir2 ;; Jump if not 4
LD A,0 ;; reset A to 0
.newdir2
PUSH AF ;; new direction
LD BC,&2000 ;; delay to separate keystrokes
.dloop2
DEC BC
LD A,B
OR C
JR NZ,dloop2
.lftar
LD A,8 ;; key code for left arrow
CALL &BB1E ;; KM TEST KEY
JR Z,cesc ;; jump if not pressed
POP AF ;; old direction
SUB 1 ;; Subtract: A=A-1
JR NC,newdir ;; Jump if Carry bit not set **
LD A,3 ;; Reset A to 3 if below 0
.newdir
PUSH AF ;; New Direction
LD BC,&2000 ;; delay loop
.dloop
DEC BC
LD A,B
OR C
JR NZ,dloop
.cesc
LD A,66 ;; key code for ESC
CALL &BB1E ;; KM TEST KEY
JR Z,check
POP AF ;; clear stack before return
POP HL
RET ;; Return to Basic
.check
POP AF
POP HL ;; only HL really wanted
PUSH AF ;; save direction code
LD A,L ;; routine to check L value
CP 0 ;; off top of screen?
JR NZ,botscr
LD L,25 ;; wrap-round, top to bottom
JR checkh ;; Jump to H check
.botscr
CP 26 ;; bottom of screen?
JR NZ,checkh
LD L,1 ;; move to top
.checkh
LD A,H ;; check H value
CP 0 ;; off left?
JR NZ,offright
LD H,40 ;; move to right edge
JR tidy ;; jump to end
.offright
CP 41 ;; off right
JR NZ,tidy
LD H,1 ;; move to left edge
.tidy
POP AF ;; tidy up the stack
JP loop ;; jump to start of main loop ***
.ship1
defb 16,56,56,56,124,124,198,130
.ship2
defb 192,112,62,31,62,112,192,0
.ship3
defb 130,198,124,124,56,56,56,16
.ship4
defb 0,3,14,124,248,124,14,3 ;; data for defining the ships.
This is one of those Left/Right, point the ship in this direction kind of routine and use the foward arrow to move it in the direction it's facing. The original program (which is mainly this) comes from Amstrad CPC464 User (before it became ACU) and the program appeared to only be CPC464 friendly. A good deal of modify it just to get it to compile in Maxam was required since the original routine was using direct addresses & bytes in the Jump & Jump Relative routine and no labels! ??? So I've tried to label the program as best as I could, result the program works. The original code never included the matrix data either, where in it was included within the BASIC Loader program, but now it should act as the BASIC program does. But I reckon there could be considerable enhancements which could be done to it if anyone is looking for a routine like this.
Dear AA,
I typed the program that you printed in your last issue, again and again, but my Amstrad gives me an error on every line. Even if I add line numbers, when I try to run it I get errors again and I don't know how to correct them.
I noticed that you didn't print the checksums so I can check if I have typed it in correctly, but I am pretty sure I did. Also, you didn't print those dots that represent spaces, those are really useful...
Is my 464 broken?
Thank you,
Th.P.
Quote from: CP/M User on 04:14, 19 December 10
I hope no-one minds me posting this old dinosaur of a routine in here! ???
org &4000
.setup
LD A,1 ;; My crude routine for setting up Scr_Mode
CALL &BC0E
LD A,240 ;; Setup Symbol Table - A Holds Character value
LD HL,ship1 ;; HL points to Symbol Data to Define to
CALL &BBA8 ;; Firmware routine to Redefine Symbol Table.
LD A,241
LD HL,ship2
CALL &BBA8
LD A,242
LD HL,ship3
CALL &BBA8
LD A,243
LD HL,ship4
CALL &BBA8
.init
ld hl,&140C ;; Initial Position
LD A,0 ;; Initial Direction
.loop
PUSH HL ;; Start of Main Loop
PUSH AF
CALL &BB75 ;; TXT SET CURSOR
POP AF
PUSH AF
ADD A,240 ;; graphic code
CALL &BB5D ;; Print
LD BC,&0C00 ;; Start Short Delay
.shtdel
DEC BC
LD A,B
OR C
JR NZ,shtdel ;; loop back if Non Zero
POP AF
POP HL ;; only HL actually wanted
PUSH HL
PUSH AF ;; the next call corrupts AF & HL
CALL &BB75 ;; TXT SET CURSOR
LD A,32 ;; code for space
CALL &BB5D ;; Print
LD A,0 ;; code for up arrow
CALL &BB1E ;; KM TEST KEY
JR Z,proa ;; Jump if Key Up
POP AF ;; reclaim direction code
POP HL ;; ..and position
CP 0 ;; Compare A with 0 - up?
JR NZ,right ;; Jump to check Right if Not
DEC L ;; Up a row
JR newpos ;; Jump to the next position
.right
CP 1 ;; Compare with 1 - right?
JR NZ,down
INC H ;; Right one column
JR newpos
.down
CP 2 ;; Down?
JR NZ,left
INC L ;; Down a row
JR newpos
.left
DEC H ;; Left - no check needed here
.newpos
PUSH HL ;; Save new position
PUSH AF ;; Protect A from the TEST KEY call
.proa
LD A,1 ;; key code for right arrow
CALL &BB1E ;; KM TEST KEY
JR Z,lftar ;; Zero if not pressed
POP AF ;; old direction
ADD A,1 ;; clockwise move
CP 4 ;; check A value in range
JR NZ,newdir2 ;; Jump if not 4
LD A,0 ;; reset A to 0
.newdir2
PUSH AF ;; new direction
LD BC,&2000 ;; delay to separate keystrokes
.dloop2
DEC BC
LD A,B
OR C
JR NZ,dloop2
.lftar
LD A,8 ;; key code for left arrow
CALL &BB1E ;; KM TEST KEY
JR Z,cesc ;; jump if not pressed
POP AF ;; old direction
SUB 1 ;; Subtract: A=A-1
JR NC,newdir ;; Jump if Carry bit not set **
LD A,3 ;; Reset A to 3 if below 0
.newdir
PUSH AF ;; New Direction
LD BC,&2000 ;; delay loop
.dloop
DEC BC
LD A,B
OR C
JR NZ,dloop
.cesc
LD A,66 ;; key code for ESC
CALL &BB1E ;; KM TEST KEY
JR Z,check
POP AF ;; clear stack before return
POP HL
RET ;; Return to Basic
.check
POP AF
POP HL ;; only HL really wanted
PUSH AF ;; save direction code
LD A,L ;; routine to check L value
CP 0 ;; off top of screen?
JR NZ,botscr
LD L,25 ;; wrap-round, top to bottom
JR checkh ;; Jump to H check
.botscr
CP 26 ;; bottom of screen?
JR NZ,checkh
LD L,1 ;; move to top
.checkh
LD A,H ;; check H value
CP 0 ;; off left?
JR NZ,offright
LD H,40 ;; move to right edge
JR tidy ;; jump to end
.offright
CP 41 ;; off right
JR NZ,tidy
LD H,1 ;; move to left edge
.tidy
POP AF ;; tidy up the stack
JP loop ;; jump to start of main loop ***
.ship1
defb 16,56,56,56,124,124,198,130
.ship2
defb 192,112,62,31,62,112,192,0
.ship3
defb 130,198,124,124,56,56,56,16
.ship4
defb 0,3,14,124,248,124,14,3 ;; data for defining the ships.
This is one of those Left/Right, point the ship in this direction kind of routine and use the foward arrow to move it in the direction it's facing. The original program (which is mainly this) comes from Amstrad CPC464 User (before it became ACU) and the program appeared to only be CPC464 friendly. A good deal of modify it just to get it to compile in Maxam was required since the original routine was using direct addresses & bytes in the Jump & Jump Relative routine and no labels! ??? So I've tried to label the program as best as I could, result the program works. The original code never included the matrix data either, where in it was included within the BASIC Loader program, but now it should act as the BASIC program does. But I reckon there could be considerable enhancements which could be done to it if anyone is looking for a routine like this.
Quote from: Gryzor on 09:55, 24 December 10
Dear AA,
I typed the program that you printed in your last issue, again and again, but my Amstrad gives me an error on every line. Even if I add line numbers, when I try to run it I get errors again and I don't know how to correct them.
I noticed that you didn't print the checksums so I can check if I have typed it in correctly, but I am pretty sure I did. Also, you didn't print those dots that represent spaces, those are really useful...
Is my 464 broken?
Thank you,
Th.P.
:laugh:
mega-rofl 8)
G. Kev is gonna be real mad to see what you've done to his thread! :-[
Quote from: arnoldemu on 11:36, 30 April 10
I have a few more ideas (hardware scrolling a tilemap, software scrolling a tilemap, reducing/stopping flicker in sprites, double buffering) and then I will ask for suggestions.
Do you have the source code for this?
I am wrestling with it at the moment and would love to see how you've done it.
New source:
http://www.cpctech.org.uk/source/intpos.asm
In relation to games:
The example shows the position of each interrupt on the CPC.
For games, it is much easier to change the mode or colours at the position of an interrupt because it doesn't waste CPU time waiting for an exact position on the screen.
By changing the vsync position, you can change the relative position of the visible part of the screen and also where the interrupts come. But then you end up with a picture shifted within the monitor display. You can get away with one char or so either up/down from the normal position.
CALL &8000
Posted by a Happy Kev.
Quote from: redbox on 18:33, 29 December 10
Do you have the source code for this?
I am wrestling with it at the moment and would love to see how you've done it.
Yes, but nothing cleaned up.
P.M. me your e-mail address and I'll send it.
New source:
http://www.cpctech.org.uk/source/scrdim.asm
This example shows:
1. position and time between CPC interrupts
2. how you can modify hsync/vsync/vdisp/hdisp to position the screen how you want (it's interactive!)
3. Then depending on vdisp/hdisp, the approx amount of ram used (really it depends on Register 9 and it's hardcoded here, and also the way the CPC screen is arranged means the calculation in this example is not perfect).
In relation to games:
This example gives an idea about how the amount of ram used changes depending on the width/height of the displayed screen.
NOTE that if hardware scrolling was used, the amount of ram used would always be 16K (or 32k if overscan) because of the way the hardware scrolling is done.
CALL &8000 to run it.
Quote from: arnoldemu on 12:01, 01 January 11
New source:
http://www.cpctech.org.uk/source/intpos.asm (http://www.cpctech.org.uk/source/intpos.asm)
Freezes after using cursor keys?
Seem to work on 6128 only?!?
Quote from: arnoldemu on 12:44, 01 January 11
New source:
http://www.cpctech.org.uk/source/scrdim.asm (http://www.cpctech.org.uk/source/scrdim.asm)
Freezes, too?!?
Quote from: Devilmarkus on 17:08, 01 January 11
Freezes after using cursor keys?
Seem to work on 6128 only?!?
hmmm.. I only tested in on Winape.
it doesn't use 6128 specific code.
You have to be careful you don't move the screen outside of the normal range or the monitor can't cope.
Also not sure it works on CRTC type 2.
Quote from: Devilmarkus on 17:09, 01 January 11
Freezes, too?!?
Not on winape.. I will build it for another emu later and see if it works ok.
I do need to stop it flickering and also I need to slow down the keys ;)
Quote from: arnoldemu on 21:56, 17 September 10
http://www.cpctech.org.uk/source/sampplay.asm (http://www.cpctech.org.uk/source/sampplay.asm)
New source:
- Shows how to play samples using digiblaster, amdrum and AY sound chip.
- All source sample data should be raw (e.g. no headers), 8-bit signed samples.
You can use Markus' tools to make this.
- shows how to create an RSX
Markus has been using similar code in his new productions.
I re-assembled the code today.
Is it possible that there's something wrong with |DRIVER,0 ? (AY driver)
I just hear crap here... ?!?
New source:
http://www.cpctech.org.uk/source/os_spr.asm
This example shows how to draw a sprite to an overscan screen. The important part here is the "scr_next_line" code.
There may be a better shorter way to do this, but this one works.
The screen is the "32k" overscan type, suitable for crtc type 2.
Control the sprite with cursors. Sprite can disapear when moving because of monitor drawing deleted version of sprite before drawing freshly drawn sprite, but the functionality is working.
Another method is used here to avoid flicker when sprite is not moving: I store previous coordinates of sprite, if these are updated I then delete and draw the sprite, otherwise I do nothing.
NOTE: I have also adjusted the screen start base so that the "problem" screen address is on the left side, meaning the code for "scr next byte" is just an inc hl. If I used a different base, then a special "scr next byte" case would be needed to cope with &07ff->&4000 case.
Thanks for that code, I'm learning by example and that's great.
Flickering can be omitted by choosing the right time to start undraw/draw sprite. If the sprite is in the upper half of the screen, then start after interrupt 3 (occurt right in middle hight of the screen). If the sprite is in the lower half of the screen then start at interrupt 0 (frame flyback). Unclear?
Quote from: TFM/FS on 23:29, 28 February 11
Flickering can be omitted by choosing the right time to start undraw/draw sprite. If the sprite is in the upper half of the screen, then start after interrupt 3 (occurt right in middle hight of the screen). If the sprite is in the lower half of the screen then start at interrupt 0 (frame flyback). Unclear?
Yes it can be done this way.
I have read of other ways too.
So, when I have a bit more time I will experiment with various ways to avoid flicker.
But methods include:
1. Sorting sprite by Y coordinate and then drawing them from top to bottom.
2. Sorting sprite by Y coordinate and then drawing them from bottom to top.
3. As you draw each sprite, erase 1 scanline, draw 1 scanline and repeat until all sprite is drawn. (this reduces flicker to a few pixels or one line).
4. double buffering.
The flicker comes because the sprite is erased completely and then drawn after.
At the top of the screen, the "monitor" has drawn the erased sprite, so that it never draws the sprite in it's new location.
When you move the sprite down the screen, there has been enough time to erase the sprite and draw it before the monitor then draws it correctly.
So although you can sort the sprites in Y and draw them this way, or choose to draw them at a different interrupt, you will still have to think where on the screen you need to erase the sprite.
So it's not exactly as simple as you say ;)
I am also talking about a general method that works with many sprites and not just 1.
Well, it like the simple solution, usually it's the most efficient and therefore best. In my progs if works all fine. But we must separate two things here. a) to omit flickering b) to reduce flickering.
And I can only warn to use too complex strategies, they usually make it too slow. As Kolumbus alrady sayd: To be genious means to keep it simple. And like my old dad sayd: Everybody can make it complex. I always keep this things in mind.
Finally there will be one perfect strategy for every kind of resolution (x, y) and way of using split screens / overscan or just 16 K V-RAM.
Edit: I implicate that sprites are erased directly before they are redrawn, anything else makes no sense. To use erase/draw scanline cycles again cost too much time IHMO.
Quote from: TFM/FS on 19:49, 01 March 11
Well, it like the simple solution, usually it's the most efficient and therefore best. In my progs if works all fine. But we must separate two things here. a) to omit flickering b) to reduce flickering.
And I can only warn to use too complex strategies, they usually make it too slow. As Kolumbus alrady sayd: To be genious means to keep it simple. And like my old dad sayd: Everybody can make it complex. I always keep this things in mind.
Finally there will be one perfect strategy for every kind of resolution (x, y) and way of using split screens / overscan or just 16 K V-RAM.
Edit: I implicate that sprites are erased directly before they are redrawn, anything else makes no sense. To use erase/draw scanline cycles again cost too much time IHMO.
I agree that complex methods can make it slow.
Well let me be a student and learn ;)
New sources:
http://www.cpctech.org.uk/source/plot1.asm (http://www.cpctech.org.uk/source/plot1.asm)
http://www.cpctech.org.uk/source/plot2.asm (http://www.cpctech.org.uk/source/plot2.asm)
http://www.cpctech.org.uk/source/plot3.asm (http://www.cpctech.org.uk/source/plot3.asm)
http://www.cpctech.org.uk/source/plot4.asm (http://www.cpctech.org.uk/source/plot4.asm)
These examples show how to plot a pixel.
Each gets more and more low level, so you can see how the firmware functions work and also how to access pixels on the screen.
plot1.asm uses graphics functions to plot a pixel and works in any mode and with upper rom enabled/disabled. (GRA PLOT ABSOLUTE)
plot2.asm uses screen functions to plot a pixel and also works in any mode with upper rom enabled/disabled. (SCR DOT POSITION, SCR PIXELS, SCR INK ENCODE)
plot3.asm uses less screen functions to plot a pixel, works in any mode, but not with upper rom enabled. (SCR DOT POSITION, SCR INK ENCODE)
plot4.asm uses less screen functions, is now for mode 0, and doesn't work with upper rom enabled.
(SCR DOT POSITION)
EDIT1: These examples are not complete. Complete examples will be uploaded later today.
EDIT2: Samples complete and uploaded.
EDIT3:
http://www.cpctech.org.uk/source/plot4m1.asm
plot4.asm example for mode 1.
http://www.cpctech.org.uk/source/plot4m2.asm
plot4.asm example for mode 2.
Interesting the number of ways you can Plot onscreen! :-[
:-[ Of course I've been doing some work with GRA PLOT ABSOLUTE and forgot about having this one huge routine. ???
;; Tag Plot in Assembly
ORG &4000
ld a,1
call &bc0e
ld b,64 ;; Number of times to loop
ld de,data_xpos ;; Load Coordinate Position into DE
ld hl,data_ypos ;; Load Coordinate Position into HL
ld (adrxpos),de
ld (adrypos),hl ;; Store address of data
push hl
ld hl,data_color
ld (addrcolor),hl
pop hl
.loop ;; Begin of Loop
push hl
push af
ld hl,(addrcolor)
ld a,(hl)
call do_color
pop af
pop hl
ld de,(adrxpos) ;; Get contents of address of Data
;; into DE
inc de
inc de ;; Increase this by 2 data is 2 bytes in size
ld (adrxpos),de ;; Put this new address into address of data
ld hl,(adrypos) ;; Put address of ypos into hl
inc hl
inc hl ;; Increase this by 2 same as DE
ld (adrypos),hl ;; Put this new address into address of data
push bc
call do_plot ;; Call this routine
pop bc
djnz loop ;; Go back if B is greater than 0
ret ;; Otherwise Exit
.do_color
call &bbde
ld hl,(addrcolor)
inc hl
ld (addrcolor),hl
ret
.do_plot
ld b,(hl) ;; Store Contents of Lower HL (YPOS Data) into B
inc hl ;; Increase address of HL
ld c,(hl) ;; Store Contents of Upper HL (YPOS Data) into C
ld hl,ypos ;; Get Lower address of HL
ld (hl),b ;; And put value of B into it
inc hl ;; Increase this by 1
ld (hl),c ;; Now put value of C into it
;; What this has effecively done is move the contents
;; of ypos in particular, from one memory location to
;; another fixed location, for where the data can go
;; into the registers & then do a call to Plot Absolute
;; (&BBEA). I used to try doing this while moving the
;; address (e.g. Get contents of first xpos & ypos,
;; then move onto the second), course it maybe possible,
;; but I found this much easier.
ex de,hl ;; Exchange Contents of DE & HL
ld b,(hl) ;; Put Contents of HL (which was DE) into B
inc hl ;; Increase HL by 1
ld c,(hl) ;; Put that into C
ld hl,xpos ;; Get address of xpos
ld (hl),b
inc hl
ld (hl),c ;; Put contents into it
;; This is really just the same as above apart from getting the
;; address of xpos, I left it with this, instead of trying to
;; Poke my own program (by replacing YPOS address with XPOS).
ld de,(xpos) ;; So with all the data being at XPOS &
ld hl,(ypos) ;; YPOS, I can do a call for Plot Absolute
call &bbea
ret
;; Data Areas
.xpos defw 0 ;; Section where XPOS & YPOS goes
.ypos defw 0
.adrxpos defw 0 ;; This is the address of the data for XPOS
.adrypos defw 0 ;; Same as Above except for YPOS
.data_xpos
defw 0 ;; Leave this line here
defw 0,2,4,6,8,10,12,14 ;; Sample Data (XPOS)
defw 0,2,4,6,8,10,12,14
defw 0,2,4,6,8,10,12,14
defw 0,2,4,6,8,10,12,14
defw 0,2,4,6,8,10,12,14
defw 0,2,4,6,8,10,12,14
defw 0,2,4,6,8,10,12,14
defw 0,2,4,6,8,10,12,14
.data_ypos
defw 0 ;; Leave this line alone
defw 0,0,0,0,0,0,0,0 ;; Sample Data (YPOS)
defw 2,2,2,2,2,2,2,2
defw 4,4,4,4,4,4,4,4
defw 6,6,6,6,6,6,6,6
defw 8,8,8,8,8,8,8,8
defw 10,10,10,10,10,10,10,10
defw 12,12,12,12,12,12,12,12
defw 14,14,14,14,14,14,14,14
.data_color
defb 1,1,0,1,0,1,1,0
defb 0,3,3,3,3,3,0,0
defb 0,0,2,2,2,0,0,0
defb 0,0,2,2,2,0,0,0
defb 0,0,2,2,2,0,0,0
defb 0,0,2,2,2,0,0,0
defb 0,0,2,2,2,0,0,0
defb 0,0,0,1,0,0,0,0
.addrcolor
defw 0
Purpose? It's clearly not ideal for Sprite Handling, though it could be made to handle large fixed images without loading in 17k Screens perhaps. Maybe possible to reduce the size of this routine/program, by reducing the reoccuring xpos & ypos values. Otherwise it's simply another routine for the dust pile! 8)
Quote from: CP/M User on 11:08, 03 March 11
Interesting the number of ways you can Plot onscreen! :-[
Well each goes lower and lower level, so that the final one (not finished yet), calcs screen address of pixel, does all the masking and plotting itself.
Purpose? It's clearly not ideal for Sprite Handling, though it could be made to handle large fixed images without loading in 17k Screens perhaps. Maybe possible to reduce the size of this routine/program, by reducing the reoccuring xpos & ypos values. Otherwise it's simply another routine for the dust pile! 8)
I see, drawing a sprite or image using GRA PLOT ABSOLUTE. Interesting idea, and I am sure this works well with cpm.
BTW, I am happy to host any routines on my website in the source section.
So you don't have to let them disapear ;)
arnoldemu wrote:
Well each goes lower and lower level, so that the final one (not finished yet), calcs screen address of pixel, does all the masking and plotting itself.The way the experts would make it! ;D
QuotePurpose? It's clearly not ideal for Sprite Handling, though it could be made to handle large fixed images without loading in 17k Screens perhaps. Maybe possible to reduce the size of this routine/program, by reducing the reoccuring xpos & ypos values. Otherwise it's simply another routine for the dust pile! 8)
I see, drawing a sprite or image using GRA PLOT ABSOLUTE. Interesting idea, and I am sure this works well with cpm.Well it was only a part of another routine I had made ages ago (which I think I posted on this forum earlier - to see if it could be improved). Originally the idea was to see how this "Tag Plot" routine would perform as a sprite routine. Not really up to it - as demonstrated from my original Bouncing Ball program which is on my website. There would be some marginal improvement if all that code was in assembly, though I can still see some delay in it - obviously not really meant for plotting an image around the screen, it works (including in CP/M) great if you love slow motion! ;D
SCR HORIZONTAL on the other hand is look a bit more promising in terms of display rate time, won't really know how well it works moving things around til I get around to it, at the moment I'm studying the last program I made and writing in the what facts and figures I can code in to make an 8x8 move around. It probably won't ever be as fast as a true sprite routine, though if it's reasonible I may find something for it!
BTW, I am happy to host any routines on my website in the source section.
So you don't have to let them disapear ;) These routines I come up with are usually work-in-progress. I don't mind whoever wants them can most certainally have them, it's Public Domain at best I reckon! ;D This one I just posted I can certainally make it better by include a Double-byte Loop which would allow for larger images and make it work better that way. By only concern is allowing for larger images will blowout the number of co-ordinate positions, really needs to be written so the table would go:
x: 0,2,4,6,8,10,12,14
y: 0,2,4,6,8,10,12,14
Increment y from 0 to 2 when x has plotted out 14 and resetting x to 0 - thus producing the next line for x to plot the points along the y axis.
Updated sources:
http://www.cpctech.org.uk/source/pscrlvrt.asm
http://www.cpctech.org.uk/source/pscrlhrz.asm
(Added some chars to screen so scroll effect is seen better over whole screen)
http://www.cpctech.org.uk/source/hardscrl.asm
(Now checks for lower case chars for keys and has chars over the screen so effect is better)
http://www.cpctech.org.uk/source/scrlhrz.asm
(Chars over the screen to see effect better, checks for lower case chars for keys, fixed R3 scrolling in both directions)
New source:
http://www.cpctech.org.uk/source/sprfirm.asm
Demonstrates a lot of the scr functions, including SCR NEXT BYTE, SCR PREV BYTE, SCR NEXT LINE, SCR PREV LINE, SCR GET LOCATION, RAM LAM.
This moves a sprite (flickering) over a background.
It uses the firmware functions to read/write the screen in a way that works with upper rom enabled.
You can activate 2 different read functions and 2 different write functions.
One read using indirections (but the lower rom must be enabled for this to work), and one using RAM LAM.
And 2 different write functions (one writing direct, another using scr pixels).
New test source:
http://www.cpctech.org.uk/source/plusscrl.asm
Mid-line screen scrolling on plus
I need to test on a real +, I am not sure full scrolling would be possible.
But may be useful for some effects.
New source:
http://www.cpctech.org.uk/source/memcheck.asm
Memory check code used in Batman Forever demo.
To use:
1. call memcheck
2. call mem_check_contig_64_blocks
A register is the first configuration where there are 64k pages side by side that can be used. So you can access the ram with one base page.
mem_unique_configs is the list of page configurations that are valid and can be used.
Up to 512k dk'tronics compatible ram is supported by this code.
So for example, you can use the ram of a dk'tronics silicon disk on a 464 and the code will still detect as having enough ram. It will then give you the list of blocks (e.g. starting from cc).
More source will come soon, including some test code, and with the musical loader I'll write up all the things I discovered and worked out in order to make it work.
New source:
http://www.cpctech.org.uk/source/sftscrl.asm
Software scrolling the screen using the firmware and SCR SW ROLL.
This also demonstrates how you update a line of the screen, depending on the direction scrolling to maintain the scroll effect.
The scroll is in char sized increments (8 lines) and is only up and down.
New source:
http://www.cpctech.org.uk/source/hrdscrl.asm
Hardware scrolling the screen using the firmware and SCR HW ROLL.
This also demonstrates how you update a line of the screen, depending on the direction scrolling to maintain the scroll effect.
The scroll is in char sized increments (8 lines) and is only up and down.
The effect is poor, clearing the line and drawing the chars takes a long time using firmware, so you can't see the power of hardware scrolling, but demonstrates this function.
Two new sources:
http://www.cpctech.org.uk/source/expstr.asm (http://www.cpctech.org.uk/source/expstr.asm)
This example uses KM SET EXPAND and KM SET TRANSLATE to associate a string with a key. e.g. when you press F1 it could print "|DISC<CR>" in basic. Same kind of functionality as KEY DEF but in asm.
http://www.cpctech.org.uk/source/autotype.asm (http://www.cpctech.org.uk/source/autotype.asm)
This example autotypes a string in basic. It uses a frame flyback interrupt, it returns each char of a string using KM CHAR RETURN, it then monitors if that char has been read yet (so this locks it to firmware 1.1 at this time - CPC6128, Plus). Typing is not as fast as Markus has been able to do with his emu ;)
Both came about after discussion with somebody about autotyping strings in order to autoboot a program.
So here we go.
NOTE: KM CHAR RETURN is used to put 1 ASCII char into the keyboard buffer. However, when it's read, it is not decoded, so you can't assign it a string with KM SET EXPAND and expect it to display a whole string. Firmware just returns the char you gave it. ;)
Arrgh. I did another edit. And I thought I had just quoted :laugh:
EDIT: Is there a way for me to revert an edit I made to my own message?
Quote from: arnoldemu on 21:29, 05 June 11
Arrgh. I did another edit. And I thought I had just quoted :laugh:
EDIT: Is there a way for me to revert an edit I made to my own message?
Google Cache (http://webcache.googleusercontent.com/search?q=cache:Et0xNoKSUjUJ:cpcwiki.eu/forum/index.php%3Ftopic%3D668.75+%22CPC+Wiki+forum%22%2B%22ASM+Source+Code%22&cd=1&hl=en&ct=clnk&gl=au&source=www.google.com.au)?
I presume it's this post:
QuoteNew source:
http://www.cpctech.org.uk/source/fwdbuff.asm (http://www.cpctech.org.uk/source/fwdbuff.asm)
Double buffering using the firmware.
Demonstrates the firmware functions MC SCREEN OFFSET and SCR SET POSITION.
Yes, even with the firmware you can double buffer graphics to make them flicker free if you want.
New source:
http://www.cpctech.org.uk/source/fwdbuff.asm (http://www.cpctech.org.uk/source/fwdbuff.asm)
Double buffering using the firmware.
Demonstrates the firmware functions MC SCREEN OFFSET and SCR SET POSITION.
Yes, even with the firmware you can double buffer graphics to make them flicker free if you want.
(Thanks it was this one)
Quote from: arnoldemu on 09:12, 06 June 11
Double buffering using the firmware.
Fantastic, thanks for this.
Please can we sticky this topic?
Quote from: arnoldemu on 09:34, 05 July 12
Please can we sticky this topic?
Sure, but (since I haven't followed it), what is it about? The title isn't super-explanatory...
Quote from: Gryzor on 09:37, 05 July 12
Sure, but (since I haven't followed it), what is it about? The title isn't super-explanatory...
ASM is shorthand for ASseMbly which usually reflects the 'asm' extension for the source code. Sometimes people might use a different extension (e.g. '.Z80'), if they want to emphasise which form of CPU their using (useful when you're dealing with a site which deals with several different platforms).
Normally if I want to look at something though I visit the 'Unofficial Amstrad WWW Resource' site though. :D
I though that Gryzor did not ask about the mean of ASM but about the goal/content of the topic, to know how to "stick it". :)
Quote from: Gryzor on 09:37, 05 July 12
Sure, but (since I haven't followed it), what is it about? The title isn't super-explanatory...
In this topic I, and others, have posted links to various example programs written in z80 assembly language.
Some of these show how to use firmware functions, others to draw sprites.
I requested the sticky because I think others would be interested to look through the posts to help them learn coding on the cpc.
If you could change the topic title to "Example Z80 assembly programs" that would be great too.
@TotO, thanks, that's indeed what I was wondering about
@Arnoldemu, sure, will do it right away :)
This is my most refined example I've made which is using GRA LINE ABSOLUTE to draw a series of lines (from the example provided) from a loop. I made an earlier example (which I might of posted elsewhere), though in this one I've setup 2 address pointers which points to the data I want to display in memory. My earlier example was taking the data from one spot, and moving it into another area and GRA LINE ABSOLUTE was accessing it from there. That method worked, though seemed to be a run around approach which I felt could be improved. This is the result.
;; Draw loop in Assembly
;; CP/M User
ORG &4000 ;; This routine can go almost anywhere
;; Initialiation stuff
;; ld a,1
;; call &bc0e ;; SCR SET MODE, Routine will work in any mode which is set.
ld a,1
call &bbde ;; GRA SET PEN (PEN 1)
ld de,100 ;; xpos position to start at
ld hl,100 ;; ypos position to start at
;; Changing these values will change where and how image is to be drawn.
call &bbc0 ;; GRA MOVE ABSOLUTE
;; Setup size of the Loop with points to plot
ld b,4 ;; number of points to loop for image
.loop ;; The main loop
ld hl,(adrypos) ;; Address contents which points to image data for ypos goes into HL
ld e,(hl) ;; \
inc hl ;; - Contents of HL which is ypos data (16bit number) goes into DE
ld d,(hl) ;; /
ex de,hl ;; That information (ypos data) needs to go into HL register
push hl ;; But I need to protect that information so I can use HL.
ld hl,(adrxpos) ;; Address contents which points to image data for xpos goes into HL
ld e,(hl) ;; \
inc hl ;; - The same process now happens for xpos data (16bit number) going into DE
ld d,(hl) ;; /
pop hl ;; I can now restore that ypos data back into HL...
push bc ;; ...though I need to protect the loop counter.
call &bbf6 ;; GRA LINE ABSOLUTE, Entry: HL = y-coordinate, DE = x-coordinate
;; Exit: AF, BC, DE & HL corrupt.
pop bc ;; Restore loop counter.
ld hl,(adrxpos) ;; \
inc hl ;; - This moves address pointer for xpos to the following address & stores it.
inc hl ;; - Because 16bit data is being used, HL is incremented twice.
ld (adrxpos),hl ;; /
ld hl,(adrypos) ;; \
inc hl ;; - And the same thing applies for the address pointer for ypos data.
inc hl ;; - And again 16bit data is used.
ld (adrypos),hl ;; /
djnz loop ;; If loop counter hasn't being reached,
;; loop counter is decreased by 1 until B = 0.
;; The following address pointer will then be used.
ld hl,data_xpos ;; \
ld (adrxpos),hl ;; :
;; - Once loop is finished, the data points for xpos & ypos needs to be restored.
ld hl,data_ypos ;; :
ld (adrypos),hl ;; /
ret ;; Returns to BASIC (if called from there).
.adrxpos
defw data_xpos
.adrypos
defw data_ypos
.data_xpos
defw 100,200,200,100,0 ;; Standard graphic points to draw for xpos.
.data_ypos
defw 200,150,100,100,0 ;; Standard graphic points to draw for ypos.
The pseudo random number generator from the cpcrslib for SDCC.
Look simple and efficient, as shown into the game named Totems (http://www.cpcwiki.eu/forum/news-events/totems-by-esp-soft/).
_cpc_Random::
LD A,(#valor_previo)
LD L,A
LD A,R
ADD L
LD (#valor_previo),A
LD L,A
LD H,#0 ; value return in HL
RET
valor_previo:
.db #0xFF
A few years ago, i put a lot of snippets in this thread (http://www.amstrad.es/forum/viewtopic.php?f=6&t=1680) of the spanish forum, feel free to use them, and if somebody needs english comments, only ask :)
A new example:
http://www.cpctech.org.uk/source/colour_split.asm (http://www.cpctech.org.uk/source/colour_split.asm)
This example changes the whole palette at each interrupt. The screen is set to mode 1 and text is printed for each pen. (pen 1, pen 2, pen 3).
So here you can see how games change colours on the screen to give the illusion there are more colours than just 4 in mode 1.
This example uses the firmware.
If a sprite moves between the areas, then it's colours will automatically change, in this way we have our own kind of "colour clash".
A new example:
This shows how you can setup a double buffered overscan ("32k style") screen that fits within 64k.
It's a simple example that clears each screen and flips between them.
The screen is 46 wide and 32 tall.
The comments at the top show the free memory ranges that can be used and the size of ram if no scrolling is used.
This is not a "crossfire" example.
normal interrupt mode 1 interrupts are available.
biggest range is 1152 bytes. others are smaller.
if you wanted to, a simple game could fit into the memory ranges, with code organised all over the memory.
for a 64k machine it doesn't leave much room (20k total), but would be an interesting challenge.
For showing a double buffered overscan screen it's fine, although you would need to load the screens in a single block and reorganise them after loading. I can knock up an example that does just this another day, so opening up some nice graphical techniques for the "lowly poor 64k machines that get much hate" ;)
http://www.cpctech.org.uk/source/overdbf.asm (http://www.cpctech.org.uk/source/overdbf.asm)
NOTE: The locations of the screens have been carefully chosen so that the "problem" addresses appear on the right side (or perhaps left, can't remember, therefore making sprite routines easier and faster to make).
NOTE2: In addition the address has been chosen, so there is the potential for the firmware to be used to load all the data, then turn it off, and re-arrange it to get the final layout.
I had Kevin help me with this many years ago which shows the process of setting up a Table for Sprites along with the processes for moving a sprite around the screen. I made a couple of improvements to the code as well.
org &4000
.conkey equ &bb1e
ld a,0
call &bc0e
ld bc,&0101
call &bc38
call setcolors
call initialise
ld hl,(xpos)
call findcolumn
ld (scradr),hl
ex de,hl ;; ld de,(scradr) <- ex de,hl is more efficent way to get something from HL to DE.
ld hl,sprdata
ld b,8
ld c,15
call disspr
.mainloop
call control
ld a,66 ;; Check if ESC has been Pressed
call conkey ;; Routine to Check for Key Pressed
jr z,mainloop ;; Return to Mainloop if ESC has not been pressed
call &bc02 ;; Otherwise Proceed to Exit, Reset Colours
ld a,2 ;; And Return
call &bc0e ;; To Mode 2.
ret ;; Return to BASIC if called from there.
;; .conkey
;; call &bb1e ;; Disabled cause there's no real need to have
;; ret ;; as a routine plus save a byte :)
.setcolors
ld hl,sprcolor ;; Address to INK Colours
ld a,0 ;; PEN Number
.colloop
ld c,(hl) ;; Contents of INKs is stored into C
ld b,c ;; and B Registers.
push af ;; Protect PEN Number Value
push hl ;; And the Address to the INK Colours
call &bc32 ;; SCR SET INK
pop hl ;; Restore Address to the INK Colours
pop af ;; Restore PEN Number Value
inc hl ;; Point to next address for INKS
inc a ;; Increase PEN Number
cp 10 ;; Has PEN 15 been reached?
jr c,colloop ;; Jump to Loop if value hasn't been reached.
.control
ld a,8 ;; Was Left Arrow Key Pressed?
call conkey ;; KM TEST KEY
jr nz,moveleft ;; Proceed to moveleft if it has
ld a,1 ;; Was Right Arrow Key Pressed?
call conkey ;; KM TEST KEY
jr nz,moveright ;; Proceed to moveright if it has
ld a,0 ;; Was Up Arrow Key Pressed?
call conkey ;; KM TEST KEY
jr nz,moveup ;; Proceed to moveup if it has
ld a,2 ;; Was Down Arrow Key Pressed?
call conkey ;; KM TEST KEY
jp nz,movedown ;; Proceed To movedown if it has.
;; ld a,66
;; call conkey
;; jr nz,exit
ret
.moveleft
ld a,&0 ;; Does Accumulator = 0
ld hl,(xpos)
cp h ;; Check with XPOS
jp nz,doleft ;; Only Move if possible.
.showleft
ld hl,(xpos) ;; New Position of XPOS
call findcolumn ;; Convert XPOS into Screen Address
ld (scradr),hl ;; Store New Screen Address
ex de,hl ;; ld de,(scradr) ;; Put this into DE
ld hl,sprdata ;; Sprite address to HL
ld b,8 ;; Length
ld c,15 ;; Width
call disspr ;; Display Sprite
ret
.doleft
ld hl,(xpos) ;; Proceed to Decrease XPOS
dec h
ld (xpos),hl ;; Store new value to XPOS.
jp showleft ;; And proceed to Display in New Position.
.moveright
ld a,&46
ld hl,(xpos)
cp h
jp nz,doright
.showright
ld hl,(xpos)
call findcolumn
ld (scradr),hl
ex de,hl ;; ld de,(scradr)
ld hl,sprdata
ld b,8
ld c,15
call disspr
ret
.doright
ld hl,(xpos)
inc h
ld (xpos),hl
jp showright
.moveup
ld a,&0
ld hl,(xpos)
cp l
jp nz,doup
.showup
ld hl,(xpos)
call findcolumn
ld (scradr),hl
ex de,hl ;; ld de,(scradr)
ld hl,sprdata
ld b,8
ld c,15
call disspr
ret
.doup
ld hl,(xpos)
dec l
ld (xpos),hl
jp showup
.movedown
ld a,&b6
ld hl,(xpos)
cp l
jp nz,dodown
.showdown
ld hl,(xpos)
call findcolumn
ld (scradr),hl
ex de,hl ;; ld de,(scradr)
ld hl,sprdata
ld b,8
ld c,15
call disspr
ret
.dodown
ld hl,(xpos)
inc l
ld (xpos),hl
jp showdown
.findcolumn
;; H = x coordinate (0-79)
;; L = y coordinate (0-199)
;; HL = screen address (top-left of sprite)
push bc ;; store BC because we are modifying it in this
;; routine
push de ;; store DE because we are modifying it in this
;; routine
ld c,h ;; store x coordinate in C register
ld h,0 ;; L = y coordinate, H = 0
add hl,hl ;; double L. Now L is a byte offset from the
;; start of the table pointing to the
;; entry corresponding to screen Y
;; coordinate. We double because each entry
;; is two bytes.
ld de,table ;; base of table
add hl,de ;; add offset to base to get actual address in
;; memory of the table entry
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ;; HL = value from table. it is the screen
;; address for the start of this line
;; corresponding to the Y coordinate
ld b,0 ;; BC = x coordinate as a 16-bit value. C = x
;; coordinate
add hl,bc ;; add on X coordinate
;; HL = final screen coordinate for x,y position
pop de ;; restore registers we used
pop bc
ret
.initialise ;; Routine to Setup Screen Addresses to Table.
ld de,table
ld hl,&c000
ld b,&19
.next
push bc
push hl
ld b,&8
.loop
push bc
ld a,l
ld (de),a
inc de
ld a,h
ld (de),a
inc de
ld bc,&800
add hl,bc
pop bc
djnz loop
pop hl
ld bc,&50
add hl,bc
pop bc
djnz next
ret
.disspr
;; Entry Conditions:
;;
;; DE = Sprite Address to display sprite at
;; HL = Sprite Location
;; B = Sprite Width
;; C = Sprite Height
LD A,B
LD (p1+1),A
.loop1
PUSH DE
.p1
LD B,&0
.loop2
LDI
INC C
DJNZ loop2
POP DE
LD A,D ;;
ADD &8 ;;
LD D,A ;;
JR NC,end ;;
LD A,E ;; Step down a line
ADD &50 ;;
LD E,A ;;
LD A,D ;;
ADC &C0 ;;
LD D,A ;;
.end
DEC C
JR NZ,loop1
RET
.table
defs 400 ;; 200 scanlines * 2 for the size of each entry.
.scradr
defw &c000
.xpos
defb &00
.ypos
defb &00
.scrrow
defb 0
.sprcolor
defb 0,26,0,6,3,15,18,1,2,20,0
.sprdata
defb 12,12,12,12,12,12,12,12
defb 8,0,0,0,0,0,0,4
defb 8,0,&54,&fc,0,0,0,4
defb 8,0,&a9,3,&a8,0,0,4
defb 8,0,&f0,&f0,&a0,0,0,4
defb 8,&44,&f0,&a0,&a0,0,0,4
defb 8,&44,&e4,&70,&a0,0,0,4
defb 8,&44,&b0,&10,&20,0,0,4
defb 8,&44,&b0,0,0,0,0,4
defb 8,0,&e4,&30,&20,&68,0,4
defb 8,0,&83,&e9,&83,&16,&80,4
defb 8,&41,&d6,&fc,&a8,&68,0,4
defb 8,0,&56,&56,2,0,0,4
defb 8,0,&c3,&41,&82,0,0,4
defb 8,0,0,0,0,0,0,4
defb 12,12,12,12,12,12,12,12
This routine is nice and fast.
Could you do the same with a sprite which doesnt destroy the background?
Quote from: Devilmarkus on 14:09, 12 January 13
This routine is nice and fast.
Could you do the same with a sprite which doesnt destroy the background?
Not with the Sprite Driver I'm using because it wasn't designed for Pixel Accuracy (as explained in the article). The routine comes from AA53 Cracking the code p39-40. There is another example on p40 which I think is more about the accuracy, though more processes are involved within the routine.
I was looking at some other sprite routines Rob Buckley at in AA112 p16 & AA113 p16 as well, which relates more to drawing sprites with a Background or over other Sprites, though I'm a bit of a dunce when it comes to how they work because the articles were limited in space. :'(
Sean McManus had some interesting example ESD2 I think it's called which had some Pixel Accurate Sprites moving over one another which looks a little bit more in my league, not sure if that's his example from the AA112-113 issues.
I've had a look at this simple 8bit Random Number Generator which is on the Wiki and I've strapped a simple 8bit Unsigned Divide and I've loaded the Accumulator with 20 which produces some Random Like Results between 0 & 19:
;; 8 Bit Random Number Generator
org &4000
.rand8 ld a,(seed)
ld b,a
add a,a
add a,a
add a,b
inc a
ld (seed),a
ld a,20 ;; Divide Begins here
ld c,a
ld a,0
ld hl,(seed)
ld b,16
.divide add hl,hl
rla
cp c
jr c,end
sub c
inc l
.end djnz divide
ld (result),a
ret
.seed defb 0
defb 0
.result defb 0
Here's a little test program (in BASIC) :D
10 FOR a=1 TO 1000:CALL &4000:PRINT "Seed:";PEEK(&4022);" ";"Result:";PEEK(&4024):NEXT a
Any docs on how to read from disk, not using the firmware?
Thank you for this great thread!
Quote from: AugustoRuiz on 16:09, 27 March 13
Any docs on how to read from disk, not using the firmware?
Thank you for this great thread!
I've got some example code already. I'll dig it out.
You want code that goes directly to the 765 disc controller?
I'd like to read a big file in chunks, so I can process each chunk while reading the next one. For audio playing ;)
Quote from: AugustoRuiz on 22:49, 27 March 13
I'd like to read a big file in chunks, so I can process each chunk while reading the next one. For audio playing ;)
a musical disc loader is different from a normal loader.
I do have a musical loader.
I will post the code to a normal loader first.
http://www.cpctech.org.uk/source/fdcload.asm (http://www.cpctech.org.uk/source/fdcload.asm)
Simple loader that reads whole sectors into memory.
I will update the comments for the source to explain more about what the code means.
Quote from: arnoldemu on 12:15, 29 March 13
http://www.cpctech.org.uk/source/fdcload.asm (http://www.cpctech.org.uk/source/fdcload.asm)
Simple loader that reads whole sectors into memory.
I will update the comments for the source to explain more about what the code means.
more comments added.
EDIT: And more added.
If you read the comments perhaps you will get ideas of how a musical loader is done ;)
I will post other code soon, building up to a release of my musical loader code.
I want people to understand how it is possible, and the theory behind it.
Thank you so much!
Example of how to make a multi-load game/program:
http://www.cpctech.org.uk/download/modasm.zip (http://www.cpctech.org.uk/download/modasm.zip)
In this asm example I use pasmo because it makes .lst files that can be included in other asm files.
main.s is built, it has the main functions and the main code. lst is generated that has it's labels.
Now I build level.s and include the labels from main. One label defines where level.s should be located, others are used so we can call functions in main.
main.s loads level.s and executes it, so we can see how we can have code and data in the levels.
So to load next level, we only need to call a function in main to load the level and execute it.
we could have level1.s level2.s level3.s all setup like level.s.
And there we have our multi-load game/program.
This shows how easy it is to do with pasmo and asm.
This is what I've come up with in Assembly today which is the Z80 equivalent of Chris Wootton Starscroller 10-Liner from October 1990 ACU.
Originally when I compiled what I'd written (in Winape Assembler), it was functioning with a "jr mainloop" jumping back to it, though it appeared to be exceeding the -126 bytes limit and yet it the program was still functioning.
My other quibble at the moment with the random number generator is to do with producing numbers between 0-640 for the random horizontal alignment, unfortunately I don't really quite understand why. I created a divider which kind of produces numbers within that range, but at the moment it's like I've put the largest as one part of my result (&FF) & my second part of the result is producing numbers between 0-7, I've only put it like that cause it seems to be the best random result. Earlier I had it setup so my first random result was between 0-80 & my second being 0-2 so it would look like it was somewhere between 0 & 280h which would give me my random 640, though the results were trending, not sure why. :(
org &4000
.inkey equ &bb09
.mode equ &bc0e
.inks equ &bc32
.border equ &bc38
.print equ &bb5a
.matrix equ &bba8
.plot equ &bbea
.pen equ &bb90
.grapen equ &bbde
.scroll equ &bc4d
.locate equ &bb75
.frame equ &bd19
.colres equ &bc02
call setup
ld a,(xpos)
ld h,a
ld l,25
call locate
ld a,254
call print
ld a,255
call print
ld hl,direction
ld a,&3d ;; dec a
ld (hl),a
.mainloop
call inkey
cp &0d
jr z,exit
ld a,(xpos)
.direction
defb 0 ;; Decrement/Increment goes here.
ld (xpos),a
ld h,a
ld l,25
call locate
call frame
ld a,254
call print
ld a,255
call print
call frame
ld a,(xpos)
cp &1 ;; checks for xpos value and
call z,change_value1 ;; call appropriate routine if true
ld a,(xpos)
cp &13 ;; checks for xpos value and
call z,change_value2 ;; call appropriate routine if true
ld hl,divider
ld a,3 ;; get a value between 0..3
ld (hl),a
call rand8 ;; has to look random
inc a ;; has to be a value between 1 & 4
ld (result),a ;; not sure
ld a,(result) ;; why I'm doing this
call grapen
ld hl,divider
ld a,255 ;; first random number be a large as possible
ld (hl),a
call rand8
ld (result),a ;; store into result
ld hl,divider
ld a,7 ;; not sure why 7, seems to create random effect
ld (hl),a
call rand8
ld (result+1),a ;; a trick way of making a 16bit random from a 8bit
;; number generator. Not sure how effective it is.
;; Wanted to produce random numbers between 0 & 640.
ld de,(result)
ld hl,398
call plot
ld b,0
ld a,0
call scroll
jp mainloop ;; This was a jr maintop, but I think it would of been
;; illegal on a real cpc because it exceeded -126
;; bytes!!
.exit ret
.setup xor a
call mode
ld a,4
call pen
ld bc,0
call border
ld hl,colours
ld a,0
.setup_inks
ld c,(hl)
ld b,c
push af
push hl
call inks
pop hl
pop af
inc hl
inc a
cp &5
jr c,setup_inks
ld a,254
ld hl,pattern1
call matrix
ld a,255
ld hl,pattern2
call matrix
ret
.change_value1
ld hl,direction
ld a,&3c ;; inc a
ld (hl),a
ret
.change_value2
ld hl,direction
ld a,&3d ;; dec a
ld (hl),a
ret
.rand8 ld a,(seed)
ld b,a
add a,a
add a,a
add a,b
inc a
ld (seed),a
ld a,(divider)
ld c,a
ld a,0
ld hl,(seed)
ld b,16
.divide add hl,hl
rla
cp c
jr c,end
sub c
inc l
.end djnz divide
ret
.colours
defb 0,26,26,13,6
.pattern1
defb 1,1,65,67,71,127,67,1
.pattern2
defb 128,128,130,194,226,254,194,128
.xpos defb 10
.seed defb 7
.result defb 0,0
.divider
defb 3
Quote from: AMSDOS on 11:21, 10 June 13
My other quibble at the moment with the random number generator is to do with producing numbers between 0-640 for the random horizontal alignment
It's random enough for the routine, but actually not very random. If you turn off the call to the firmware scroll you'll see it build up on the top line of the screen.
You could poke the "stars" directly to the screen memory instead. This is &50 (80) bytes wide which would mean an easier 8-bit random routine. There's also enough head room (bit 7, i.e. 128, on or off) to also include whether or not the "star" gets shown in the first or second pixel of the byte.
The inks in your routine are set to 0,26,26,13 and 6. This is why you're requiring another call of the random routine between the ranges of 0-3 because this selects one of the INKs before drawing the star. So the choices are 0 (black = no star), 26 (white), 26 (white) or 13 (grey). The routine therefore should draw twice as many white stars as grey stars, and sometimes it draws a black star too.
Quote from: AMSDOS on 11:21, 10 June 13
This is what I've come up with in Assembly today which is the Z80 equivalent of Chris Wootton Starscroller 10-Liner from October 1990 ACU.
Tenuously linked post ahead!If you're interested, here's the horizontal star-scroller from the XOR cracktros...
Just assmeble in WinAPE/Maxam and CALL &A000 to see what it does. If you're using WinAPE, then it's best to keep the boot-screen up, so you can see that it doesn't affect the text on screen while it runs.
For better results, try changing the background colours to #00 (BLACK) and inks 1 & 3 to #26 (BRIGHT WHITE) and 13 (WHITE) respectively. It gives a slight impression of a star-trail as it moves across the screen.
org #a000
.inflp call stars
jp inflp
.stars ld de,#0000
ld hl,here2
ld b,25
.loop1 ld a,(hl)
ld e,a
inc hl
ld a,(hl)
ld d,a
dec hl
ld a,(de)
cp #fe
jr nz,jump1
xor a
ld (de),a
.jump1 inc de
ld a,d
cp #00
jr nz,jump2
push hl
ld hl,#c000
add hl,de
ex de,hl
pop hl
.jump2 ld a,(de)
cp #00
jr nz,jump3
ld a,#fe
ld (de),a
.jump3 ld a,e
ld (hl),a
inc hl
ld a,d
ld (hl),a
inc hl
djnz loop1
ld hl,here3
ld b,25
.loop2 ld a,(hl)
ld e,a
inc hl
ld a,(hl)
ld d,a
dec hl
ld a,(de)
cp #fe
jr nz,jump4
xor a
ld (de),a
.jump4 inc de
inc de
ld a,d
cp #00
jr nz,jump5
push hl
ld hl,#c000
add hl,de
ex de,hl
pop hl
.jump5 ld a,(de)
cp #00
jr nz,jump6
ld a,#fe
ld (de),a
.jump6 ld a,e
ld (hl),a
inc hl
ld a,d
ld (hl),a
inc hl
djnz loop2
call #bd19
ret
.here2
db #00,#c0,#55,#c0,#c0,#c0,#f4,#c0
db #68,#c1,#a9,#c1,#20,#c2,#55,#c2
db #82,#c2,#e0,#c2,#4a,#c3,#a0,#c3
db #d9,#c3,#49,#c4,#a0,#c4,#d9,#c4
db #48,#c5,#65,#c5,#c6,#c5,#fa,#c5
db #85,#c6,#d5,#c6,#20,#c7,#49,#c7
db #a0,#c7
.here3
db #30,#d0,#90,#d8,#a0,#f0,#10,#d1
db #7a,#e1,#a0,#e9,#00,#ca,#30,#d2
db #b0,#e2,#e0,#ea,#50,#d3,#75,#db
db #e0,#f3,#20,#d4,#a0,#cc,#e9,#dc
db #0a,#ed,#65,#dd,#a9,#d5,#15,#f6
db #85,#ee,#a5,#ee,#ff,#ce,#4a,#e7
db #b0,#ef
(P.S. The code isn't originally mine, so I'm not trying to steal the glory here or anything!)
Nice stars!
When you change this:
.inflp call stars
jp inflp
to:
.inflp call stars
ret
you can call it from BASIC like:
10 CALL &A000:GOTO 10
Quote from: redbox on 11:42, 10 June 13
It's random enough for the routine, but actually not very random. If you turn off the call to the firmware scroll you'll see it build up on the top line of the screen.
You could poke the "stars" directly to the screen memory instead. This is &50 (80) bytes wide which would mean an easier 8-bit random routine. There's also enough head room (bit 7, i.e. 128, on or off) to also include whether or not the "star" gets shown in the first or second pixel of the byte.
This seems to be a good idea, I'm not quite sure if it would work, would rolling the screen change the offset, I was just wondering if using SCR Pixels would be better since it asks for a PEN mask, Pixel Mask & Screen Address.
I started off playing around with the random number routine to generate a random colour number, and then use a routine (I was familiar with from AA) to work out which byte to use in relation to that, though that wasn't quite working for me. :(
QuoteThe inks in your routine are set to 0,26,26,13 and 6. This is why you're requiring another call of the random routine between the ranges of 0-3 because this selects one of the INKs before drawing the star. So the choices are 0 (black = no star), 26 (white), 26 (white) or 13 (grey). The routine therefore should draw twice as many white stars as grey stars, and sometimes it draws a black star too.
That is correct (those are the original ink colours from the program I got it from), initially the Simple Random Number routine I'm using to get random number, I've stuck a divider on it (from another book ;D ), which returns numbers within the specified range, so in this case I made it ld a,3 which gives me numbers between 0..2 (not 0..3, which is a commented mistake :o ), and after that process I've increased the value of A which should give values between 1 to 3 and not 1 to 4 as I've mistakingly written in. So there shouldn't be any Red stars which I haven't noticed and no black ones because the value will always be greater than 0.
Quote from: AMSDOS on 13:04, 11 June 13
I'm not quite sure if it would work, would rolling the screen change the offset
Good point.
But I'm always looking at it from an optimisation point of view, which of course would mean completely removing use of the firmware which isn't the point of your project ;)
Nice to see what you've done though and you've exposed some of the issues of translation between BASIC > Firmware > Assembler and vice versa. The firmware (which in turn BASIC uses) has some excellent routines which don't have the confines of rigid "8/16-bit ness", but the caveat is that they're generally slow.
Quote from: redbox on 13:10, 11 June 13
Good point.
But I'm always looking at it from an optimisation point of view, which of course would mean completely removing use of the firmware which isn't the point of your project ;)
Initially when I started writing this Assembly version, I was looking for a way to write an assembly equivalent of "xpos:=xpos+xdir" with "xdir" either being 1 or -1, which I did by checking the values of the position and poking the appropriate "INC" or "DEC" to reverse the direction of the Space craft that way.
Though now it looks like I'll need to find a better random number generator if I'm to apply it in the 0-640 number range or use the screen to position the stars. With the current routine I'm using, I was think in terms of 640 as 280h, and was trying to apply numbers between 0-80 as my low byte and numbers between 0-2 as my high byte, though when I applied that, the program was generating a distinctive pattern and a trending pattern of Stars across the screen with areas appearing to be out of range. :-X The program I posted sets up the low byte divider to be anything from 0-FFh & 0-7h (I think) for the high byte, which makes the stars appear more random, though because it's setup like that, there are numbers exceeding the 640 limit, which is why some stars won't even be shown, hence the gaps along the line numbers.I figure that if a 16bit Random Number generator produces numbers between 0-65535, then to get it back close to the 0-640 range it only has to be divided by 102 times, though I'm not very good on these Shift and Rotating instructions if they are other little tricks or faster ways of calculating results within certain ranges.QuoteNice to see what you've done though and you've exposed some of the issues of translation between BASIC > Firmware > Assembler and vice versa. The firmware (which in turn BASIC uses) has some excellent routines which don't have the confines of rigid "8/16-bit ness", but the caveat is that they're generally slow.
BASIC might use the firmware, though Assembly or a Compiled Language can improve it by taking machine language immediately. Yeah it's not perfect, though for this program it's fine and can be improved. :D
Quote from: AMSDOS on 11:05, 12 June 13
Though now it looks like I'll need to find a better random number generator if I'm to apply it in the 0-640 number range or use the screen to position the stars. With the current routine I'm using, I was think in terms of 640 as 280h, and was trying to apply numbers between 0-80 as my low byte and numbers between 0-2 as my high byte, though when I applied that, the program was generating a distinctive pattern and a trending pattern of Stars across the screen with areas appearing to be out of range. :-X
...
I figure that if a 16bit Random Number generator produces numbers between 0-65535, then to get it back close to the 0-640 range it only has to be divided by 102 times, though I'm not very good on these Shift and Rotating instructions if they are other little tricks or faster ways of calculating results within certain ranges.
If you have random numbers in the range 0..32767 (which IIRC you do, you can do this):
; entry HL = 15 bit random number
; exit HL = scaled to 0..639, A and BC corrupted, carry clear
ld b,h
ld c,l
xor a
add hl,hl ; *2 (HL now 0..65534)
add hl,hl ; *2 (HL now 0..65532)
adc a,a ; carry into A (A:HL now 0..131068)
add hl,bc ; *5
adc a,0 ; A:HL now 5*original or 0..163835
ld l,h
ld h,a ; HL now in range 0..639 (163835/256)
Thanks for that, it has made a difference and things appear a bit more random. :)
org &4000
.inkey equ &bb09
.mode equ &bc0e
.inks equ &bc32
.border equ &bc38
.print equ &bb5a
.matrix equ &bba8
.plot equ &bbea
.pen equ &bb90
.grapen equ &bbde
.scroll equ &bc4d
.locate equ &bb75
.frame equ &bd19
call setup
ld a,(xpos)
ld h,a
ld l,25
call locate
ld a,254
call print
ld a,255
call print
ld hl,direction
ld a,&3d
ld (hl),a
.mainloop
call inkey
cp &0d
jr z,exit
ld a,(xpos)
.direction
defb 0
ld (xpos),a
ld h,a
ld l,25
call locate
call frame
ld a,254
call print
ld a,255
call print
call frame
ld a,(xpos)
cp 1
call z,change_value1
ld a,(xpos)
cp 19
call z,change_value2
call rand8
srl a
srl a
srl a
srl a
srl a
srl a
srl a
inc a
ld (result),a
ld a,(result)
call grapen
call rand8
ld (result),a
call rand8
srl a
ld (result+1),a
ld hl,(result)
call scale_number
ld (result),hl
ex hl,de
ld de,(result)
ld hl,398
call plot
ld b,0
ld a,0
call scroll
jp mainloop
.exit ret
.setup xor a
call mode
ld a,4
call pen
ld bc,0
call border
ld hl,colours
ld a,0
.setup_inks
ld c,(hl)
ld b,c
push af
push hl
call inks
pop hl
pop af
inc hl
inc a
cp &5
jr c,setup_inks
ld a,254
ld hl,pattern1
call matrix
ld a,255
ld hl,pattern2
call matrix
ret
.change_value1
ld hl,direction
ld a,&3c
ld (hl),a
ret
.change_value2
ld hl,direction
ld a,&3d
ld (hl),a
ret
.rand8 ld a,(seed)
ld b,a
add a,a
add a,a
add a,b
inc a
ld (seed),a
ret
.scale_number
;; entry HL = 15 bit random number
;; exit HL = scaled to 0..639,
;; A & BC Corrupt, carry clear
ld b,h
ld c,l
xor a
add hl,hl ;; *2 (HL now 0..65534)
add hl,hl ;; *2 (HL now 0..65532)
adc a,a ;; carry into A (A:HL now 0..131068)
add hl,bc ;; *5
adc a,0 ;; A:HL now 5*original or 0..163835
ld l,h
ld h,a ;; HL now in range 0..639 (163835/256)
ret
.colours
defb 0,26,13,0,6
.pattern1
defb 1,1,65,67,71,127,67,1
.pattern2
defb 128,128,130,194,226,254,194,128
.xpos defb 10
.seed defb 127
.result defb 0,0
This is what I've come up with and have now implemented srl to shift the values into their appropriate places (instead of relying on a Divide).
For the coloured stars, I'm using "srl a" 7 times which gets me a value between 0 & 1 depending on what number seed comes out of the 8bit random number generator. Don't need 0 so I'm adding 1 which will get me either 1 or 2, which seems good enough, I wasn't sure if there was a better way of doing it instead of having 7 "srl a" though. :)
To get a number between 0..32767 though, it seems ideal to have a "srl" in there instead of a whole Divide and cuts down on the code. :D
Quote from: AMSDOS on 04:14, 19 December 10
I hope no-one minds me posting this old dinosaur of a routine in here!
org &4000
.setup
LD A,1 ;; My crude routine for setting up Scr_Mode
CALL &BC0E
LD A,240 ;; Setup Symbol Table - A Holds Character value
LD HL,ship1 ;; HL points to Symbol Data to Define to
CALL &BBA8 ;; Firmware routine to Redefine Symbol Table.
LD A,241
LD HL,ship2
CALL &BBA8
LD A,242
LD HL,ship3
CALL &BBA8
LD A,243
LD HL,ship4
CALL &BBA8
.init
ld hl,&140C ;; Initial Position
LD A,0 ;; Initial Direction
.loop
PUSH HL ;; Start of Main Loop
PUSH AF
CALL &BB75 ;; TXT SET CURSOR
POP AF
PUSH AF
ADD A,240 ;; graphic code
CALL &BB5D ;; Print
LD BC,&0C00 ;; Start Short Delay
.shtdel
DEC BC
LD A,B
OR C
JR NZ,shtdel ;; loop back if Non Zero
POP AF
POP HL ;; only HL actually wanted
PUSH HL
PUSH AF ;; the next call corrupts AF & HL
CALL &BB75 ;; TXT SET CURSOR
LD A,32 ;; code for space
CALL &BB5D ;; Print
LD A,0 ;; code for up arrow
CALL &BB1E ;; KM TEST KEY
JR Z,proa ;; Jump if Key Up
POP AF ;; reclaim direction code
POP HL ;; ..and position
CP 0 ;; Compare A with 0 - up?
JR NZ,right ;; Jump to check Right if Not
DEC L ;; Up a row
JR newpos ;; Jump to the next position
.right
CP 1 ;; Compare with 1 - right?
JR NZ,down
INC H ;; Right one column
JR newpos
.down
CP 2 ;; Down?
JR NZ,left
INC L ;; Down a row
JR newpos
.left
DEC H ;; Left - no check needed here
.newpos
PUSH HL ;; Save new position
PUSH AF ;; Protect A from the TEST KEY call
.proa
LD A,1 ;; key code for right arrow
CALL &BB1E ;; KM TEST KEY
JR Z,lftar ;; Zero if not pressed
POP AF ;; old direction
ADD A,1 ;; clockwise move
CP 4 ;; check A value in range
JR NZ,newdir2 ;; Jump if not 4
LD A,0 ;; reset A to 0
.newdir2
PUSH AF ;; new direction
LD BC,&2000 ;; delay to separate keystrokes
.dloop2
DEC BC
LD A,B
OR C
JR NZ,dloop2
.lftar
LD A,8 ;; key code for left arrow
CALL &BB1E ;; KM TEST KEY
JR Z,cesc ;; jump if not pressed
POP AF ;; old direction
SUB 1 ;; Subtract: A=A-1
JR NC,newdir ;; Jump if Carry bit not set **
LD A,3 ;; Reset A to 3 if below 0
.newdir
PUSH AF ;; New Direction
LD BC,&2000 ;; delay loop
.dloop
DEC BC
LD A,B
OR C
JR NZ,dloop
.cesc
LD A,66 ;; key code for ESC
CALL &BB1E ;; KM TEST KEY
JR Z,check
POP AF ;; clear stack before return
POP HL
RET ;; Return to Basic
.check
POP AF
POP HL ;; only HL really wanted
PUSH AF ;; save direction code
LD A,L ;; routine to check L value
CP 0 ;; off top of screen?
JR NZ,botscr
LD L,25 ;; wrap-round, top to bottom
JR checkh ;; Jump to H check
.botscr
CP 26 ;; bottom of screen?
JR NZ,checkh
LD L,1 ;; move to top
.checkh
LD A,H ;; check H value
CP 0 ;; off left?
JR NZ,offright
LD H,40 ;; move to right edge
JR tidy ;; jump to end
.offright
CP 41 ;; off right
JR NZ,tidy
LD H,1 ;; move to left edge
.tidy
POP AF ;; tidy up the stack
JP loop ;; jump to start of main loop ***
.ship1
defb 16,56,56,56,124,124,198,130
.ship2
defb 192,112,62,31,62,112,192,0
.ship3
defb 130,198,124,124,56,56,56,16
.ship4
defb 0,3,14,124,248,124,14,3 ;; data for defining the ships.
This is one of those Left/Right, point the ship in this direction kind of routine and use the foward arrow to move it in the direction it's facing. The original program (which is mainly this) comes from Amstrad CPC464 User (before it became ACU) and the program appeared to only be CPC464 friendly. A good deal of modify it just to get it to compile in Maxam was required since the original routine was using direct addresses & bytes in the Jump & Jump Relative routine and no labels! So I've tried to label the program as best as I could, result the program works. The original code never included the matrix data either, where in it was included within the BASIC Loader program, but now it should act as the BASIC program does. But I reckon there could be considerable enhancements which could be done to it if anyone is looking for a routine like this.
Quote from: Gryzor on 09:55, 24 December 10
Dear AA,
I typed the program that you printed in your last issue, again and again, but my Amstrad gives me an error on every line. Even if I add line numbers, when I try to run it I get errors again and I don't know how to correct them.
I noticed that you didn't print the checksums so I can check if I have typed it in correctly, but I am pretty sure I did. Also, you didn't print those dots that represent spaces, those are really useful...
Is my 464 broken?
Thank you,
Th.P.
I don't understand, does this mean that routine above doesn't work? I would of done it in Winape Assembler which is just a matter of compiling it to memory @ &4000 and "CALL &4000" should have it working with redefined character and all. :'( I was lazy in setting up a Matrix Table (BASIC equivalent to SYMBOL AFTER 240), which seems to become more important if you generate a Binary File with an Executable Address as that defines an area of memory to put your redefined SYMBOLs - as I have done in that routine using &BBA8.
New example:
http://www.cpctech.org.uk/source/spec_spr.asm (http://www.cpctech.org.uk/source/spec_spr.asm)
Shows how to draw a sprite on a Spectrum sized screen.
It explains some benefits of using a spectrum sized screen.
Somebody will be a long soon to say "don't use a spectrum sized screen" :laugh:
New example:
http://www.cpctech.org.uk/source/comp_spr.asm (http://www.cpctech.org.uk/source/comp_spr.asm)
This example shows what I call "compressed sprites".
I have a "large" sprite which has many areas that are fully transparent. Normally we would waste time masking these areas if a standard masking sprite routine was used for the whole sprite. (e.g. we don't split it into smaller sprites and just draw those).
In the code there are 2 draw functions. One shows the sprite itself (I am no graphics artist ;). It moves and you can see it masked over the screen. The other draws pixels for the control codes so that you can see where it recognises fully transparent, masked, fully opaque and end of line conditions.
Turn it on to see the difference.
There are other ways to compress sprites, this is one example.
The code is not optimised, and this method may not be the fastest but it shows how to draw large sprites in this way.
New example:
http://www.cpctech.org.uk/source/cpl_spr.asm (http://www.cpctech.org.uk/source/cpl_spr.asm)
This example shows what I call "compiled sprites".
In the code there are 3 sprites. For each of these there is 1 drawing function. Within the function you will see the instructions for masking, writing opaque pixels and for skipping fully transparent pixels and for moving to the next line. The code is not optimised - I also think there is a bug in the code generation meaning the pixels are not correct but it's enough for this example so you can see what a sprite of this type looks like.
NOTE: If I wanted to have pre-shifted sprites, I would need more functions. If I want more sprites I also need more functions. The advantage of this method is that it's faster to draw a sprite but at the expense of needing more ram to store the drawing routines. - More useful if you are making a game for cpcay cartridge OR mixing hard and software sprites in a plus game.
I think now I have shown the methods to draw sprites on a cpc:
I have covered:
- preshifted sprites
- compiled sprites
- compressed sprites
- masked sprites
- xor sprites
- "mode 3 sprites"/bitplanes sprites. (I think I did an example of this???) hmmm.. not sure now ;)
I haven't show enough methods for erasing sprites yet.
So far shown:
- storing background to restore it back
- using XOR to redraw the sprite to erase it in addition to drawing it.
Here's a "sprite" routine I've just written to add to the mix...
The problem I was having is that if you compress "big" sprites (e.g. logos, status bars etc - mainly the type of thing you want to draw to the screen once and drawing it isn't time critical) with Exomizer or similar then you have to decompress them to RAM first before drawing them on the screen (due to the CPC's video addressing format) which is kind of self-defeating.
Therefore, I wrote a routine that only compresses data within a set boundary, i.e. one horizontal screen line of the sprite. Then on decompression we can draw it directly to the screen without using any kind of buffer whatsoever.
It works nicely and in the example provided the saving is 17% over the original. The routines demonstrate simple repetition based compression and are descriptive (i.e. not optimised) so feel free to adapt to your purpose/speed requirements.
I typed in a tape turboload and turbosave routine. (It's not soooo turboish, but provides colour striped border)
This program originally comes from the Spanish CPC mag. "Amstrad Personal" no. 09.
;; TURBOSAVE - TURBOLOAD for tapes
;; Typed-in and slightly modified
;; by Devilmarkus
;; Found in "Amstrad Personal" no. 09
;; Original author: Pedro M. Cuenca
;; To SAVE a file to tape:
;; |TURBOSAVE,<start>,<length>
;; To LOAD a file from tape:
;; |TURBOLOAD,<start>,<length>
color2 equ 85
color1 equ 80
org &8000
ld bc, table
ld hl, space
jp &bcd1
table:
defw name
JP rsave
JP rload
name:
db "TURBOSAV","E"+&80
db "TURBOLOA","D"+&80
db 0
space:
defs 4
rsave:
cp 2
ret nz
ld l,(ix+0)
ld h,(ix+1)
inc hl
ld (length),hl
ld l,(ix+2)
ld h,(ix+3)
ld (address),hl
jp saveroutine
rload:
cp 2
ret nz
ld l,(ix+0)
ld h,(ix+1)
;inc hl
ld (length),hl
ld l,(ix+2)
ld h,(ix+3)
ld (address),hl
jp loadroutine
saveroutine:
di
ex af,af'
push af
ex af,af'
exx
push bc
ld bc,&f610
out (c),c
exx
ld b,3
retar:
ld hl, 0
buc1:
dec hl
ld a,h
or l
jr nz,buc1
djnz retar
ld bc,&7f10
ld a,color2
out (c),c
out (c),a
call savecab
ld hl,(address)
ld de,(length)
call save
exx
ld c,0
out (c),c
pop bc
exx
ex af,af'
pop af
ex af,af'
ei
ret
save:
ld a,(hl)
call sbyte
inc hl
dec de
ld a,d
or e
jr nz,save
ret
sbyte:
ld b,8
sbuc:
exx
rra
jr c,bit1
bit0:
ld hl,100
ld (stime1),hl
ld (stime2),hl
jr sig
bit1:
ld hl,25
ld (stime1),hl
ld (stime2),hl
jr sig
sig:
ex af,af'
ld a,%00110000
out (c),a
ld a,&10
out (&7f),a
ld a,color1
out (&7f),a
defb &21
stime1:
defw 0
reto1:
dec hl
ld a,h
or l
jr nz, reto1
ld a,%00010000
out (c),a
ld a,&10
out (&7f),a
ld a,color2
out (&7f),a
defb &21
stime2:
defw 0
reto2:
dec hl
ld a,h
or l
jr nz, reto2
ex af,af'
exx
djnz sbuc
ret
savecab:
ld b,128
cabuc:
push bc
ld a, &aa
call sbyte
pop bc
djnz cabuc
ld b,1
exx
jp bit0
ret
loadroutine:
di
ex af,af'
push af
ex af,af'
exx
push bc
ld bc,&f610
out (c),c
ld b,&f5
exx
fallo:
ld b,3
retarl
ld hl,0
buc1l:
dec hl
ld a,h
or l
jr nz, buc1l
djnz retarl
ld bc,&7f10
ld a,color2
out (c),c
out (c),a
call loadcab
ld hl,(address)
ld de,(length)
call load
jr c,fallo
exx
ld bc, &f600
out (c),c
pop bc
exx
ex af,af'
pop af
ex af,af'
ei
ret
loadcab:
ld b,128
loopcab:
call lbyte
jr c, loadcab
cp &aa
jr nz,loadcab
djnz loopcab
call w_bajo
jp w_alto
load:
call lbyte
ret c
ld (hl),a
inc hl
dec de
ld a,d
or e
jr nz,load
ret
lbyte:
push bc
ld b,8
lbuc:
ex af,af'
call w_bajo
jr c,error
call w_alto
jr c,error
ld a,(talto)
cp 40
jr c,es1
es0:
ld a,(tbajo)
cp 40
jr c,error
ex af,af'
or a
jr salida
es1:
ld a,(tbajo)
cp 40
jr nc, error
ex af,af'
scf
salida:
rra
djnz lbuc
or a
pop bc
ret
error:
ex af,af'
scf
pop bc
ret
w_bajo:
ld a,&10
out (&7f),a
ld a,color2
out (&7f),a
exx
ld hl, talto
ld (hl),1
bucalto:
in a,(c)
rla
jr c,s1
inc (hl)
jr z,n0
jr bucalto
w_alto:
ld a,&10
out (&7f),a
ld a,color1
out (&7f),a
exx
ld hl, tbajo
ld (hl),1
bucbajo:
in a,(c)
rla
jr nc, s1
inc (hl)
jr z, n0
jr bucbajo
s1:
or a
exx
ret
n0:
scf
exx
ret
address: defs 2
length: defs 2
talto: defs 1
tbajo: defs 1
For the non-ASM coders (BASIC only):
10 AD=&8000:L=&01C7
20 READ a:POKE AD+P,a
30 P=P+1:IF P=L THEN END
40 GOTO 20
50 DATA &01,&09,&80,&21,&24,&80,&C3,&D1,&BC,&11,&80,&C3,&28,&80,&C3,&41
60 DATA &80,&54,&55,&52,&42,&4F,&53,&41,&56,&C5,&54,&55,&52,&42,&4F,&4C
70 DATA &4F,&41,&C4,&00,&00,&00,&00,&00,&FE,&02,&C0,&DD,&6E,&00,&DD,&66
80 DATA &01,&23,&22,&C3,&81,&DD,&6E,&02,&DD,&66,&03,&22,&C1,&81,&C3,&59
90 DATA &80,&FE,&02,&C0,&DD,&6E,&00,&DD,&66,&01,&22,&C3,&81,&DD,&6E,&02
100 DATA &DD,&66,&03,&22,&C1,&81,&C3,&FA,&80,&F3,&08,&F5,&08,&D9,&C5,&01
110 DATA &10,&F6,&ED,&49,&D9,&06,&03,&21,&00,&00,&2B,&7C,&B5,&20,&FB,&10
120 DATA &F6,&01,&10,&7F,&3E,&55,&ED,&49,&ED,&79,&CD,&E8,&80,&2A,&C1,&81
130 DATA &ED,&5B,&C3,&81,&CD,&93,&80,&D9,&0E,&00,&ED,&49,&C1,&D9,&08,&F1
140 DATA &08,&FB,&C9,&7E,&CD,&9E,&80,&23,&1B,&7A,&B3,&20,&F6,&C9,&06,&08
150 DATA &D9,&1F,&38,&0B,&21,&64,&00,&22,&C8,&80,&22,&DC,&80,&18,&0B,&21
160 DATA &19,&00,&22,&C8,&80,&22,&DC,&80,&18,&00,&08,&3E,&30,&ED,&79,&3E
170 DATA &10,&D3,&7F,&3E,&50,&D3,&7F,&21,&00,&00,&2B,&7C,&B5,&20,&FB,&3E
180 DATA &10,&ED,&79,&3E,&10,&D3,&7F,&3E,&55,&D3,&7F,&21,&00,&00,&2B,&7C
190 DATA &B5,&20,&FB,&08,&D9,&10,&B9,&C9,&06,&80,&C5,&3E,&AA,&CD,&9E,&80
200 DATA &C1,&10,&F7,&06,&01,&D9,&C3,&A4,&80,&C9,&F3,&08,&F5,&08,&D9,&C5
210 DATA &01,&10,&F6,&ED,&49,&06,&F5,&D9,&06,&03,&21,&00,&00,&2B,&7C,&B5
220 DATA &20,&FB,&10,&F6,&01,&10,&7F,&3E,&55,&ED,&49,&ED,&79,&CD,&39,&81
230 DATA &2A,&C1,&81,&ED,&5B,&C3,&81,&CD,&4C,&81,&38,&DC,&D9,&01,&00,&F6
240 DATA &ED,&49,&C1,&D9,&08,&F1,&08,&FB,&C9,&06,&80,&CD,&58,&81,&38,&F9
250 DATA &FE,&AA,&20,&F5,&10,&F5,&CD,&8B,&81,&C3,&A3,&81,&CD,&58,&81,&D8
260 DATA &77,&23,&1B,&7A,&B3,&20,&F5,&C9,&C5,&06,&08,&08,&CD,&8B,&81,&38
270 DATA &26,&CD,&A3,&81,&38,&21,&3A,&C5,&81,&FE,&28,&38,&0B,&3A,&C6,&81
280 DATA &FE,&28,&38,&13,&08,&B7,&18,&09,&3A,&C6,&81,&FE,&28,&30,&08,&08
290 DATA &37,&1F,&10,&D7,&B7,&C1,&C9,&08,&37,&C1,&C9,&3E,&10,&D3,&7F,&3E
300 DATA &55,&D3,&7F,&D9,&21,&C5,&81,&36,&01,&ED,&78,&17,&38,&1D,&34,&28
310 DATA &1D,&18,&F6,&3E,&10,&D3,&7F,&3E,&50,&D3,&7F,&D9,&21,&C6,&81,&36
320 DATA &01,&ED,&78,&17,&30,&05,&34,&28,&05,&18,&F6,&B7,&D9,&C9,&37,&D9
330 DATA &C9,&00,&00,&00,&00,&00,&00
Have fun with it!
Attachment: Original listing. Thanks to SyX for sharing it!
New Asm examples:
Showing different ways to handle the cpc's interrupts in interrupt mode 1. These show how to hit the hardware directly.
http://www.cpctech.org.uk/source/hwint.asm (http://www.cpctech.org.uk/source/hwint.asm)
http://www.cpctech.org.uk/source/hwint2.asm (http://www.cpctech.org.uk/source/hwint2.asm)
http://www.cpctech.org.uk/source/hwint3.asm (http://www.cpctech.org.uk/source/hwint3.asm)
http://www.cpctech.org.uk/source/hwint4.asm (http://www.cpctech.org.uk/source/hwint4.asm)
http://www.cpctech.org.uk/source/hwint5.asm (http://www.cpctech.org.uk/source/hwint5.asm)
http://www.cpctech.org.uk/source/hwintdelay.asm (http://www.cpctech.org.uk/source/hwintdelay.asm)
Quote from: arnoldemu on 09:46, 30 August 13
I think now I have shown the methods to draw sprites on a cpc:
I have covered:
- preshifted sprites
- compiled sprites
- compressed sprites
- masked sprites
- xor sprites
- "mode 3 sprites"/bitplanes sprites. (I think I did an example of this???) hmmm.. not sure now ;)
I haven't show enough methods for erasing sprites yet.
So far shown:
- storing background to restore it back
- using XOR to redraw the sprite to erase it in addition to drawing it.
Not directly relating to Sprites, though I noticed the article on Collision Detection (http://www.cpctech.org.uk/docs/colldet.html) looks in need of a tune up. ACU had an article on this in it's early days along with example, though the example (as lengthy as it is), relies on using the character set in conjunction with it's graphical position, I'm not sure how difficult it would be to upgrade it to graphical sprite for the collision detection.
Quote from: AMSDOS on 09:19, 07 January 14
Not directly relating to Sprites, though I noticed the article on Collision Detection (http://www.cpctech.org.uk/docs/colldet.html) looks in need of a tune up. ACU had an article on this in it's early days along with example, though the example (as lengthy as it is), relies on using the character set in conjunction with it's graphical position, I'm not sure how difficult it would be to upgrade it to graphical sprite for the collision detection.
I used exact collision on Balloonacy using a mask.
I do plan to write up box based collision which is most commonly used. LOL, I laughed when I read that link of mine.
Busy with other projects for the moment.
Quote from: arnoldemu on 10:02, 07 January 14
I used exact collision on Balloonacy using a mask.
I do plan to write up box based collision which is most commonly used. LOL, I laughed when I read that link of mine.
Busy with other projects for the moment.
I'm having a look at the bits and pieces I've made for putting together for a game, though I'm having issues with the collision detection. For the main character I'm using a routine to draw a triangular shape on screen using a series of Lines and wasn't sure if a test for colour check would be sufficient enough to provide an accurate collision detection given the angled nature of the character doesn't have square edges facing what it needs to attack.
Quote from: Jonah (Tasteful Mr) Ship on 13:23, 10 June 13
Tenuously linked post ahead!
If you're interested, here's the horizontal star-scroller from the XOR cracktros...
Just assmeble in WinAPE/Maxam and CALL &A000 to see what it does. If you're using WinAPE, then it's best to keep the boot-screen up, so you can see that it doesn't affect the text on screen while it runs.
For better results, try changing the background colours to #00 (BLACK) and inks 1 & 3 to #26 (BRIGHT WHITE) and 13 (WHITE) respectively. It gives a slight impression of a star-trail as it moves across the screen.
org #a000
.inflp call stars
jp inflp
.stars ld de,#0000
ld hl,here2
ld b,25
.loop1 ld a,(hl)
ld e,a
inc hl
ld a,(hl)
ld d,a
dec hl
ld a,(de)
cp #fe
jr nz,jump1
xor a
ld (de),a
.jump1 inc de
ld a,d
cp #00
jr nz,jump2
push hl
ld hl,#c000
add hl,de
ex de,hl
pop hl
.jump2 ld a,(de)
cp #00
jr nz,jump3
ld a,#fe
ld (de),a
.jump3 ld a,e
ld (hl),a
inc hl
ld a,d
ld (hl),a
inc hl
djnz loop1
ld hl,here3
ld b,25
.loop2 ld a,(hl)
ld e,a
inc hl
ld a,(hl)
ld d,a
dec hl
ld a,(de)
cp #fe
jr nz,jump4
xor a
ld (de),a
.jump4 inc de
inc de
ld a,d
cp #00
jr nz,jump5
push hl
ld hl,#c000
add hl,de
ex de,hl
pop hl
.jump5 ld a,(de)
cp #00
jr nz,jump6
ld a,#fe
ld (de),a
.jump6 ld a,e
ld (hl),a
inc hl
ld a,d
ld (hl),a
inc hl
djnz loop2
call #bd19
ret
.here2
db #00,#c0,#55,#c0,#c0,#c0,#f4,#c0
db #68,#c1,#a9,#c1,#20,#c2,#55,#c2
db #82,#c2,#e0,#c2,#4a,#c3,#a0,#c3
db #d9,#c3,#49,#c4,#a0,#c4,#d9,#c4
db #48,#c5,#65,#c5,#c6,#c5,#fa,#c5
db #85,#c6,#d5,#c6,#20,#c7,#49,#c7
db #a0,#c7
.here3
db #30,#d0,#90,#d8,#a0,#f0,#10,#d1
db #7a,#e1,#a0,#e9,#00,#ca,#30,#d2
db #b0,#e2,#e0,#ea,#50,#d3,#75,#db
db #e0,#f3,#20,#d4,#a0,#cc,#e9,#dc
db #0a,#ed,#65,#dd,#a9,#d5,#15,#f6
db #85,#ee,#a5,#ee,#ff,#ce,#4a,#e7
db #b0,#ef
(P.S. The code isn't originally mine, so I'm not trying to steal the glory here or anything!)
This is pretty much the kind of thing I want to eventually implement in the other thread I made which deals with 16 bit numbers, though this approach seems more simplified compared to what I'm trying to do in the other thread.
I cut this program down by removing the second loop that points to here3 which gives me something closer to what I'm looking for, though the stars move left->right across the screen and I'm after right->left instead. I was able to do that by changing the inc de to dec de at the loop1 label, though the program only goes so far and then it crashes, looks like the program is writing to sensitive memory locations.
It looks like this routine is designed to simply move pixels across an entire screen, I was thinking of implementing different size playing fields which made become an issue for this, otherwise would anyone know what's happening with this routine? :'(
Hi,
:)
if you look at that :
inc de
ld a,d
cp #0
jr nz,jump2
The test is on de=&0000 (when reaching the end of video memory (&C000 to &FFFF), so &FFFF+1.
If you change to dec de to have stars going the other direction, it cannot work anymore.
You should check if de=&BFFF (d=&BF), and set it to FFFF, maybe...
Quote from: Xifos on 18:19, 03 May 14inc deld a,dcp #0jr nz,jump2
inc de
ld a,d
or a,a
jr nz,jump2
Makes it 1 us more quick :)
Quote from: Xifos on 18:19, 03 May 14
if you look at that :
inc de
ld a,d
cp #0
jr nz,jump2
The test is on de=&0000 (when reaching the end of video memory (&C000 to &FFFF), so &FFFF+1.
If you change to dec de to have stars going the other direction, it cannot work anymore.
You should check if de=&BFFF (d=&BF), and set it to FFFF, maybe...
Except that doesn't check DE for 0, only D. To check DE for 0, simply change to:
dec de
ld a,d
or e
jr nz,jump2
If you want to check when DE goes to #FFFF, use:
ld a,d
or e
dec de
jr nz,jump2
Sorry, i did not make it clear, i was refering to the stars routine AMSDOS was wondering about...
This routine plots stars by setting bytes into video memory, increasing addresses, and testing when addresses go to &FFFF+1 (0) to set them to &c000.
AMSDOS changed it to decrease addresses (but it went crashing), so the test has to be done on DE going to &BFFF...
And the routine he posted is only testing D rather than DE...
;)
Quote from: Xifos on 16:51, 04 May 14
so the test has to be done on DE going to &BFFF...
Sorry, my mistake. The test for zero works only if you're incrementing past #ffff. ie. D becomes 0 next.
To test going the other way, simply use:
dec de
bit 6,d
jr nz,jump2
(ie. DE goes from #c000 to #bfff, this is the point when D drops below %11000000 to %10111111, all other high memory screen addresses have bit 6 set).
Thanks for the antidotes guys :) The end result appears to be the same, though it's good to see some refined code.
New example code:
http://www.cpctech.org.uk/source/backbuff.asm (http://www.cpctech.org.uk/source/backbuff.asm)
&4000-&7fff contains a copy of the screen from &c000-&ffff but without the sprites.
This shows how you can erase sprites using this back buffer.
another way to erase sprites.
http://www.cpctech.org.uk/source/scrlchk.asm (http://www.cpctech.org.uk/source/scrlchk.asm)
This example performs continuous chunky scroll using hardware. If we had a pixel by pixel scroll it would run at a rate of 1 pixel per frame in mode 1, but because we don't on cpc, it delays for 8 frames then scrolls.
In addition it shows how to convert from our sprite coordinates to a screen address on a hardware scrolling screen, and the draws a striped rectangle for a sprite. Also, it highlights the problem area in red so you can see where it is and how it moves with a horizontal scroll.
http://www.cpctech.org.uk/source/scrlvrt.asm (http://www.cpctech.org.uk/source/scrlvrt.asm)
Smoother vertical hardware scrolling using R5 of the CRTC but without rupture/splitting. Same method used in Legend of Kage.
New example code:
http://www.cpctech.org.uk/source/scrlv1.asm (http://www.cpctech.org.uk/source/scrlv1.asm)
This shows how to avoid the problem area when hardware vertical scrolling. The problem area is highlighted. A screen width of 32 is chosen because &400/32 gives no remainder. See how the problem area remains on the right side of the screen.
New example code
http://www.cpctech.org.uk/source/scrlh1.asm (http://www.cpctech.org.uk/source/scrlh1.asm)
This example shows how to avoid the problem area when scrolling horizontally.
For a screen of width 40, and if we want to scroll 3 screens in width, then the maximum height the screen can be is 22
lines.
We must choose our screen dimensions carefully to both have horizontal scrolling AND to avoid the problem area. in addition the scroll can't be continuous there is a minimum and maximum range.
This method is used by Action Force.
New example code:
http://www.cpctech.org.uk/source/scrltile.asm (http://www.cpctech.org.uk/source/scrltile.asm)
This example shows how to scroll a tile map horizontally.
The scroll is in a single direction and continuous.
It is meant to be simple so you can see how to setup a tile map, setup the tiles, how the tile map is queried for the tiles, how the tiles are drawn.
Quote from: arnoldemu on 16:23, 25 May 14
New example code:
http://www.cpctech.org.uk/source/scrltile.asm (http://www.cpctech.org.uk/source/scrltile.asm)
This example shows how to scroll a tile map horizontally.
The scroll is in a single direction and continuous.
It is meant to be simple so you can see how to setup a tile map, setup the tiles, how the tile map is queried for the tiles, how the tiles are drawn.
This code seems to be a bit beyond me and the Winape Assembler. :(
Quote from: AMSDOS on 23:00, 31 May 14
This code seems to be a bit beyond me and the Winape Assembler. :(
I use pasmo assembler. Build using amsdos command line option and put into a dsk file. Or use binary and load into winape debugger and call from basic.
Quote from: arnoldemu on 09:13, 01 June 14
I use pasmo assembler. Build using amsdos command line option and put into a dsk file. Or use binary and load into winape debugger and call from basic.
Ok I see that Assembler is included with the CPC BASIC 3 distribution.
I've been having a look at this routine for running BASIC programs through Assembly:
http://cpctech.cpc-live.com/source/runbas.asm (http://cpctech.cpc-live.com/source/runbas.asm)
but I'm unable to get it to work, even with the address for KL ROM SELECT. Probably because I didn't have the variables setup.
Questions:
1) Could it be made to work in Winape Assembler?
2) Could a BASIC program be included with it? Something with Variables (not 10 PRINT"HELLO WORLD", 20 GOTO 10), doesn't have to be big.
3) I was looking at a 12Kb BASIC Game, but was studying what those Addresses did in Memory, not sure if it's recommended due to the nature of the program?
4) I though this method could be used to load a BASIC program using Headerless loader and then execute this using this method, but only really makes sense to apply it for a larger program. Any thoughts?
Hi @AMSDOS (http://www.cpcwiki.eu/forum/index.php?action=profile;u=330)
This question has been a long time, but if you want I can try to help you.
Send me that basic program and we take a look, if you still need to solve the problem.
Hi @Urusergi (http://www.cpcwiki.eu/forum/index.php?action=profile;u=923)
Unfortunately I'm unable to remember what that BASIC program was, had a feeling it might of been a program which had BASIC code as well as a binary file, but I don't know that for sure. Back in 2015 I was typing in a few large programs from various magazines like Your Computer. I checked out programs which I might have considered for it, but they weren't 12kb. The only thing I could think of which came close is the early AMSOFT game Quack-A-Jack, which has a 12kb binary file & 14kb BASIC file.
It maybe better though to use one of my BASIC programs, rather than invite trouble. At the moment I've been working on this program (http://www.cpcwiki.eu/forum/general-discussion/not-been-here-long/msg157930/#msg157930), and made some progress with it yesterday after adding enemy tank (with the help I had from an AA Type-in), I also improved the shooting sequence, so the tanks can move after shots have been fired. I probably might just add some colourful sprites to the program before handing it to you if you wanted to test that.
Quote from: AMSDOS on 10:27, 31 January 15
4) I though this method could be used to load a BASIC program using Headerless loader and then execute this using this method, but only really makes sense to apply it for a larger program. Any thoughts
Do you know "2cdt" x86 program?. I think that is what you need. You can create 2 unique blocks whatever the size of the basic game. The first block can be as small as 1 byte, and the second with the rest of bytes (and you can adjust the speed too). Obviously the biggest problem is when you get a "read error b" and you have to start charging again from the beginning :doh:
Quote from: AMSDOS on 23:23, 24 March 18
I probably might just add some colourful sprites to the program before handing it to you if you wanted to test that.
Ok, pass it to me when you finish ;)
Quote from: Urusergi on 00:41, 25 March 18
Do you know "2cdt" x86 program?. I think that is what you need. You can create 2 unique blocks whatever the size of the basic game. The first block can be as small as 1 byte, and the second with the rest of bytes (and you can adjust the speed too). Obviously the biggest problem is when you get a "read error b" and you have to start charging again from the beginning :doh:
It's not a problem producing a Headerless file with 2cdt, but I thought the problem is loading a headerless file over another BASIC program which is trying to load it, hence write Assembly program to load file from another location, then use Assembly routine to run the BASIC program.
Quote
Ok, pass it to me when you finish ;)
Are you sure? Winking emoji usually means do the opposite.
Quote from: AMSDOS on 11:12, 25 March 18It's not a problem producing a Headerless file with 2cdt, but I thought the problem is loading a headerless file over another BASIC program which is trying to load it, hence write Assembly program to load file from another location, then use Assembly routine to run the BASIC program.
No, I mean create 2 turbo blocks with header that are still firmware compatible. It's almost as fast as a headerless file and can be executed with run ""
Quote from: AMSDOS on 11:12, 25 March 18Are you sure? Winking emoji usually means do the opposite.
??? At least in my country I think it means that I am willing to help or I agree to help you. Let's see if other Spaniards corroborate me or I'm wrong.
In this forum I've always helped in everything I could, maybe that's the reason I 've more likes than posts.
Quote from: Urusergi on 16:39, 25 March 18
??? At least in my country I think it means that I am willing to help or I agree to help you. Let's see if other Spaniards corroborate me or I'm wrong.
Sorry @Urusergi (http://www.cpcwiki.eu/forum/index.php?action=profile;u=923) , I think you're wrong about the emoji :) Northern spaniard here, and I've always used it as a "just joking" indicator.
Quote from: adolfo.pa on 20:21, 25 March 18
Sorry @Urusergi (http://www.cpcwiki.eu/forum/index.php?action=profile;u=923) , I think you're wrong about the emoji :) Northern spaniard here, and I've always used it as a "just joking" indicator.
Then I'm going to have to erase a few thousand of smiles that I put in ~15 years that I've been writing in forums and, interestingly, nobody told me anything about my mistake (in fact, they always reacted positively).
For example, someone sends me this message recently:
"Is it possible to have a version without the crosshair fix, we will have the option of on or off then. ;) "
What should I understand? Is it a joke? and he doesn't really want me to do that version?
Quote from: Urusergi on 21:19, 25 March 18
Then I'm going to have to erase a few thousand of smiles that I put in ~15 years that I've been writing in forums and, interestingly, nobody told me anything about my mistake (in fact, they always reacted positively).
For example, someone sends me this message recently:
"Is it possible to have a version without the crosshair fix, we will have the option of on or off then. ;) "
What should I understand? Is it a joke? and he doesn't really want me to do that version?
It is definitely a friendly emoji, so it is natural for people to react to it in a positive way. Also, most of the time the meaning will be obvious given the context; in your response it is pretty clear you used it with the meaning of a regular smiley (friendlyness).
I use it to make sure people know I'm joking. For example, the other day I posted this as a response to Duke:
QuotePlease stop making so many cool stuff! You make the rest of us look like lazy couch potatos (which we aren't, of course ;) )
If you remove the wink smiley the meaning changes quite a lot :)
Not exactly an authoritative source of information, but here is the entry in the Emojipedia (https://emojipedia.org/winking-face/).
@adolfo.pa (http://www.cpcwiki.eu/forum/index.php?action=profile;u=2309) I think you're not understanding the approach.
AMSDOS thinks I'm not going to help him with the problem if I tell him in this way:
"Ok, pass it to me when you finish ;) "
Recently someone (foreign) asked me for help in this way:
"Is it possible to have a version without the crosshair fix, we will have the option of on or off then. (http://www.cpcwiki.eu/forum/Smileys/SoLoSMiLeYS1/wink.gif) "
Of course I made that version he asked me and I didn't think he was kidding
That's why I think that depending on the country we may understand the emoticons in different ways.
What do you think in this case?
@AMSDOS (http://www.cpcwiki.eu/forum/index.php?action=profile;u=330) as you haven't finished your game yet, I've created two examples with a spanish game (Star Sordium):
- Original is 10 Blocks at 2000 baud and loads in 2 minutes and 11 seconds.
- 2 Blocks at 2000 baud loads in 1 minute and 23 seconds.
- 2 Blocks at 2500 baud loads in 1 minute and 6 seconds.
look at the attachments (here I used to put a wink emoticon, but better not)
Quote from: Urusergi on 23:03, 25 March 18
What do you think in this case?
Well, I think you're giving too much importance to this ;)
I don't think there's any country specific thing going on here, and AFAIK, the meaning of the winky smiley is the same on all western/european countries. In my job I chat regularly with people from western europe, USA, and Brazil, and all of them seem to use it in that sense. Proof of that is that I haven't been fired yet :D
Cheers!
Quote from: adolfo.pa on 23:33, 25 March 18
Well, I think you're giving too much importance to this ;)
I don't give importance, it's just curiosity but I see that you don't want to answer (Lo entiendo ;) )
Let's leave it that way....
Quote from: Urusergi on 23:47, 25 March 18
I don't give importance, it's just curiosity but I see that you don't want to answer (Lo entiendo ;) )
Now I'm confused, because I though I had answered you ???
Anyway, this is waaay off-topic, so yep, let's forget about it.
Cheers!
Quote from: Urusergi on 16:39, 25 March 18
No, I mean create 2 turbo blocks with header that are still firmware compatible. It's almost as fast as a headerless file and can be executed with run ""
I'm familiar with that approach as I used to do that with all my AMSOFT games with JL-Copy, but that's not taking my BASIC program and using and Assembly routine to execute that BASIC from Assembly. I think the size of my BASIC code and number of variables it uses throws me in the deep end when it comes to that routine, I think it just needs a short program with a couple of variables just to show it's function properly, but as it is I'm having trouble following it.
Ok, I see that you want to use exclusively the machine code routine for load, and then run the basic file.
Tonight I'll try with a little example.
It doesn't have to load, but I would like to see it in an Assembler format with the BASIC embedded in as defb statements. I think something simple like this should be fine:
10 a%=1000
20 b%=256
30 PRINT a%+b%
40 PRINT"8)"
50 END
Thanks
Sorry but I've already created a headerless file with my prime number generator in basic.
Machine code:
kl_rom_select equ &B90F
org &A000
ld hl,&0170 ; load basic start
ld de,&00E9 ; basic length
ld a,&16 ; sync file char
call &bca1
ld hl,(length)
ld c,0
call kl_rom_select
ld a,(&c002)
cp 0
jp z,cpc464
ld (&ae66),hl
ld (&ae68),hl
ld (&ae6a),hl
ld (&ae6c),hl
cp 1
jp z,cpc664
jp &ea78 ;; run BASIC CPC6128
.cpc664
jp &ea7d ;; run BASIC CPC664
.cpc464
ld (&ae83),hl
ld (&ae85),hl
ld (&ae87),hl
ld (&ae89),hl
jp &e9bd ;; run BASIC CPC464
length dw &025A ; Address of start of variables (&AE66-67 in cpc6128-664, &AE83-84 in cpc464)
If you don't understand something, don't hesitate to ask me, but I think it's pretty simple to follow.
@AMSDOS (http://www.cpcwiki.eu/forum/index.php?action=profile;u=330) Here is your Basic example 8)
kl_rom_select equ &B90F
ORG &A000
LD HL,Data
LD DE,&0170 ; Basic start
LD BC,EndData-Data
LDIR
ld hl,(length)
ld c,0
call kl_rom_select
ld a,(&c002)
cp 0
jp z,cpc464
ld (&ae66),hl
ld (&ae68),hl
ld (&ae6a),hl
ld (&ae6c),hl
cp 1
jp z,cpc664
jp &ea78 ;; run BASIC CPC6128
.cpc664
jp &ea7d ;; run BASIC CPC664
.cpc464
ld (&ae83),hl
ld (&ae85),hl
ld (&ae87),hl
ld (&ae89),hl
jp &e9bd ;; run BASIC CPC464
;PRINT HEX$(PEEK(&AE67))
;PRINT HEX$(PEEK(&AE66))
length dw &01AC ; Address of start of variables (&AE66-67 in cpc6128-664, &AE83-84 in cpc464)
.Data
DB &0D,&00,&0A,&00,&02,&00,&00,&E1
DB &EF,&1A,&E8,&03,&00,&0D,&00,&14
DB &00,&02,&00,&00,&E2,&EF,&1A,&00
DB &01,&00,&10,&00,&1E,&00,&BF,&20
DB &02,&00,&00,&E1,&F4,&02,&00,&00
DB &E2,&00,&0A,&00,&28,&00,&BF,&22
DB &38,&29,&22,&00,&06,&00,&32,&00
DB &98,&00,&00,&00
.EndData
You might want to add this code (http://www.cpcwiki.eu/forum/programming/how-to-readwrite-a-file-'byte-by-byte'-using-firmware-but-much-faster!/msg162099/#msg162099) to Source codes too.
Quote from: ikonsgr on 09:39, 01 July 18
You might want to add this code (http://www.cpcwiki.eu/forum/programming/how-to-readwrite-a-file-'byte-by-byte'-using-firmware-but-much-faster!/msg162099/#msg162099) to Source codes too.
I've added a page (http://www.cpcwiki.eu/index.php/Programming:Read/Write_a_file_quickly_byte-by-byte), please inspect it though. Registration to the CPCWiki is seperate from the forum, so feel free to register and amend where necessary.
Ok, thanks!
Hi @Urusergi (https://www.cpcwiki.eu/forum/index.php?action=profile;u=923) , I have a question about the code, why 170+code_size is copied 4 times?
Quote from: Urusergi on 21:10, 27 March 18@AMSDOS (http://www.cpcwiki.eu/forum/index.php?action=profile;u=330) Here is your Basic example 8)
kl_rom_select equ &B90F
ORG &A000
LD HL,Data
LD DE,&0170 ; Basic start
LD BC,EndData-Data
LDIR
ld hl,(length)
ld c,0
call kl_rom_select
ld a,(&c002)
cp 0
jp z,cpc464
ld (&ae66),hl
ld (&ae68),hl
ld (&ae6a),hl
ld (&ae6c),hl
cp 1
jp z,cpc664
jp &ea78 ;; run BASIC CPC6128
.cpc664
jp &ea7d ;; run BASIC CPC664
.cpc464
ld (&ae83),hl
ld (&ae85),hl
ld (&ae87),hl
ld (&ae89),hl
jp &e9bd ;; run BASIC CPC464
;PRINT HEX$(PEEK(&AE67))
;PRINT HEX$(PEEK(&AE66))
length dw &01AC ; Address of start of variables (&AE66-67 in cpc6128-664, &AE83-84 in cpc464)
.Data
DB &0D,&00,&0A,&00,&02,&00,&00,&E1
DB &EF,&1A,&E8,&03,&00,&0D,&00,&14
DB &00,&02,&00,&00,&E2,&EF,&1A,&00
DB &01,&00,&10,&00,&1E,&00,&BF,&20
DB &02,&00,&00,&E1,&F4,&02,&00,&00
DB &E2,&00,&0A,&00,&28,&00,&BF,&22
DB &38,&29,&22,&00,&06,&00,&32,&00
DB &98,&00,&00,&00
.EndData
Quote from: issalig on 15:58, 08 June 21
Hi @Urusergi (https://www.cpcwiki.eu/forum/index.php?action=profile;u=923) , I have a question about the code, why 170+code_size is copied 4 times?
Hi, those four memory locations must have the same data. You can find out what they mean in this web page:
http://www.cantrell.org.uk/david/tech/cpc/cpc-firmware/mem-use.htm
Look at &AE66, &AE68, &AE6A, &AE6C
Hello, i'm learning about assembler z80. First i created a asm code with CPCTelera. When i read the default code i see for example the lines :
.area _DATA
----
---
.area _CODE
what mean these? for example i imagine _DATA is a macro define. DATA and CODE are areas of data programme (256bytes) and CODE is code programme. But the compiler start with $4000 address, how set this address?
Quote from: NicolasCanadea on 11:51, 28 August 22Hello, i'm learning about assembler z80. First i created a asm code with CPCTelera. When i read the default code i see for example the lines :
.area _DATA
----
---
.area _CODE
what mean these? for example i imagine _DATA is a macro define. DATA and CODE are areas of data programme (256bytes) and CODE is code programme. But the compiler start with $4000 address, how set this address?
Actually those areas are required due to the assembler version that it uses.
You may write everything after your .area _CODE line.
In cpctelera, there is a configuration file for make,
./cfg/build_config.mk and there you can find that configuration,
# Name of the project (without spaces, as it will be used as filename)
# and Z80 memory location where code will start in the generated binary
PROJNAME := menace
Z80CODELOC := 0x4000
there you have default code location. You may update it if required.
I would give a go to a different assembler.
CPCTelera uses the SDCC compiler suite that comes with an assembler that is powerful but has a few weird things in its syntax. On top of that, it uses a linker, and that's where the code and data sections kick in.
Is not impossible, but if you aren't using C, it adds a lot of complexity that may not play in your favour if you're learning.
Some people use pasmo, rasm, or the winape integrated assembler. IMHO those are better options.
FutureOS ASM , a nice quick thing :
Use the Q/W/E/S keys to move the "A" over the graphic.
Every time you move the "A" the image is updated very quickly without flickering.
It stops at the edges.
Use the "a" key to exit the program.
greeting
------------------------------------------
ORG &8000
; mode 1
LD A,(RAMCHAR)
SET 0,A
RES 1,A
LD (RAMCHAR),A
LD B,&7F
OUT (C),A
LD IX,LESC
CALL ROM_A2C
LD HL,S80X25
CALL ROM_A
LD BC,&7F10 ;border
OUT (C),C
LD A,&55
OUT (C),A
LD (BORDER),A ;border color &40-&5F
LD BC,&7F00 ;INK 0
OUT (C),C
LD A,&54
OUT (C),A
LD (INK_0),A ;paper color &40-&5F
LD BC,&7F01 ;INK 1
OUT (C),C
LD A,&52
OUT (C),A
LD (INK_1),A ;INK 1 color &40-&5F
LD BC,&7F02 ;INK 2
OUT (C),C
LD A,&4f
OUT (C),A
LD (INK_2),A ;INK 2 color &40-&5F
LD BC,&7F03 ;INK 3
OUT (C),C
LD A,&4c
OUT (C),A
LD (INK_3),A ;INK 3 color &40-&5F
LD A,(REG_PC+1)
ld a,0
LD (MEDIUM),A
;Lade Bild in E-RAM
LD BC,&7fc4
LD (AKT_RAM),BC
LD DE,LBI
CALL LABIER
anfang:
schleife:
call H_ALLET
jr z,schleife
ld (hl),a
cp "q"
jp nz,weiter1
ld a,(TXT+4)
dec a
cp &ff
jr nz,mache
jr gehe
mache:
ld (TXT+4),a
call posxy
gehe:
jp anfang
weiter1:
ld (hl),a
cp "e"
jr nz,weiter2
ld a,(TXT+4)
inc a
cp 40
jr nz,mache1
jr gehe1
mache1:
ld (TXT+4),a
call posxy
gehe1:
jp anfang
weiter2:
ld (hl),a
cp "w"
jr nz,weiter3
ld a,(TXT+3)
dec a
cp &ff
jr nz,mache2
jr gehe2
mache2:
ld (TXT+3),a
call posxy
gehe2:
jp anfang
weiter3:
ld (hl),a
cp "s"
jr nz,weiter4
ld a,(TXT+3)
inc a
cp 25
jr nz,mache3
jr gehe3
mache3:
ld (TXT+3),a
call posxy
jr gehe3
gehe3:
jp anfang
weiter4:
ld (hl),a
cp "a"
jp nz,anfang
call ende
TXT DB &02,&10, &1F,10,10,"A",&00
LBI DB &00,"BILDF001SCR"
MEDIUM DB &00
ende:
LD HL,TUR_E
JP ROM_D
ret
posxy:
LD BC,&7fc4
OUT (C),C
LD HL,&4000
LD DE,&C000
LD BC,&4000
LD IX,F_MOVE
CALL ROM_A2C
LD HL,TXT
CALL TER_BB
call FRAME
ret
FRAME:
LD B,&F5
FRA_L
IN A,(C)
RRCA
JR NC,FRA_L
RET
LABIER
LD A,&03
LD (REG08_4),A ;Laden in E-RAM
LD HL,&4000
LD (REG16_3),HL ;Ziel-Adresse ist &4000 im E-RAM bei 16 KB Bildern
LD A,(MEDIUM) ;Quell-Medium
LD IX,LADE_N
CALL ROM_A2C ;Lade Bild
INC A
JR NZ,LB_ERR ;A<>&FF --> Fehler beim Laden!
LD BC,&FA7E
LD A,(MO_ST)
OUT (C),A ;Laufwerks-Motoren ausschalten
LD BC,&7FC0
OUT (C),C ;Bank in Main RAM
LD A,&FF
RET ;A = &FF --> Bild wurde erfolgreich geladen!
;Fehler beim Laden
LB_ERR
LD BC,&FA7E
LD A,(MO_ST)
OUT (C),A
LD BC,&7FC0
OUT (C),C
XOR A
RET
;Switch ROM char set on = lower RAM on
romchar:
LD A,(RAMCHAR) ;actual RAM/ROM state
RES 2,A
LD (RAMCHAR),A ;set L-RAM on
LD B,&7F
OUT (C),A
ret
;Switch ROM char set off = lower ROM off
ramchar:
LD A,(RAMCHAR) ;actual RAM/ROM state
SET 2,A
LD (RAMCHAR),A ;set L-ROM off
LD B,&7F
OUT (C),A
ret
H_ALLET EQU &C02F
TER_GB EQU &CDF6
TER_BB EQU &CD4C
TER_GG EQU &CE80
TER_RR EQU &CF2A
AKT_RAM EQU &B84C
F_MOVE EQU &C0C8
LADE_N EQU &FD5C
REG_PC EQU &B8DA ;RAM
REG08_4 EQU &B8E0
REG16_3 EQU &B8EA
MO_ST EQU &B97F
STR_BB EQU &CA1C
C_POS EQU &B848
WATA EQU &FD38
TUR_E EQU &FE9D
RAMCHAR EQU &B847
LESC EQU &C017
ROM_A2C EQU &FF2A
OSRON_A EQU &FF22
OSRON_B EQU &FF58
OSRON_C EQU &FF8E
OSRON_D EQU &FFD6
ROM_A EQU &FF00
ROM_C EQU &FF0C
ROM_D EQU &FF12
ROM_D2A EQU &FFBA
S64X32 EQU &D5A8
S80X25 EQU &D60E
BORDER EQU &BB91
INK_0 EQU &BB92
INK_1 EQU &BB93
INK_2 EQU &BB94
INK_3 EQU &BB95
TERM_2 EQU &D48C
TERM_2D EQU &D2F7
TERM_2I EQU &D358
TERM_2K EQU &D3C0
TERM_2U EQU &D42
Please put it on disc, the picture to be loaded is missing. Also there is a missing letter in the source code: TERM_2U EQU &D42C
This Picture is in the BILDF001.ZIP 1,33kb
"C" is been stolen...
greeting.