code cleanup: unify getGAM/getGAMAddress/putGAM (first step)
This commit is contained in:
parent
57c7a23bd5
commit
be68ad2357
2 changed files with 218 additions and 294 deletions
487
cpu.cpp
487
cpu.cpp
|
@ -153,17 +153,17 @@ void cpu::setRegisterLowByte(const int nr, const bool word_mode, const uint16_t
|
|||
}
|
||||
}
|
||||
|
||||
bool cpu::put_result(const uint16_t a, const uint8_t dst_mode, const uint8_t dst_reg, const bool word_mode, const uint16_t value)
|
||||
bool cpu::put_result(const gam_rc_t & g, const uint16_t value)
|
||||
{
|
||||
if (dst_mode == 0) {
|
||||
setRegisterLowByte(dst_reg, word_mode, value);
|
||||
if (g.addr.has_value() == false) {
|
||||
setRegisterLowByte(g.reg, g.word_mode, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
b->write(a, word_mode, value, false);
|
||||
b->write(g.addr.value(), g.word_mode, value, false);
|
||||
|
||||
return a != ADDR_PSW;
|
||||
return g.addr.value() != ADDR_PSW;
|
||||
}
|
||||
|
||||
uint16_t cpu::addRegister(const int nr, const bool prev_mode, const uint16_t value)
|
||||
|
@ -322,150 +322,84 @@ void cpu::addToMMR1(const uint8_t mode, const uint8_t reg, const bool word_mode)
|
|||
}
|
||||
|
||||
// GAM = general addressing modes
|
||||
uint16_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool prev_mode)
|
||||
gam_rc_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool prev_mode, const bool read_value)
|
||||
{
|
||||
uint16_t next_word = 0;
|
||||
uint16_t temp = 0;
|
||||
gam_rc_t g { false, false, false, { }, 0 };
|
||||
g.word_mode = word_mode; // word/byte
|
||||
g.prev_mode = prev_mode; // run mode
|
||||
g.set = getBitPSW(11);
|
||||
|
||||
int set = getBitPSW(11);
|
||||
uint16_t next_word = 0;
|
||||
|
||||
switch(mode) {
|
||||
case 0: // 000
|
||||
return getRegister(reg, set, prev_mode) & (word_mode ? 0xff : 0xffff);
|
||||
g.reg = reg;
|
||||
g.value = getRegister(reg, g.set, prev_mode) & (word_mode ? 0xff : 0xffff);
|
||||
break;
|
||||
case 1:
|
||||
return b -> read(getRegister(reg, set, prev_mode), word_mode, prev_mode);
|
||||
g.addr = getRegister(reg, g.set, prev_mode);
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
break;
|
||||
case 2:
|
||||
temp = b -> read(getRegister(reg, set, prev_mode), word_mode, prev_mode);
|
||||
g.addr = getRegister(reg, g.set, prev_mode);
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? 2 : 1);
|
||||
return temp;
|
||||
break;
|
||||
case 3:
|
||||
temp = b -> read(b -> read(getRegister(reg, set, prev_mode), false, prev_mode), word_mode, prev_mode);
|
||||
g.addr = b->read(getRegister(reg, g.set, prev_mode), false, prev_mode);
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
addRegister(reg, prev_mode, 2);
|
||||
return temp;
|
||||
break;
|
||||
case 4:
|
||||
addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? -2 : -1);
|
||||
return b -> read(getRegister(reg, set, prev_mode), word_mode, prev_mode);
|
||||
case 5:
|
||||
addRegister(reg, prev_mode, -2);
|
||||
return b -> read(b -> read(getRegister(reg, set, prev_mode), false, prev_mode), word_mode, prev_mode);
|
||||
case 6:
|
||||
next_word = b -> read(getPC(), false, prev_mode);
|
||||
addRegister(7, prev_mode, + 2);
|
||||
temp = b -> read(getRegister(reg, set, prev_mode) + next_word, word_mode, prev_mode);
|
||||
return temp;
|
||||
case 7:
|
||||
next_word = b -> read(getPC(), false, prev_mode);
|
||||
addRegister(7, prev_mode, + 2);
|
||||
return b -> read(b -> read(getRegister(reg, set, prev_mode) + next_word, false, prev_mode), word_mode, prev_mode);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool cpu::putGAM(const uint8_t mode, const int reg, const bool word_mode, const uint16_t value, bool const prev_mode)
|
||||
{
|
||||
uint16_t next_word = 0;
|
||||
int addr = -1;
|
||||
|
||||
int set = getBitPSW(11);
|
||||
|
||||
uint16_t dummy = 0;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
setRegister(reg, prev_mode, value);
|
||||
break;
|
||||
case 1:
|
||||
addr = getRegister(reg, set, prev_mode);
|
||||
b -> write(addr, word_mode, value, false);
|
||||
break;
|
||||
case 2:
|
||||
addr = getRegister(reg, set, prev_mode);
|
||||
b -> write(addr, word_mode, value, false);
|
||||
addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? 2 : 1);
|
||||
break;
|
||||
case 3:
|
||||
addr = b -> readWord(getRegister(reg, set, prev_mode));
|
||||
b -> write(addr, word_mode, value, false);
|
||||
addRegister(reg, prev_mode, 2);
|
||||
break;
|
||||
case 4:
|
||||
dummy = addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? -2 : -1);
|
||||
b -> write(dummy, word_mode, value, false);
|
||||
g.addr = getRegister(reg, g.set, prev_mode);
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
break;
|
||||
case 5:
|
||||
addRegister(reg, prev_mode, -2);
|
||||
addr = b -> readWord(getRegister(reg, set, prev_mode));
|
||||
b -> write(addr, word_mode, value, false);
|
||||
g.addr = b->read(getRegister(reg, g.set, prev_mode), false, prev_mode);
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
break;
|
||||
case 6:
|
||||
next_word = b -> readWord(getPC());
|
||||
addRegister(7, prev_mode, 2);
|
||||
addr = (getRegister(reg, set, prev_mode) + next_word) & 0xffff;
|
||||
b -> write(addr, word_mode, value, false);
|
||||
next_word = b -> read(getPC(), false, prev_mode);
|
||||
addRegister(7, prev_mode, + 2);
|
||||
g.addr = getRegister(reg, g.set, prev_mode) + next_word;
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
break;
|
||||
case 7:
|
||||
next_word = b -> readWord(getPC());
|
||||
addRegister(7, prev_mode, 2);
|
||||
addr = b -> readWord(getRegister(reg, set, prev_mode) + next_word);
|
||||
b -> write(addr, word_mode, value, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
// error
|
||||
next_word = b -> read(getPC(), false, prev_mode);
|
||||
addRegister(7, prev_mode, + 2);
|
||||
g.addr = b->read(getRegister(reg, g.set, prev_mode) + next_word, false, prev_mode);
|
||||
if (read_value)
|
||||
g.value = b->read(g.addr.value(), word_mode, prev_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
return addr == -1 || addr != ADDR_PSW;
|
||||
return g;
|
||||
}
|
||||
|
||||
uint16_t cpu::getGAMAddress(const uint8_t mode, const int reg, const bool word_mode)
|
||||
bool cpu::putGAM(const gam_rc_t & g, const uint16_t value)
|
||||
{
|
||||
uint16_t next_word = 0;
|
||||
uint16_t temp = 0;
|
||||
if (g.addr.has_value()) {
|
||||
b->write(g.addr.value(), g.word_mode, value, g.prev_mode);
|
||||
|
||||
int set = getBitPSW(11);
|
||||
int run_mode = psw >> 14;
|
||||
|
||||
constexpr uint16_t sp_pointers[] = { ADDR_KERNEL_SP, ADDR_SV_SP, 0xffff, ADDR_USER_SP };
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
// registers are also mapped in memory
|
||||
if (reg < 6)
|
||||
return (run_mode == 3 ? ADDR_USER_R : ADDR_KERNEL_R) + reg;
|
||||
|
||||
if (reg == 7)
|
||||
return ADDR_PC;
|
||||
|
||||
return sp_pointers[run_mode];
|
||||
case 1:
|
||||
return getRegister(reg, set, false);
|
||||
case 2:
|
||||
temp = getRegister(reg, set, false);
|
||||
addRegister(reg, false, !word_mode || reg == 6 || reg == 7 ? 2 : 1);
|
||||
return temp;
|
||||
case 3:
|
||||
temp = b -> readWord(getRegister(reg, set, false));
|
||||
addRegister(reg, false, 2);
|
||||
return temp;
|
||||
case 4:
|
||||
addRegister(reg, false, !word_mode || reg == 6 || reg == 7 ? -2 : -1);
|
||||
return getRegister(reg, set, false);
|
||||
case 5:
|
||||
addRegister(reg, false, -2);
|
||||
return b -> readWord(getRegister(reg, set, false));
|
||||
case 6:
|
||||
next_word = b -> readWord(getPC());
|
||||
addRegister(7, false, 2);
|
||||
return getRegister(reg, set, false) + next_word;
|
||||
case 7:
|
||||
next_word = b -> readWord(getPC());
|
||||
addRegister(7, false, 2);
|
||||
return b -> readWord(getRegister(reg, set, false) + next_word);
|
||||
return g.addr.value() != ADDR_PSW;
|
||||
}
|
||||
|
||||
return -1;
|
||||
setRegister(g.reg, g.set, g.prev_mode, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gam_rc_t cpu::getGAMAddress(const uint8_t mode, const int reg, const bool word_mode)
|
||||
{
|
||||
return getGAM(mode, reg, word_mode, false, false);
|
||||
}
|
||||
|
||||
bool cpu::double_operand_instructions(const uint16_t instr)
|
||||
|
@ -484,7 +418,10 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
const uint8_t src_mode = (src >> 3) & 7;
|
||||
const uint8_t src_reg = src & 7;
|
||||
|
||||
const uint16_t src_value = operation == 0b110 ? 0 : getGAM(src_mode, src_reg, word_mode, false);
|
||||
gam_rc_t g_src { false, false, false, { }, 0 };
|
||||
|
||||
if (operation != 0b110)
|
||||
g_src = getGAM(src_mode, src_reg, word_mode, false);
|
||||
|
||||
const uint8_t dst = instr & 63;
|
||||
const uint8_t dst_mode = (dst >> 3) & 7;
|
||||
|
@ -497,14 +434,17 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
addToMMR1(src_mode, src_reg, word_mode);
|
||||
|
||||
if (word_mode && dst_mode == 0)
|
||||
setRegister(dst_reg, false, int8_t(src_value)); // int8_t: sign extension
|
||||
else
|
||||
set_flags = putGAM(dst_mode, dst_reg, word_mode, src_value, false);
|
||||
setRegister(dst_reg, false, int8_t(g_src.value.value())); // int8_t: sign extension
|
||||
else {
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
set_flags = putGAM(g_dst, g_src.value.value());
|
||||
}
|
||||
|
||||
addToMMR1(dst_mode, dst_reg, word_mode);
|
||||
|
||||
if (set_flags)
|
||||
setPSW_flags_nzv(src_value, word_mode);
|
||||
setPSW_flags_nzv(g_src.value.value(), word_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -512,23 +452,23 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
case 0b010: { // CMP/CMPB Compare Word/Byte
|
||||
addToMMR1(src_mode, src_reg, word_mode);
|
||||
|
||||
uint16_t dst_value = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
uint16_t temp = (src_value - dst_value) & (word_mode ? 0xff : 0xffff);
|
||||
uint16_t temp = (g_src.value.value() - g_dst.value.value()) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
addToMMR1(dst_mode, dst_reg, word_mode);
|
||||
|
||||
setPSW_n(SIGN(temp, word_mode));
|
||||
setPSW_z(IS_0(temp, word_mode));
|
||||
setPSW_v(SIGN((src_value ^ dst_value) & (~dst_value ^ temp), word_mode));
|
||||
setPSW_c(src_value < dst_value);
|
||||
setPSW_v(SIGN((g_src.value.value() ^ g_dst.value.value()) & (~g_dst.value.value() ^ temp), word_mode));
|
||||
setPSW_c(g_src.value.value() < g_dst.value.value());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0b011: { // BIT/BITB Bit Test Word/Byte
|
||||
uint16_t dst_value = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t result = (dst_value & src_value) & (word_mode ? 0xff : 0xffff);
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t result = (g_dst.value.value() & g_src.value.value()) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
setPSW_flags_nzv(result, word_mode);
|
||||
|
||||
|
@ -536,51 +476,51 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b100: { // BIC/BICB Bit Clear Word/Byte
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
uint16_t result = b->read(a, word_mode, false) & ~src_value;
|
||||
uint16_t result = g_dst.value.value() & ~g_src.value.value();
|
||||
|
||||
if (put_result(a, dst_mode, dst_reg, word_mode, result))
|
||||
if (put_result(g_dst, result))
|
||||
setPSW_flags_nzv(result, word_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0b101: { // BIS/BISB Bit Set Word/Byte
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
uint16_t result = b->read(a, word_mode, false) | src_value;
|
||||
uint16_t result = g_dst.value.value() | g_src.value.value();
|
||||
|
||||
if (put_result(a, dst_mode, dst_reg, word_mode, result))
|
||||
if (put_result(g_dst, result))
|
||||
setPSW_flags_nzv(result, word_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0b110: { // ADD/SUB Add/Subtract Word
|
||||
int16_t ssrc_value = getGAM(src_mode, src_reg, false, false);
|
||||
auto g_ssrc = getGAM(src_mode, src_reg, false, false);
|
||||
|
||||
uint16_t dst_addr = getGAMAddress(dst_mode, dst_reg, false);
|
||||
int16_t dst_value = b->readWord(dst_addr);
|
||||
int16_t result = 0;
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, false, false);
|
||||
|
||||
bool set_flags = dst_addr != ADDR_PSW;
|
||||
int16_t result = 0;
|
||||
|
||||
bool set_flags = g_dst.addr.has_value() ? g_dst.addr.value() != ADDR_PSW : true;
|
||||
|
||||
if (instr & 0x8000) {
|
||||
result = (dst_value - ssrc_value) & 0xffff;
|
||||
result = (g_dst.value.value() - g_ssrc.value.value()) & 0xffff;
|
||||
|
||||
if (set_flags) {
|
||||
//setPSW_v(sign(ssrc_value) != sign(dst_value) && sign(ssrc_value) == sign(result));
|
||||
setPSW_v(((ssrc_value ^ dst_value) & 0x8000) && !((dst_value ^ result) & 0x8000));
|
||||
setPSW_c(uint16_t(dst_value) < uint16_t(ssrc_value));
|
||||
//setPSW_v(sign(g_ssrc.value.value()) != sign(g_dst.value.value()) && sign(g_ssrc.value.value()) == sign(result));
|
||||
setPSW_v(((g_ssrc.value.value() ^ g_dst.value.value()) & 0x8000) && !((g_dst.value.value() ^ result) & 0x8000));
|
||||
setPSW_c(uint16_t(g_dst.value.value()) < uint16_t(g_ssrc.value.value()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = (dst_value + ssrc_value) & 0xffff;
|
||||
result = (g_dst.value.value() + g_ssrc.value.value()) & 0xffff;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_v(sign(ssrc_value) == sign(dst_value) && sign(dst_value) != sign(result));
|
||||
setPSW_c(uint16_t(result) < uint16_t(ssrc_value));
|
||||
setPSW_v(sign(g_ssrc.value.value()) == sign(g_dst.value.value()) && sign(g_dst.value.value()) != sign(result));
|
||||
setPSW_c(uint16_t(result) < uint16_t(g_ssrc.value.value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,10 +529,7 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
setPSW_z(result == 0);
|
||||
}
|
||||
|
||||
if (dst_mode == 0)
|
||||
setRegister(dst_reg, false, result);
|
||||
else
|
||||
b->writeWord(dst_addr, result);
|
||||
putGAM(g_dst, result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -613,8 +550,11 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
|
|||
|
||||
switch(operation) {
|
||||
case 0: { // MUL
|
||||
int16_t R1 = getRegister(reg);
|
||||
int16_t R2 = getGAM(dst_mode, dst_reg, true, false);
|
||||
int16_t R1 = getRegister(reg);
|
||||
|
||||
auto R2g = getGAM(dst_mode, dst_reg, false, false);
|
||||
int16_t R2 = R2g.value.value();
|
||||
|
||||
int32_t result = R1 * R2;
|
||||
|
||||
setRegister(reg, result >> 16);
|
||||
|
@ -628,7 +568,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 1: { // DIV
|
||||
int16_t divider = getGAM(dst_mode, dst_reg, false, false);
|
||||
auto R2g = getGAM(dst_mode, dst_reg, false, false);
|
||||
int16_t divider = R2g.value.value();
|
||||
|
||||
if (divider == 0) { // divide by zero
|
||||
setPSW_n(false);
|
||||
|
@ -666,7 +607,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
|
|||
|
||||
case 2: { // ASH
|
||||
uint32_t R = getRegister(reg), oldR = R;
|
||||
uint16_t shift = getGAM(dst_mode, dst_reg, false, false) & 077;
|
||||
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, false, false);
|
||||
uint16_t shift = g_dst.value.value() & 077;
|
||||
|
||||
bool sign = SIGN(R, false);
|
||||
|
||||
// extend sign-bit
|
||||
|
@ -708,7 +652,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
|
|||
|
||||
case 3: { // ASHC
|
||||
uint32_t R0R1 = (getRegister(reg) << 16) | getRegister(reg | 1);
|
||||
uint16_t shift = getGAM(dst_mode, dst_reg, false, false) & 077;
|
||||
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, false, false);
|
||||
uint16_t shift = g_dst.value.value() & 077;
|
||||
|
||||
bool sign = R0R1 & 0x80000000;
|
||||
|
||||
setPSW_v(false);
|
||||
|
@ -761,17 +708,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 4: { // XOR (word only)
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, false);
|
||||
uint16_t vl = b->read(a, false, false) ^ getRegister(reg);
|
||||
bool set_flags = true;
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, false, false);
|
||||
uint16_t vl = g_dst.value.value() ^ getRegister(reg);
|
||||
|
||||
if (dst_mode == 0)
|
||||
putGAM(dst_mode, dst_reg, false, vl, false);
|
||||
else {
|
||||
b->write(a, false, vl, false);
|
||||
|
||||
set_flags = a != ADDR_PSW;
|
||||
}
|
||||
bool set_flags = putGAM(g_dst, vl);
|
||||
|
||||
if (set_flags)
|
||||
setPSW_flags_nzv(vl, false);
|
||||
|
@ -809,25 +749,13 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
if (word_mode) // handled elsewhere
|
||||
return false;
|
||||
else {
|
||||
uint16_t v = 0;
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
if (dst_mode == 0) {
|
||||
v = getRegister(dst_reg);
|
||||
uint16_t v = g_dst.value.value();
|
||||
|
||||
v = ((v & 0xff) << 8) | (v >> 8);
|
||||
v = ((v & 0xff) << 8) | (v >> 8);
|
||||
|
||||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
v = b->readWord(a);
|
||||
|
||||
v = ((v & 0xff) << 8) | (v >> 8);
|
||||
|
||||
set_flags = a != ADDR_PSW;
|
||||
|
||||
b->writeWord(a, v);
|
||||
}
|
||||
set_flags = putGAM(g_dst, v);
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_flags_nzv(v, true);
|
||||
|
@ -839,71 +767,52 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b000101000: { // CLR/CLRB
|
||||
if (dst_mode == 0) {
|
||||
uint16_t r = 0;
|
||||
{
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
uint16_t r = 0;
|
||||
|
||||
// CLRB only clears the least significant byte
|
||||
if (word_mode)
|
||||
r = getGAM(dst_mode, dst_reg, false, false) & 0xff00;
|
||||
r = g_dst.value.value() & 0xff00;
|
||||
|
||||
putGAM(dst_mode, dst_reg, false, r, false);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
bool set_flags = putGAM(g_dst, r);
|
||||
|
||||
set_flags = a != ADDR_PSW;
|
||||
|
||||
b -> write(a, word_mode, 0, false);
|
||||
}
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(false);
|
||||
setPSW_z(true);
|
||||
setPSW_v(false);
|
||||
setPSW_c(false);
|
||||
if (set_flags) {
|
||||
setPSW_n(false);
|
||||
setPSW_z(true);
|
||||
setPSW_v(false);
|
||||
setPSW_c(false);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0b000101001: { // COM/COMB
|
||||
if (dst_mode == 0) {
|
||||
uint16_t v = getRegister(dst_reg);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t v = a.value.value();
|
||||
|
||||
if (word_mode)
|
||||
v ^= 0xff;
|
||||
else
|
||||
v ^= 0xffff;
|
||||
if (word_mode)
|
||||
v ^= 0xff;
|
||||
else
|
||||
v ^= 0xffff;
|
||||
|
||||
setPSW_flags_nzv(v, word_mode);
|
||||
set_flags = putGAM(a, v);
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_flags_nzv(v, word_mode);
|
||||
setPSW_c(true);
|
||||
|
||||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t v = b -> read(a, word_mode, false);
|
||||
|
||||
if (word_mode)
|
||||
v ^= 0xff;
|
||||
else
|
||||
v ^= 0xffff;
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_flags_nzv(v, word_mode);
|
||||
setPSW_c(true);
|
||||
}
|
||||
|
||||
b->write(a, word_mode, v, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0b000101010: { // INC/INCB
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t v = a.value.value();
|
||||
|
||||
if (dst_mode == 0) {
|
||||
uint16_t v = getRegister(dst_reg);
|
||||
uint16_t add = word_mode ? v & 0xff00 : 0;
|
||||
|
||||
v = (v + 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
@ -916,11 +825,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t v = b -> read(a, word_mode, false);
|
||||
int32_t vl = (v + 1) & (word_mode ? 0xff : 0xffff);
|
||||
int32_t vl = (a.value.value() + 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(vl, word_mode));
|
||||
|
@ -928,13 +835,14 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_v(word_mode ? vl == 0x80 : v == 0x8000);
|
||||
}
|
||||
|
||||
b->write(a, word_mode, vl, false);
|
||||
b->write(a.addr.value(), word_mode, vl, false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0b000101011: { // DEC/DECB
|
||||
// TODO unify
|
||||
if (dst_mode == 0) {
|
||||
uint16_t v = getRegister(dst_reg);
|
||||
uint16_t add = word_mode ? v & 0xff00 : 0;
|
||||
|
@ -949,11 +857,11 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t v = b -> read(a, word_mode, false);
|
||||
int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t v = a.value.value();
|
||||
int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(vl, word_mode));
|
||||
|
@ -961,7 +869,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_v(word_mode ? vl == 0x7f : vl == 0x7fff);
|
||||
}
|
||||
|
||||
b->write(a, word_mode, vl, false);
|
||||
b->write(a.addr.value(), word_mode, vl, false);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -983,12 +891,12 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t v = -b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t v = -a.value.value();
|
||||
|
||||
b->write(a, word_mode, v, false);
|
||||
b->write(a.addr.value(), word_mode, v, false);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1019,14 +927,14 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
const uint16_t vo = b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
const uint16_t vo = a.value.value();
|
||||
bool org_c = getPSW_c();
|
||||
uint16_t v = (vo + org_c) & (word_mode ? 0x00ff : 0xffff);
|
||||
|
||||
b->write(a, word_mode, v, false);
|
||||
b->write(a.addr.value(), word_mode, v, false);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1061,14 +969,14 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
const uint16_t vo = b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
const uint16_t vo = a.value.value();
|
||||
bool org_c = getPSW_c();
|
||||
uint16_t v = (vo - org_c) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
b->write(a, word_mode, v, false);
|
||||
b->write(a.addr.value(), word_mode, v, false);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1085,7 +993,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
|
||||
case 0b000101111: { // TST/TSTB
|
||||
uint16_t v = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t v = getGAM(dst_mode, dst_reg, word_mode, false).value.value();
|
||||
|
||||
setPSW_flags_nzv(v, word_mode);
|
||||
setPSW_c(false);
|
||||
|
@ -1116,8 +1024,8 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_v(getPSW_c() ^ getPSW_n());
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t t = b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t t = a.value.value();
|
||||
bool new_carry = t & 1;
|
||||
|
||||
uint16_t temp = 0;
|
||||
|
@ -1126,9 +1034,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
else
|
||||
temp = (t >> 1) | (getPSW_c() << 15);
|
||||
|
||||
b->write(a, word_mode, temp, false);
|
||||
b->write(a.addr.value(), word_mode, temp, false);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_c(new_carry);
|
||||
|
@ -1163,8 +1071,8 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_v(getPSW_c() ^ getPSW_n());
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t t = b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t t = a.value.value();
|
||||
bool new_carry = false;
|
||||
|
||||
uint16_t temp = 0;
|
||||
|
@ -1177,9 +1085,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
temp = (t << 1) | getPSW_c();
|
||||
}
|
||||
|
||||
b->write(a, word_mode, temp, false);
|
||||
b->write(a.addr.value(), word_mode, temp, false);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_c(new_carry);
|
||||
|
@ -1218,8 +1126,8 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_v(getPSW_n() ^ getPSW_c());
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t v = b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t v = a.value.value();
|
||||
uint16_t add = word_mode ? v & 0xff00 : 0;
|
||||
|
||||
bool hb = word_mode ? v & 128 : v & 32768;
|
||||
|
@ -1236,9 +1144,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
v |= hb << 15;
|
||||
}
|
||||
|
||||
b->write(a, word_mode, v, false);
|
||||
b->write(a.addr.value(), word_mode, v, false);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1265,11 +1173,11 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setRegister(dst_reg, false, v);
|
||||
}
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
uint16_t vl = b -> read(a, word_mode, false);
|
||||
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
uint16_t vl = a.value.value();
|
||||
uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
bool set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1278,7 +1186,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_v(getPSW_n() ^ getPSW_c());
|
||||
}
|
||||
|
||||
b->write(a, word_mode, v, false);
|
||||
b->write(a.addr.value(), word_mode, v, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1296,16 +1204,16 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
v = getRegister(dst_reg, getBitPSW(11), true);
|
||||
else {
|
||||
// calculate address in current address space
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, false);
|
||||
auto a = getGAMAddress(dst_mode, dst_reg, false);
|
||||
|
||||
set_flags = a != ADDR_PSW;
|
||||
set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (a >= 0160000) {
|
||||
if (a.addr.value() >= 0160000) {
|
||||
// read from previous space
|
||||
v = b -> read(a, false, true);
|
||||
v = b -> read(a.addr.value(), false, true);
|
||||
}
|
||||
else {
|
||||
auto phys = b->calculate_physical_address((getPSW() >> 12) & 3, a);
|
||||
auto phys = b->calculate_physical_address((getPSW() >> 12) & 3, a.addr.value());
|
||||
|
||||
//b->check_address(true, true, phys, false, word_mode, (getPSW() >> 12) & 3);
|
||||
|
||||
|
@ -1339,21 +1247,21 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
if (dst_mode == 0)
|
||||
setRegister(dst_reg, true, v);
|
||||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, false);
|
||||
auto a = getGAMAddress(dst_mode, dst_reg, false);
|
||||
|
||||
set_flags = a != ADDR_PSW;
|
||||
set_flags = a.addr.value() != ADDR_PSW;
|
||||
|
||||
if (a >= 0160000)
|
||||
b->write(a, false, v, true); // put in '13/12' address space
|
||||
if (a.addr.value() >= 0160000)
|
||||
b->write(a.addr.value(), false, v, true); // put in '13/12' address space
|
||||
else {
|
||||
auto phys = b->calculate_physical_address((getPSW() >> 12) & 3, a);
|
||||
auto phys = b->calculate_physical_address((getPSW() >> 12) & 3, a.addr.value());
|
||||
|
||||
DOLOG(debug, true, "MTPI/D %06o -> %o / %o", a, phys.physical_instruction, phys.physical_data);
|
||||
|
||||
// FILE *fh = fopen("og2-kek.dat", "a+");
|
||||
// fprintf(fh, "%lu %06o MTPI %06o: %06o\n", mtpi_count, oldpc, a, v);
|
||||
// fclose(fh);
|
||||
DOLOG(debug, true, "%lu %06o MTPI %06o: %06o", mtpi_count, oldpc, a, v);
|
||||
DOLOG(debug, true, "%lu %06o MTPI %06o: %06o", mtpi_count, oldpc, a.addr.value(), v);
|
||||
|
||||
mtpi_count++;
|
||||
|
||||
|
@ -1375,7 +1283,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
case 0b000110100: // MARK/MTPS (put something in PSW)
|
||||
if (word_mode) { // MTPS
|
||||
psw &= 0xff00; // only alter lower 8 bits
|
||||
psw |= getGAM(dst_mode, dst_reg, word_mode, false) & 0xef; // can't change bit 4
|
||||
psw |= getGAM(dst_mode, dst_reg, word_mode, false).value.value() & 0xef; // can't change bit 4
|
||||
}
|
||||
else {
|
||||
setRegister(6, getPC() + dst * 2);
|
||||
|
@ -1387,7 +1295,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
break;
|
||||
|
||||
case 0b000110111: // MFPS (get PSW to something) / SXT
|
||||
case 0b000110111: { // MFPS (get PSW to something) / SXT
|
||||
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
if (word_mode) { // MFPS
|
||||
uint16_t temp = psw & 0xff;
|
||||
bool extend_b7 = psw & 128;
|
||||
|
@ -1395,7 +1305,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
if (extend_b7 && dst_mode == 0)
|
||||
temp |= 0xff00;
|
||||
|
||||
set_flags = putGAM(dst_mode, dst_reg, word_mode, temp, false);
|
||||
bool set_flags = putGAM(g_dst, temp);
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_z(temp == 0);
|
||||
|
@ -1404,17 +1314,16 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
}
|
||||
}
|
||||
else { // SXT
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode);
|
||||
|
||||
int32_t vl = -getPSW_n();
|
||||
|
||||
if (put_result(a, dst_mode, dst_reg, word_mode, vl)) {
|
||||
if (put_result(g_dst, vl)) {
|
||||
setPSW_z(getPSW_n() == false);
|
||||
setPSW_v(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
@ -1620,15 +1529,15 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
int dst_reg = instr & 7;
|
||||
|
||||
bool word_mode = false;
|
||||
setPC(getGAMAddress(dst_mode, dst_reg, word_mode));
|
||||
setPC(getGAMAddress(dst_mode, dst_reg, word_mode).addr.value());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((instr & 0b1111111000000000) == 0b0000100000000000) { // JSR
|
||||
int link_reg = (instr >> 6) & 7;
|
||||
uint16_t dst_value = getGAMAddress((instr >> 3) & 7, instr & 7, false);
|
||||
int link_reg = (instr >> 6) & 7;
|
||||
auto dst_value = getGAMAddress((instr >> 3) & 7, instr & 7, false).addr.value();
|
||||
|
||||
// PUSH link
|
||||
pushStack(getRegister(link_reg));
|
||||
|
|
25
cpu.h
25
cpu.h
|
@ -5,12 +5,26 @@
|
|||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "bus.h"
|
||||
|
||||
typedef struct {
|
||||
bool word_mode;
|
||||
bool prev_mode;
|
||||
bool set;
|
||||
|
||||
union {
|
||||
std::optional<uint16_t> addr;
|
||||
int reg;
|
||||
};
|
||||
|
||||
std::optional<uint16_t> value;
|
||||
} gam_rc_t;
|
||||
|
||||
class cpu
|
||||
{
|
||||
private:
|
||||
|
@ -43,10 +57,11 @@ private:
|
|||
uint16_t addRegister(const int nr, const bool prev_mode, const uint16_t value);
|
||||
|
||||
void addToMMR1(const uint8_t mode, const uint8_t reg, const bool word_mode);
|
||||
uint16_t getGAMAddress(const uint8_t mode, const int reg, const bool word_mode);
|
||||
uint16_t getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool MF_MT);
|
||||
// returns false when flag registers should not be updated
|
||||
bool putGAM(const uint8_t mode, const int reg, const bool word_mode, const uint16_t value, const bool MF_FT);
|
||||
|
||||
|
||||
gam_rc_t getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool prev_mode, const bool read_value = true);
|
||||
gam_rc_t getGAMAddress(const uint8_t mode, const int reg, const bool word_mode);
|
||||
bool putGAM(const gam_rc_t & g, const uint16_t value); // returns false when flag registers should not be updated
|
||||
|
||||
bool double_operand_instructions(const uint16_t instr);
|
||||
bool additional_double_operand_instructions(const uint16_t instr);
|
||||
|
@ -137,5 +152,5 @@ public:
|
|||
uint16_t getRegister(const int nr, const int mode, const bool sp_prev_mode) const;
|
||||
uint16_t getRegister(const int nr) const;
|
||||
|
||||
bool put_result(const uint16_t a, const uint8_t dst_mode, const uint8_t dst_reg, const bool word_mode, const uint16_t value);
|
||||
bool put_result(const gam_rc_t & g, const uint16_t value);
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue