Update to v100r02 release.
byuu says:
Sigh ... I'm really not a good person. I'm inherently selfish.
My responsibility and obligation right now is to work on loki, and
then on the Tengai Makyou Zero translation, and then on improving the
Famicom emulation.
And yet ... it's not what I really want to do. That shouldn't matter;
I should work on my responsibilities first.
Instead, I'm going to be a greedy, self-centered asshole, and work on
what I really want to instead.
I'm really sorry, guys. I'm sure this will make a few people happy,
and probably upset even more people.
I'm also making zero guarantees that this ever gets finished. As always,
I wish I could keep these things secret, so if I fail / give up, I could
just drop it with no shame. But I would have to cut everyone out of the
WIP process completely to make it happen. So, here goes ...
This WIP adds the initial skeleton for Sega Mega Drive / Genesis
emulation. God help us.
(minor note: apparently the new extension for Mega Drive games is .md,
neat. That's what I chose for the folders too. I thought it was .smd,
so that'll be fixed in icarus for the next WIP.)
(aside: this is why I wanted to get v100 out. I didn't want this code in
a skeleton state in v100's source. Nor did I want really broken emulation,
which the first release is sure to be, tarring said release.)
...
So, basically, I've been ruminating on the legacy I want to leave behind
with higan. 3D systems are just plain out. I'm never going to support
them. They're too complex for my abilities, and they would run too slowly
with my design style. I'm not willing to compromise my design ideals. And
I would never want to play a 3D game system at native 240p/480i resolution
... but 1080p+ upscaling is not accurate, so that's a conflict I want
to avoid entirely. It's also never going to emulate computer systems
(X68K, PC-98, FM-Towns, etc) because holy shit that would completely
destroy me. It's also never going emulate arcade machines.
So I think of higan as a collection of 2D emulators for consoles
and handhelds. I've gone over every major 2D gaming system there is,
looking for ones with games I actually care about and enjoy. And I
basically have five of those systems supported already. Looking at the
remaining list, I see only three systems left that I have any interest
in whatsoever: PC-Engine, Master System, Mega Drive. Again, I'm not in
any way committing to emulating any of these, but ... if I had all of
those in higan, I think I'd be content to really, truly, finally stop
writing more emulators for the rest of my life.
And so I decided to tackle the most difficult system first. If I'm
successful, the Z80 core should cover a lot of the work on the SMS. And
the HuC6280 should land somewhere between the NES and SNES in terms of
difficulty ... closer to the NES.
The systems that just don't appeal to me at all, which I will never touch,
include, but are not limited to:
* Atari 2600/5200/7800
* Lynx
* Jaguar
* Vectrex
* Colecovision
* Commodore 64
* Neo-Geo
* Neo-Geo Pocket / Color
* Virtual Boy
* Super A'can
* 32X
* CD-i
* etc, etc, etc.
And really, even if something were mildly interesting in there ... we
have to stop. I can't scale infinitely. I'm already way past my limit,
but I'm doing this anyway. Too many cores bloats everything and kills
quality on everything. I don't want higan to become MESS v2.
I don't know what I'll do about the Famicom Disk System, PC-Engine CD,
and Mega CD. I don't think I'll be able to achieve 60fps emulating the
Mega CD, even if I tried to.
I don't know what's going to happen here with even the Mega Drive. Maybe
I'll get driven crazy with the documentation and quit. Maybe it'll end
up being too complicated and I'll quit. Maybe the emulation will end up
way too slow and I'll give up. Maybe it'll take me seven years to get
any games playable at all. Maybe Steve Snake, AamirM and Mike Pavone
will pool money to hire a hitman to come after me. Who knows.
But this is what I want to do, so ... here goes nothing.
2016-07-09 04:21:37 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
//Motorola M68000
|
|
|
|
|
|
|
|
namespace Processor {
|
|
|
|
|
|
|
|
struct M68K {
|
2016-07-22 12:03:25 +00:00
|
|
|
enum : bool { User, Supervisor };
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
enum : uint { Byte, Word, Long };
|
2016-07-22 12:03:25 +00:00
|
|
|
enum : bool { NoUpdate = 0, Reverse = 1 };
|
|
|
|
|
|
|
|
enum : uint {
|
|
|
|
DataRegisterDirect,
|
|
|
|
AddressRegisterDirect,
|
|
|
|
AddressRegisterIndirect,
|
|
|
|
AddressRegisterIndirectWithPostIncrement,
|
|
|
|
AddressRegisterIndirectWithPreDecrement,
|
|
|
|
AddressRegisterIndirectWithDisplacement,
|
|
|
|
AddressRegisterIndirectWithIndex,
|
|
|
|
AbsoluteShortIndirect,
|
|
|
|
AbsoluteLongIndirect,
|
|
|
|
ProgramCounterIndirectWithDisplacement,
|
|
|
|
ProgramCounterIndirectWithIndex,
|
|
|
|
Immediate,
|
|
|
|
};
|
Update to v100r06 release.
byuu says:
Up to ten 68K instructions out of somewhere between 61 and 88, depending
upon which PDF you look at. Of course, some of them aren't 100% completed
yet, either. Lots of craziness with MOVEM, and BCC has a BSR variant
that needs stack push/pop functions.
This WIP actually took over eight hours to make, going through every
possible permutation on how to design the core itself. The updated design
now builds both the instruction decoder+dispatcher and the disassembler
decoder into the same main loop during M68K's constructor.
The special cases are also really psychotic on this processor, and
I'm afraid of missing something via the fallthrough cases. So instead,
I'm ordering the instructions alphabetically, and including exclusion
cases to ignore binding invalid cases. If I end up remapping an existing
register, then it'll throw a run-time assertion at program startup.
I wanted very much to get rid of struct EA (EffectiveAddress), but
it's too difficult to keep track of the internal effective address
without it. So I split out the size to a separate parameter, since
every opcode only has one size parameter, and otherwise it was getting
duplicated in opcodes that take two EAs, and was also awkward with the
flag testing. It's a bit more typing, but I feel it's more clean this way.
Overall, I'm really worried this is going to be too slow. I don't want
to turn the EA stuff into templates, because that will massively bloat
out compilation times and object sizes, and will also need a special DSL
preprocessor since C++ doesn't have a static for loop. I can definitely
optimize a lot of EA's address/read/write functions away once the core
is completed, but it's never going to hold a candle to a templatized
68K core.
----
Forgot to include the SA-1 regression fix. I always remember immediately
after I upload and archive the WIP. Will try to get that in next time,
I guess.
2016-07-16 08:39:44 +00:00
|
|
|
|
2016-07-12 22:47:04 +00:00
|
|
|
M68K();
|
|
|
|
|
2016-07-10 05:28:26 +00:00
|
|
|
virtual auto step(uint clocks) -> void = 0;
|
2016-07-17 03:24:28 +00:00
|
|
|
virtual auto read(bool word, uint24 addr) -> uint16 = 0;
|
|
|
|
virtual auto write(bool word, uint24 addr, uint16 data) -> void = 0;
|
2016-07-10 05:28:26 +00:00
|
|
|
|
|
|
|
auto power() -> void;
|
|
|
|
auto reset() -> void;
|
2016-07-22 12:03:25 +00:00
|
|
|
auto supervisor() -> bool;
|
2016-07-10 05:28:26 +00:00
|
|
|
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
//registers.cpp
|
2016-07-23 02:32:35 +00:00
|
|
|
struct DataRegister {
|
|
|
|
explicit DataRegister(uint number_) : number(number_) {}
|
|
|
|
uint3 number;
|
|
|
|
};
|
|
|
|
template<uint Size = Long> auto read(DataRegister reg) -> uint32;
|
|
|
|
template<uint Size = Long> auto write(DataRegister reg, uint32 data) -> void;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
struct AddressRegister {
|
|
|
|
explicit AddressRegister(uint number_) : number(number_) {}
|
|
|
|
uint3 number;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
};
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size = Long> auto read(AddressRegister reg) -> uint32;
|
|
|
|
template<uint Size = Long> auto write(AddressRegister reg, uint32 data) -> void;
|
2016-07-12 10:19:31 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
auto readCCR() -> uint8;
|
|
|
|
auto readSR() -> uint16;
|
|
|
|
auto writeCCR(uint8 ccr) -> void;
|
|
|
|
auto writeSR(uint16 sr) -> void;
|
2016-07-12 10:19:31 +00:00
|
|
|
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
//memory.cpp
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
template<uint Size> auto read(uint32 addr) -> uint32;
|
2016-07-22 12:03:25 +00:00
|
|
|
template<uint Size, bool Order = 0> auto write(uint32 addr, uint32 data) -> void;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
template<uint Size = Word> auto readPC() -> uint32;
|
2016-07-22 12:03:25 +00:00
|
|
|
template<uint Size> auto pop() -> uint32;
|
|
|
|
template<uint Size> auto push(uint32 data) -> void;
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
//effective-address.cpp
|
|
|
|
struct EffectiveAddress {
|
|
|
|
explicit EffectiveAddress(uint mode_, uint reg_) : mode(mode_), reg(reg_) {
|
|
|
|
if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11}
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
}
|
|
|
|
|
2016-07-17 03:24:28 +00:00
|
|
|
uint4 mode;
|
2016-07-23 02:32:35 +00:00
|
|
|
uint3 reg;
|
2016-07-12 10:19:31 +00:00
|
|
|
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
boolean valid;
|
|
|
|
uint32 address;
|
|
|
|
};
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
|
|
|
|
template<uint Size, bool Update = 1> auto read(EffectiveAddress& ea) -> uint32;
|
|
|
|
template<uint Size, bool Update = 1> auto write(EffectiveAddress& ea, uint32 data) -> void;
|
|
|
|
template<uint Size> auto flush(EffectiveAddress& ea, uint32 data) -> void;
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
|
2016-07-12 10:19:31 +00:00
|
|
|
//instruction.cpp
|
|
|
|
auto trap() -> void;
|
|
|
|
auto instruction() -> void;
|
|
|
|
|
|
|
|
//instructions.cpp
|
|
|
|
auto testCondition(uint4 condition) -> bool;
|
2016-07-12 22:47:04 +00:00
|
|
|
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto bytes() -> uint;
|
2016-07-22 12:03:25 +00:00
|
|
|
template<uint Size> auto bits() -> uint;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto lsb() -> uint32;
|
|
|
|
template<uint Size> auto msb() -> uint32;
|
2016-07-22 12:03:25 +00:00
|
|
|
template<uint Size> auto mask() -> uint32;
|
Update to v100r08 release.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
2016-07-17 22:11:29 +00:00
|
|
|
template<uint Size> auto clip(uint32 data) -> uint32;
|
|
|
|
template<uint Size> auto sign(uint32 data) -> int32;
|
|
|
|
|
|
|
|
template<uint Size> auto zero(uint32 result) -> bool;
|
|
|
|
template<uint Size> auto negative(uint32 result) -> bool;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto instructionADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> void;
|
|
|
|
template<uint Size> auto instructionANDI(EffectiveAddress ea) -> void;
|
|
|
|
auto instructionANDI_TO_CCR() -> void;
|
|
|
|
auto instructionANDI_TO_SR() -> void;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto ASL(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionASL(uint4 shift, DataRegister modify) -> void;
|
|
|
|
template<uint Size> auto instructionASL(DataRegister shift, DataRegister modify) -> void;
|
|
|
|
auto instructionASL(EffectiveAddress modify) -> void;
|
|
|
|
template<uint Size> auto ASR(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionASR(uint4 shift, DataRegister modify) -> void;
|
|
|
|
template<uint Size> auto instructionASR(DataRegister shift, DataRegister modify) -> void;
|
|
|
|
auto instructionASR(EffectiveAddress modify) -> void;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
auto instructionBCC(uint4 condition, uint8 displacement) -> void;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto instructionBTST(DataRegister dr, EffectiveAddress ea) -> void;
|
|
|
|
template<uint Size> auto instructionBTST(EffectiveAddress ea) -> void;
|
|
|
|
template<uint Size> auto instructionCLR(EffectiveAddress ea) -> void;
|
|
|
|
template<uint Size> auto instructionCMP(DataRegister dr, EffectiveAddress ea) -> void;
|
|
|
|
auto instructionDBCC(uint4 condition, DataRegister dr) -> void;
|
|
|
|
auto instructionEORI_TO_CCR() -> void;
|
|
|
|
auto instructionEORI_TO_SR() -> void;
|
|
|
|
auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto LSL(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionLSL(uint4 immediate, DataRegister dr) -> void;
|
|
|
|
template<uint Size> auto instructionLSL(DataRegister sr, DataRegister dr) -> void;
|
|
|
|
auto instructionLSL(EffectiveAddress ea) -> void;
|
|
|
|
template<uint Size> auto LSR(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionLSR(uint4 immediate, DataRegister dr) -> void;
|
|
|
|
template<uint Size> auto instructionLSR(DataRegister shift, DataRegister dr) -> void;
|
|
|
|
auto instructionLSR(EffectiveAddress ea) -> void;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto instructionMOVE(EffectiveAddress to, EffectiveAddress from) -> void;
|
|
|
|
template<uint Size> auto instructionMOVEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
|
|
|
template<uint Size> auto instructionMOVEM(uint1 direction, EffectiveAddress ea) -> void;
|
|
|
|
auto instructionMOVEQ(DataRegister dr, uint8 immediate) -> void;
|
|
|
|
auto instructionMOVE_FROM_SR(EffectiveAddress ea) -> void;
|
|
|
|
auto instructionMOVE_TO_CCR(EffectiveAddress ea) -> void;
|
|
|
|
auto instructionMOVE_TO_SR(EffectiveAddress ea) -> void;
|
|
|
|
auto instructionMOVE_USP(uint1 direction, AddressRegister ar) -> void;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
auto instructionNOP() -> void;
|
2016-07-23 02:32:35 +00:00
|
|
|
auto instructionORI_TO_CCR() -> void;
|
|
|
|
auto instructionORI_TO_SR() -> void;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto ROL(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionROL(uint4 shift, DataRegister modify) -> void;
|
|
|
|
template<uint Size> auto instructionROL(DataRegister shift, DataRegister modify) -> void;
|
|
|
|
auto instructionROL(EffectiveAddress modify) -> void;
|
|
|
|
template<uint Size> auto ROR(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionROR(uint4 shift, DataRegister modify) -> void;
|
|
|
|
template<uint Size> auto instructionROR(DataRegister shift, DataRegister modify) -> void;
|
|
|
|
auto instructionROR(EffectiveAddress modify) -> void;
|
|
|
|
template<uint Size> auto ROXL(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionROXL(uint4 shift, DataRegister modify) -> void;
|
|
|
|
template<uint Size> auto instructionROXL(DataRegister shift, DataRegister modify) -> void;
|
|
|
|
auto instructionROXL(EffectiveAddress modify) -> void;
|
|
|
|
template<uint Size> auto ROXR(uint32 result, uint shift) -> uint32;
|
|
|
|
template<uint Size> auto instructionROXR(uint4 shift, DataRegister modify) -> void;
|
|
|
|
template<uint Size> auto instructionROXR(DataRegister shift, DataRegister modify) -> void;
|
|
|
|
auto instructionROXR(EffectiveAddress modify) -> void;
|
2016-07-22 12:03:25 +00:00
|
|
|
auto instructionRTS() -> void;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto instructionSUBQ(uint4 immediate, EffectiveAddress ea) -> void;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto instructionTST(EffectiveAddress ea) -> void;
|
2016-07-12 10:19:31 +00:00
|
|
|
|
|
|
|
//disassembler.cpp
|
|
|
|
auto disassemble(uint32 pc) -> string;
|
2016-07-12 22:47:04 +00:00
|
|
|
auto disassembleRegisters() -> string;
|
|
|
|
|
2016-07-10 05:28:26 +00:00
|
|
|
struct Registers {
|
2016-07-23 02:32:35 +00:00
|
|
|
uint32 d[8];
|
|
|
|
uint32 a[8];
|
|
|
|
uint32 sp;
|
2016-07-10 05:28:26 +00:00
|
|
|
uint32 pc;
|
2016-07-12 10:19:31 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
bool c; //carry
|
|
|
|
bool v; //overflow
|
|
|
|
bool z; //zero
|
|
|
|
bool n; //negative
|
|
|
|
bool x; //extend
|
|
|
|
uint3 i; //interrupt mask
|
|
|
|
bool s; //supervisor mode
|
|
|
|
bool t; //trace mode
|
2016-07-10 05:28:26 +00:00
|
|
|
} r;
|
|
|
|
|
2016-07-12 10:19:31 +00:00
|
|
|
uint16 opcode = 0;
|
2016-07-10 05:28:26 +00:00
|
|
|
uint instructionsExecuted = 0;
|
2016-07-12 22:47:04 +00:00
|
|
|
|
|
|
|
function<void ()> instructionTable[65536];
|
Update to v100r06 release.
byuu says:
Up to ten 68K instructions out of somewhere between 61 and 88, depending
upon which PDF you look at. Of course, some of them aren't 100% completed
yet, either. Lots of craziness with MOVEM, and BCC has a BSR variant
that needs stack push/pop functions.
This WIP actually took over eight hours to make, going through every
possible permutation on how to design the core itself. The updated design
now builds both the instruction decoder+dispatcher and the disassembler
decoder into the same main loop during M68K's constructor.
The special cases are also really psychotic on this processor, and
I'm afraid of missing something via the fallthrough cases. So instead,
I'm ordering the instructions alphabetically, and including exclusion
cases to ignore binding invalid cases. If I end up remapping an existing
register, then it'll throw a run-time assertion at program startup.
I wanted very much to get rid of struct EA (EffectiveAddress), but
it's too difficult to keep track of the internal effective address
without it. So I split out the size to a separate parameter, since
every opcode only has one size parameter, and otherwise it was getting
duplicated in opcodes that take two EAs, and was also awkward with the
flag testing. It's a bit more typing, but I feel it's more clean this way.
Overall, I'm really worried this is going to be too slow. I don't want
to turn the EA stuff into templates, because that will massively bloat
out compilation times and object sizes, and will also need a special DSL
preprocessor since C++ doesn't have a static for loop. I can definitely
optimize a lot of EA's address/read/write functions away once the core
is completed, but it's never going to hold a candle to a templatized
68K core.
----
Forgot to include the SA-1 regression fix. I always remember immediately
after I upload and archive the WIP. Will try to get that in next time,
I guess.
2016-07-16 08:39:44 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
//disassembler.cpp
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto disassembleADD(DataRegister dr, uint1 direction, EffectiveAddress ea) -> string;
|
|
|
|
template<uint Size> auto disassembleANDI(EffectiveAddress ea) -> string;
|
|
|
|
auto disassembleANDI_TO_CCR() -> string;
|
|
|
|
auto disassembleANDI_TO_SR() -> string;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto disassembleASL(uint4 shift, DataRegister modify) -> string;
|
|
|
|
template<uint Size> auto disassembleASL(DataRegister shift, DataRegister modify) -> string;
|
|
|
|
auto disassembleASL(EffectiveAddress modify) -> string;
|
|
|
|
template<uint Size> auto disassembleASR(uint4 shift, DataRegister modify) -> string;
|
|
|
|
template<uint Size> auto disassembleASR(DataRegister shift, DataRegister modify) -> string;
|
|
|
|
auto disassembleASR(EffectiveAddress modify) -> string;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
auto disassembleBCC(uint4 condition, uint8 displacement) -> string;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto disassembleBTST(DataRegister dr, EffectiveAddress ea) -> string;
|
|
|
|
template<uint Size> auto disassembleBTST(EffectiveAddress ea) -> string;
|
|
|
|
template<uint Size> auto disassembleCLR(EffectiveAddress ea) -> string;
|
|
|
|
template<uint Size> auto disassembleCMP(DataRegister dr, EffectiveAddress ea) -> string;
|
|
|
|
auto disassembleDBCC(uint4 condition, DataRegister dr) -> string;
|
|
|
|
auto disassembleEORI_TO_CCR() -> string;
|
|
|
|
auto disassembleEORI_TO_SR() -> string;
|
|
|
|
auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto disassembleLSL(uint4 immediate, DataRegister dr) -> string;
|
|
|
|
template<uint Size> auto disassembleLSL(DataRegister sr, DataRegister dr) -> string;
|
|
|
|
auto disassembleLSL(EffectiveAddress ea) -> string;
|
|
|
|
template<uint Size> auto disassembleLSR(uint4 immediate, DataRegister dr) -> string;
|
|
|
|
template<uint Size> auto disassembleLSR(DataRegister shift, DataRegister dr) -> string;
|
|
|
|
auto disassembleLSR(EffectiveAddress ea) -> string;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto disassembleMOVE(EffectiveAddress to, EffectiveAddress from) -> string;
|
|
|
|
template<uint Size> auto disassembleMOVEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
|
|
|
template<uint Size> auto disassembleMOVEM(uint1 direction, EffectiveAddress ea) -> string;
|
|
|
|
auto disassembleMOVEQ(DataRegister dr, uint8 immediate) -> string;
|
|
|
|
auto disassembleMOVE_FROM_SR(EffectiveAddress ea) -> string;
|
|
|
|
auto disassembleMOVE_TO_CCR(EffectiveAddress ea) -> string;
|
|
|
|
auto disassembleMOVE_TO_SR(EffectiveAddress ea) -> string;
|
|
|
|
auto disassembleMOVE_USP(uint1 direction, AddressRegister ar) -> string;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
auto disassembleNOP() -> string;
|
2016-07-23 02:32:35 +00:00
|
|
|
auto disassembleORI_TO_CCR() -> string;
|
|
|
|
auto disassembleORI_TO_SR() -> string;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto disassembleROL(uint4 shift, DataRegister modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROL(DataRegister shift, DataRegister modify) -> string;
|
|
|
|
auto disassembleROL(EffectiveAddress modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROR(uint4 shift, DataRegister modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROR(DataRegister shift, DataRegister modify) -> string;
|
|
|
|
auto disassembleROR(EffectiveAddress modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROXL(uint4 shift, DataRegister modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROXL(DataRegister shift, DataRegister modify) -> string;
|
|
|
|
auto disassembleROXL(EffectiveAddress modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROXR(uint4 shift, DataRegister modify) -> string;
|
|
|
|
template<uint Size> auto disassembleROXR(DataRegister shift, DataRegister modify) -> string;
|
|
|
|
auto disassembleROXR(EffectiveAddress modify) -> string;
|
2016-07-22 12:03:25 +00:00
|
|
|
auto disassembleRTS() -> string;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto disassembleSUBQ(uint4 immediate, EffectiveAddress ea) -> string;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto disassembleTST(EffectiveAddress ea) -> string;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
|
|
|
|
template<uint Size> auto _read(uint32 addr) -> uint32;
|
|
|
|
template<uint Size = Word> auto _readPC() -> uint32;
|
2016-07-25 13:15:54 +00:00
|
|
|
auto _dataRegister(DataRegister dr) -> string;
|
|
|
|
auto _addressRegister(AddressRegister ar) -> string;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
template<uint Size> auto _immediate() -> string;
|
2016-07-23 02:32:35 +00:00
|
|
|
template<uint Size> auto _address(EffectiveAddress& ea) -> string;
|
2016-07-25 13:15:54 +00:00
|
|
|
template<uint Size> auto _effectiveAddress(EffectiveAddress& ea) -> string;
|
2016-07-17 03:24:28 +00:00
|
|
|
auto _branch(uint8 displacement) -> string;
|
Update to v100r09 release.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
2016-07-19 09:12:05 +00:00
|
|
|
template<uint Size> auto _suffix() -> string;
|
2016-07-17 03:24:28 +00:00
|
|
|
auto _condition(uint4 condition) -> string;
|
Update to v100r06 release.
byuu says:
Up to ten 68K instructions out of somewhere between 61 and 88, depending
upon which PDF you look at. Of course, some of them aren't 100% completed
yet, either. Lots of craziness with MOVEM, and BCC has a BSR variant
that needs stack push/pop functions.
This WIP actually took over eight hours to make, going through every
possible permutation on how to design the core itself. The updated design
now builds both the instruction decoder+dispatcher and the disassembler
decoder into the same main loop during M68K's constructor.
The special cases are also really psychotic on this processor, and
I'm afraid of missing something via the fallthrough cases. So instead,
I'm ordering the instructions alphabetically, and including exclusion
cases to ignore binding invalid cases. If I end up remapping an existing
register, then it'll throw a run-time assertion at program startup.
I wanted very much to get rid of struct EA (EffectiveAddress), but
it's too difficult to keep track of the internal effective address
without it. So I split out the size to a separate parameter, since
every opcode only has one size parameter, and otherwise it was getting
duplicated in opcodes that take two EAs, and was also awkward with the
flag testing. It's a bit more typing, but I feel it's more clean this way.
Overall, I'm really worried this is going to be too slow. I don't want
to turn the EA stuff into templates, because that will massively bloat
out compilation times and object sizes, and will also need a special DSL
preprocessor since C++ doesn't have a static for loop. I can definitely
optimize a lot of EA's address/read/write functions away once the core
is completed, but it's never going to hold a candle to a templatized
68K core.
----
Forgot to include the SA-1 regression fix. I always remember immediately
after I upload and archive the WIP. Will try to get that in next time,
I guess.
2016-07-16 08:39:44 +00:00
|
|
|
|
|
|
|
uint32 _pc;
|
|
|
|
function<string ()> disassembleTable[65536];
|
Update to v100r02 release.
byuu says:
Sigh ... I'm really not a good person. I'm inherently selfish.
My responsibility and obligation right now is to work on loki, and
then on the Tengai Makyou Zero translation, and then on improving the
Famicom emulation.
And yet ... it's not what I really want to do. That shouldn't matter;
I should work on my responsibilities first.
Instead, I'm going to be a greedy, self-centered asshole, and work on
what I really want to instead.
I'm really sorry, guys. I'm sure this will make a few people happy,
and probably upset even more people.
I'm also making zero guarantees that this ever gets finished. As always,
I wish I could keep these things secret, so if I fail / give up, I could
just drop it with no shame. But I would have to cut everyone out of the
WIP process completely to make it happen. So, here goes ...
This WIP adds the initial skeleton for Sega Mega Drive / Genesis
emulation. God help us.
(minor note: apparently the new extension for Mega Drive games is .md,
neat. That's what I chose for the folders too. I thought it was .smd,
so that'll be fixed in icarus for the next WIP.)
(aside: this is why I wanted to get v100 out. I didn't want this code in
a skeleton state in v100's source. Nor did I want really broken emulation,
which the first release is sure to be, tarring said release.)
...
So, basically, I've been ruminating on the legacy I want to leave behind
with higan. 3D systems are just plain out. I'm never going to support
them. They're too complex for my abilities, and they would run too slowly
with my design style. I'm not willing to compromise my design ideals. And
I would never want to play a 3D game system at native 240p/480i resolution
... but 1080p+ upscaling is not accurate, so that's a conflict I want
to avoid entirely. It's also never going to emulate computer systems
(X68K, PC-98, FM-Towns, etc) because holy shit that would completely
destroy me. It's also never going emulate arcade machines.
So I think of higan as a collection of 2D emulators for consoles
and handhelds. I've gone over every major 2D gaming system there is,
looking for ones with games I actually care about and enjoy. And I
basically have five of those systems supported already. Looking at the
remaining list, I see only three systems left that I have any interest
in whatsoever: PC-Engine, Master System, Mega Drive. Again, I'm not in
any way committing to emulating any of these, but ... if I had all of
those in higan, I think I'd be content to really, truly, finally stop
writing more emulators for the rest of my life.
And so I decided to tackle the most difficult system first. If I'm
successful, the Z80 core should cover a lot of the work on the SMS. And
the HuC6280 should land somewhere between the NES and SNES in terms of
difficulty ... closer to the NES.
The systems that just don't appeal to me at all, which I will never touch,
include, but are not limited to:
* Atari 2600/5200/7800
* Lynx
* Jaguar
* Vectrex
* Colecovision
* Commodore 64
* Neo-Geo
* Neo-Geo Pocket / Color
* Virtual Boy
* Super A'can
* 32X
* CD-i
* etc, etc, etc.
And really, even if something were mildly interesting in there ... we
have to stop. I can't scale infinitely. I'm already way past my limit,
but I'm doing this anyway. Too many cores bloats everything and kills
quality on everything. I don't want higan to become MESS v2.
I don't know what I'll do about the Famicom Disk System, PC-Engine CD,
and Mega CD. I don't think I'll be able to achieve 60fps emulating the
Mega CD, even if I tried to.
I don't know what's going to happen here with even the Mega Drive. Maybe
I'll get driven crazy with the documentation and quit. Maybe it'll end
up being too complicated and I'll quit. Maybe the emulation will end up
way too slow and I'll give up. Maybe it'll take me seven years to get
any games playable at all. Maybe Steve Snake, AamirM and Mike Pavone
will pool money to hire a hitman to come after me. Who knows.
But this is what I want to do, so ... here goes nothing.
2016-07-09 04:21:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|