Skip to content

Commit

Permalink
Almost done with basic instructions.
Browse files Browse the repository at this point in the history
  • Loading branch information
ExpandingMan committed May 10, 2017
1 parent 4004f30 commit 6216e6b
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 36 deletions.
11 changes: 11 additions & 0 deletions src/cpu.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

# this is the default stack page
const STACK_PAGE = 0x0100

# TODO WTF is with the break (B) flag?

Expand Down Expand Up @@ -79,3 +81,12 @@ export status, status!, status_string
</status register access>
===================================================================================================#


#===================================================================================================
<special pointers>
===================================================================================================#
stackpointer(c::CPU) = Π(STACK_PAGE + c.SP)
#===================================================================================================
</special pointers>
===================================================================================================#

129 changes: 114 additions & 15 deletions src/instructions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Some conventions:
TODO symbols passed for lookup should be implemented through macros !!! (i.e. at compile time)
TODO investigate inlining
TODO warn about the stack doing weird things
=====================================================================================================#

# these can be passed to instructions to specify addressing modes when appropriate
Expand Down Expand Up @@ -50,6 +52,17 @@ function store!{T<:AddressingMode}(::Type{T}, ptr::Π, c::CPU, m::Memory, val::U
store!(m, pointer(T, ptr, c, m), val)
end

stackpush!(c::CPU, m::Memory, val::UInt8) = (store!(m, stackpointer(c), val); c.SP -= 1)
stackpush!(c::CPU, m::Memory, val::UInt16) = (storeback!(m, stackpointer(c), val); c.SP -= 2)

stackpull!(c::CPU, m::Memory) == deref(stackpointer(c), val); c.SP += 1; ξ)
stackpull!(::Type{UInt16}, c::CPU, m::Memory) = (stackpull!(c, m) + 0x0100 * stackpull!(c, m))


# this is for the weird arithmetic of the branching instructions (\boxplus)
# TODO FINISH THIS !!!
(x::UInt16, y::UInt8) = ()


#===================================================================================================
<load, store instructions>
Expand Down Expand Up @@ -138,29 +151,23 @@ end

txs!(c::CPU) = (c.SP = c.X)

function pha!(c::CPU) # push A to stack
store!(m, Π(c.SP), c.A)
c.SP -= 0x01
end
pha!(c::CPU, m::Memory) = stackpush!(c, m, c.A)

function php!(c::CPU) # push P (processor status) to stack
store!(m, Π(c.SP), c.P)
c.SP -= 0x01
end
php!(c::CPU, m::Memory) = stackpush!(c, m, c.P)

function pla!(c::CPU) # pull stack onto A
c.A = deref(Π(c.SP), m)

function pla!(c::CPU, m::Memory) # pull stack onto A
c.A = stackpull!(c, m)
checkNflag!(c, c.A)
checkZflag!(c, c.A)
c.SP += 0x01
c.A
end

# in example this doesn't set the blank or B flags for some reason... wtf?
function plp!(c::CPU) # pull stack onto P
c.P = deref(Π(c.SP), m)
c.SP += 0x01
end
plp!(c::CPU, m::Memory) = (c.P = stackpull!(c, m))


export tsx!, txs!, pha!, php!, pla!, plp!
#===================================================================================================
</stack operations>
===================================================================================================#
Expand Down Expand Up @@ -392,3 +399,95 @@ export arithmetic_shiftleft!, asl!, logical_shiftright!, lsr!, rotateleft!, rol!
===================================================================================================#


#===================================================================================================
<jumps and calls>
TODO be __very__ careful about how you implement the byte counting of these!!!
===================================================================================================#
# note that this takes UInt16 arguments
jmp!(c::CPU, val::UInt16) = (c.PC = val)

# note, the assembly syntax for this function is really fucking weird
# confusingly, the references call this indirect mode
jmp!(c::CPU, m::Memory, ::Type{Direct}, ptr:{UInt16}) = jmp!(c, deref(UInt16, ptr, m))
jmp!(c::CPU, m::Memory, ptr:{UInt16}) = jmp!(c, m, Direct, ptr)

function jsr!(c::CPU, m::Memory, val::UInt16)
stackpush!(c, m, c.PC + 0x0002)
c.PC = val
end


rts!(c::CPU, m::Memory) = (c.PC = stackpull!(UInt16, c, m))


export jmp!, jsr!, rts!
#===================================================================================================
</jumps and calls>
===================================================================================================#


#===================================================================================================
<branches>
# TODO again be __very__ careful about how you implement byte counting for these!!!
===================================================================================================#
bcc!(c::CPU, m::Memory, val::Integer) = (!status(c, :C) && (c.PC += val); val)

bcs!(c::CPU, m::Memory, val::Integer) = (status(c, :C) && (c.PC += val); val)


#===================================================================================================
</branches>
===================================================================================================#


#===================================================================================================
<status flag changes>
===================================================================================================#
clc!(c::CPU) = status!(c, :C, false)

cld!(c::CPU) = status!(c, :D, false)

cli!(c::CPU) = status!(c, :I, false)

clv!(c::CPU) = status!(c, :V, false)

sec!(c::CPU) = status!(c, :C, true)

sed!(c::CPU) = status!(c, :D, true)

sei!(c::CPU) = status!(c, :I, true)

export clc!, cld!, cli!, clv!, sec!, sed!, sei!
#===================================================================================================
<status flag changes>
===================================================================================================#


