News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Example Z80 assembly programs (was:ASM source code)

Started by arnoldemu, 08:59, 04 April 10

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

arnoldemu

A new example:

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".


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

arnoldemu

#101
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

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.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

AMSDOS

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
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Devilmarkus

This routine is nice and fast.
Could you do the same with a sprite which doesnt destroy the background?
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

AMSDOS

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.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

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



* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AugustoRuiz

Any docs on how to read from disk, not using the firmware?

Thank you for this great thread!

arnoldemu

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?

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

AugustoRuiz

I'd like to read a big file in chunks, so I can process each chunk while reading the next one. For audio playing ;)

arnoldemu

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.


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

arnoldemu

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.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

#111
Quote from: arnoldemu on 12:15, 29 March 13
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.

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


arnoldemu

Example of how to make a multi-load game/program:

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.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

AMSDOS


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
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

redbox

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.

tastefulmrship

#116
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!)

Devilmarkus

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
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

AMSDOS

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.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

redbox

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.


AMSDOS


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
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ralferoo

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)

AMSDOS

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
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

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.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

arnoldemu

New example:

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:
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Powered by SMFPacks Menu Editor Mod