Dethmunk wrote:Its a pretty quick and dirty digitization through Image2BBC, I added the text and tidied a few pixels up. I would probably spend and fair bit of time tidying it up more for proper artwork for a game.

Wow, these look amazing! OK, I promise I will dust off the code and start looking at this again on my commute home tonight. It might be a while before I need you services to remake the artwork but this is certainly an incentive!

Dethmunk wrote:Its a pretty quick and dirty digitization through Image2BBC, I added the text and tidied a few pixels up. I would probably spend and fair bit of time tidying it up more for proper artwork for a game.

Wow, these look amazing! OK, I promise I will dust off the code and start looking at this again on my commute home tonight. It might be a while before I need you services to remake the artwork but this is certainly an incentive!

LOL. Well I've finished up on WhiteLight (shoot-em-up) for Sarah Walker. Unless she has any last minute tweaks she wants. I do have my own projects I'm currently fiddling with , but I'm always willing to help when I can.

Dethmunk wrote:LOL. Well I've finished up on WhiteLight (shoot-em-up) for Sarah Walker. Unless she has any last minute tweaks she wants. I do have my own projects I'm currently fiddling with , but I'm always willing to help when I can.

I just started wading back through the (epic amounts of) PoP code. First step will be to try and get the level rendering code up & running in MODE 1. I think it will be a long while before I require your artistic services but thank you for the offer. I will keep you posted as to my progress and look forward to seeing any new projects you come up with in the meantime.

Dethmunk wrote:LOL. Well I've finished up on WhiteLight (shoot-em-up) for Sarah Walker. Unless she has any last minute tweaks she wants. I do have my own projects I'm currently fiddling with , but I'm always willing to help when I can.

I just started wading back through the (epic amounts of) PoP code. First step will be to try and get the level rendering code up & running in MODE 1. I think it will be a long while before I require your artistic services but thank you for the offer. I will keep you posted as to my progress and look forward to seeing any new projects you come up with in the meantime.

No problem... give us a shout when you're ready

Currently I'm doing a run of ZX Spectrum games...Foggy's Quest - Finished

Currently finishing... Circuitry

They're coded and built with AGD (Arcade Game Designer) for the ZX Spectrum 48k. Might do one more before the end of the year and then dip back onto the BBC Micro..

Finally, some visible progress to report! I have managed to port the level screen plotting code over to the Beeb and then attach my MODE 4 sprite plotting routine to it. This has been quite an epic journey so far, having ported about 9 of the 29 source modules (although not every function within) and already pushing up against the limits of main memory. The fact that the original game makes extensive use of jump tables as the interface between modules has been invaluable, meaning I can compile with stubs and port functions one at a time as required.

The attached ssd images will step through the 24 screens that comprise level 1 and level 4 respectively. If you don't want to download then try the following jsbeeb links: Level 1Level 4. This is built for a Master so requires PAGE at &E00 and one bank of SWRAM for the background sprites & level data.

As this is a direct port, it is using the same level draw logic from the Apple II game and works on the level description data & sprite data straight from the GitHub source. I have left it in MODE 4 for now because of (a) memory and (b) the Apple II hi-res screen is technically B&W (albeit with artefact colour) so it is easier to test the bit rotation without the complications of additional lookups for MODE 1 conversion.

I'm quite pleased that I have made it this far and a real boost to my conviction that a full Master port is possible. Next step will be to get the high-level main loop in place and see if I can get the main Kid character routines going. Still a lot of work to do.

Looking great Kieran. Well done. Always bowled over by your work!I've been reading the thread with interest and remember you showing your sprite plotting routine at Cambridge.

As you progress, it'd be great to see a dev diary of sorts - I guess you're doing that now. I'd love to read about how you solve the various issues you're facing.. like squishing all the code and data into SWRAM banks compared to the two 64k banks of the Apple II.

jbnbeeb wrote:Looking great Kieran. Well done. Always bowled over by your work!I've been reading the thread with interest and remember you showing your sprite plotting routine at Cambridge.

