documentation updats

This commit is contained in:
Colby 2016-08-19 20:49:24 +10:00
parent 7ae56c04ed
commit 5ee093760d
7 changed files with 33 additions and 48 deletions

View file

@ -51,7 +51,6 @@ module Waterfoul
# Read bootstrap instruction given an index (memory location)
# @return Integer - instruction or immediate value
def self.[](i)
ROM[i]
end

View file

@ -9,8 +9,8 @@ require 'waterfoul/instructions/shift'
require 'waterfoul/instructions/prefix'
module Waterfoul
# These constants represent each state in the F register and are used as a helper to
# reference the state when setting/resetting a state bit. Any combination of these
# These constants represent status bit in the F register. These are used as a
# helper when setting/resetting a state bit. Any combination of these
# states can be set at any one time.
#
# Z_FLAG: Zero Flag
@ -18,25 +18,20 @@ module Waterfoul
# H_FLAG: half carry flag
# C_FLAG: Carry Flag
# BIT 0-3 Always 0 and not used
#
Z_FLAG = 0b1000_0000
N_FLAG = 0b0100_0000
H_FLAG = 0b0010_0000
C_FLAG = 0b0001_0000
# number of cycles a HALT will puase program execution for
HALT_CYCLES = 6
##
# The CPU emulates the Sharp LR35902 CPU that is built into the device, similar to the
# Intel 8080 and Zilog Z80 processor. Each instruction is categorized
# into a subset of instructions by the type of action performed by the instruction.
# The CPU emulates the Sharp LR35902 CPU that is built into the device,
# similar to the Intel 8080 and Zilog Z80 processor. Each instruction
# is categorized into a subset of instructions by the type of action
# performed by the instruction.
#
# See lib/instuctions/ for the implementation for the CPU instruction set.
# See lib/instuctions for the implementation for the CPU instruction set.
#
# I recommend looking at http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html for an
# easy to understand chart for each instruction.
#
class CPU
include Helper
include Instructions::Opcode
@ -51,7 +46,7 @@ module Waterfoul
# 8 bit registers
attr_reader :a, :b, :c, :d, :e, :f, :h, :l, :f
# 8 CPU clock
# CPU cycle count
attr_reader :m
# 16 bit registers
attr_reader :sp, :pc
@ -89,10 +84,10 @@ module Waterfoul
end
def halted?
@halt == true
@halt
end
# Execute the instruction and
# Execute the instruction and
def perform_instruction(instruction)
operation = OPCODE[instruction]
raise 'instruction not found' if operation.nil?
@ -103,7 +98,7 @@ module Waterfoul
# fetch the next byte to be executed from memory and increment the program
# counter (except under particular circumstances, see interrupts)
def fetch_instruction(increment_pc = false)
def fetch_instruction(no_increment_pc = false)
instruction_byte = $mmu.read_byte @pc
@pc = (@pc + 1) & 0xFFFF unless increment_pc
instruction_byte

View file

@ -1,22 +1,18 @@
require 'sdl2'
module Waterfoul
# The Emulator is the abstraction of the emulator as a whole, it initializes
# each component and performs the tick.
class Emulator
def initialize(rom_filename, options = {})
SDL2.init SDL2::INIT_EVERYTHING
# read the rom into host memory
rom = read_program(rom_filename).bytes
# initialize emulated CPU, GPU & Sound components
# read the given file as binary and break it down into an array of bytes
rom = File.binread(rom_filename).bytes
# initialize emulated CPU, GPU & Scren components
cartridge = Cartridge.new rom
# initialize emulated memory management unit
$mmu = MMU.new
$mmu.cartridge = cartridge
cpu = CPU.new
@cpu = options.has_key?('skip_boot') ? SkipBoot.set_state(cpu) : cpu
@cpu = CPU.new
@cpu = SkipBoot.set_state(@cpu) if options.has_key?('skip_boot')
@gpu = GPU.new
# @input = Input.new
@screen = Screen.new
# @sound = Sound.new
end
def run
@ -25,14 +21,7 @@ module Waterfoul
@gpu.step @cpu.m
@screen.render @gpu.framebuffer if @gpu.vblank?
# @input.step @cpu.m
# @sound.step
end
end
private
def read_program(rom)
File.binread rom
end
end
end

View file

@ -1,5 +1,6 @@
module Waterfoul
module Helper
def pop_from_stack(word = true)
if word
lower = $mmu.read_byte @sp

View file

@ -12,6 +12,7 @@ module Waterfoul
INTERRUPT_SERIAL = 0x8
INTERRUPT_JOYPAD = 0x10
#
def self.request_interrupt(interrupt)
if_reg = $mmu.read_byte IF_REG_MEM_LOC
$mmu.write_byte IF_REG_MEM_LOC, (if_reg | interrupt)

View file

@ -7,12 +7,11 @@ module Waterfoul
# does not implement any IO instructions.
class MMU
MEMORY_SIZE = 65536 # bytes
# location in memory that when written to will unmap the boot rom from
# memory
# unmap boot rom register address
UNMAP_BOOT_ROM_MEM_LOC = 0xFF50
# location in memory where the boot rom ends
BOOT_ROM_END_MEM_LOC = 0xFF
# location in memory where DMA transfer is init
# DMA register function address
DMA_TRANSFER_MEM_LOC = 0xFF46
# DIV register memory location
DIV_MEM_LOC = 0xFF04
@ -23,19 +22,19 @@ module Waterfoul
# Set the initial state the memory management unit when program starts
def initialize
@cartridge = []
# flag to indicate if the boot rom is mapped to memory
# map the boot rom by default
@map_boot_rom = true
# storage for usable memory (zero filled)
@memory = Array.new MEMORY_SIZE, 0
end
# Read 1 byte from memory given address
# @param i Integer location in memory to read value
def [](i)
raise MemoryOutOfBounds if i > MEMORY_SIZE || i < 0
case i
when 0x0000...0x8000 # ROM Bank 0 + n
# if the boot rom is enabled and the address is < 0x100
if @map_boot_rom && i <= BOOT_ROM_END_MEM_LOC
BootROM[i]
else
@ -54,14 +53,12 @@ module Waterfoul
end
end
##
# Storage 1 byte into memory given address
# @param i Integer location in memory to storage value
# @param v Integer value to be written into memory
# Write 1 byte into memory
def []=(i, v, options = {})
# raise exception if an attempt is made to read memory that is out of bounds
raise MemoryOutOfBounds if i > MEMORY_SIZE || i < 0
# ignore memory rules if emulated hardware components need to write to
# memory
unless options[:hardware_operation]
case i
when UNMAP_BOOT_ROM_MEM_LOC # unmap the boot rom when 0xFF50 is wrtiten to in memory

View file

@ -1,7 +1,10 @@
module Waterfoul
# Set the state of the emulator after it has finished running the bootloader and ready to execute
# the game program. This lets us run the game program without needing to execute the boot rom every time
# the emulator is started.
# Set the state of the emulator as defined to the same state as it typically
# is after it has finished running the bootloader and ready to execute the
# game program.
# This lets us run the game without needing to execute the boot rom
# every time the emulator is started.
class SkipBoot
def self.set_state(cpu)
# CPU registers