Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Expanding Elite

Started by Fessor, 18:15, 21 July 21

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


Out of boredom I started ghidra and started to disassemble Elite to see if we could get the full shipset in there.
Elite draws its graphics mainly in a background bitmap at address 0xa000 to 0xc000 and then copies it to the screenmemory at 0xc000, so banking should be possible. After several hours, proof-of-concept for a 128k version is achieved.

Thanks to banking, it has now been possible to free up space for the ships' data storage in the invisible program code, which is stored in the image memory,

The routines stored in the image memory are now, enriched with the ship definitions and the character set, stored in bank C9 and graphics routines are patched in such a way that they activate the image memory again when something is to be displayed. *)

There was also room in the program code itself, as the table with the ship's data was moved to the banked area and a routine that transferred the character set from the ROM to the hidden screen area could also be thrown out.

I was able to find graphic data for the ships in dissassembled versions for the Apple and C64, unfortunately the information in the headers and from the edges and faces differ and I have not yet been able to get Elite to display one of the newly added models because the purpose of some of the data in the headers is unknown. In the versions for the 6052s, the header is 20 bytes; at the CPC (and probably also Speccy) 23 bytes. Part of the data is identical, but is in different places.

The basic idea of ​​the whole thing is, since Elite is a Speccy port, to compare the codes with each other and then to compare the codes with the Russian extension and possibly port them ....
Unfortunately, I am not familiar with the spectrum at all and have no ideas how I can get the binary files from TAP files or disk images and would be very grateful if someone could send me the bin files with load addresses

*) The routines for the text screens have successfully evaded treatment for several hours and you sat in front of a screen and wondered why nothing happened after the second splash screen and it looked as if the program was hanging before i found out, that bankswitching of the routine was wrong and the text was drawn on the wrong bank.


OMG - this is fantastic. Elite on the CPC was the game I spent most time with in my whole life. Although I only reached "deadly" status.

So, I hope you are still bored for a few more sessions ;-) and I will definitely give this a try once it's playable.



@reidrac is familar with both systems, maybe he can offer some support.


This is a very exciting project!
I'm wondering, if you're changing it from a screen buffer copy method to banking, is there a small speed-up?


Very cool. But since you now have more memory, maybe revamp the game a bit more and add, for example, music? Like "battle" music when enemies are encountered, "docking" music, "station" music, etc. Could be interesting. But that implies being able to detect such situation, which may not be so easy.

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

Sykobee (Briggsy)

Can you share all the ship header + data from the BBC and the CPC versions? Maybe some group investigation will find a solution.


Wasn't the BBC Micro source code for Elite released long time ago from Ian Bell ?


Quote from: SkulleateR on 12:52, 22 July 21
Wasn't the BBC Micro source code for Elite released long time ago from Ian Bell ?




Finding disassemblies for the 6502s is no problem. I use the code from the Apple version , and everything is pretty well documented there and also the c-source of Elite TNK to understand the flow of the Program.. They all profit from the published source code for the BBC. (Dont know if it would be possible to use the c-source with sdcc)
But you can't find anything for the Z80. I have expected, since the ZX scene is bigger, that someone would have published something. But even of the extended Russian versions "Elite 2 / Elite 3" there is no source code to be found.
The MSX has been given a completely independent version, but there is nothing to be found there either.

Using the color tables, I was able to locate the various menus (marketplace, planet info, galactic / local map, etc.) and I want to trace through the galactic map in order to locate the graphic functions, among other things. Perhaps I can use the graphics functions to track down the problem of why the supposedly cleanly converted data is not drawn. Somewhere the whole calculation has to lead to a list of coordinates according to which the lines are to be drawn.

Attached are the CPC ship definitions for comparison with the 6502 versions, structure definitions as a c-header file and, if one want to debug, a symbol table for the first recognized functions for Winape.


Holy cow! I didn't know it's a Spectrum port - and still that quick!
However, looking at Starglider / Starfox the speed difference is visible.

