1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-02 04:55:56 +00:00

Implement SAL, SAR.

This commit is contained in:
Thomas Harte 2023-10-14 21:42:33 -04:00
parent f1cba4eb78
commit e38fe7dffc
2 changed files with 114 additions and 1 deletions

View File

@ -1114,6 +1114,109 @@ inline void ror(IntT &destination, uint8_t count, Status &status) {
(destination ^ (destination << 1)) & Numeric::top_bit<IntT>()
);
}
/*
tempCOUNT (COUNT AND 1FH);
tempDEST DEST;
WHILE (tempCOUNT 0)
DO
IF instruction is SAL or SHL
THEN
CF MSB(DEST);
ELSE (* instruction is SAR or SHR *)
CF LSB(DEST);
FI;
IF instruction is SAL or SHL
THEN
DEST DEST 2;
ELSE
IF instruction is SAR
THEN
DEST DEST / 2 (*Signed divide, rounding toward negative infinity*);
ELSE (* instruction is SHR *)
DEST DEST / 2 ; (* Unsigned divide *);
FI;
FI;
tempCOUNT tempCOUNT 1;
OD;
(* Determine overflow for the various instructions *)
IF COUNT = 1
THEN
IF instruction is SAL or SHL
THEN
OF MSB(DEST) XOR CF;
ELSE
IF instruction is SAR
THEN
OF 0;
ELSE (* instruction is SHR *)
OF MSB(tempDEST);
FI;
FI;
ELSE
IF COUNT = 0
THEN
All flags remain unchanged;
ELSE (* COUNT neither 1 or 0 *)
OF undefined;
FI;
FI;
*/
/*
The CF flag contains the value of the last bit shifted out of the destination operand;
it is undefined for SHL and SHR instructions where the count is greater than or equal to
the size (in bits) of the destination operand. The OF flag is affected only for 1-bit shifts
(see Description above); otherwise, it is undefined.
The SF, ZF, and PF flags are set according to the result. If the count is 0, the flags are not affected.
For a non-zero count, the AF flag is undefined.
*/
template <typename IntT>
inline void sal(IntT &destination, uint8_t count, Status &status) {
switch(count) {
case 0: return;
case Numeric::bit_size<IntT>():
status.set_from<Flag::Carry, Flag::Overflow>(destination & 1);
destination = 0;
break;
default:
if(count > Numeric::bit_size<IntT>()) {
status.set_from<Flag::Carry, Flag::Overflow>(0);
destination = 0;
} else {
const auto mask = (Numeric::top_bit<IntT>() >> (count - 1));
status.set_from<Flag::Carry>(
destination & mask
);
status.set_from<Flag::Overflow>(
(destination ^ (destination << 1)) & mask
);
destination <<= count;
}
break;
}
status.set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
}
template <typename IntT>
inline void sar(IntT &destination, uint8_t count, Status &status) {
if(!count) {
return;
}
const IntT sign = Numeric::top_bit<IntT>() & destination;
if(count >= Numeric::bit_size<IntT>()) {
destination = sign ? IntT(~0) : IntT(0);
status.set_from<Flag::Carry>(sign);
} else {
const IntT mask = 1 << (count - 1);
status.set_from<Flag::Carry>(destination & mask);
destination = (destination >> count) | (sign ? ~(IntT(~0) >> count) : 0);
}
status.set_from<Flag::Overflow>(0);
status.set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
}
}
template <
@ -1279,6 +1382,8 @@ template <
case Operation::RCR: Primitive::rcr(destination(), shift_count(), status); break;
case Operation::ROL: Primitive::rol(destination(), shift_count(), status); break;
case Operation::ROR: Primitive::ror(destination(), shift_count(), status); break;
case Operation::SAL: Primitive::sal(destination(), shift_count(), status); break;
case Operation::SAR: Primitive::sar(destination(), shift_count(), status); break;
case Operation::CLC: Primitive::clc(status); return;
case Operation::CLD: Primitive::cld(status); return;

View File

@ -415,7 +415,6 @@ struct FailedExecution {
// NOP
@"90.json.gz",
*/
// TODO: POP, POPF, PUSH, PUSHF
// TODO: SAL, SAR, SHR
@ -435,6 +434,15 @@ struct FailedExecution {
// ROR
@"D0.1.json.gz", @"D2.1.json.gz",
@"D1.1.json.gz", @"D3.1.json.gz",
*/
// SAL
// @"D0.4.json.gz", @"D2.4.json.gz",
// @"D1.4.json.gz", @"D3.4.json.gz",
// SAR
@"D0.7.json.gz", @"D2.7.json.gz",
@"D1.7.json.gz", @"D3.7.json.gz",
/*
@"F8.json.gz", // CLC