#===================================================================================================
<system functions>
===================================================================================================#
# TODO this will require some special handling
brk!(c::CPU) = status!(c, :B, true)

nop!(c::CPU) = ()

# __NOTE!!__ that PC is also incremented the normal way afterwards from reading the instruction
function rti!(c::CPU, m::Memory)
ptr = stackpointer(c) + 0x01 # are you sure about this?
c.P = deref(ptr, m)
ptr = ptr + 0x01
pc_small = deref(ptr, m)
ptr = ptr + 0x01
pc_big = deref(ptr, m)
c.PC = 0x0100*pc_big + pc_small
c.SP += 0x03 # not completely confident in this either
end

export brk!, nop!, rti!
#===================================================================================================
</system functions>
===================================================================================================#


46 changes: 29 additions & 17 deletions src/memory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,13 @@ struct Memory
end
export Memory

reset!(m::Memory) = (m.v .= zeros(UInt8, length(m.v)))
export reset!

fetch(m::Memory, idx::T) where T<:Unsigned = m.v[idx+one(T)]
fetch(m::Memory, idx::AbstractVector{T}) where T<:Unsigned = m.v[idx+one(T)]

Base.getindex(m::Memory, T) = fetch(m, T)

Base.setindex!(m::Memory, val::UInt8, idx::T) where T<:Unsigned = (m.v[idx+one(T)] = val)


#===================================================================================================
<pointers>
===================================================================================================#
abstract type AbstractΠ end # uses capital Π

# note that, somewhat confusingly, T is the type of the pointer, not the value being pointed to
type Π{T<:Unsigned} <: AbstractΠ
addr::UInt16
addr::T

Π{T}(addr::Unsigned) where T<:Unsigned = new(addr)
end
Expand All @@ -38,7 +26,25 @@ const Π8 = Π{UInt8} # zero page pointer
const Π16 = Π{UInt16} # standard 6502 memory pointer
export Π8, Π16

dereference{T}(ptr:{T}, m::Memory) = m.v[ptr.addr+one(T)]


reset!(m::Memory) = (m.v .= zeros(UInt8, length(m.v)))
export reset!

fetch(m::Memory, idx::T) where T<:Unsigned = m.v[idx+one(T)]
fetch(m::Memory, idx::AbstractVector{T}) where T<:Unsigned = m.v[idx+one(T)]

Base.getindex(m::Memory, idx) = m.v[idx + 0x0001]
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)


#===================================================================================================
<referencing>
===================================================================================================#
dereference{T}(ptr:{T}, m::Memory) = m[ptr]
deref(ptr:, m::Memory) = dereference(ptr, m)
()(ptr:, m::Memory) = dereference(ptr, m) # this symbol is \mapsto

Expand All @@ -49,7 +55,7 @@ deref(::Type{UInt8}, ptr::Π, m::Memory) = dereference(ptr, Π)
function dereference{T}(::Type{UInt16}, ptr:{T}, m::Memory)::UInt16
least_sig = deref(ptr, m)
most_sig = deref(ptr + one(T), m)
(convert(UInt16, most_sig) << 8) + least_sig
0x0100 * most_sig + least_sig
end
deref(::Type{UInt16}, ptr:, m::Memory) = dereference(UInt16, ptr, m)
()(ptr:, m::Memory) = dereference(UInt16, ptr, m) # this symbol is \rightarrowtriangle
Expand All @@ -62,7 +68,13 @@ function dereference{T}(ptr::Π{T}, m::Memory, ℓ::Integer)
end
deref(ptr:, m::Memory, ℓ::Integer) = dereference(ptr, m, ℓ)

store!{T}(m::Memory, ptr:{T}, val::UInt8) = (m.v[ptr.addr+one(T)] = val)
store!{T}(m::Memory, ptr:{T}, val::UInt8) = (m[ptr.addr] = val)
# this stores backwards from the supplied memory address
function storeback!{T}(m::Memory, ptr:{T}, val::UInt16)
m[ptr] = UInt8(val >> 8)
m[ptr - 0x01] = UInt8(0x00ff & val)
val
end

(+){T}(ptr1:{T}, ptr2:{T}) = Π{T}(ptr1.addr + ptr2.addr)
(-){T}(ptr1:{T}, ptr2:{T}) = Π{T}(ptr1.addr - ptr2.addr)
Expand All @@ -72,7 +84,7 @@ store!{T}(m::Memory, ptr::Π{T}, val::UInt8) = (m.v[ptr.addr+one(T)] = val)

export dereference, deref, , , store!, +, -
#===================================================================================================
</pointers>
</referencing>
===================================================================================================#


13 changes: 9 additions & 4 deletions test/instructions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ end
# @p lda!(c, 0x40)
# @p bit!(c, m, Π(0x00))

@p ldx!(c, 0x40)
@p stx!(c, m, Π(0x00))
# @p lda!(c, 0x02)
# @p sta!(c, m, Π(0x0a00))
#
# @p lda!(c, 0x02)
# @p sta!(c, m, Π(0x0a01))
#
# @p jmp!(c, m, Π(0x0a00))

@p lda!(c, 0x80)
@p asl!(c, m, Π(0x00))
@p jsr!(c, m, 0x0610)
@p rts!(c, m)

0 comments on commit 6216e6b

Please sign in to comment.