As you progress, it'd be great to see a dev diary of sorts - I guess you're doing that now. I'd love to read about how you solve the various issues you're facing.. like squishing all the code and data into SWRAM banks compared to the two 64k banks of the Apple II.

Thanks. Yes, memory is going to be a huge challenge...

According to my GitHub check-ins, it's been about 9 days of work to go from the sprite plotting code to getting the level screens drawing. This doesn't include a large amount of research, reading and preparation that went on beforehand! If people are interested I will try to post more work-in-progress updates, although a lot of the time there won't be much to see just many technical details.

I'll see if I can do a quick post after each day's work (not working every day but most week days if I am commuting on the train.) Happy for people to ask questions and I can add more detail or clarify.

;address 1<width in bytes><height in bytes><data>;address 2<width in bytes><height in bytes><data>etc.

Because of memory requirements I discounted converting the sprites into Beeb screen format for the time being (but may revisit this in future.) For now I just wanted to get something displayed on screen, so the simplest way was to convert the sprite data on the fly.

Apple II hi-res screen data is 7 pixels per byte in reversed order (so the lsb is the left-most pixel) with bit 7 providing a colour clock phase. To convert a byte of data we can LSR so that pixels fall into the Carry flag then ROL into a Beeb byte that can be displayed in MODE 4 (msb as the left-most pixel.) Care has to be taken with the bit counts vs byte boundaries and the character row layout of Beeb screen memory.

Colour is a bit harder but essentially once we have a sequence of B&W bits we can use 3 bits at a time as a lookup into a colour table to reproduce artefact colour. More details on this old thread that I unearthed: https://groups.google.com/forum/#!topic/comp.sys.apple2.programmer/iSmIAVA95WA. Obviously we don't have orange on the Beeb but could be replaced by yellow/red dithering potentially.

This plot routine is pretty slow as we're having to LSR & ROL every pixel, but it works and was enough to get me started on the journey. We can worry about optimising the routine later (e.g. with more lookups) or pre-converting to Beeb sprite format etc.

Next step was to port across the two main header files from the Apple II source: EQ.S and GAMEEQ.S. Where "EQ" means "equates". These files contain the labels for every memory location in the code: zero page variables, local, global & game variables, code modules, jump tables, pre-built tables, data addresses for levels, sprites etc.

In general, the "porting" process consists of:

- Copying and renaming the file (so I keep an original close to hand for reference)- Ensuring all comments start with \ for BeebAsm- Putting IF / ENDIF statements round grand swathes of code that I'm not ready to deal with yet- Fix up some standard syntax differences for IF/ENDIF, ORG, SKIP etc.- Adding an INCLUDE into my master .asm file- Assembling repeatedly removing / fixing any errors that occur

I'm not sure which assembler was originally used but the syntax is slightly different and it has a couple of more advanced features than BeebAsm, including the ability to identify local labels and variables for reuse. In addition, it is clear that originally each module was compiled independently and then copied to be loaded off disk. I am creating a master .asm file that includes all the other code modules with suitable directives to ensure the code is compiled in the right place in memory etc.

It does mean there are potential for name clashes between variables and (local) labels so I do have to be careful about this. I prefer to go through and fix things up by hand where possible, rather than relying heavily on search & replace, so that I get a feel & better understanding for the code structure as I go. Thankfully this game was written late in the Apple II lifecycle and Jordan was a good programmer enforcing lots of structure & consistency!

My first goal was to get some of the plotting functions ported so I could draw a screen of a level. I identified a function "SURE" in the module FRAMEADV.S that is commented in the code as "Draw entire 10 x 3 screen from scratch". The process then is to move that module over to my Beeb source, comment everything out apart from the SURE function and then go about fixing the errors until it assembles...

- Uncomment ZP and global variables that are in use- Uncomment additional functions in that code module that are used by SURE- Repeat