Great project! Good luck!  :) :) :) --> Get the revolutionary FutureOS (Update: 2023.11.30) --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)


Quote from: GUNHED on 02:21, 23 July 21
Holy cow! I didn't know it's a Spectrum port - and still that quick!
However, looking at Starglider / Starfox the speed difference is visible.

Great project! Good luck!  :) :) :)

Although based on the Speccy version, it's pretty obvious a fair bit of effort went into improving the code for the Amstrad specifically. The Speccy version didn't have colour planets for example.


Quote from: andycadley on 08:12, 23 July 21

Although based on the Speccy version, it's pretty obvious a fair bit of effort went into improving the code for the Amstrad specifically. The Speccy version didn't have colour planets for example.
Maybe, but it still uses the speccy screen and then converts it to CPC. --> Get the revolutionary FutureOS (Update: 2023.11.30) --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

Sykobee (Briggsy)

It sounds like there's a lot of room for improvement when it comes to the graphics rendering pipeline.


I was able to successfully narrow down the drawing routine for the circles, even if I don't quite understand the mechanics behind it. I have no idea whether you can put a mask on the outer boundary or I just haven't found it yet. The code modifies itself to set a mask, but that only affects the rough inside of the circle. I might guess that these bytes are simply drawn from a table depending on the radius.

The spectrum also has filled circles, e.g. used for the sun. They probably had to make compromises because of the color clashing and made the decision to leave it to simple circles. Filled planets and xored vector graphics probably didn't look that good.


Thanks to Breakpoint on memory change I have found the drawing routine for the lines.
Actually, there are two routines, I suspect a dependence on the direction in which should be drawn.
At address position 0x800d, the one and 0x8025 is directly following the other.
putPixelbyteRoutine1                                             XREF[3]:     ram:7d37(j), ram:8020(j),
    ram:800d 7e                 LD                 A,(HL)
    ram:800e b1                 OR                 C
    ram:800f 77                 LD                 (HL),A
    ram:8010 15                 DEC                D
    ram:8011 c8                 RET                Z
    ram:8012 7b                 LD                 A,E
    ram:8013 80                 ADD                A,B
    ram:8014 5f                 LD                 E,A
    ram:8015 3005               JR                 NC,LAB_ram_801c
                LAB_ram_8017+1                                                   XREF[0,1]:   ram:7d14(W) 
    ram:8017 cb09               RRC                C                                           ; or rlc c
    ram:8019 3001               JR                 NC,LAB_ram_801c
                LAB_ram_801b                                                     XREF[1]:     ram:7d1b(W) 
    ram:801b 2c                 INC                L                                           ; or dec l
                LAB_ram_801c                                                     XREF[2]:     ram:8015(j), ram:8019(j) 
    ram:801c 7d                 LD                 A,L
                LAB_ram_801d                                                     XREF[1]:     ram:7d22(W) 
    ram:801d c640               ADD                A,0x40                                      ; unchanged byte 0xc6; next Screenline of Background-Bitmap
    ram:801f 6f                 LD                 L,A
    ram:8020 30eb               JR                 NC,putPixelbyteRoutine1
                LAB_ram_8022                                                     XREF[1]:     ram:7d29(W) 
    ram:8022 24                 INC                H                                           ; unchanged byte 0x24
    ram:8023 18e8               JR                 putPixelbyteRoutine1

