Jump to content


Photo

Free space and code optimisation in Manic Miner


  • Please log in to reply
22 replies to this topic

#1 IRF

IRF

    Advanced Member

  • Contributor
  • 4,228 posts

Posted 21 November 2018 - 01:17 PM

I thought I might create a similar 'optimisation' thread to the JSW one.

 

I implemented a lot of code optimisations of the MM game engine in the recent release 'Manic Mixup'.  However, this one slipped through the next (I've only just thought of it):

 

It involves a rewrite of the routine at #92DC which plays the theme tune (Blue Danube).  I think this saves around 12 bytes.  EDIT: It actually saves eight bytes.  (I forgot to count the CALL to test the Enter key, and the RET back to the Title Screen routine if Enter is pressed.)

 

start:

       LD A, (IY+$00)

       INC A

       RET Z

       LD BC, #5028

       CALL update_piano_keys

       LD B, #00

       LD C, (IY+$00)

       LD H, D

       LD L, E

tune_loop:

       OUT (#FE), A

       DEC D

       JR NZ, not_time_for_note_1

       LD D, H

       XOR #18

not_time_for_note_1:

       DEC E

       JR NZ, not_time_for_note_2

       LD E, L

       XOR #18

not_time_for_note_2:

       DJNZ tune_loop

       DEC C

       JR NZ, tune_loop

       LD BC, #3838

       CALL update_piano_keys

       CALL #9337                            Check whether ENTER or the fire button is being pressed

       RET NZ

       LD DE,#0003

       ADD IY, DE

       JR start

 

update_piano_keys:

       LD A, (IY+$01)

       LD D, A

       CALL #932B

       LD (HL), B

       LD A, (IY+$02)

       LD E, A

       CALL #932B

       LD (HL), C

       RET


Edited by IRF, 23 November 2018 - 11:24 AM.


#2 IRF

IRF

    Advanced Member

  • Contributor
  • 4,228 posts

Posted 22 November 2018 - 09:18 AM

This doesn't relate to code optimisation, but it's an observation about a bug/glitch/peculiarity in the original Manic Miner.

 

When the title screen tune is playing, there is a pause towards the end (enacted by having a pair of 'zero notes', at #8541 and #8542).  You might expect that none of the piano keys are highlighted at that point, since no notes are being played, but in fact the left-most key of the piano is highlighted (in cyan).

 

I know that the positioning of the coloured keys isn't actually representative of the notes that would be played on a real piano, but the above seems particularly incongruous.


Edited by IRF, 22 November 2018 - 09:18 AM.


#3 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 235 posts

Posted 22 November 2018 - 10:45 AM

If the zero's are changed to any other value you can move the illuminated note up to any position, as long as they both stay the same value, you will still have silence. Which does not change the fact that the keyboard illuminates. 

Since the design of the keyboard looks like it was constructed from several broken ones. Lets just assume that the far left key is not working, and when struck the keyboard makes no noise. 


Edited by Norman Sword, 22 November 2018 - 10:45 AM.


#4 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 235 posts

Posted 23 November 2018 - 11:51 AM

My original edit of this from around six months ago is only 12 bytes shorter than the post #0

I admit I have had numerous attempts at shrinking the code, in most case the end result  stayed about the same size. So those numerous attempts where deleted months ago.

I did however try one more time to edit this routine, and I did save a few bytes. My final edit for the overall Manic Miner Music routine is around 57 bytes smaller than the Music routine from post #0

 

I did however try one more time to edit this routine, and I did save a few bytes. My final edit for the overall Manic Miner Music routine is around 57 bytes smaller than the overall Music routine from post #0

So you know it can be done.


Addendum

The music routine consists of two parts. The code to play the music and the music data. One without the other serve no purpose in the game. 


Edited by Norman Sword, 23 November 2018 - 02:48 PM.


#5 IRF

IRF

    Advanced Member

  • Contributor
  • 4,228 posts

Posted 23 November 2018 - 01:07 PM

It did strike me that there's still some repetition of code in my rewrite - the use of D and then E as pitch delay counters for the two notes could possibly utilise a shared subroutine, if the registers were swapped about carefully?

 

Oh, I presume that there's a comma missing in the last post: "My final edit for the overall Manic Miner Music routine is around 57 bytes smaller than the Music routine from post #0" should read "My final edit for the overall Manic Miner Music routine is around 57 bytes, smaller than the Music routine from post #0" - unless you've managed to compress the routine down to 14 bytes in length! :o


Edited by IRF, 23 November 2018 - 01:10 PM.


#6 IRF

IRF

    Advanced Member

  • Contributor
  • 4,228 posts

Posted 23 November 2018 - 04:19 PM

The music routine consists of two parts. The code to play the music and the music data. One without the other serve no purpose in the game.


So you're saying that you compressed the data, as well as optimising the Z80 code?

Edited by IRF, 23 November 2018 - 09:33 PM.


#7 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 235 posts

Posted 27 November 2018 - 12:42 AM

Compressed the data and the optimised the code routine size. I have since chopped another fives bytes of the routine, so around 62 bytes smaller. Going solely from your data of eight bytes. I assume a saving of around 70 bytes from the original.



#8 Norman Sword

Norman Sword

    Advanced Member

  • Member
  • PipPipPip
  • 235 posts

Posted 27 November 2018 - 12:53 AM

Edited and swapped some registers around - another 2+ bytes smaller

 

This code can be placed anywhere in ram.

 

;The complete title music routine (data and code) for Manic Miner

;
Manic_Miner_Title_Music:
        ld de,Tune_Data
;
manic_loop:
        ld a,(de) 
        OR A          
        RET Z
        AND 3              
        LD HL,TIME_SHIFT
        CALL STEP_INDEX  

        LD C,A                                << added   
        LD (S_M_C_ahead),A
        LD A,(DE)
        LD HL,NOTE_SHIFT
        CALL STEP1_INDEX

        LD B,A                               << added
        LD C,A
        INC DE
        LD A,(DE) 
        inc de
        push de
        ld d,a   ;NOTE 1            
        CALL NOTE_PLACE
        push hl
        ld (hl),#50
        ld a,d

        add a,b                             << added        
        add a,c 
        ld e,a  :NOTE 2           
        call NOTE_PLACE  
        push    hl
        ld (hl),#28
        LD A,L 
        ld l,e  ;NOTE 2   (lows)  
        ld h,d ;NOTE 1 (highs)

        ld b,0                              <<added
S_M_C_ahead: equ $+1
        ld      bc,0   

tune_loop:
        OUT (#FE), A 
        DEC D   :NOTE 1 (highs)                  
        JR NZ,tl_1  
        LD D,H                
        XOR #18                 
tl_1:
        DEC E : NOTE 2 (lows)                   
        JR NZ,tl_2  
        LD E,L                  
        XOR #18                 
tl_2:
        DJNZ tune_loop          
        DEC C                   
        JR NZ, tune_loop        
        POP HL             
        LD (HL),56
        POP HL             
        LD (HL),56
       POP DE
        CALL test_enter ;#9337
        RET NZ               
        JR manic_loop          

;
NOTE_PLACE:
        LD HL,#59e0       ; with this code, the piano address can be at the start of any attribute line
        SUB 8      
        CPL 
STEP1_INDEX
        RRCA
        RRCA
        RRCA
        and 31
STEP_INDEX:
        ADD A,L
        LD L,A
        ADC A,H
        SUB L
        LD H,A
        LD A,(HL)
        RET

;
TIME_SHIFT: DB 25,50,80,100
NOTE_SHIFT: DB  0, 1, 6, 8, 10, 11, 13, 20, 21, 24, 32, 43, 75, 77, 128, 154
;
Tune_Data:  
DB 2+8*1,128
DB 2+8*1,102
DB 2+8*1,86
DB 1+8*1,86
DB 1+8*10,171
DB 1+8*3,43
DB 1+8*3,43
DB 1+8*10,51
DB 1+8*6,64
DB 1+8*6,64

DB 1+8*10,171
DB 1+8*1,128
DB 1+8*1,128
DB 1+8*1,102
DB 1+8*1,86
DB 1+8*4,86
DB 1+8*8,171
DB 1+8*4,43
DB 1+8*4,43
DB 1+8*8,171

DB 1+8*7,48
DB 1+8*7,48
DB 1+8*8,171
DB 1+8*1,136
DB 1+8*1,136
DB 1+8*1,114
DB 1+8*1,76
DB 1+8*1,76
DB 1+8*8,171
DB 1+8*8,38

DB 1+8*8,38
DB 1+8*8,171
DB 1+8*7,48
DB 1+8*7,48
DB 1+8*8,171
DB 1+8*1,136
DB 1+8*1,136
DB 1+8*1,114
DB 1+8*1,76
DB 1+8*1,76

DB 1+8*10,171
DB 1+8*6,38
DB 1+8*6,38
DB 1+8*10,171
DB 1+8*6,51
DB 1+8*6,51
DB 1+8*10,171
DB 1+8*1,128
DB 1+8*1,128
DB 1+8*1,102

DB 1+8*1,86
DB 1+8*1,64
DB 1+8*11,128
DB 1+8*5,32
DB 1+8*5,32
DB 1+8*11,128
DB 1+8*3,43
DB 1+8*3,43
DB 1+8*11,128
DB 1+8*1,128

DB  1+8*1,128
DB 1+8*1,102
DB 1+8*1,86
DB 1+8*1,64
DB 1+8*9,128
DB 1+8*2,32
DB 1+8*2,32
DB 1+8*9,128
DB 1+8*4,38
DB 1+8*4,38

DB 1+8*0,0
DB 1+8*1,114
DB 1+8*1,114
DB 1+8*1,96
DB 1+8*1,76
DB 1+8*13,76
DB 1+8*1,77
DB 1+8*1,77 
DB 1+8*13,76
DB 1+8*1,91

DB 1+8*1,86
DB 1+8*15,51
DB 1+8*1,51
DB 1+8*1,51
DB 1+8*15,51
DB 1+8*1,64
DB 1+8*1,102
DB 1+8*1,102
DB 3+8*1,114
DB 1+8*1,76

DB 1+8*1,86

DB 1+8*12,128
DB 0+8*14,128 
DB 0+8*1,128
DB 1+8*12,128

DB 0 ;

 

 

Addendum:-

 

slight change shortens code by 3 more bytes so around 73+ bytes smaller.
 


Edited by Norman Sword, 04 December 2018 - 01:02 AM.


#9 IRF

IRF

    Advanced Member

  • Contributor
  • 4,228 posts

Posted 27 November 2018 - 06:14 PM

A most cunning rewrite, Norman!  Especially the shared subroutine for decompressing the data and determining which piano key gets highlighted!

 

I presume that this element (the bit in bold):

 

 


ADD A, L

LD L, A

ADC A,H
SUB A, L
LD H,A

LD A, (HL)

 

is there to take into account the possibility that the 'time shift' and 'note shift' look-up tables might be in a position which straddles two pages of memory?  That's a very useful technique; thanks for drawing my attention to it.

 

Incidentally, I believe that the following would achieve the same thing (in the same number of bytes):

 

    ADD A, L

    LD L, A

    JR NC, grab_data

    INC H

grab_data:

    LD A, (HL)

 

 

******

 

One subtle visual difference that your alternative code might produce - the pair of 'almost matching' notes at the start of the tune holds pitch values #80 and #81.  With the original code, playing that pair of 'almost matching' notes only illuminates a single piano key (in cyan).  With your version, I believe (without having tried it out yet) that two adjacent keys will be illuminated (one in red, one cyan).  This is because the two notes end up on opposite sides of an 'octal boundary'.  (Each piano key corresponds to an 'octet' of pitch values. i.e. for every increase in the pitch value of 8, we proceed from highlighting one piano key to the next).

 

That discrepancy could be resolved by tweaking the data (so that the corresponding pitch values are #7F and #80, and a similar consideration could be given for other values that are close to an 'octal boundary').  I don't believe that the perceived difference in pitch would be audible.

 

**

 

On the other hand, your code has the effect of fixing a little-known 'bug'* in the original game engine - namely that if you try to play a note of extremely high pitch (holding a value between #01 and #07), then the leftmost piano key gets highlighted, whereas you would expect the far right-hand piano key to be the one that is illuminated for such a high-pitched note.  (*It's a 'theoretical bug', because of course no note of that pitch manifests itself in the title tune data.)

 

The fix which I came up with for that is to replace the SUB A, #08 at #932B with a DEC A; I think your code will have the same effect in terms of determining when the transition from one highlighted key to another occurs.

 

(Your previous comment about "design of the keyboard [looking] like it was constructed from several broken ones" is also relevant here!)


Edited by IRF, 28 November 2018 - 04:39 PM.


#10 IRF

IRF

    Advanced Member

  • Contributor
  • 4,228 posts

Posted 28 November 2018 - 09:20 AM

LD (HL), 56


I've got so used to thinking in hexadecimal that I thought at first you were colouring in the piano keys with yellow INK with that command! :lol:


Edited by IRF, 28 November 2018 - 10:09 AM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users