Class: Badline::VIC

Inherits:
Cycleable show all
Includes:
Addressable, IntegerHelper
Defined in:
lib/badline/vic.rb,
lib/badline/vic/bank.rb,
lib/badline/vic/sprite.rb,
lib/badline/vic/sprites.rb,
lib/badline/vic/registers.rb,
lib/badline/vic/sequencer.rb,
lib/badline/vic/display_state.rb,
lib/badline/vic/graphics_mode.rb

Defined Under Namespace

Modules: GraphicsMode Classes: Bank, DisplayState, Registers, Sequencer, Sprite, Sprites

Constant Summary collapse

SPRITE_BA_RANGES =
[
  55..59, 57..61, 59..62,
  0..2, 0..4, 2..6, 4..8, 6..10
].freeze

Instance Attribute Summary collapse

Attributes included from Addressable

#end, #length, #start

Attributes inherited from Cycleable

#cycles

Instance Method Summary collapse

Methods included from IntegerHelper

#bcd, #bcd_to_i, #format16, #format8, #high_byte, #low_byte, #signed_int8, #uint16

Methods included from Addressable

#[], #[]=, #addressable_at, #in_range?, #peek16, #poke16, #range

Methods inherited from Cycleable

#pending_write?

Constructor Details

#initialize(address_bus = nil, debug: false) ⇒ VIC

Returns a new instance of VIC.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/badline/vic.rb', line 22

def initialize(address_bus = nil, debug: false)
  addressable_at(0xd000, length: 2**10)
  @address_bus = address_bus || AddressBus.new
  @vic_bank = VIC::Bank.new(@address_bus)
  @debug = debug

  @width = 504
  @height = 312

  @registers = VIC::Registers.new
  @display_state = VIC::DisplayState.new(@registers)
  @sequencer = VIC::Sequencer.new(@width, @registers, @vic_bank)
  @sprites = VIC::Sprites.new(@registers, @vic_bank, @width)
  @display = Array.new(@width * @height, 0)
  @dirty_lines = Array.new(@height, true)

  @column = 0
  @rasterline = 0
  @columns_per_line = @width / 8
  @last_line = @height - 1

  @character_buffer = Array.new(40, 0)
  @color_buffer = Array.new(40, 0)
  @sprite_ba = Array.new(@width / 8, false)

  super()
end

Instance Attribute Details

#address_busObject (readonly)

Returns the value of attribute address_bus.



14
15
16
# File 'lib/badline/vic.rb', line 14

def address_bus
  @address_bus
end

#columnObject (readonly)

Returns the value of attribute column.



14
15
16
# File 'lib/badline/vic.rb', line 14

def column
  @column
end

#dirty_linesObject (readonly)

Returns the value of attribute dirty_lines.



14
15
16
# File 'lib/badline/vic.rb', line 14

def dirty_lines
  @dirty_lines
end

#displayObject (readonly)

Returns the value of attribute display.



14
15
16
# File 'lib/badline/vic.rb', line 14

def display
  @display
end

#heightObject (readonly)

Returns the value of attribute height.



14
15
16
# File 'lib/badline/vic.rb', line 14

def height
  @height
end

#rasterlineObject (readonly)

Returns the value of attribute rasterline.



14
15
16
# File 'lib/badline/vic.rb', line 14

def rasterline
  @rasterline
end

#vic_bankObject (readonly)

Returns the value of attribute vic_bank.



14
15
16
# File 'lib/badline/vic.rb', line 14

def vic_bank
  @vic_bank
end

#widthObject (readonly)

Returns the value of attribute width.



14
15
16
# File 'lib/badline/vic.rb', line 14

def width
  @width
end

Instance Method Details

#ba_low?Boolean

Returns:

  • (Boolean)


103
104
105
106
107
# File 'lib/badline/vic.rb', line 103

def ba_low?
  return true if @sprite_ba[@column]

  @display_state.bad_line? && @column >= 13 && @column < 56
end

#blanking?Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/badline/vic.rb', line 117

def blanking?
  @rasterline < 16 || @rasterline > 299 || @column < 10 || @column > 60
end

#clear_dirty_lines!Object

Reset the dirty flags once the frontend has consumed them.



122
123
124
# File 'lib/badline/vic.rb', line 122

def clear_dirty_lines!
  @dirty_lines.fill(false)
end

#cycle!Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/badline/vic.rb', line 50

def cycle!
  if @column.zero?
    @display_state.new_frame if @rasterline.zero?
    check_raster_irq!
    @sequencer.new_line(@rasterline)
    @sprites.start_line(@rasterline)
    rebuild_sprite_ba
    @display_state.new_line
  end

  @display_state.cycle(@rasterline, @column)

  fetch_character_data! if dma_active?

  draw!

  @column += 1
  if @column == @columns_per_line
    finish_line!
    @column = 0
    @rasterline = @rasterline == @last_line ? 0 : @rasterline + 1
  end
  nil
end

#dma_active?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/badline/vic.rb', line 99

def dma_active?
  @display_state.bad_line? && @column >= 15 && @column < 55
end

#hblank?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/badline/vic.rb', line 109

def hblank?
  @column < 10 || @column > 60
end

#interrupted?Boolean

The IRQ line is held asserted while any enabled latch bit is set in $D019/$D01A, until the program acknowledges it by writing to $D019.

Returns:

  • (Boolean)


77
78
79
# File 'lib/badline/vic.rb', line 77

def interrupted?
  @registers.irq_line?
end

#peek(addr) ⇒ Object



81
82
83
84
85
86
87
88
89
# File 'lib/badline/vic.rb', line 81

def peek(addr)
  i = index(addr) % (2**6)
  case i
  when 0x11 then (@registers[0x11] & 0x7f) | ((rasterline & 0x100) >> 1)
  when 0x12 then rasterline & 0xff
  when 0x19 then irq_status # Latch + master IRQ bit, unused bits read 1
  else @registers.read(i)
  end
end

#poke(addr, value) ⇒ Object



91
92
93
# File 'lib/badline/vic.rb', line 91

def poke(addr, value)
  @registers.write(index(addr) % (2**6), value)
end

#positionObject



95
96
97
# File 'lib/badline/vic.rb', line 95

def position
  (@rasterline * @width) + (@column * 8)
end

#vblank?Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/badline/vic.rb', line 113

def vblank?
  @rasterline < 16 || @rasterline > 299
end