putPixelbyteRoutine2                                             XREF[3]:     ram:7d7b(j), ram:8038(j),
    ram:8025 7e                 LD                 A,(HL)
    ram:8026 b1                 OR                 C
    ram:8027 77                 LD                 (HL),A
    ram:8028 15                 DEC                D
    ram:8029 c8                 RET                Z
    ram:802a 7b                 LD                 A,E
    ram:802b 80                 ADD                A,B
    ram:802c 5f                 LD                 E,A
    ram:802d 3007               JR                 NC,LAB_ram_8036
    ram:802f 7d                 LD                 A,L
                LAB_ram_8030                                                     XREF[1]:     ram:7d58(W) 
    ram:8030 c640               ADD                A,0x40                                      ; unchanged byte 0xc6
    ram:8032 6f                 LD                 L,A
    ram:8033 3001               JR                 NC,LAB_ram_8036
                LAB_ram_8035                                                     XREF[1]:     ram:7d5f(W) 
    ram:8035 24                 INC                H                                           ; unchanged byte 0x24
                LAB_ram_8036+1                                                   XREF[2,1]:   ram:802d(j), ram:8033(j),
                LAB_ram_8036                                                                  ram:7d66(W) 
    ram:8036 cb09               RRC                C                                           ; or rlc c
    ram:8038 30eb               JR                 NC,putPixelbyteRoutine2
                LAB_ram_803a                                                     XREF[1]:     ram:7d6d(W) 
    ram:803a 2c                 INC                L                                           ; or dec l
    ram:803b 18e8               JR                 putPixelbyteRoutine2

A central location for the LINEDRAWs takes on the routine at address 0x7EFC, which calculates the byte address of a coordinate in the offscreen bitmap
                todo_CalcPointAdressinBitmap                                     XREF[4]:     ram:7ccc(c), ram:7cd9(c),
                                                                                              ram:7e9a(c), ram:7ed8(c) 
    ram:7efc c5                 PUSH               BC
    ram:7efd d5                 PUSH               DE
    ram:7efe d9                 EXX
    ram:7eff c1                 POP                BC                                          ; startcoordinates?
    ram:7f00 d1                 POP                DE                                          ; endcoordinates?
    ram:7f01 cb4a               BIT                0x1,D                                       ; purpose unknown
    ram:7f03 2005               JR                 NZ,LAB_ram_7f0a
    ram:7f05 3e7f               LD                 A,0x7f
    ram:7f07 80                 ADD                A,B
    ram:7f08 1803               JR                 LAB_ram_7f0d
                LAB_ram_7f0a                                                     XREF[1]:     ram:7f03(j) 
    ram:7f0a 3e7f               LD                 A,0x7f
    ram:7f0c 90                 SUB                B
                LAB_ram_7f0d                                                     XREF[1]:     ram:7f08(j) 
    ram:7f0d 47                 LD                 B,A
    ram:7f0e cb42               BIT                0x0,D
    ram:7f10 2805               JR                 Z,LAB_ram_7f17
    ram:7f12 3e3f               LD                 A,0x3f
    ram:7f14 81                 ADD                A,C
    ram:7f15 1803               JR                 .calcAdressforBM
                LAB_ram_7f17                                                     XREF[1]:     ram:7f10(j) 
    ram:7f17 3e3f               LD                 A,0x3f
    ram:7f19 91                 SUB                C
                .calcAdressforBM                                                 XREF[1]:     ram:7f15(j) 
    ram:7f1a 48                 LD                 C,B
    ram:7f1b 2602               LD                 H,0x2                                       ; 16k memory Block (0..3)
    ram:7f1d 6f                 LD                 L,A                                         ; Adresscalculation (Memblock*2+1)*32 + x/4 (because of 4 Pixel per
                                                                                               ; Byte in Mode 1) + y*64
    ram:7f1e 29                 ADD                HL,HL
    ram:7f1f 24                 INC                H                                           ; make Sure the Calculation leads to Adress 0xa000 (upper 8k of block 2)
    ram:7f20 29                 ADD                HL,HL
    ram:7f21 29                 ADD                HL,HL
    ram:7f22 29                 ADD                HL,HL
    ram:7f23 29                 ADD                HL,HL
    ram:7f24 29                 ADD                HL,HL
    ram:7f25 79                 LD                 A,C
    ram:7f26 cb3f               SRL                A
    ram:7f28 cb3f               SRL                A
    ram:7f2a 85                 ADD                A,L
    ram:7f2b 6f                 LD                 L,A
    ram:7f2c 79                 LD                 A,C
    ram:7f2d e603               AND                0x3                                         ; Pixellocation in the byte?
    ram:7f2f 3c                 INC                A
    ram:7f30 47                 LD                 B,A
    ram:7f31 0e11               LD                 C,0x11
                LAB_ram_7f33                                                     XREF[1]:     ram:7f35(j) 
    ram:7f33 cb09               RRC                C
    ram:7f35 10fc               DJNZ               LAB_ram_7f33
    ram:7f37 43                 LD                 B,E
    ram:7f38 1e80               LD                 E,0x80
    ram:7f3a d9                 EXX
    ram:7f3b c9                 RET

