Is it possible and doable?.. To take a commercial game that is written for 32 bit single core cpus and then rewrite them into 64 bit with multi-cores aka threading.  :shock:
Posted on 2012-09-29 03:38:51 by hockey97
In theory everything is doable.
In practice, not really.
If you have the sourcecode, you'd probably still need to modify the code before it compiles and works in 64-bit mode properly, unless the developers planned ahead and avoided 64-bit issues while writing the code.
Implementing multithreading is a very difficult problem in general, and would require redesigning the whole application.
I believe John Carmack once said something like:
Anyone who says "Just multithread it" simply doesn't get it.
Posted on 2012-09-29 03:46:40 by Scali
The only thing you need to do is use the variable sized datatypes like wchar_t, and it will build for 32 or 64 bit from the same source.
If you are using third party libraries, they probably have different binaries for these cases already ala unicode or char,

Have a nice day :)
Posted on 2012-09-29 05:12:04 by Homer
Is it possible and doable?.. To take a commercial game that is written for 32 bit single core cpus and then rewrite them into 64 bit with multi-cores aka threading.  :shock:


If it's a commercial game, my first question is "do you have the source?" If not, then it'd be easier to just write a clone of the game (which I'm sure won't be very easy).

If the source is available, you will need to replace the data types with the more portable ones (like homer suggested), except it's not an issue of Unicode vs. ASCII, rather all data types need to be changed. So using variable types like intmax_t and uintmax_t in place of int and unsigned int.

As Scali mentioned, multiprocessing/multithreading will be an issue unto itself. The biggest issue is making sure that you remove as many global variables as possible (giving them a localized context). If you can't help but have global variables, then you need to provide a locking mechanism to prevent multiple threads from trying to read/write at the same time.
Posted on 2012-09-29 22:37:39 by Synfire

rather all data types need to be changed. So using variable types like intmax_t and uintmax_t in place of int and unsigned int.


