Skip to content

Commit 04db26a

Browse files
committed
Rewrite ADC, ADD, AND, ANDN
1 parent 17469fe commit 04db26a

7 files changed

Lines changed: 473 additions & 368 deletions

File tree

src/Emulator/Core/CPU/CPU.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ namespace HyperCPU {
118118
std::array<read_operation_handler, 256> read_io_handlers;
119119
std::array<write_operation_handler, 256> write_io_handlers;
120120
std::unique_ptr<SimpleIOImpl> io_ctl;
121+
122+
class CPU_InstrImpl;
121123

122124
public:
123125
CPU(std::uint16_t core_count, std::uint64_t mem_size, char* binary = nullptr, std::uint64_t binary_size = 0);

src/Emulator/Core/CPU/InstructionsImpl/ADC.cpp

Lines changed: 133 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,184 @@
1+
#include "Common/LanguageSpec/Flags.hpp"
12
#include "Emulator/Core/CPU/ALU.hpp"
23
#include "Emulator/Core/CPU/CPU.hpp"
34

5+
#include "Emulator/Core/CPU/Decoders/StdDecoder.hpp"
6+
#include "Emulator/Core/CPU/Interrupts/ReservedInterrupts.hpp"
7+
#include "Emulator/Misc/smallest_type.hpp"
48
#include "Emulator/Misc/bit_cast.hpp"
59
#include "Emulator/Misc/overflow.hpp"
610

7-
using namespace HyperALU;
11+
12+
class HyperCPU::CPU::CPU_InstrImpl {
13+
public:
14+
constexpr CPU_InstrImpl() { }
15+
16+
/* R_R implementation */
17+
template<typename T1, typename T2>
18+
static constexpr void __hcpu_adc_rr_impl(HyperCPU::OperandContainer& op1, HyperCPU::OperandContainer& op2, CPU& cpu) {
19+
static_assert(std::is_same_v<T1, T2>); // Locked by current CPU specification
20+
21+
cpu.ovf = AdditionWillOverflow(op1.deref<T1>(), op2.deref<T2>());
22+
op1.deref<T1>() = HyperALU::__hcpu_add(op1.deref<T1>(), HyperCPU::bit_cast_from<T2>(op2.ptr<T2>()));
23+
24+
if (cpu.crf)
25+
++op1.deref<T1>();
26+
}
27+
28+
/* R_RM implementation */
29+
template<typename T1, typename T2>
30+
void __hcpu_adc_rrm_impl(HyperCPU::OperandContainer& op1, HyperCPU::OperandContainer& op2, CPU& cpu) {
31+
static_assert(std::is_same_v<T2, std::uint64_t>); // Locked by current CPU specification
32+
33+
T2 ptr = HyperCPU::bit_cast_from<T2>(op2.ptr<T2>());
34+
T1 val = cpu.mem_controller->Read8(ptr);
35+
cpu.ovf = AdditionWillOverflow(op1.deref<T1>(), val);
36+
37+
op1.deref<T1>() = HyperALU::__hcpu_add(op1.deref<T1>(), val);
38+
39+
if (cpu.crf)
40+
++op1.deref<T1>();
41+
}
42+
43+
/* R_M implementation */
44+
template<typename T1, typename T2>
45+
void __hcpu_adc_rm_impl(HyperCPU::OperandContainer& op1, HyperCPU::OperandContainer& op2, CPU& cpu) {
46+
static_assert(std::is_same_v<T2, std::uint64_t>); // Locked by current CPU specification
47+
48+
T2 ptr = HyperCPU::bit_cast<T2>(op2);
49+
T1 val = cpu.mem_controller->Read8(ptr);
50+
cpu.ovf = AdditionWillOverflow(op1.deref<T1>(), val);
51+
52+
op1.deref<T1>() = HyperALU::__hcpu_add(op1.deref<T1>(), val);
53+
54+
if (cpu.crf)
55+
++op1.deref<T1>();
56+
}
57+
58+
/* R_IMM implementation */
59+
template<typename T1, typename T2>
60+
void __hcpu_adc_rimm_impl(HyperCPU::OperandContainer& op1, HyperCPU::OperandContainer& op2, CPU& cpu) {
61+
static_assert(std::is_same_v<T1, T2>); // Locked by current CPU specification
62+
63+
T1 val = HyperCPU::bit_cast<T1>(op2);
64+
cpu.ovf = AdditionWillOverflow(op1.deref<T1>(), val);
65+
op1.deref<T1>() = HyperALU::__hcpu_add(op1.deref<T1>(), val);
66+
67+
if (cpu.crf)
68+
++op1.deref<T1>();
69+
}
70+
};
71+
72+
template<typename T1, typename TImpl>
73+
[[gnu::always_inline]]
74+
void ResolveOP2Mode(HyperCPU::Mode md2, HyperCPU::OperandContainer& op1, HyperCPU::OperandContainer& op2, HyperCPU::CPU& cpu) {
75+
TImpl impl;
76+
77+
switch (md2) {
78+
case HyperCPU::Mode::b8: impl.template invoke<T1, std::uint8_t>(op1, op2, cpu); break;
79+
case HyperCPU::Mode::b16: impl.template invoke<T1, std::uint16_t>(op1, op2, cpu); break;
80+
case HyperCPU::Mode::b32: impl.template invoke<T1, std::uint32_t>(op1, op2, cpu); break;
81+
case HyperCPU::Mode::b64: impl.template invoke<T1, std::uint64_t>(op1, op2, cpu); break;
82+
default: std::abort();
83+
}
84+
}
885

986
void HyperCPU::CPU::ExecADC(const IInstruction& instr, OperandContainer op1, OperandContainer op2) {
87+
CPU_InstrImpl impl;
88+
1089
switch (instr.m_op_types) {
1190
case OperandTypes::R_R: {
12-
switch (instr.m_opcode_mode) {
91+
if (instr.m_opcode_mode.md1 != instr.m_opcode_mode.md2) {
92+
TriggerInterrupt(HyperCPU::cpu_exceptions::IO);
93+
return;
94+
}
95+
96+
/* ADC R_R does not support different register sizes - we can call implementation directly */
97+
switch (instr.m_opcode_mode.md1) {
1398
case Mode::b8:
14-
ovf = AdditionWillOverflow(op1.deref<std::uint8_t>(), op2.deref<std::uint8_t>());
15-
op1.deref<std::uint8_t>() = HyperALU::__hcpu_add(op1.deref<std::uint8_t>(), HyperCPU::bit_cast_from<std::uint8_t>(op2.ptr<std::uint8_t>()));
16-
if (crf)
17-
++op1.deref<std::uint8_t>();
99+
impl.__hcpu_adc_rr_impl<std::uint8_t, std::uint8_t>(op1, op2, *this);
18100
break;
19-
20101
case Mode::b16:
21-
ovf = AdditionWillOverflow(op1.deref<std::uint16_t>(), op2.deref<std::uint16_t>());
22-
op1.deref<std::uint16_t>() = HyperALU::__hcpu_add(op1.deref<std::uint16_t>(), HyperCPU::bit_cast_from<std::uint16_t>(op2.ptr<std::uint16_t>()));
23-
if (crf)
24-
++op1.deref<std::uint16_t>();
102+
impl.__hcpu_adc_rr_impl<std::uint16_t, std::uint16_t>(op1, op2, *this);
25103
break;
26-
27104
case Mode::b32:
28-
ovf = AdditionWillOverflow(op1.deref<std::uint32_t>(), op2.deref<std::uint32_t>());
29-
op1.deref<std::uint32_t>() = HyperALU::__hcpu_add(op1.deref<std::uint32_t>(), HyperCPU::bit_cast_from<std::uint32_t>(op2.ptr<std::uint32_t>()));
30-
if (crf)
31-
++op1.deref<std::uint32_t>();
105+
impl.__hcpu_adc_rr_impl<std::uint32_t, std::uint32_t>(op1, op2, *this);
32106
break;
33-
34107
case Mode::b64:
35-
ovf = AdditionWillOverflow(op1.deref<std::uint64_t>(), op2.deref<std::uint64_t>());
36-
op1.deref<std::uint64_t>() = HyperALU::__hcpu_add(op1.deref<std::uint64_t>(), HyperCPU::bit_cast_from<std::uint64_t>(op2.ptr<std::uint64_t>()));
37-
if (crf)
38-
++op1.deref<std::uint64_t>();
108+
impl.__hcpu_adc_rr_impl<std::uint64_t, std::uint64_t>(op1, op2, *this);
39109
break;
40110
}
41111
break;
42112
}
43113

44114
case OperandTypes::R_RM: {
45-
std::uint64_t ptr = HyperCPU::bit_cast_from<std::uint64_t>(op2.ptr<std::uint64_t>());
46-
47-
switch (instr.m_opcode_mode) {
48-
case Mode::b8: {
49-
std::uint8_t val = mem_controller->Read8(ptr);
50-
ovf = AdditionWillOverflow(op1.deref<std::uint8_t>(), val);
51-
op1.deref<std::uint8_t>() = HyperALU::__hcpu_add(op1.deref<std::uint8_t>(), val);
52-
if (crf)
53-
++op1.deref<std::uint8_t>();
54-
break;
115+
if (instr.m_opcode_mode.md2 != Mode::b64) {
116+
TriggerInterrupt(HyperCPU::cpu_exceptions::IO);
117+
return;
55118
}
56119

57-
case Mode::b16: {
58-
std::uint16_t val = mem_controller->Read16(ptr);
59-
ovf = AdditionWillOverflow(op1.deref<std::uint16_t>(), val);
60-
op1.deref<std::uint16_t>() = HyperALU::__hcpu_add(op1.deref<std::uint16_t>(), val);
61-
if (crf)
62-
++op1.deref<std::uint16_t>();
120+
/* ADC R_RM does not support different register sizes - we can call implementation directly */
121+
switch (instr.m_opcode_mode.md1) {
122+
case Mode::b8:
123+
impl.__hcpu_adc_rrm_impl<std::uint8_t, std::uint64_t>(op1, op2, *this);
63124
break;
64-
}
65-
66-
case Mode::b32: {
67-
std::uint32_t val = mem_controller->Read32(ptr);
68-
ovf = AdditionWillOverflow(op1.deref<std::uint32_t>(), val);
69-
op1.deref<std::uint32_t>() = HyperALU::__hcpu_add(op1.deref<std::uint32_t>(), val);
70-
if (crf)
71-
++op1.deref<std::uint32_t>();
125+
case Mode::b16:
126+
impl.__hcpu_adc_rrm_impl<std::uint16_t, std::uint64_t>(op1, op2, *this);
72127
break;
73-
}
74-
75-
case Mode::b64: {
76-
std::uint64_t val = mem_controller->Read64(ptr);
77-
ovf = AdditionWillOverflow(op1.deref<std::uint64_t>(), val);
78-
op1.deref<std::uint64_t>() = HyperALU::__hcpu_add(op1.deref<std::uint64_t>(), val);
79-
if (crf)
80-
++op1.deref<std::uint64_t>();
128+
case Mode::b32:
129+
impl.__hcpu_adc_rrm_impl<std::uint32_t, std::uint64_t>(op1, op2, *this);
130+
break;
131+
case Mode::b64:
132+
impl.__hcpu_adc_rrm_impl<std::uint64_t, std::uint64_t>(op1, op2, *this);
81133
break;
82-
}
83134
}
84135
break;
85136
}
86137

87138
case OperandTypes::R_M: {
88-
std::uint64_t ptr = HyperCPU::bit_cast<std::uint64_t>(op2);
89-
90-
switch (instr.m_opcode_mode) {
91-
case Mode::b8: {
92-
std::uint8_t val = mem_controller->Read8(ptr);
93-
ovf = AdditionWillOverflow(op1.deref<std::uint8_t>(), val);
94-
op1.deref<std::uint8_t>() = HyperALU::__hcpu_add(op1.deref<std::uint8_t>(), val);
95-
if (crf)
96-
++op1.deref<std::uint8_t>();
97-
break;
139+
if (instr.m_opcode_mode.md2 != Mode::b64) {
140+
TriggerInterrupt(HyperCPU::cpu_exceptions::IO);
141+
return;
98142
}
99143

100-
case Mode::b16: {
101-
std::uint16_t val = mem_controller->Read16(ptr);
102-
ovf = AdditionWillOverflow(op1.deref<std::uint16_t>(), val);
103-
op1.deref<std::uint16_t>() = HyperALU::__hcpu_add(op1.deref<std::uint16_t>(), val);
104-
if (crf)
105-
++op1.deref<std::uint16_t>();
144+
/* ADC R_RM does not support different register sizes - we can call implementation directly */
145+
switch (instr.m_opcode_mode.md1) {
146+
case Mode::b8:
147+
impl.__hcpu_adc_rm_impl<std::uint8_t, std::uint64_t>(op1, op2, *this);
106148
break;
107-
}
108-
109-
case Mode::b32: {
110-
std::uint32_t val = mem_controller->Read32(ptr);
111-
ovf = AdditionWillOverflow(op1.deref<std::uint32_t>(), val);
112-
op1.deref<std::uint32_t>() = HyperALU::__hcpu_add(op1.deref<std::uint32_t>(), val);
113-
if (crf)
114-
++op1.deref<std::uint32_t>();
149+
case Mode::b16:
150+
impl.__hcpu_adc_rm_impl<std::uint16_t, std::uint64_t>(op1, op2, *this);
115151
break;
116-
}
117-
118-
case Mode::b64: {
119-
std::uint64_t val = mem_controller->Read64(ptr);
120-
ovf = AdditionWillOverflow(op1.deref<std::uint64_t>(), val);
121-
op1.deref<std::uint64_t>() = HyperALU::__hcpu_add(op1.deref<std::uint64_t>(), val);
122-
if (crf)
123-
++op1.deref<std::uint64_t>();
152+
case Mode::b32:
153+
impl.__hcpu_adc_rm_impl<std::uint32_t, std::uint64_t>(op1, op2, *this);
154+
break;
155+
case Mode::b64:
156+
impl.__hcpu_adc_rm_impl<std::uint64_t, std::uint64_t>(op1, op2, *this);
124157
break;
125-
}
126158
}
127159
break;
128160
}
129161

130162
case OperandTypes::R_IMM: {
131-
switch (instr.m_opcode_mode) {
132-
case Mode::b8: {
133-
std::uint8_t val = HyperCPU::bit_cast<std::uint8_t>(op2);
134-
ovf = AdditionWillOverflow(op1.deref<std::uint8_t>(), val);
135-
op1.deref<std::uint8_t>() = HyperALU::__hcpu_add(op1.deref<std::uint8_t>(), val);
136-
if (crf)
137-
++op1.deref<std::uint8_t>();
138-
break;
163+
if (instr.m_opcode_mode.md2 != instr.m_opcode_mode.md1) {
164+
TriggerInterrupt(HyperCPU::cpu_exceptions::IO);
165+
return;
139166
}
140167

141-
case Mode::b16: {
142-
std::uint16_t val = HyperCPU::bit_cast<std::uint16_t>(op2);
143-
ovf = AdditionWillOverflow(op1.deref<std::uint16_t>(), val);
144-
op1.deref<std::uint16_t>() = HyperALU::__hcpu_add(op1.deref<std::uint16_t>(), val);
145-
if (crf)
146-
++op1.deref<std::uint16_t>();
168+
/* ADC R_RM does not support different register sizes - we can call implementation directly */
169+
switch (instr.m_opcode_mode.md1) {
170+
case Mode::b8:
171+
impl.__hcpu_adc_rimm_impl<std::uint8_t, std::uint8_t>(op1, op2, *this);
147172
break;
148-
}
149-
150-
case Mode::b32: {
151-
std::uint32_t val = HyperCPU::bit_cast<std::uint32_t>(op2);
152-
ovf = AdditionWillOverflow(op1.deref<std::uint32_t>(), val);
153-
op1.deref<std::uint32_t>() = HyperALU::__hcpu_add(op1.deref<std::uint32_t>(), val);
154-
if (crf)
155-
++op1.deref<std::uint32_t>();
173+
case Mode::b16:
174+
impl.__hcpu_adc_rimm_impl<std::uint16_t, std::uint16_t>(op1, op2, *this);
156175
break;
157-
}
158-
159-
case Mode::b64: {
160-
std::uint64_t val = HyperCPU::bit_cast<std::uint64_t>(op2);
161-
ovf = AdditionWillOverflow(op1.deref<std::uint64_t>(), val);
162-
op1.deref<std::uint64_t>() = HyperALU::__hcpu_add(op1.deref<std::uint64_t>(), val);
163-
if (crf)
164-
++op1.deref<std::uint64_t>();
176+
case Mode::b32:
177+
impl.__hcpu_adc_rimm_impl<std::uint32_t, std::uint32_t>(op1, op2, *this);
178+
break;
179+
case Mode::b64:
180+
impl.__hcpu_adc_rimm_impl<std::uint64_t, std::uint64_t>(op1, op2, *this);
165181
break;
166-
}
167182
}
168183
break;
169184
}

0 commit comments

Comments
 (0)