2016-07-12 10:19:31 +00:00
|
|
|
auto M68K::trap() -> void {
|
|
|
|
instructionsExecuted--;
|
|
|
|
r.pc -= 2;
|
|
|
|
print("[M68K] unimplemented instruction: ", hex(r.pc, 6L), " = ", hex(opcode, 4L), "\n");
|
|
|
|
print("[M68K] instructions executed: ", instructionsExecuted, "\n");
|
|
|
|
while(true) step(5);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto M68K::instruction() -> void {
|
|
|
|
instructionsExecuted++;
|
2016-07-23 02:32:35 +00:00
|
|
|
|
2016-07-26 10:46:43 +00:00
|
|
|
//if(instructionsExecuted >= 2000010) trap();
|
2016-07-23 02:32:35 +00:00
|
|
|
|
2016-07-26 10:46:43 +00:00
|
|
|
//if(instructionsExecuted >= 2000000) {
|
|
|
|
// print(disassembleRegisters(), "\n");
|
|
|
|
// print(disassemble(r.pc), "\n");
|
|
|
|
// print("\n");
|
|
|
|
//}
|
2016-07-12 10:19:31 +00:00
|
|
|
|
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
|
|
|
opcode = readPC();
|
2016-07-12 22:47:04 +00:00
|
|
|
return instructionTable[opcode]();
|
|
|
|
}
|
2016-07-12 10:19:31 +00:00
|
|
|
|
2016-07-12 22:47:04 +00:00
|
|
|
M68K::M68K() {
|
2016-07-22 12:03:25 +00:00
|
|
|
#define bind(id, name, ...) { \
|
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
|
|
|
assert(!instructionTable[id]); \
|
|
|
|
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
2016-07-22 12:03:25 +00:00
|
|
|
disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define unbind(id) { \
|
|
|
|
instructionTable[id].reset(); \
|
|
|
|
disassembleTable[id].reset(); \
|
|
|
|
}
|
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
|
|
|
|
|
|
|
#define pattern(s) \
|
|
|
|
std::integral_constant<uint16_t, bit::test(s)>::value
|
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
|
|
|
|
|
|
|
//ADD
|
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
|
|
|
for(uint3 dreg : range(8))
|
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
|
|
|
for(uint1 direction : range(2))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
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 opcode = pattern("1101 ---- ++-- ----") | dreg << 9 | direction << 8 | mode << 3 | reg << 0;
|
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
|
|
|
if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue;
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
DataRegister dr{dreg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 0 << 6, ADD<Byte>, dr, direction, ea);
|
|
|
|
bind(opcode | 1 << 6, ADD<Word>, dr, direction, ea);
|
|
|
|
bind(opcode | 2 << 6, ADD<Long>, dr, direction, ea);
|
2016-07-22 12:03:25 +00:00
|
|
|
|
|
|
|
if(direction == 0 && mode == 1) unbind(opcode | 0 << 6);
|
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-26 10:46:43 +00:00
|
|
|
//ADDA
|
|
|
|
for(uint3 areg : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1101 ---+ 11-- ----") | areg << 9 | mode << 3 | reg << 0;
|
|
|
|
if(mode == 7 && reg >= 5) continue;
|
|
|
|
|
|
|
|
AddressRegister ar{areg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 0 << 8, ADDA<Word>, ar, ea);
|
|
|
|
bind(opcode | 1 << 8, ADDA<Long>, ar, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADDI
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0000 0110 ++-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode | 0 << 6, ADDI<Byte>, modify);
|
|
|
|
bind(opcode | 1 << 6, ADDI<Word>, modify);
|
|
|
|
bind(opcode | 2 << 6, ADDI<Long>, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ADDQ
|
|
|
|
for(uint3 data : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0101 ---0 ++-- ----") | data << 9 | mode << 3 | reg << 0;
|
|
|
|
if(mode == 7 && reg >= 2) continue;
|
|
|
|
|
|
|
|
uint4 immediate = data ? (uint4)data : (uint4)8;
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode | 0 << 6, ADDQ<Byte>, immediate, modify);
|
|
|
|
bind(opcode | 1 << 6, ADDQ<Word>, immediate, modify);
|
|
|
|
bind(opcode | 2 << 6, ADDQ<Long>, immediate, modify);
|
|
|
|
|
|
|
|
if(mode == 1) unbind(opcode | 0 << 6);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//ANDI
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0;
|
2016-07-22 12:03:25 +00:00
|
|
|
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
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
|
|
|
EffectiveAddress ea{mode, reg};
|
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
|
|
|
bind(opcode | 0 << 6, ANDI<Byte>, ea);
|
|
|
|
bind(opcode | 1 << 6, ANDI<Word>, ea);
|
|
|
|
bind(opcode | 2 << 6, ANDI<Long>, ea);
|
|
|
|
}
|
2016-07-12 22:47:04 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
//ANDI_TO_CCR
|
|
|
|
{ auto opcode = pattern("0000 0010 0011 1100");
|
|
|
|
|
|
|
|
bind(opcode, ANDI_TO_CCR);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ANDI_TO_SR
|
|
|
|
{ auto opcode = pattern("0000 0010 0111 1100");
|
|
|
|
|
|
|
|
bind(opcode, ANDI_TO_SR);
|
|
|
|
}
|
|
|
|
|
2016-07-25 13:15:54 +00:00
|
|
|
//ASL (immediate)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++00 0---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto shift = count ? (uint4)count : (uint4)8;
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ASL<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ASL<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ASL<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASL (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++10 0---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{sreg};
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ASL<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ASL<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ASL<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASL (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0001 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode, ASL, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASR (immediate)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++00 0---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto shift = count ? (uint4)count : (uint4)8;
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ASR<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ASR<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ASR<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASR (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++10 0---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{sreg};
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ASR<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ASR<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ASR<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ASR (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0000 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode, ASR, modify);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//BCC
|
|
|
|
for(uint4 condition : range( 16))
|
|
|
|
for(uint8 displacement : range(256)) {
|
|
|
|
auto opcode = pattern("0110 ---- ---- ----") | condition << 8 | displacement << 0;
|
2016-07-12 22:47:04 +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
|
|
|
bind(opcode, BCC, condition, displacement);
|
|
|
|
}
|
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-22 12:03:25 +00:00
|
|
|
//BTST (register)
|
|
|
|
for(uint3 dreg : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0000 ---1 00-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
2016-07-22 12:03:25 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
DataRegister dr{dreg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
if(mode == 0) bind(opcode, BTST<Long>, dr, ea);
|
|
|
|
if(mode != 0) bind(opcode, BTST<Byte>, dr, ea);
|
2016-07-22 12:03:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//BTST (immediate)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0000 1000 00-- ----") | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode == 1 || (mode == 7 && (reg == 2 || reg >= 5))) continue;
|
2016-07-22 12:03:25 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
EffectiveAddress ea{mode, reg};
|
2016-07-22 12:03:25 +00:00
|
|
|
if(mode == 0) bind(opcode, BTST<Long>, ea);
|
|
|
|
if(mode != 0) bind(opcode, BTST<Byte>, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CLR
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 0010 ++-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
EffectiveAddress ea{mode, reg};
|
2016-07-22 12:03:25 +00:00
|
|
|
bind(opcode | 0 << 6, CLR<Byte>, ea);
|
|
|
|
bind(opcode | 1 << 6, CLR<Word>, ea);
|
|
|
|
bind(opcode | 2 << 6, CLR<Long>, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CMP
|
|
|
|
for(uint3 dreg : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1011 ---0 ++-- ----") | dreg << 9 | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode == 7 && reg >= 5) continue;
|
2016-07-22 12:03:25 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
DataRegister dr{dreg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 0 << 6, CMP<Byte>, dr, ea);
|
|
|
|
bind(opcode | 1 << 6, CMP<Word>, dr, ea);
|
|
|
|
bind(opcode | 2 << 6, CMP<Long>, dr, ea);
|
2016-07-22 12:03:25 +00:00
|
|
|
|
|
|
|
if(mode == 1) unbind(opcode | 0 << 6);
|
|
|
|
}
|
|
|
|
|
2016-07-26 10:46:43 +00:00
|
|
|
//CMPA
|
|
|
|
for(uint3 areg : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1011 ---+ 11-- ----") | areg << 9 | mode << 3 | reg << 0;
|
|
|
|
|
|
|
|
AddressRegister ar{areg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 0 << 8, CMPA<Word>, ar, ea);
|
|
|
|
bind(opcode | 1 << 8, CMPA<Long>, ar, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CMPI
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0000 1100 ++-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 0 << 6, CMPI<Byte>, ea);
|
|
|
|
bind(opcode | 1 << 6, CMPI<Word>, ea);
|
|
|
|
bind(opcode | 2 << 6, CMPI<Long>, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CMPM
|
|
|
|
for(uint3 xreg : range(8))
|
|
|
|
for(uint3 yreg : range(8)) {
|
|
|
|
auto opcode = pattern("1011 ---1 ++00 1---") | xreg << 9 | yreg << 0;
|
|
|
|
|
|
|
|
EffectiveAddress ax{AddressRegisterIndirectWithPostIncrement, xreg};
|
|
|
|
EffectiveAddress ay{AddressRegisterIndirectWithPostIncrement, yreg};
|
|
|
|
bind(opcode | 0 << 6, CMPM<Byte>, ax, ay);
|
|
|
|
bind(opcode | 1 << 6, CMPM<Word>, ax, ay);
|
|
|
|
bind(opcode | 2 << 6, CMPM<Long>, ax, ay);
|
|
|
|
}
|
|
|
|
|
2016-07-22 12:03:25 +00:00
|
|
|
//DBCC
|
|
|
|
for(uint4 condition : range(16))
|
|
|
|
for(uint3 dreg : range( 8)) {
|
|
|
|
auto opcode = pattern("0101 ---- 1100 1---") | condition << 8 | dreg << 0;
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
DataRegister dr{dreg};
|
|
|
|
bind(opcode, DBCC, condition, dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//EORI_TO_CCR
|
|
|
|
{ auto opcode = pattern("0000 1010 0011 1100");
|
|
|
|
|
|
|
|
bind(opcode, EORI_TO_CCR);
|
|
|
|
}
|
|
|
|
|
|
|
|
//EORI_TO_SR
|
|
|
|
{ auto opcode = pattern("0000 1010 0111 1100");
|
|
|
|
|
|
|
|
bind(opcode, EORI_TO_SR);
|
2016-07-22 12:03:25 +00:00
|
|
|
}
|
|
|
|
|
2016-07-26 10:46:43 +00:00
|
|
|
//JSR
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 1110 10-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg >= 4)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress target{mode, reg};
|
|
|
|
bind(opcode, JSR, target);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//LEA
|
|
|
|
for(uint3 areg : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 ---1 11-- ----") | areg << 9 | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg >= 4)) continue;
|
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-23 02:32:35 +00:00
|
|
|
AddressRegister ar{areg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode, LEA, ar, ea);
|
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-12 10:19:31 +00:00
|
|
|
|
2016-07-25 13:15:54 +00:00
|
|
|
//LSL (immediate)
|
|
|
|
for(uint3 data : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++00 1---") | data << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto immediate = data ? (uint4)data : (uint4)8;
|
|
|
|
DataRegister dr{dreg};
|
|
|
|
bind(opcode | 0 << 6, LSL<Byte>, immediate, dr);
|
|
|
|
bind(opcode | 1 << 6, LSL<Word>, immediate, dr);
|
|
|
|
bind(opcode | 2 << 6, LSL<Long>, immediate, dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LSL (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++10 1---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister sr{sreg};
|
|
|
|
DataRegister dr{dreg};
|
|
|
|
bind(opcode | 0 << 6, LSL<Byte>, sr, dr);
|
|
|
|
bind(opcode | 1 << 6, LSL<Word>, sr, dr);
|
|
|
|
bind(opcode | 2 << 6, LSL<Long>, sr, dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LSL (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0011 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode, LSL, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LSR (immediate)
|
|
|
|
for(uint3 data : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++00 1---") | data << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto immediate = data ? (uint4)data : (uint4)8;
|
|
|
|
DataRegister dr{dreg};
|
|
|
|
bind(opcode | 0 << 6, LSR<Byte>, immediate, dr);
|
|
|
|
bind(opcode | 1 << 6, LSR<Word>, immediate, dr);
|
|
|
|
bind(opcode | 2 << 6, LSR<Long>, immediate, dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LSR (register)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++10 1---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{count};
|
|
|
|
DataRegister dr{dreg};
|
|
|
|
bind(opcode | 0 << 6, LSR<Byte>, shift, dr);
|
|
|
|
bind(opcode | 1 << 6, LSR<Word>, shift, dr);
|
|
|
|
bind(opcode | 2 << 6, LSR<Long>, shift, dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//LSR (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0010 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode, LSR, ea);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//MOVE
|
|
|
|
for(uint3 toReg : range(8))
|
|
|
|
for(uint3 toMode : range(8))
|
|
|
|
for(uint3 fromMode : range(8))
|
|
|
|
for(uint3 fromReg : range(8)) {
|
|
|
|
auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0;
|
2016-07-22 12:03:25 +00:00
|
|
|
if(toMode == 1 || (toMode == 7 && toReg >= 2)) continue;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(fromMode == 7 && fromReg >= 5) continue;
|
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
|
|
|
EffectiveAddress to{toMode, toReg};
|
|
|
|
EffectiveAddress from{fromMode, fromReg};
|
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
|
|
|
bind(opcode | 1 << 12, MOVE<Byte>, to, from);
|
|
|
|
bind(opcode | 3 << 12, MOVE<Word>, to, from);
|
|
|
|
bind(opcode | 2 << 12, MOVE<Long>, to, from);
|
2016-07-22 12:03:25 +00:00
|
|
|
|
|
|
|
if(fromMode == 1) unbind(opcode | 1 << 12);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//MOVEA
|
|
|
|
for(uint3 areg : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode == 7 && reg >= 5) continue;
|
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
|
|
|
AddressRegister ar{areg};
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 3 << 12, MOVEA<Word>, ar, ea);
|
|
|
|
bind(opcode | 2 << 12, MOVEA<Long>, ar, ea);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//MOVEM
|
|
|
|
for(uint1 direction : range(2))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 1-00 1+-- ----") | direction << 10 | mode << 3 | reg << 0;
|
2016-07-22 12:03:25 +00:00
|
|
|
if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2)));
|
2016-07-25 13:15:54 +00:00
|
|
|
if(direction == 1 && (mode <= 1 || mode == 4 || (mode == 7 && reg >= 4)));
|
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
|
|
|
EffectiveAddress ea{mode, reg};
|
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
|
|
|
bind(opcode | 0 << 6, MOVEM<Word>, direction, ea);
|
|
|
|
bind(opcode | 1 << 6, MOVEM<Long>, direction, ea);
|
|
|
|
}
|
|
|
|
|
|
|
|
//MOVEQ
|
|
|
|
for(uint3 dreg : range( 8))
|
|
|
|
for(uint8 immediate : range(256)) {
|
|
|
|
auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0;
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
DataRegister dr{dreg};
|
|
|
|
bind(opcode, MOVEQ, dr, immediate);
|
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-22 12:03:25 +00:00
|
|
|
//MOVE_FROM_SR
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 0000 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode == 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
EffectiveAddress ea{mode, reg};
|
2016-07-22 12:03:25 +00:00
|
|
|
bind(opcode, MOVE_FROM_SR, ea);
|
|
|
|
}
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
//MOVE_TO_CCR
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 0100 11-- ----") | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
2016-07-23 02:32:35 +00:00
|
|
|
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode, MOVE_TO_CCR, ea);
|
|
|
|
}
|
|
|
|
|
2016-07-22 12:03:25 +00:00
|
|
|
//MOVE_TO_SR
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 0110 11-- ----") | mode << 3 | reg << 0;
|
2016-07-25 13:15:54 +00:00
|
|
|
if(mode == 1 || (mode == 7 && reg >= 5)) continue;
|
2016-07-22 12:03:25 +00:00
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
EffectiveAddress ea{mode, reg};
|
2016-07-22 12:03:25 +00:00
|
|
|
bind(opcode, MOVE_TO_SR, ea);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//MOVE_USP
|
|
|
|
for(uint1 direction : range(2))
|
|
|
|
for(uint3 areg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0;
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
AddressRegister ar{areg};
|
|
|
|
bind(opcode, MOVE_USP, direction, ar);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//NOP
|
|
|
|
{ auto opcode = pattern("0100 1110 0111 0001");
|
|
|
|
|
|
|
|
bind(opcode, NOP);
|
|
|
|
}
|
|
|
|
|
2016-07-23 02:32:35 +00:00
|
|
|
//ORI_TO_CCR
|
|
|
|
{ auto opcode = pattern("0000 0000 0011 1100");
|
|
|
|
|
|
|
|
bind(opcode, ORI_TO_CCR);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ORI_TO_SR
|
|
|
|
{ auto opcode = pattern("0000 0000 0111 1100");
|
|
|
|
|
|
|
|
bind(opcode, ORI_TO_SR);
|
|
|
|
}
|
|
|
|
|
2016-07-25 13:15:54 +00:00
|
|
|
//ROL (immediate)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++01 1---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto shift = count ? (uint4)count : (uint4)8;
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROL<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROL<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROL<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROL (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++11 1---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{sreg};
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROL<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROL<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROL<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROL (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0111 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode, ROL, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROR (immediate)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++01 1---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto shift = count ? (uint4)count : (uint4)8;
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROR<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROR<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROR<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROR (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++11 1---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{sreg};
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROR<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROR<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROR<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROR (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0110 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode, ROR, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROXL (immediate)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++01 0---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto shift = count ? (uint4)count : (uint4)8;
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROXL<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROXL<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROXL<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROXL (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---1 ++11 0---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{sreg};
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROXL<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROXL<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROXL<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROXL (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0101 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode, ROXL, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROXR (immediate)
|
|
|
|
for(uint3 count : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++01 0---") | count << 9 | dreg << 0;
|
|
|
|
|
|
|
|
auto shift = count ? (uint4)count : (uint4)8;
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROXR<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROXR<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROXR<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROXR (register)
|
|
|
|
for(uint3 sreg : range(8))
|
|
|
|
for(uint3 dreg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 ---0 ++11 0---") | sreg << 9 | dreg << 0;
|
|
|
|
|
|
|
|
DataRegister shift{sreg};
|
|
|
|
DataRegister modify{dreg};
|
|
|
|
bind(opcode | 0 << 6, ROXR<Byte>, shift, modify);
|
|
|
|
bind(opcode | 1 << 6, ROXR<Word>, shift, modify);
|
|
|
|
bind(opcode | 2 << 6, ROXR<Long>, shift, modify);
|
|
|
|
}
|
|
|
|
|
|
|
|
//ROXR (effective address)
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("1110 0100 11-- ----") | mode << 3 | reg << 0;
|
|
|
|
if(mode <= 1 || (mode == 7 && reg >= 2)) continue;
|
|
|
|
|
|
|
|
EffectiveAddress modify{mode, reg};
|
|
|
|
bind(opcode, ROXR, modify);
|
|
|
|
}
|
|
|
|
|
2016-07-22 12:03:25 +00:00
|
|
|
//RTS
|
|
|
|
{ auto opcode = pattern("0100 1110 0111 0101");
|
|
|
|
|
|
|
|
bind(opcode, RTS);
|
|
|
|
}
|
|
|
|
|
2016-07-25 13:15:54 +00:00
|
|
|
//SUBQ
|
|
|
|
for(uint3 data : range(8))
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0101 ---1 ++-- ----") | data << 9 | mode << 3 | reg << 0;
|
|
|
|
if(mode == 7 && reg >= 2) continue;
|
|
|
|
|
|
|
|
auto immediate = data ? (uint4)data : (uint4)8;
|
|
|
|
EffectiveAddress ea{mode, reg};
|
|
|
|
bind(opcode | 0 << 6, SUBQ<Byte>, immediate, ea);
|
|
|
|
bind(opcode | 1 << 6, SUBQ<Word>, immediate, ea);
|
|
|
|
bind(opcode | 2 << 6, SUBQ<Long>, immediate, ea);
|
|
|
|
|
|
|
|
if(mode == 1) unbind(opcode | 0 << 6);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
//TST
|
|
|
|
for(uint3 mode : range(8))
|
|
|
|
for(uint3 reg : range(8)) {
|
|
|
|
auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
|
2016-07-22 12:03:25 +00:00
|
|
|
if(mode == 7 && reg >= 2) continue;
|
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
|
|
|
EffectiveAddress ea{mode, reg};
|
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
|
|
|
bind(opcode | 0 << 6, TST<Byte>, ea);
|
|
|
|
bind(opcode | 1 << 6, TST<Word>, ea);
|
|
|
|
bind(opcode | 2 << 6, TST<Long>, ea);
|
2016-07-22 12:03:25 +00:00
|
|
|
|
|
|
|
if(mode == 1) unbind(opcode | 0 << 6);
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
#undef bind
|
2016-07-22 12:03:25 +00:00
|
|
|
#undef unbind
|
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
|
|
|
#undef pattern
|
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
|
|
|
|
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
|
|
|
uint unimplemented = 0;
|
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
|
|
|
for(uint16 opcode : range(65536)) {
|
|
|
|
if(instructionTable[opcode]) continue;
|
|
|
|
instructionTable[opcode] = [=] { trap(); };
|
|
|
|
disassembleTable[opcode] = [=] { return 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
|
|
|
unimplemented++;
|
2016-07-12 10:19:31 +00:00
|
|
|
}
|
2016-07-22 12:03:25 +00:00
|
|
|
print("[M68K] unimplemented opcodes: ", unimplemented, "\n");
|
2016-07-12 10:19:31 +00:00
|
|
|
}
|