Well, you don't need to change ALL data types.
An int is the same size in 32 and 64-bit, always 32-bit.
In most cases that will be fine (don't use more precision than you need, changing every int to 64-bit will just eat more memory/cache).
The problem is mainly where you do pointer arithmetic.
You should use types like intptr_t there, which gives you an integer type of the same size as a pointer (since in 64-bit mode, a pointer is 64-bit, but a regular int is still 32-bit, so casting between them causes problems).

There are also some performance issues to consider. The stack for example. Each entry on the stack is now 64-bit rather than 32-bit. So if you make heavy use of the stack (for example in recursive functions), that may become a bottleneck, and your code may actually run slower when compiled in 64-bit mode than it did it 32-bit mode.
Posted on 2012-09-30 04:57:23 by Scali
Well, you don't need to change ALL data types.
An int is the same size in 32 and 64-bit, always 32-bit.


Generally that's true. I've learned not to make assumptions about a users platform. Some 64-bit systems (non-Intel) have 'int' set to 64-bits. That's why I like features like intmax_t and intmin_t for portable code because it lets the compiler pick the best size for the machine.

In most cases that will be fine (don't use more precision than you need, changing every int to 64-bit will just eat more memory/cache).


Very true. However, my assumption was that he was wanting to make the game use the larger types. Otherwise, I wouldn't see much of a point in changing the games code.

There are also some performance issues to consider. The stack for example. Each entry on the stack is now 64-bit rather than 32-bit. So if you make heavy use of the stack (for example in recursive functions), that may become a bottleneck, and your code may actually run slower when compiled in 64-bit mode than it did it 32-bit mode.


As long as you keep the parameter counts down, I wouldn't see much of a problem. At least on Intel systems, most parameters are pasted through registers. However, something I've failed to understand, on some Intel systems (Windows specifically) you also have to make sure that there is enough space allocated on the stack for 4 registers even if you don't use them.  :lol:
Posted on 2012-09-30 05:22:19 by Synfire

Generally that's true. I've learned not to make assumptions about a users platform. Some 64-bit systems (non-Intel) have 'int' set to 64-bits. That's why I like features like intmax_t and intmin_t for portable code because it lets the compiler pick the best size for the machine.


I'd say that is exactly what you DON'T want when you want to write portable code.
If the compiler picks a larger type than what you anticipated, at least it will function correctly in most cases, but it may affect performance.
But if it picks a SMALLER type, your code may get overflows and no longer run as expected.
On some platforms, int is 16-bit, for example, while most code generally assumes int is at least 32-bit these days.
The best way to write portable code is to use explicitly typedef'ed types to a certain size, such as int16_t, int32_t, int64_t etc.
These are defined in stdint.h, and will behave the same regardless of the size of a native int on the machine.
That way you'll neither run the risk of getting a type that is smaller than what you expected, nor are you wasting a lot of memory/bandwidth/performance by using bigger datatypes than required for everything (eg, intmax_t will be 64-bit on 32-bit Windows code, because int64_t is the largest int size. However, this is not a native size to a 32-bit CPU obviously, so it will use 64-bit macros for all arithmetic, even simple adds. Which cuts into your performance considerably).

The only exception here is pointers, where you'd use intptr_t, so that your pointer arithmetic is done with the same precision as the pointers. So there's no fixed size you can pick there.

A side-issue, at least on Windows, is that some API functions have been updated to use such intptr_t-like parameters. Such as SetWindowLongPtr()/SetClassLongPtr().
If you still use deprecated SetWindowLong/SetClassLong, you need to change it to the new 64-bit compatible versions, which will also compile correctly on 32-bit.


Very true. However, my assumption was that he was wanting to make the game use the larger types. Otherwise, I wouldn't see much of a point in changing the games code.


Oh, well I assumed he wanted to make use of the extra performance that 64-bit can deliver.
Using larger types will only decrease performance in most cases. So that's exactly what you DON'T want. If 32-bit ints are good enough, stick to 32-bit ints, because 64-bit ints will make caching a lot less efficient.
If you already used 64-bit types, you probably already used in64_t types or whatnot, which the compiler would translate to helper functions on 32-bit platforms, but will now automatically be converted to native operations. So you probably won't have to do anything there.


As long as you keep the parameter counts down, I wouldn't see much of a problem. At least on Intel systems, most parameters are pasted through registers.


Yes, on 64-bit, fastcall is common, where the first 4 parameters are passed through registers, the rest on stack (see also http://msdn.microsoft.com/en-us/magazine/cc300794.aspx)
So yes, keeping parameter count down is important, even moreso in 64-bit than in 32-bit mode (in 32-bit, stdcall and cdecl were the most common, which passed all parameters on stack). Especially in object-oriented code, where the first parameter is the this-pointer, leaving only 3 registers for parameters.
That's the main performance bottleneck I ran into when I first converted my code to 64-bit (despite fastcall, I noticed).
If you need a lot of parameters, you can choose to convert your function from direct parameters to using a struct. On stack, all values have to be 64-bit, but in a struct, you can use the exact types you want. So if you want to pass a bunch of 8, 16 or 32-bit values, you don't waste 64-bit on each of them. You just fill the struct, then pass a pointer to the struct to your function, and you've saved some precious bandwidth.

Also, I noticed that I had gotten a tad lazy myself, and passed gratuitous parameters around. Things that could easily have been class members, or even global values/constants. Yes, it looked cleaner when they were passed around as parameters to a function, but they started to become a performance issue in 64-bit. So for the sake of performance I reduced the actual parameters for some functions to a minimum, and stored the rest as class members or globals.
Posted on 2012-09-30 06:35:15 by Scali
I'd say that is exactly what you DON'T want when you want to write portable code.
If the compiler picks a larger type than what you anticipated, at least it will function correctly in most cases, but it may affect performance.
But if it picks a SMALLER type, your code may get overflows and no longer run as expected.


That's kinda the point, you don't anticipate. When using intmax_t you think of the integer as an abstract storage space where you don't care how big it is, only that it's an integer and you want it to be as large as possible.

On some platforms, int is 16-bit, for example, while most code generally assumes int is at least 32-bit these days.
The best way to write portable code is to use explicitly typedef'ed types to a certain size, such as int16_t, int32_t, int64_t etc.


Yes, being explicit with sizes is the best way to go for consistency. However, being explicit doesn't bode well for flexible designs.

Yes, on 64-bit, fastcall is common, where the first 4 parameters are passed through stack (see also http://msdn.microsoft.com/en-us/magazine/cc300794.aspx)


I'm assuming that's a typing error? With fastcall the first four parameters are passed through registers, not the stack.

Integer arguments beyond the first four are passed on the stack. The this pointer is considered an integer argument, so can always be found in the RCX register.


Posted on 2012-09-30 07:59:46 by Synfire

That's kinda the point, you don't anticipate. When using intmax_t you think of the integer as an abstract storage space where you don't care how big it is, only that it's an integer and you want it to be as large as possible.


I understand that part, my point is that 'as large as possible' is generally not a desirable trait.
So while intmax_t has its uses, it should certainly not be used as the default integer type just to make code portable.
As I said, in general you know that you need no less than N bits of precision, and no more than M bits of precision. So generally you'll just pick the datatype explicitly. This is the best way to ensure the code works as expected, and does not suffer from unnecessary performance loss (as I said: using intmax_t on 32-bit Windows will result in 64-bit datatypes throughout, with lots of extra overhead).

I have never actually used intmax_t myself, anywhere. Never had the need.


Yes, being explicit with sizes is the best way to go for consistency. However, being explicit doesn't bode well for flexible designs.


Well no, but portable code tends to be less flexible anyway.
You could get around this using templates or by using your own typedefs, for example.
That way you can quickly change the datatype for an entire part of your code by just changing the definition in one place.

If I take my 286-code as example... Its native integer type is only 16-bit. I have ported some of my 486-code to the 286-codebase, but things are not as simple as just using int32_t everywhere. On 486 there is no penalty for that, but on 286 there is.
So I have to be careful to only use int32_t in those places where it is needed.
The code was 'portable' from 486 to 286 in the sense that it could be made to compile...
But it was never intended to run on anything with less than 32-bit integers, so no attention was paid to making datatypes 16-bit only where it matters, or even fine-tuning some parts of the code so that it could use 16-bit precision. I was rather liberal with precision, simply because the platform allowed me to be.
In some places I even used int64_t, which simply isn't available at all on 286. If I used intmax_t, assuming it'd be at least 64-bit, things would fail unnoticed. Now I got compiler errors and could write workarounds for places where int64_t was used. It was obvious from the code that at least 64-bit precision was required because of the datatype used.
After the modifications I did to make it faster on 286, it is still portable back to 486, although it now runs much faster on 286 as well.


I'm assuming that's a typing error? With fastcall the first four parameters are passed through registers, not the stack.


Yes, already corrected it.
Posted on 2012-09-30 08:17:29 by Scali


I'm assuming that's a typing error? With fastcall the first four parameters are passed through registers, not the stack.


Yes, already corrected it.


Regarding stack allocation for register parameters the rule for x64 Windows as per http://msdn.microsoft.com/en-us/library/ms235286.aspx is:
"The caller is responsible for allocating space for parameters to the callee, and must always allocate sufficient space for the 4 register parameters, even if the callee doesn’t have that many parameters".
Posted on 2012-09-30 10:23:02 by p1ranha
Yes, I have the source code of the game in pure ASM. It was written in C++ for the game engine part. So, the really technical parts of the game is in C++. While the game's logic uses LUA for everything relating directly to the game play logic.

The game is written in 2004. It's currently abandon but hackers have made mods to the game.  They reverse engineered the game to the point they written a program in ASM that will read the LUA's files of the games. The game is pretty much abandoned and I am currently learning ASM. I Just know the basics of 8 , 16, 32 and 64 bit ASM. Like the registers and other basic stuff. I do know the numbering system like binary, hex, octal etc.

However, I was thinking to do a project where I can just get this game converted to use a 64bit system. Alot of the gamers think it will be better performance if the game can run on a multi-core cpu and grab more ram past that 4 gig mark.

The game when it was created in 2004 was very heavy on the single cpu computers. Now since we got multi-core. I am sure alot of hackers are right now trying to get the game into the 64 bit world.

The game is abandoned and the people that made it lost their jobs and currently the company is using a new team to make a new game that continues the series. Yet, their works currently sucks and so most don't buy their new ones and don't even want to play it. The hackers have been making mods to this old game but the game is still stuck in 32bit mode. I thought this would be a good project for me to learn enough to be able to convert a program from 32 bit to 64 bit.

It's been a while since I been back here. So, do let me know if I go over any rules on this website. I don't intend to violate any rules.

I am just starting out as a ASM programmer and would like to take on a project that after I finish it. I myself and others can enjoy. I thought about taking on this 64bit project. I personally thought all I have to do is just change the ASM source code to use just the 64 bit system registers and other parts of the code to be using 64 bit instructions instead of 32 bit.  This is what I thought. If it's not as easy or as simple as just looking at the code and just deleting the 32 bit instructions and replacing it with 64 bit instructions. I will think hard about it before attempting it.

I personally thought it was something simple that would take a long time like maybe 2 months max to rewrite the code. However, I could be wrong and that is why I came here to ask you guys if it's possible and if it's possible how long would it normally take and how hard is it?

Posted on 2013-05-04 04:00:05 by hockey97
Anything is possible.  The length of time it takes depends purely on your skill set.  The more experienced you are the faster you can accomplish your goal.

Since you have the C++ source code why don't you first start out by compiling with 64-bit enabled and examine the results.  You can output an assembly listing from the compiler to see how the compiler translates the code to x64.  With that knowledge you can start investigating possible optimizations - provided the game executes successfully in the first place.
Posted on 2013-05-04 08:17:56 by p1ranha

If you are using third party libraries, they probably have different binaries for these cases already ala unicode or char,


Unicode and 'char' (I suppose you mean ASCII, also called multi-byte in Microsoft-speak) apply only to the encoding of strings. Unicode in Windows means all strings are using UTF-16, which effectively means you are using (at least) 16-bit per character, where ASCII uses 8-bit characters.
This has nothing to do with 32-bit vs 64-bit (Unicode support has been in NT since the first version, which was 32-bit obviously).
Posted on 2013-06-05 04:47:32 by Scali

Now since we got multi-core. I am sure alot of hackers are right now trying to get the game into the 64 bit world.


This statement sounds a bit odd. You seem to be confusing multi-core and 64-bit processing.
There have been 32-bit multi-core systems, and you don't necessarily need to run 64-bit software in order to make use of multiple cores.
All the threading and synchronization primitives required to make use of multiple cores have been available since the earliest versions of Windows NT, and can be used from 32-bit applications as well as 64-bit ones.

So do you want to convert the code to 64-bit, or make it multi-threaded? They are two separate problems. I wouldn't recommend trying to do both at the same time.
There is likely to be little gain in making the code 64-bit. Depending on how heavy the processing load is, and to what extent it can be parallelized, you may be able to get reasonable gains out of multithreading it.
Posted on 2013-06-05 04:51:53 by Scali