And then there is another nice part that modifies the drawing routines at runtime
                todo_drawJumpEntrypoint2                                         XREF[6]:     ram:7ce2(j), ram:7f62(j),
                                                                                              ram:7f65(j), ram:7f6e(j),
                                                                                              ram:7f71(j), ram:7f7e(j) 
    ram:7ce5 d9                 EXX
    ram:7ce6 fe02               CP                 0x2
    ram:7ce8 3002               JR                 NC,LAB_ram_7cec
    ram:7cea 3e02               LD                 A,0x2
                LAB_ram_7cec                                                     XREF[1]:     ram:7ce8(j) 
    ram:7cec 3d                 DEC                A
    ram:7ced 57                 LD                 D,A
    ram:7cee d9                 EXX
    ram:7cef 7a                 LD                 A,D
    ram:7cf0 e61c               AND                0x1c
    ram:7cf2 fe0e               CP                 0xe
    ram:7cf4 3044               JR                 NC,manipulate_drawroutine2
    ram:7cf6 fe06               CP                 0x6
                manipulate_drawroutine1                                          XREF[3]:     ram:73a8(c), ram:7450(c),
    ram:7cf8 300c               JR                 NC,LAB_ram_7d06
    ram:7cfa fe02               CP                 0x2
    ram:7cfc 212d01             LD                 HL,0x12d                                    ; 0x01 to change from 0xcb,0x09 "RRC C" to 0xcb,0x01 "RLC C"; 0x2d to
                                                                                              ; change from 0x2c "INC L" to 0x2d "DEC L"
    ram:7cff 1124c6             LD                 DE,0xc624                                   ; dont know, why its here, because nothing is changed and the code left
                                                                                              ; by add a,0x40 and inc h
    ram:7d02 380f               JR                 C,.md1_patchcommands
    ram:7d04 180a               JR                 LAB_ram_7d10
                LAB_ram_7d06                                                     XREF[1]:     ram:7cf8(j) 
    ram:7d06 fe0a               CP                 0xa
    ram:7d08 212c09             LD                 HL,0x92c                                    ; switches codes to "rrc c" and "inc l"
    ram:7d0b 1124c6             LD                 DE,0xc624                                   ; has no effect as nothing changes
    ram:7d0e 3803               JR                 C,.md1_patchcommands
                LAB_ram_7d10                                                     XREF[1]:     ram:7d04(j) 
    ram:7d10 cbe2               SET                0x4,D
    ram:7d12 1c                 INC                E
                .md1_patchcommands                                               XREF[2]:     ram:7d02(j), ram:7d0e(j) 
    ram:7d13 7c                 LD                 A,H
    ram:7d14 321880             LD                 (LAB_ram_8017+1),A                          ; RLC C
    ram:7d17 324b80             LD                 (LAB_ram_804a+1),A                          ; RLC C
    ram:7d1a 7d                 LD                 A,L
    ram:7d1b 321b80             LD                 (LAB_ram_801b),A                            ; inc l
    ram:7d1e 324e80             LD                 (LAB_ram_804e),A                            ; inc l
    ram:7d21 7a                 LD                 A,D
    ram:7d22 321d80             LD                 (LAB_ram_801d),A                            ; add a,0x40
    ram:7d25 325080             LD                 (LAB_ram_8050),A                            ; add a,0x40
    ram:7d28 7b                 LD                 A,E
    ram:7d29 322280             LD                 (LAB_ram_8022),A                            ; inc h
    ram:7d2c 325580             LD                 (LAB_ram_8055),A                            ; inc h
    ram:7d2f d9                 EXX
    ram:7d30 3af18c             LD                 A,(BYTE_ram_8cf1)
    ram:7d33 a7                 AND                A
    ram:7d34 c23d80             JP                 NZ,LAB_ram_803d
    ram:7d37 c30d80             JP                 putPixelbyteRoutine1
                manipulate_drawroutine2                                          XREF[1]:     ram:7cf4(j) 
    ram:7d3a fe16               CP                 0x16
    ram:7d3c 300c               JR                 NC,LAB_ram_7d4a
    ram:7d3e fe12               CP                 0x12
    ram:7d40 2124c6             LD                 HL,0xc624                                   ; has no effect as nothing changes
    ram:7d43 112d01             LD                 DE,0x12d                                    ; changes codes to "RLC C" and "DEC L"
    ram:7d46 380f               JR                 C,.md2_patchcommands
    ram:7d48 180a               JR                 LAB_ram_7d54
                LAB_ram_7d4a                                                     XREF[1]:     ram:7d3c(j) 
    ram:7d4a fe1a               CP                 0x1a
    ram:7d4c 2124c6             LD                 HL,0xc624                                   ; has no effect as nothing changes
    ram:7d4f 112c09             LD                 DE,0x92c                                    ; changes codes to "RRC C" and "INC L"
    ram:7d52 3803               JR                 C,.md2_patchcommands
                LAB_ram_7d54                                                     XREF[1]:     ram:7d48(j) 
    ram:7d54 cbe4               SET                0x4,H
    ram:7d56 2c                 INC                L
                .md2_patchcommands                                               XREF[2]:     ram:7d46(j), ram:7d52(j) 
    ram:7d57 7c                 LD                 A,H
    ram:7d58 323080             LD                 (LAB_ram_8030),A
    ram:7d5b 326680             LD                 (LAB_ram_8066),A
    ram:7d5e 7d                 LD                 A,L
    ram:7d5f 323580             LD                 (LAB_ram_8035),A
    ram:7d62 326b80             LD                 (LAB_ram_806b),A
    ram:7d65 7a                 LD                 A,D
    ram:7d66 323780             LD                 (LAB_ram_8036+1),A
    ram:7d69 326d80             LD                 (LAB_ram_806c+1),A
    ram:7d6c 7b                 LD                 A,E
    ram:7d6d 323a80             LD                 (LAB_ram_803a),A
    ram:7d70 327080             LD                 (LAB_ram_8070),A
    ram:7d73 d9                 EXX
    ram:7d74 3af18c             LD                 A,(BYTE_ram_8cf1)
    ram:7d77 a7                 AND                A
    ram:7d78 c25880             JP                 NZ,LAB_ram_8058
    ram:7d7b c32580             JP                 putPixelbyteRoutine2

