mirror of
https://github.com/JorjBauer/lua-6502.git
synced 2024-10-17 12:24:37 +00:00
fixes for SBC in BCD mode
This commit is contained in:
parent
7ad050b3c2
commit
b11851912e
72
6502.lua
72
6502.lua
@ -1020,46 +1020,66 @@ _M.operations = {
|
|||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
[_M.optype.SBC] = function(self, param)
|
[_M.optype.SBC] = function(self, param)
|
||||||
local ret = 0
|
local ret = 0 -- number of additional cycles
|
||||||
local memTemp = self:readmem(param) ~ 0xFF
|
local B = self:readmem(param) ~ 0xFF
|
||||||
|
local Cin = (self.F & self.flags.C)
|
||||||
|
local Cout -- expected carry out
|
||||||
|
local Vout -- expected oVerflow out
|
||||||
|
local Aout -- expected accumulator out
|
||||||
|
|
||||||
local c,v
|
if ((self.F & self.flags.D) == 0x00) then
|
||||||
if ((self.F & self.flags.D) ~= 0x00) then
|
-- Simple Bin mode. Same as ADC's bin mode.
|
||||||
-- Decimal mode
|
|
||||||
ret = 1
|
Aout = self.A + B + Cin
|
||||||
c = (self.A & 0x0F) + (memTemp & 0x0F) + (self.F & self.flags.C)
|
Vout = (self.A ~ Aout) & (B ~ Aout) & 0x80
|
||||||
if (c < 0x10) then
|
Cout = (Aout >= 0x100) and 1 or 0
|
||||||
c = (c - 0x06) & 0x0F
|
self.A = Aout & 0xFF
|
||||||
end
|
|
||||||
c = c + (self.A & 0xF0) + (memTemp & 0xF0)
|
|
||||||
if (c < 0x100) then
|
|
||||||
c = (c + 0xa0) & 0xFF
|
|
||||||
end
|
|
||||||
v = (c ~ self.A) & 0x80
|
|
||||||
else
|
else
|
||||||
c = self.A + memTemp + (self.F & self.flags.C)
|
-- Emulating decimal mode's handling of
|
||||||
v = (c ~ self.A) & 0x80
|
-- invalid BCD values is tricky.
|
||||||
|
ret = 1
|
||||||
|
|
||||||
|
-- FIXME: This can probably be optimized;
|
||||||
|
-- this passes all 6502 decimal mode tests,
|
||||||
|
-- but is seemingly doing a lot of the same
|
||||||
|
-- work twice
|
||||||
|
|
||||||
|
-- First calculate the V and C flags
|
||||||
|
Aout = (self.A & 0x0F) + (B & 0x0F) + Cin
|
||||||
|
if (Aout < 0x10) then
|
||||||
|
Aout = (Aout - 0x06) & 0x0F
|
||||||
|
end
|
||||||
|
Aout = Aout + (self.A & 0xF0) + (B & 0xF0)
|
||||||
|
Vout = (self.A ~ Aout) & (B ~ Aout) & 0x80
|
||||||
|
if (Aout < 0x100) then
|
||||||
|
Aout = (Aout + 0xa0) & 0xFF
|
||||||
|
end
|
||||||
|
|
||||||
|
Cout = (Aout >= 0x100) and 1 or 0
|
||||||
|
|
||||||
|
-- Calculate the actual A output
|
||||||
|
B = self:readmem(param)
|
||||||
|
local AL = (self.A & 0x0F) - (B & 0x0F) + (Cin - 1)
|
||||||
|
Aout = self.A - B + Cin - 1
|
||||||
|
if (Aout < 0) then Aout = Aout - 0x60 end
|
||||||
|
if (AL < 0) then Aout = Aout - 0x06 end
|
||||||
|
|
||||||
|
self.A = Aout & 0xFF
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (Cout ~= 0x00) then
|
||||||
if (((self.A ~ memTemp) & 0x80) ~= 0) then
|
|
||||||
v = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
if (c > 0xFF) then
|
|
||||||
self.F = self.F | self.flags.C
|
self.F = self.F | self.flags.C
|
||||||
else
|
else
|
||||||
self.F = self.F & ~self.flags.C
|
self.F = self.F & ~self.flags.C
|
||||||
end
|
end
|
||||||
|
if (Vout ~= 0x00) then
|
||||||
if (v ~= 0x00) then
|
|
||||||
self.F = self.F | self.flags.V
|
self.F = self.F | self.flags.V
|
||||||
else
|
else
|
||||||
self.F = self.F & ~self.flags.V
|
self.F = self.F & ~self.flags.V
|
||||||
end
|
end
|
||||||
|
|
||||||
self.A = c & 0xFF
|
|
||||||
self:setnz(self.A)
|
self:setnz(self.A)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end,
|
end,
|
||||||
[_M.optype.ADC] = function(self, param)
|
[_M.optype.ADC] = function(self, param)
|
||||||
|
Loading…
Reference in New Issue
Block a user