ADC decimal mode fixes
This commit is contained in:
parent
515f4c7a98
commit
7ad050b3c2
134
6502.lua
134
6502.lua
|
@ -472,6 +472,7 @@ _M.opcodes = {
|
||||||
-- 6502 emulation mode (e=1)
|
-- 6502 emulation mode (e=1)
|
||||||
|
|
||||||
_M.getParam = {
|
_M.getParam = {
|
||||||
|
[_M.addrmode.ILLEGAL] = function(self) return nil end,
|
||||||
[_M.addrmode.IMP] = function(self) return nil end,
|
[_M.addrmode.IMP] = function(self) return nil end,
|
||||||
[_M.addrmode.ACC] = function(self) return nil end,
|
[_M.addrmode.ACC] = function(self) return nil end,
|
||||||
[_M.addrmode.IMM] = function(self)
|
[_M.addrmode.IMM] = function(self)
|
||||||
|
@ -698,7 +699,6 @@ _M.operations = {
|
||||||
end,
|
end,
|
||||||
[_M.optype.DEX] = function(self, param)
|
[_M.optype.DEX] = function(self, param)
|
||||||
self.X = (self.X - 1) & 0xFF
|
self.X = (self.X - 1) & 0xFF
|
||||||
if (self.X < 0) then self.X = 0xFF end
|
|
||||||
self:setnz(self.X)
|
self:setnz(self.X)
|
||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
|
@ -923,7 +923,7 @@ _M.operations = {
|
||||||
else
|
else
|
||||||
self.F = self.F & ~self.flags.C
|
self.F = self.F & ~self.flags.C
|
||||||
end
|
end
|
||||||
v = v << 1
|
v = (v << 1) & 0xFF
|
||||||
if ((v & 0x80) ~= 0x00) then
|
if ((v & 0x80) ~= 0x00) then
|
||||||
self.F = self.F | self.flags.N
|
self.F = self.F | self.flags.N
|
||||||
else
|
else
|
||||||
|
@ -960,7 +960,7 @@ _M.operations = {
|
||||||
end,
|
end,
|
||||||
[_M.optype.ROL] = function(self, param)
|
[_M.optype.ROL] = function(self, param)
|
||||||
local m = self:readmem(param)
|
local m = self:readmem(param)
|
||||||
local v = m << 1
|
local v = (m << 1) & 0xFF
|
||||||
if ((self.F & self.flags.C) ~= 0x00) then
|
if ((self.F & self.flags.C) ~= 0x00) then
|
||||||
v = v | 0x01
|
v = v | 0x01
|
||||||
end
|
end
|
||||||
|
@ -1020,19 +1020,22 @@ _M.operations = {
|
||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
[_M.optype.SBC] = function(self, param)
|
[_M.optype.SBC] = function(self, param)
|
||||||
|
local ret = 0
|
||||||
local memTemp = self:readmem(param) ~ 0xFF
|
local memTemp = self:readmem(param) ~ 0xFF
|
||||||
|
|
||||||
local c,v
|
local c,v
|
||||||
if ((self.F & self.flags.D) ~= 0x00) then
|
if ((self.F & self.flags.D) ~= 0x00) then
|
||||||
-- Decimal mode
|
-- Decimal mode
|
||||||
|
ret = 1
|
||||||
c = (self.A & 0x0F) + (memTemp & 0x0F) + (self.F & self.flags.C)
|
c = (self.A & 0x0F) + (memTemp & 0x0F) + (self.F & self.flags.C)
|
||||||
if (c < 0x10) then
|
if (c < 0x10) then
|
||||||
c = (c - 0x06) & 0x0F
|
c = (c - 0x06) & 0x0F
|
||||||
end
|
end
|
||||||
c = c + (self.A & 0xF0) + (memTemp & 0xF0)
|
c = c + (self.A & 0xF0) + (memTemp & 0xF0)
|
||||||
v = (c >> 1) ~ c
|
|
||||||
if (c < 0x100) then
|
if (c < 0x100) then
|
||||||
c = (c + 0xa0) & 0xFF
|
c = (c + 0xa0) & 0xFF
|
||||||
end
|
end
|
||||||
|
v = (c ~ self.A) & 0x80
|
||||||
else
|
else
|
||||||
c = self.A + memTemp + (self.F & self.flags.C)
|
c = self.A + memTemp + (self.F & self.flags.C)
|
||||||
v = (c ~ self.A) & 0x80
|
v = (c ~ self.A) & 0x80
|
||||||
|
@ -1057,45 +1060,89 @@ _M.operations = {
|
||||||
|
|
||||||
self.A = c & 0xFF
|
self.A = c & 0xFF
|
||||||
self:setnz(self.A)
|
self:setnz(self.A)
|
||||||
return 0
|
return ret
|
||||||
end,
|
end,
|
||||||
[_M.optype.ADC] = function(self, param)
|
[_M.optype.ADC] = function(self, param)
|
||||||
local memTemp = self:readmem(param)
|
local ret = 0 -- number of additional cycles
|
||||||
|
local B = self:readmem(param)
|
||||||
|
local Cin = (self.F & self.flags.C)
|
||||||
|
local Cout -- expected carry out
|
||||||
|
local Vout -- expected oVerflow out
|
||||||
|
local Aout -- expected accumulator out
|
||||||
|
|
||||||
local ret = 0
|
if ((self.F & self.flags.D) == 0x00) then
|
||||||
local c,v
|
|
||||||
if ((self.F & self.flags.D) ~= 0x00) then
|
-- Simple Bin mode. Thank goodness.
|
||||||
-- decimal mode
|
|
||||||
ret = 1
|
Aout = self.A + B + Cin
|
||||||
c = (self.A & 0x0F) + (memTemp & 0x0F) + (self.F & self.flags.C)
|
-- 'v' is described really well here:
|
||||||
if (c > 0x09) then
|
-- http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
|
||||||
c = (c - 0x0a) | 0x10
|
|
||||||
end
|
-- Overflow means "answer does not fit in to a signed byte".
|
||||||
c = c + (self.A & 0xF0) + (memTemp & 0xF0)
|
--
|
||||||
v = (c >> 1) ~ c
|
-- If bits A7 and B7 are not the same, then there's never overflow.
|
||||||
if (c > 0x99) then
|
--
|
||||||
c = c + 0x60
|
-- If the signs of the two are the same,
|
||||||
end
|
-- but the sign of the output is different,
|
||||||
|
-- then overflow obviously happened. Both of these do that...
|
||||||
|
-- Vout = (((self.A ~ B) & 0x80) == 0x00) and ((Aout ~ B) & 0x80) or 0
|
||||||
|
Vout = (self.A ~ Aout) & (B ~ Aout) & 0x80
|
||||||
|
|
||||||
|
Cout = (Aout >= 0x100) and 1 or 0
|
||||||
|
self.A = Aout & 0xFF
|
||||||
else
|
else
|
||||||
c = self.A + memTemp + (self.F & self.flags.C)
|
-- Complex Dec mode.
|
||||||
v = (c ~ self.A) & 0x80
|
-- Per
|
||||||
|
-- http://www.6502.org/tutorials/decimal_mode.html.
|
||||||
|
ret = 1
|
||||||
|
|
||||||
|
-- Done with the V flag processing. Calculate Aout and Cout.
|
||||||
|
Aout = (self.A & 0x0F) + (B & 0x0F) + Cin
|
||||||
|
local tmpOverflow = 0
|
||||||
|
if (Aout >= 0x0A) then
|
||||||
|
tmpOverflow = 0x10
|
||||||
|
Aout = (Aout + 0x06) & 0x0F
|
||||||
|
end
|
||||||
|
Aout = Aout | (self.A & 0xF0)
|
||||||
|
Aout = Aout + (B & 0xF0) + tmpOverflow
|
||||||
|
|
||||||
|
-- Overflow for BCD mode is calculated
|
||||||
|
-- here, before rolling over the high
|
||||||
|
-- nybble. If both A and B have the same
|
||||||
|
-- sign, and the sign for Aout is different
|
||||||
|
-- than A and B, then overflow happened.
|
||||||
|
|
||||||
|
Vout = 0
|
||||||
|
if ( ((self.A ~ B) & 0x80) == 0x00 ) then
|
||||||
|
-- A and B are of the same sign
|
||||||
|
if (((self.A ~ Aout)&0x80) ~= 0x00) then
|
||||||
|
-- A/B have a different sign from C, so it overflowed
|
||||||
|
Vout = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Back to calculating the resultant A and C
|
||||||
|
if (Aout >= 0xA0) then
|
||||||
|
Aout = Aout + 0x60
|
||||||
|
Cout = 1
|
||||||
|
else
|
||||||
|
Cout = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
self.A = Aout & 0xFF
|
||||||
end
|
end
|
||||||
|
|
||||||
if (((self.A ~ memTemp) & 0x80) ~= 0x00) then
|
if (Cout ~= 0x00) 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 (v ~= 0x00) then
|
if (Vout ~= 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
|
||||||
|
@ -1165,7 +1212,17 @@ _M.operations = {
|
||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
[_M.optype.ILLEGAL] = function(self, _, _, m)
|
[_M.optype.ILLEGAL] = function(self, _, _, m)
|
||||||
print("Programming error: unhandled opcode " .. m)
|
-- Treat these all as NOPs. Also emulate the
|
||||||
|
-- 65C02 behavior...
|
||||||
|
if (m == 0x02 or m == 0x22 or m == 0x42 or m == 0x62 or m == 0x82 or
|
||||||
|
m == 0xC2 or m == 0xE2 or m == 0x44 or m == 0x54 or m == 0xd4 or
|
||||||
|
m == 0xf4) then
|
||||||
|
self.pc = (self.pc + 1) & 0xFFFF
|
||||||
|
end
|
||||||
|
if (m == 0x5c or m == 0xdc or m == 0xfc) then
|
||||||
|
self.pc = (self.pc + 2) & 0xFFFF
|
||||||
|
end
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
@ -1303,21 +1360,6 @@ function _M:step()
|
||||||
self.pc = (self.pc + 1) & 0xFFFF
|
self.pc = (self.pc + 1) & 0xFFFF
|
||||||
|
|
||||||
local opcode = self.opcodes[m]
|
local opcode = self.opcodes[m]
|
||||||
if (opcode[1] == self.opcodes.ILLEGAL or
|
|
||||||
opcode[2] == self.addrmode.ILLEGAL) then
|
|
||||||
print(string.format("** Illegal opcode 0x%X at address 0x%X", m, self.pc-1))
|
|
||||||
-- Special invalid opcodes tht also have arguments...
|
|
||||||
if (m == 0x02 or m == 0x22 or m == 0x42 or m == 0x62 or m == 0x82 or
|
|
||||||
m == 0xC2 or m == 0xE2 or m == 0x44 or m == 0x54 or m == 0xd4 or
|
|
||||||
m == 0xf4) then
|
|
||||||
self.pc = (self.pc + 1) & 0xFFFF
|
|
||||||
end
|
|
||||||
if (m == 0x5c or m == 0xdc or m == 0xfc) then
|
|
||||||
self.pc = (self.pc + 2) & 0xFFFF
|
|
||||||
end
|
|
||||||
m = 0xEA -- substitute NOP
|
|
||||||
opcode = self.opcodes[m]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Look at the addressing mode to determine the parameter
|
-- Look at the addressing mode to determine the parameter
|
||||||
local param, zprelParam2 = self.getParam[opcode[2]](self)
|
local param, zprelParam2 = self.getParam[opcode[2]](self)
|
||||||
|
@ -1338,7 +1380,7 @@ function _M:readmem(a)
|
||||||
end
|
end
|
||||||
|
|
||||||
function _M:writemem(a,v)
|
function _M:writemem(a,v)
|
||||||
self.ram[a] = v & 0xFF
|
self.ram[a] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
return _M
|
return _M
|
||||||
|
|
Loading…
Reference in New Issue