One big challenge with PoP on the Beeb will be ZP variables. The 128KB Apple II has two sets of ZP variables as the entire 64KB banks are switched in & out. For the time-being I am not worrying about this and just letting the assembler allocate them in order until I run out. I doubt that all the variables need to be in ZP, I'll just have to find somewhere to stash the less important ones. Also there is a concept of reused "local" ZP variables in PoP which will use a fixed section of the ZP.

TABLES.S - pre-calculated tables, e.g. multiplication tablesGRAFIX.S - functions to manage all of the graphics lists before they are actually plotted to the screen in a different module (HIRES.S)BGDATA.S - data tables about pieces of the background (walls, panels, floor etc.)

This turned out to be three days of wading through functions and data tables, having to rename / uncomment / comment out / tweak many lines until it finally built. You feel like you're going down a rabbit hole and hoping to return at some point and not have to abandon the endeavour and start again!

Which means any external code module can just do "JSR drawall" (equivalent to JSR $0403) and this will be routed through the jump table via "jmp DRAWALL". This means that the code within the GRAFIX.S module can move around freely without any external modules having to worry about where the DRAWALL function actually resides. This would have been done back in the day as assembling the entire 128KB of code & data would have been impossible and/or quite a slow process, so you do it in pieces at fixed addresses.

We don't have to do this for BeebAsm as the whole thing can be compiled on a modern PC in seconds but it is very handy for the porting effort as it means we can declare the entire jump table for a module without having to implement any code (yet.) This enables the entire code to be assembled more easily and allows us to implement individual functions or even replace, redirect or stub them out without affecting the rest of the code.

I've commented out the ORG command as we're letting the assembler decide where this module lives (for now.) Only the 'drawall' function is implemented whilst the others are replaced with a 'BRK' instruction. If any of those functions get called at runtime then I will get an exception and can find out where the call came from (this is done in the b-em debugger.) I can then either implement a missing function or replace the 'BRK' with 'RTS' and stub the function out for the time being, allowing the code to continue without worrying about porting less important parts.

kieranhj wrote:I'm not sure which assembler was originally used but the syntax is slightly different and it has a couple of more advanced features than BeebAsm, including the ability to identify local labels and variables for reuse.

In beebasm you can use braces {} to create blocks. Labels and variables are local to a block. You can even nest blocks. So you end up with something like this and the variable "loop" can be reused elsewhere:

ctr wrote:In beebasm you can use braces {} to create blocks. Labels and variables are local to a block. You can even nest blocks. So you end up with something like this and the variable "loop" can be reused elsewhere:

Indeed, and I do like it. But you can't promote labels outside of scope, for example. At least not without the extensions that haven't been adopted as an official release yet.

In addition the Apple assembler used has prefixes for labels that make them local at file scope and also distinguishes between labels and variables that can be reassigned. This is used for generic 'branch rts_variable' statements which mean you don't need to worry about exactly which is the closest RTS statement if you want to return from a function.

All small things but need to be watched out for, particularly when overloading global variable names. My goal is to make this buildable with out of the box tools.

It's a bit grindy but disk layout optimisation is way down the list! There are definitely still some obvious rendering bugs (not least the left-hand side is always wall and the flasks leave a glitch elsewhere on the screen) but I'm quite pleased with the progress. We're still in MODE 4 as memory is currently blown until I partition the code so that the gameplay modules can reside in SHADOW RAM.

I am a bit behind on the dev diaries, which I will endeavour to do over the weekend, but essentially I have ported great swathes of code that derive from the "first boot" and "main loop" functions. I haven't tried to get them running yet, this is just using the "load level" and "draw screen" functions directly. I've hooked simonm's disksys module from our demos into the file functions so it's loading the level 'blueprints' and all the sprite data each time directly into swram.

After a week off work, and therefore the commute & programming time, I got back to looking at PoP today. It took a while to remember where I'd got up to but managed to make some small progress by the time I got home. The attached screenshot looks like the earlier one but with a couple of important changes - firstly it's in 280x192 resolution as I had to make a custom shrunk version of the MODE 4 screen mode to save memory (yes, things are getting that tight) and secondly there is a gate instead of a wall in the top left cell where the game starts. This is because the screen is being rendered as part of the main game loop, so is using all of the correct level information, rather than as a direct call to "plot screen X".

