Skip to content

Commit

Permalink
Can now run programs.
Browse files Browse the repository at this point in the history
  • Loading branch information
ExpandingMan committed May 15, 2017
1 parent 84de981 commit ed3050c
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 68 deletions.
100 changes: 42 additions & 58 deletions src/boilerplate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,125 +6,102 @@ Here we keep some macros for doing boilerplate code generation...
opfuncname(opcode::UInt8) = Symbol(string("op", hexstring(opcode), "!"))


opdict(opcode::UInt8, nbytes::Int) = :(OPCODES[$opcode] = ($nbytes, $(opfuncname(opcode))))
function opdict(opcode::UInt8, nbytes::Int, ncycles::Int)
:(OPCODES[$opcode] = ($(opfuncname(opcode)), $nbytes, $ncycles))
end


function opdef_Immediate(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_Immediate(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = ($opname(cs.cpu, bytes2arg(bytes)); $nbytes)
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, bytes[1])
end
end

function opdef_ZeroPage(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_ZeroPage(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, Π8(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, Π8(bytes))
end
end

function opdef_ZeroPageX(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_ZeroPageX(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, DirectX, Π8(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, DirectX, Π8(bytes))
end
end

function opdef_ZeroPageY(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_ZeroPageY(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, DirectY, Π8(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, DirectY, Π8(bytes))
end
end

function opdef_Absolute(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_Absolute(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, Π16(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, Π16(bytes))
end
end

function opdef_AbsoluteX(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_AbsoluteX(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, DirectX, Π16(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, DirectX, Π16(bytes))
end
end

function opdef_AbsoluteY(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_AbsoluteY(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, DirectY, Π16(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, DirectY, Π16(bytes))
end
end

function opdef_IndirectX(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_IndirectX(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, IndirectX, Π8(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, IndirectX, Π8(bytes))
end
end

function opdef_IndirectY(opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef_IndirectY(opname::Symbol, opcode::UInt8)
fname = opfuncname(opcode)
quote
function $fname(cs::Chipset, bytes::AbstractVector{UInt8})
$opname(cs.cpu, cs.ram, IndirectY, Π8(bytes))
$ncycles
end
$fname(cs::Chipset, bytes::AbstractVector{UInt8}) = $opname(cs.cpu, cs.ram, IndirectY, Π8(bytes))
end
end





function opdef(mode::Symbol, opname::Symbol, opcode::UInt8, nbytes::Int, ncycles::Int)
function opdef(mode::Symbol, opname::Symbol, opcode::UInt8)
if mode == :Implicit
return opdef_Implicit(opname, opcode, nbytes, ncycles)
return opdef_Implicit(opname, opcode)
elseif mode == :Accumulator
return opdef_Accumulator(opname, opcode, nbytes, ncycles)
return opdef_Accumulator(opname, opcode)
elseif mode == :Immediate
return opdef_Immediate(opname, opcode, nbytes, ncycles)
return opdef_Immediate(opname, opcode)
elseif mode == :ZeroPage
return opdef_ZeroPage(opname, opcode, nbytes, ncycles)
return opdef_ZeroPage(opname, opcode)
elseif mode == :ZeroPageX
return opdef_ZeroPageX(opname, opcode, nbytes, ncycles)
return opdef_ZeroPageX(opname, opcode)
elseif mode == :ZeroPageY
return opdef_ZeroPageY(opname, opcode, nbytes, ncycles)
return opdef_ZeroPageY(opname, opcode)
elseif mode == :Absolute
return opdef_Absolute(opname, opcode, nbytes, ncycles)
return opdef_Absolute(opname, opcode)
elseif mode == :AbsoluteX
return opdef_AbsoluteX(opname, opcode, nbytes, ncycles)
return opdef_AbsoluteX(opname, opcode)
elseif mode == :AbsoluteY
return opdef_AbsoluteY(opname, opcode, nbytes, ncycles)
return opdef_AbsoluteY(opname, opcode)
elseif mode == :IndirectX
return opdef_IndirectX(opname, opcode, nbytes, ncycles)
return opdef_IndirectX(opname, opcode)
elseif mode == :IndirectY
return opdef_IndirectY(opname, opcode, nbytes, ncycles)
return opdef_IndirectY(opname, opcode)
elseif mode == :Relative
return opdef_Relative(opname, opcode, nbytes, ncycles)
return opdef_Relative(opname, opcode)
else
throw(ArgumentError("Invalid oparation mode $mode."))
end
Expand All @@ -136,6 +113,13 @@ end


macro opdef(opname::Symbol, defblock::Expr)

@capture(defblock, begin defs__ end)
defs = [tuple(ex.args...) for ex defs]
funcdefs = [opdef(d[1], opname, d[2]) for d defs]
dictries = [opdict(d[2], d[3], d[4]) for d defs]
esc(quote
$(funcdefs...)
$(dictries...)
end)
end

7 changes: 7 additions & 0 deletions src/memory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const Π8 = Π{UInt8} # zero page pointer
const Π16 = Π{UInt16} # standard 6502 memory pointer
export Π8, Π16

Π8(x::AbstractVector{UInt8}) = Π{UInt8}(x[1])

Π16(x::AbstractVector{UInt8}) = Π{UInt16}(bincat(x[1], x[2]))


reset!(m::Memory) = (m.v .= zeros(UInt8, length(m.v)))
Expand All @@ -40,6 +43,10 @@ Base.getindex(m::Memory, ptr::Π) = fetch(m, ptr.addr)
Base.setindex!(m::Memory, val::UInt8, idx::T) where T<:Unsigned = (m.v[idx+one(T)] = val)
Base.setindex!(m::Memory, val::UInt8, ptr:) = setindex!(m, val, ptr.addr)

function Base.setindex!(m::Memory, v::AbstractVector{UInt8}, idx::AbstractVector{T}) where T <: Integer
m.v[idx+one(T)] = v
end


#===================================================================================================
<referencing>
Expand Down
79 changes: 69 additions & 10 deletions src/opcodes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,101 @@ const N_OPCODES = 256
instruction(c::CPU, m::Memory) = deref(Π(c.PC), m)
instruction(cs::Chipset) = instruction(cs.cpu, cs.ram)

# this doesn't do any checking
bytes2arg(bytes::AbstractVector{UInt8}) = bincat(bytes[1], bytes[2])

# this gets the arguments to the op given the pointer to the instruction and nbytes total
deref_opargs(cs::Chipset, ptr:, nbytes::Integer) = deref(ptr+0x01, cs.ram, nbytes-1)


#===================================================================================================
<execution>
===================================================================================================#
# this doesn't do the sleeping
function compute!(cs::Chipset)
nbytes, ncycles = op!(cs, Π(c.PC))
function tick!(cs::Chipset)
nbytes, ncycles = op!(cs, Π(cs.cpu.PC))
cs.cpu.PC += nbytes
ncycles
cs.clock += ncycles
nbytes, ncycles
end


# op! doesn't increment clock or instruction pointer
function op!(cs::Chipset, bytes::AbstractVector{UInt8})
exe!, nbytes, ncycles = OPCODES[bytes[1]]
exe!(cs, bytes[2:end])
nbytes, ncycles
end

function op!(cs::Chipset, ptr:)
opcode = deref(ptr, cs.ram)
exe!, nbytes = OPCODES[opcode]
ncycles = exe!(cs, deref_opargs(cs, ptr, nbytes))
nbyes, ncycles
exe!, nbytes, ncycles = OPCODES[deref(ptr, cs.ram)]
exe!(cs, deref_opargs(cs, ptr, nbytes))
nbytes, ncycles
end


export op!, tick!
#===================================================================================================
</execution>
===================================================================================================#



#===================================================================================================
<opcodes>
===================================================================================================#
const OPCODES = Dict{Int,Tuple{Function, Int}}(); sizehint!(OPCODES, N_OPCODES)
# returns func, nbytes, ncycles
const OPCODES = Dict{UInt8,Tuple{Function,Int,Int}}(); sizehint!(OPCODES, N_OPCODES)


# TODO this is a mock-up of what this should ultimately look like
@opdef lda! begin
Immediate, 0x69, 2, 2
ZeroPage, 0x65, 2, 3
ZeroPageX, 0x75, 2, 4
Absolute, 0x6d, 3, 4
AbsoluteX, 0x7d, 3, 4 # should automatically take care of page crossings
AbsoluteX, 0x7d, 3, 4 # TODO should automatically take care of page crossings
AbsoluteY, 0x79, 3, 4
IndirectX, 0x61, 2, 6
IndirectY, 0x71, 2, 5
end

@opdef ldx! begin
Immediate, 0xa2, 2, 2
ZeroPage, 0xa6, 2, 3
ZeroPageY, 0xb6, 2, 4
Absolute, 0xae, 3, 4
AbsoluteY, 0xbe, 3, 4
end

@opdef ldy! begin
Immediate, 0xa0, 2, 2
ZeroPage, 0xa4, 2, 3
ZeroPageX, 0xb4, 2, 4
Absolute, 0xac, 3, 4
AbsoluteX, 0xbc, 3, 4
end

@opdef sta! begin
ZeroPage, 0x85, 2, 3
ZeroPageX, 0x95, 2, 4
Absolute, 0x8d, 3, 4
AbsoluteX, 0x9d, 3, 5
AbsoluteY, 0x99, 3, 5
IndirectX, 0x81, 2, 6
IndirectX, 0x91, 2, 6
end

@opdef stx! begin
ZeroPage, 0x86, 2, 3
ZeroPageY, 0x96, 2, 4
Absolute, 0x8e, 3, 4
end

@opdef sty! begin
ZeroPage, 0x84, 2, 3
ZeroPageX, 0x94, 2, 4
Absolute, 0x8c, 2, 4
end

#===================================================================================================
</opcodes>
Expand Down
3 changes: 3 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

# little-endian
bincat(x::UInt8, y::UInt8)::UInt16 = convert(UInt16, x) + (convert(UInt16, y) << 8)

hexstring(n::Unsigned) = string("0x", hex(n, sizeof(n)<<1))

# as simple as this seems in retrospect, it was confusing to figure out, hence the shortcut
Expand Down
28 changes: 28 additions & 0 deletions test/opcodes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Sim6502

cs = Chipset()


macro p(expr)
esc(:($expr; println(cs.cpu)))
end

macro program(vec)
esc(quote
cs.ram[0x0600:(0x0600+length($vec)-1)] = $vec
end)
end

cs.ram[0x00] = 0x01
cs.ram[0x01] = 0x02

cs.ram[0xa000] = 0x05
cs.ram[0xa001] = 0x06

# @p Sim6502.op0x65!(cs, [0x00])
# @p Sim6502.op0x6d!(cs, [0x01, 0xa0])
@program [0x65, 0x00, 0x6d, 0x01, 0xa0]

@p tick!(cs)
@p tick!(cs)

0 comments on commit ed3050c

Please sign in to comment.