I wonder what has to be changed at the drawingroutines to draw for mode 0. As there exists an interrupt driven colorsplit, inserting the GA-Commands for modesplit should be no problem.


Oooh interesting.
Will the purpose of this project be to speed up the gameplay? I remember it plays a lot slower than the BBC original and that made me sad when I saw them compared :(


I still have no idea where the project will take me. I still want to patch the additional ships in and have still no idea, why its not showing them.
A first milestone has been reached, the source code has been reconstructed to such an extent that all data and code areas are clearly uncovered and the assembler can turn it into an executable program.

Now I want to try to relocate parts of the program to move the screen memory to 0x4000. Move all routines that are now in memory bank 1 to memory bank 3. And move the parts that are "behind" the screen memory to 0x4000.
If that works, look to get rid of the offscreen bitmap and draw directly into the screenmemory

And if that works: try double buffering. If I got it right:
Banking mode C1 results in memory banks 0,1,2,7 and C3 results in memory banks 0,3,2,7.
So both banks for the screen memory are always at central 0x4000-0x7fff and an always present bank 7 for the code from 0xc000-0xffff.

Since the CRTC can only see the original memory banks 0..3, and not the switched ones, it should be possible to organize which of the banks is to be displayed when when drawing operations are completed.

C1: 0,1,2,7, drawing in bank 1, displaying original bank 3 at 0xc000
C3: 0,3,2,7, drawing in switched-in bank 3, displaying original bank 1 at 0x4000

With luck, Elite will run faster because copying from the offscreen bitmap to the screen memory is no longer necessary.
It should be possible to adapt the drawing routines to the image memory organization of the CPC with relatively little effort.


Yes, that is great what you're doing - get to grips with the code and place/arrange it more suited to the Amstrad and how you can understand it, etc. I get it.
Then it'll be interesting to see what improvements are gained and what can be done.
Obviously at that point I'd say priority for me would be improving the speed.
But I didn't know ships were missing. Are many missing compared to the BBC version?

When this is achieved I'd definitely be interested in streaming this to my audience on Twitch etc.


We are missing 12 ships and one Station.

Dodecahedron Station


You can gain a further 16kb if you can put some code into ROM - since ROM is readonly, you can leave it paged in always over the screen RAM - and as long as you don't put variables in that area, you can just write to the paged in ROM and it will go to screen RAM.  Of course that limits the game to those who have a ROM board of some type.


Time for a little Experiment.Insert on the english Version in Elite.bas, before the CALL &1C82, POKE &1EDF,8. Its a counter for the copyloop of the Framebuffer, and sets it to copy only half of the Framebuffer to the screen, enough to see an increase of fps. Compare it with an parallel running Emulator.
So avoiding the Framebuffer and going to Doublebuffering will lead to a massive boost in fps.
The Cockpit has also Transferroutines, but i have not found yet the Routines where the Indicators where drawn.
Thats the bigger Part of the screen and don't use unrolled LDIs for the transfer to the screenmemory.


i wonder if you have disassembled it that far, whether it can have a Raspberry Pi patch for the CPC's Raspberry Pi card?  There is a tube port for BBC which gives it a performance boost - i wonder if the CPC would gain a similar performance boost?


The program is almost completely disassembled.
But I don't know what a patch for the card could look like and what it should do. Somebody else can do that as soon as I've published the source code.

I have serious problems recognizing the mathematical functions. I can see them roughly in the program flow, but I don't know what which function actually does. There may also be potential for acceleration in the math routines, as the index registers are used a lot, but that is far beyond my knowledge, and maybe not neccessary, as the biggest brake, however, is the transfer from the framebuffer to the screen memory.
In my opinion, the render pipeline is a bit too long because it sorts out which lines are to be drawn predominantly horizontally and which lines are predominantly to be drawn vertically.

That made sense with the 6502s, where the lines were drawn without double buffering and then immediately deleted, but led also to extreme flickering.
This drawing strategy means that a large part of the ship's dimension is always present on the screen and the ship is easier to recognize. BBC may currently have better FPS, but it is flickering and has very noticeable drops in the frame rate.

This drawing strategy makes no sense when drawing in a backbuffer. You can just go ahead and draw and when the scenery is finished, just show it. Bresenham is already used for drawing, they "only" have to be adapted to the memory organization of the CPC and draw directly into the screen memory.

RASM says:------ statistics ------------------
1 file
0 binary include
90163 words
2451 labels
0 struct
0 var
33529 expressions
0 macro
67 aliass
3 ORG zones
261 virtual spaces

327909 bytes of pure code
474 Labels have been named, many with todo-flags for further inspection


I retraced the drawing routines after the line drawing was halfway adapted to the screen memory.
The drawing itself works, but the number of line segments doesn't fit. Somewhere there is still something in the Bresenham algorithm that calculates the line length incorrectly if you feed it with memory addresses from the CPC screen memory.

At least I was able to find where the data for the vertices, edges and faces are read out and identify another data field in the header and had to try it out right away.

Et voila: The Constrictor

Powered by SMFPacks Menu Editor Mod