It crashes immediately afterwards trying to render the player, of course, but it is still progress.

I'll write out today's dev diary and then see if I can fill in the blanks for the last few I didn't post before the break.

Today's quandary was all about memory usage (I think this will be an ongoing theme...) I continued to stub out functions with RTS calls in the jump table in an attempt to get the main loop running. At some point memory was getting trampled unexpectedly so I needed to debug with b-em's handy watch memory write feature. I realised that now I was loading all the different sprites into different SWRAM banks I needed a way to switch between them when appropriate, otherwise I'll be reading garbage instead of the sprite pointer table. Fortunately POP already had the concept of banks for sprites, as on the Apple II these reside in both main & aux RAM. I borrowed the BANK ZP variable for my own Beeb plot function and changed the existing sprite bank table with SWRAM slot numbers.

I next realised that the level "blueprints" are quite liberally and freely accessed across the code, so my plan to keep these in the same SWRAM bank as the background sprites wasn't going to work easily, as I would need to manually page this bank in for all the places it is used. This could be done (and might have to be) but I am trying to mess with the original code as little as possible for the time being until I have to resort to serious Beeb specific optimisations. The level blueprints are &900 bytes (2304 bytes) which turned out to be too much to find in lower memory space. After some deliberating I decided to keep ploughing ahead, so knocked up a quick set of CRTC variables to shrink the MODE 4 screen to 280x192, which saved me enough RAM to store these lower down. I am going to have to make a big move to using SHADOW RAM at some point in the near future but I am trying to put it off for as long as possible to keep things simple!

Finally, I ported the function to add moveable objects to the display list, as this seemed to be a good step forward and resulted in the gate appearing in its correct position.

Currently the code is reaching about the 2nd function call inside the main Kid routine. There are about another 16 to stub or port but I believe this will result in the final set of data tables which represent all of the animation sequences & loops etc. getting pulled in. This may again necessitate some refactoring or memory tinkering but I will deal with that when I come to it.

Now seems a good a time as any to jump back to some more details about plotting Apple II sprite on a Beeb screen. I showed some of you my sprite plotting routine at ABug a while back which appears to work great but had one limitation - it only plotted on byte boundaries, so 8 pixels in MODE 4.

The Apple II hi-res screen has a weird pixel format which gives 7 pixels per byte, so even though the background tiles are plotted on character column boundaries (10 pieces across x 4 bytes each wide = 10 x 28 pixels = 280 screen width = 40 columns @ 7 pixels per byte) this is completely unhelpful for a Beeb with 8 pixels per byte / character.

Because my sprite plot routine works by essentially emulating in a very simple way the Apple II screen works (rotating bits of data one at a time into a Beeb screen byte) this wasn't too difficult to compensate for. For a given 0-39 character column coordinate on the Apple II screen, we can calculate the nearest Beeb byte plus a remainder, which is the number of bits we can already assume are in our "bit pipeline". For example, column 1 is at 7 pixels along, so our Beeb byte is at address 0 but with 7 pixels already accounted for - this means after 1 more Apple bit is rotated the Beeb byte will be flushed to screen. For column 2 at 14 pixels, the Beeb byte is address 1 with 6 pixels accounted for etc.

Things are slightly complicated (and still not yet fully resolved) by the fact that PoP has quite a sophisticated sprite plotting system that uses self-modifying code to specify how the pixels are written to the screen - straight STA, ORA, EOR etc. I can rip the original code and table for doing this as it's all 6502 opcodes, which is handy. However because of the above 7 vs 8 pixels per byte issue, we need to mask to the screen when the original Apple code would have just done a straight write. At the moment I'm just forcing STA to be ORA but this results in some rendering errors - you can see where an item has been blended with a foreground piece rather than hidden by it.

