Class: Amaterasu::GameBoy::Dma
- Inherits:
-
Object
- Object
- Amaterasu::GameBoy::Dma
- Defined in:
- lib/amaterasu/game_boy/dma.rb
Overview
Models the RAM chip within the Game Boy.
On the real Game Boy, the CPU and DMA share the same physical bus. During DMA, the DMA controller physically takes over the bus lines — the CPU is electrically disconnected from the bus (except HRAM, which is on a separate internal path).
Constant Summary collapse
- OAM_START_ADDRESS =
0xFE00- DMA_START_DELAY =
1- DMA_TOTAL_CYCLES =
160 + DMA_START_DELAY
Instance Attribute Summary collapse
-
#internal_latch ⇒ Object
readonly
Returns the value of attribute internal_latch.
Instance Method Summary collapse
-
#active? ⇒ Boolean
Checks if the DMA transfer is in progress.
-
#initialize(bus, trace_dma: false) ⇒ Dma
constructor
A new instance of Dma.
-
#request_transfer(source_value:) ⇒ Object
When a value is written to 0xFF46, it means a DMA transfer was requested.
-
#tick ⇒ Object
This method is called once per M-cycle, CPU drives this.
Constructor Details
#initialize(bus, trace_dma: false) ⇒ Dma
Returns a new instance of Dma.
17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/amaterasu/game_boy/dma.rb', line 17 def initialize(bus, trace_dma: false) @bus = bus @trace_dma = trace_dma @internal_latch = 0xFF @source_address = nil @target_address = OAM_START_ADDRESS @status = :inactive @active = false @cycles = 0 end |
Instance Attribute Details
#internal_latch ⇒ Object (readonly)
Returns the value of attribute internal_latch.
15 16 17 |
# File 'lib/amaterasu/game_boy/dma.rb', line 15 def internal_latch @internal_latch end |
Instance Method Details
#active? ⇒ Boolean
Returns Checks if the DMA transfer is in progress.
76 77 78 |
# File 'lib/amaterasu/game_boy/dma.rb', line 76 def active? @active end |
#request_transfer(source_value:) ⇒ Object
When a value is written to 0xFF46, it means a DMA transfer was requested. The value represents the upper byte of the source address. This value is saved (latched), if there is a read from 0xFF46, it should return this value. Requesting a transfer with value 0x80, means the source address is 0x8000. You can multiple the given value by 0x100 to get the source address.
68 69 70 71 72 73 |
# File 'lib/amaterasu/game_boy/dma.rb', line 68 def request_transfer(source_value:) @internal_latch = source_value @source_address = source_value * 0x100 @status = :pending @cycles = 0 end |
#tick ⇒ Object
This method is called once per M-cycle, CPU drives this.
-
DMA transfer 1 byte per M-cycle, totalling 160 bytes.
-
It fills the OAM memory range from 0xFE00 - 0xFE9F.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/amaterasu/game_boy/dma.rb', line 33 def tick case @status when :inactive then nil when :pending log_state if @trace_dma @cycles += 1 start_transfer when :transferring @active = true source_byte = bus_read(address: @source_address) bus_write(address: @target_address, value: source_byte) log_state if @trace_dma @source_address += 1 @target_address += 1 @cycles += 1 complete_transfer if @cycles == DMA_TOTAL_CYCLES when :completed @cycles = 0 @source_address = nil @target_address = OAM_START_ADDRESS @status = :inactive @active = false end end |