At some point in the future I'll have to resolve all the various sprite plotting needs of the game to remove any rendering glitches, but since the routines will almost certainly have to be significantly optimised for the Beeb to make the game playable I'm holding out on this one for a while. Oh yeah, there's also the issue of getting some colour into the game as well, not just B&W!

So continuing the quest to move from plotting individual level screens to getting the real game code booted and the main loop running.

Again, it turns out the Apple II had it's own crazy weird super low-level disc system and even then PoP didn't use the standard disc format but a special system created by Broderbund. You can read all about it here: http://fabiensanglard.net/prince_of_persia/pop_boot2.php Fortunately the upshot means that the BOOT.S module was all Apple II disc specific so didn't need to be ported, yay!

The game proper begins at the "_firstboot" entry point in MASTER.S so I ported this first (with everything commented out to begin with as usual.) This module is responsible for loading all of the game data and swapping between discs etc. so a useful place to hijack and add calls to the Beeb disc loader system.

The first boot function is supposed to go into the attract loop, but I chose to skip that and focus on getting the "DoStartGame" function ported and all of its dependents. This quickly enters the TOPCTRL.S module which is responsible for the main loop ("top level control") of the game.

This turned out to be another three days of porting modules, editing code and keeping my fingers crossed that I wouldn't run out of memory and/or ZP variables. The following modules came over:

SPECIALK.S - keyboard handling (all commented out for now but where I will add the necessary OSBYTE calls to read the keyboard)SUBS.S - subsystems of MASTER.S including handling some very level specific gameplay objectsMOVER.S - moveable object system - doors, spikes, potions etc.MISC.S - miscellaneous game functions (I think these were separate due to memory constraints in the Apple II memory map more than anything else)AUTO.S - the "AI" routines for the enemy guardsCTRL.S - player character control and state machine - logic for walking, climbing, running, jumping etc.CTRLSUBS.S - subsystems for the player - a large number of helper functions including determining what is around the playerCOLL.S - collision detection

I think this is now all of the code modules moved over (albeit mostly commented out for now.) The last big file to be ported is SEQTABLE.S which contains 1700 lines of data tables that define all of the lovely animation sequences for how the player runs, jumps, climbs etc. This will be the next challenge, both from a perseverance (getting everything into BeebAsm format) and logical point of view (where to store this in memory and how.)

Thanks for this, interesting stuff. I may be missing something, but can't you take comfort from the successful C64 port that you at least won't run out of ZP locations? I don't think the C64 port had two zero pages available. I guess the issue is perhaps that you're not able to throw the OS out as you need disc access, so you can't use the whole of zero page for your own purposes?

SteveF wrote:Thanks for this, interesting stuff. I may be missing something, but can't you take comfort from the successful C64 port that you at least won't run out of ZP locations? I don't think the C64 port had two zero pages available. I guess the issue is perhaps that you're not able to throw the OS out as you need disc access, so you can't use the whole of zero page for your own purposes?

Yes! Good point well made. Not all the vars have to be ZP, will just be a case of finding a home for them elsewhere in memory (a challenge in itself.)

I just did some more reading up on the C64 port - seems like you have to use a particular memory card which allows various things to be read directly from ROM without copying to RAM, so that explains how it was crammed into 64K. I will be aiming for everything to run from a regular DFS floppy disk but will be Master only. If I ever find enough memory for a colour version then there'll be a NULA release to dispay the right shade of orange..!

So I finally bit the SHADOW RAM bullet today and it turned out to be nowhere near as bad as I feared, mainly because PoP was so well written and carefully architected to use the 128K of banked memory on the Apple II in the first place. From the comments:

This is great because only the hires routines touch the screen buffer in main mem and only the hires modules uses the hrtables data. The rest of the game runs in aux mem and switches to main mem when plotting. An example from hires.s:

I restructured my top-level beebasm file to build core, main and aux assemblies and save these to the disc. The core executable then loads the main & aux code modules into main and SHADOW RAM at boot. The game runs entirely with aux (=SHADOW) switched in and lets the hires functions page in main memory before doing any writes to the screen buffer.

The CRTC is setup to always display from main memory. If I do end up with enough space to keep the double-buffered screen then these will both reside in main memory and just be switched with the CRTC address registers rather than switching to read from SHADOW RAM.

At the moment I have &231 bytes free in the core section, &2359 bytes free in main memory (so enough for a second MODE 4 screen buffer...) and &1F00 bytes free in aux mem so totalling a luxurious 17K. There are a couple of pages unused from OS RAM at the bottom end as well which I can stash some buffers in later on.

There is still plenty of code, and a large amount of animation sequence data, to bring over yet so I'm not presuming that the memory juggling has finished but certainly should make things a lot easier for the moment.

Nothing visual to show but this morning's commuter milestone was to get the MainLoop running without crashing or hitting a BRK! This has involved porting many collision detection functions relating to the player (and ignoring the guard and traps etc. for now.)

Once I've got the animation sequence table data ported the last big job will be to implement the additional features of the sprite plotting routine, so the ability to plot on a pixel offset (not just byte aligned) plus mirroring and cropping of sprite data. Oh yeah, and the screen peeling.

This evening's update. The good news is that I managed to get some player (Kid) sprites drawing, albeit hacking the plot function. The bad news is that he dies when he hits the floor! I'm not actually worried about this because it will just be some gameplay function I've not implemented yet which is causing his energy to be 0 for whatever reason.

More worryingly the game runs at about 1 fps. And this is before I've implemented the additional sprite functions for mirroring & pixel precision plotting etc. I am going to have to have a think about this for a while. The next goal will be to correctly implement the sprite plot routines regardless of speed and then figure out optimisations or alternative rendering approaches from there.

Lots of pondering going on at the moment. The more I think about it, the more the 7 pixels per byte format of the Apple II is a massive PITA. My current exploration is to convert the Apple II sprite data offline to MODE 4 (for now) screen format and store in column order for faster writing to the Beeb character row screen.

The problem is, even plotting a sprite to a "simple" Apple byte aligned position requires a read, mask out the bits we're not interested in, shift our Beeb data, mask in those bits, write back to screen. So even the PoP "fast" sprites for which each byte can be written in a single LDA+STA combo require LDA screen; AND mask; LDX sprite; LDA shift, X; ORA data; STA screen etc. I know the Beeb runs at 2MHz vs Apple II's 1.023MHz but that's a lot more instructions.

I guess I need that for the general purpose sprite plotting routine anyway so maybe it's just a one-size fits all approach rather than the fast/slow optimised functions that are in PoP today. I've never actually written a proper Beeb sprite plot routine believe it or not, at least not one that wasn't Teletext / MODE 7!

Alternatively I could look at expanding the PoP sprite set to be multiples of 8 pixels, so increase the horizontal resolution to 320 instead of 280, i.e. still keep the 40 columns. This might make everything look a bit "fat" though and will require me to investigate how to change other parts of the code. Could be feasible though.

My gut instinct on this is that the only bit which you can probably truly 'port' is the game/animation logic, basically all the high-level stuff. The graphics routines are going to need to get a total rewrite to conform more with the Beeb hardware.

My take on it would be to bite the bullet and go to MODE 2 (or 1). You could keep the tile size the same, and store the sprites in a more native format; so 10 tiles of 14 (or 28) pixels wide, which fits nicely on a byte boundary still, and allows for a 70 column wide screen. Perhaps I haven't grasped quite how low memory is! Obviously doing that would double the size of the sprite data (and it's already doubled the size of the screen), but I suspect it'd be possible to compress the sprites, even with a RLE type method. I would find a way to avoid having to do double-buffering so you can at least use a shadow screen, and keep main RAM for non-graphics related stuff.

Do you have a basic overview of the memory needs for PoP? In honesty, I'm struggling to imagine how it can be so demanding - unless it's just that there are a lot of frames of animation.