badline 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/CLAUDE.md +20 -3
- data/CONTRIBUTING.md +8 -3
- data/README.md +6 -2
- data/lib/badline/c128/drives.rb +95 -0
- data/lib/badline/c128/fast_serial.rb +62 -0
- data/lib/badline/c128/mmu.rb +15 -0
- data/lib/badline/c128/saved_state.rb +1 -0
- data/lib/badline/c128.rb +9 -7
- data/lib/badline/cia/fast_forward.rb +42 -0
- data/lib/badline/cia/serial.rb +12 -0
- data/lib/badline/cia/timer.rb +39 -0
- data/lib/badline/cia.rb +2 -0
- data/lib/badline/computer/attachments.rb +6 -0
- data/lib/badline/drive/core.rb +172 -0
- data/lib/badline/{drive1541 → drive}/idle.rb +18 -19
- data/lib/badline/drive/idle_cpu.rb +28 -0
- data/lib/badline/{drive1541 → drive}/orbit.rb +2 -1
- data/lib/badline/drive/serial_lines.rb +73 -0
- data/lib/badline/{drive1541 → drive}/sleep.rb +4 -3
- data/lib/badline/drive/watch.rb +150 -0
- data/lib/badline/drive.rb +9 -0
- data/lib/badline/drive1541/bus.rb +5 -129
- data/lib/badline/drive1541/byte_ready.rb +48 -0
- data/lib/badline/drive1541/cpu.rb +1 -19
- data/lib/badline/drive1541/disk.rb +77 -20
- data/lib/badline/drive1541/disk_state.rb +7 -2
- data/lib/badline/drive1541/disk_via.rb +3 -0
- data/lib/badline/drive1541/mechanism.rb +48 -14
- data/lib/badline/drive1541/mechanism_state.rb +5 -4
- data/lib/badline/drive1541/rotation.rb +5 -5
- data/lib/badline/drive1541/serial_port.rb +4 -60
- data/lib/badline/drive1541.rb +13 -172
- data/lib/badline/drive1571/bus.rb +111 -0
- data/lib/badline/drive1571/cpu.rb +11 -0
- data/lib/badline/drive1571/serial_port.rb +37 -0
- data/lib/badline/drive1571/serial_via.rb +25 -0
- data/lib/badline/drive1571/wd1770.rb +34 -0
- data/lib/badline/drive1571.rb +225 -0
- data/lib/badline/frontend/app.rb +1 -1
- data/lib/badline/frontend/drive_led.rb +1 -1
- data/lib/badline/frontend/menu_media.rb +3 -3
- data/lib/badline/frontend/menu_pages.rb +2 -1
- data/lib/badline/iec_bus.rb +54 -4
- data/lib/badline/machine.rb +7 -5
- data/lib/badline/media/true_drive.rb +26 -23
- data/lib/badline/options/help.rb +2 -1
- data/lib/badline/options/table.rb +1 -1
- data/lib/badline/roms/README +9 -0
- data/lib/badline/roms/dos1571.rom +0 -0
- data/lib/badline/storage/d64_image.rb +3 -0
- data/lib/badline/storage/d71_image.rb +9 -4
- data/lib/badline/storage/g64_image.rb +7 -2
- data/lib/badline/time_of_day.rb +9 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/via/fast_forward.rb +3 -3
- data/lib/badline/vic20/attachments.rb +6 -0
- data/lib/badline/z80/arithmetic.rb +117 -0
- data/lib/badline/z80/bit_page.rb +55 -0
- data/lib/badline/z80/block_io.rb +58 -0
- data/lib/badline/z80/block_transfers.rb +59 -0
- data/lib/badline/z80/bus_cycles.rb +111 -0
- data/lib/badline/z80/core.rb +111 -0
- data/lib/badline/z80/exchanges.rb +50 -0
- data/lib/badline/z80/extended_page.rb +89 -0
- data/lib/badline/z80/flags.rb +37 -0
- data/lib/badline/z80/interrupt_acceptance.rb +46 -0
- data/lib/badline/z80/jumps.rb +82 -0
- data/lib/badline/z80/loads.rb +98 -0
- data/lib/badline/z80/main_page.rb +134 -0
- data/lib/badline/z80/registers.rb +120 -0
- data/lib/badline/z80/shifts.rb +64 -0
- data/lib/badline/z80.rb +11 -0
- metadata +36 -4
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Z80
|
|
5
|
+
# Taking NMI and INT between instructions. Either wakes a halted CPU,
|
|
6
|
+
# whose program counter already points past the HALT.
|
|
7
|
+
module InterruptAcceptance
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# An opcode fetch whose byte is ignored, a T-state more, and a call
|
|
11
|
+
# to $0066. IFF2 keeps what IFF1 held, for RETN to restore.
|
|
12
|
+
def take_nmi
|
|
13
|
+
@nmi_pending = false
|
|
14
|
+
@halted = false
|
|
15
|
+
@iff1 = false
|
|
16
|
+
@bus.fetch(@pc)
|
|
17
|
+
refresh
|
|
18
|
+
@cycles += 5
|
|
19
|
+
push(@pc)
|
|
20
|
+
@pc = 0x66
|
|
21
|
+
@wz = 0x66
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The acknowledge cycle, an M1 with two wait states, reads a byte
|
|
25
|
+
# from the device. Mode 0 runs it as an opcode, which is a RST in
|
|
26
|
+
# practice, mode 1 calls $0038, and mode 2 calls through the vector
|
|
27
|
+
# at I and that byte.
|
|
28
|
+
def take_int
|
|
29
|
+
@halted = false
|
|
30
|
+
@f &= ~PF if @after_ld_a_ir
|
|
31
|
+
@iff1 = @iff2 = false
|
|
32
|
+
@after_ld_a_ir = false
|
|
33
|
+
@prefix = 0
|
|
34
|
+
data = @bus.acknowledge
|
|
35
|
+
refresh
|
|
36
|
+
@cycles += 6
|
|
37
|
+
return execute(data) if @im.zero?
|
|
38
|
+
|
|
39
|
+
@cycles += 1
|
|
40
|
+
push(@pc)
|
|
41
|
+
@pc = @im == 1 ? 0x38 : read_word((@i << 8) | data)
|
|
42
|
+
@wz = @pc
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Z80
|
|
5
|
+
# Jumps, calls and returns. Each leaves its target in WZ, and JP cc and
|
|
6
|
+
# CALL cc do whether they jump or not.
|
|
7
|
+
module Jumps
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# The conditions bits 5-3 pick: NZ Z NC C PO PE P M.
|
|
11
|
+
def condition?(index)
|
|
12
|
+
case index
|
|
13
|
+
when 0 then @f.nobits?(ZF)
|
|
14
|
+
when 1 then @f.anybits?(ZF)
|
|
15
|
+
when 2 then @f.nobits?(CF)
|
|
16
|
+
when 3 then @f.anybits?(CF)
|
|
17
|
+
when 4 then @f.nobits?(PF)
|
|
18
|
+
when 5 then @f.anybits?(PF)
|
|
19
|
+
when 6 then @f.nobits?(SF)
|
|
20
|
+
else @f.anybits?(SF)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# NOP, EX AF,AF', DJNZ, JR and JR cc.
|
|
25
|
+
def relative_jump(row)
|
|
26
|
+
case row
|
|
27
|
+
when 0 then nil
|
|
28
|
+
when 1 then exchange_af
|
|
29
|
+
when 2 then decrement_and_jump
|
|
30
|
+
when 3 then jump_relative(fetch_byte)
|
|
31
|
+
else
|
|
32
|
+
offset = fetch_byte
|
|
33
|
+
jump_relative(offset) if condition?(row - 4)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def decrement_and_jump
|
|
38
|
+
@cycles += 1
|
|
39
|
+
offset = fetch_byte
|
|
40
|
+
@b = (@b - 1) & 0xff
|
|
41
|
+
jump_relative(offset) unless @b.zero?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def jump_relative(offset)
|
|
45
|
+
@cycles += 5
|
|
46
|
+
@pc = (@pc + offset - (offset > 127 ? 256 : 0)) & 0xffff
|
|
47
|
+
@wz = @pc
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def jump(taken)
|
|
51
|
+
@wz = fetch_word
|
|
52
|
+
@pc = @wz if taken
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def call(taken)
|
|
56
|
+
@wz = fetch_word
|
|
57
|
+
return unless taken
|
|
58
|
+
|
|
59
|
+
@cycles += 1
|
|
60
|
+
push(@pc)
|
|
61
|
+
@pc = @wz
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def conditional_return(index)
|
|
65
|
+
@cycles += 1
|
|
66
|
+
return_from_call if condition?(index)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def return_from_call
|
|
70
|
+
@pc = pop
|
|
71
|
+
@wz = @pc
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def restart(address)
|
|
75
|
+
@cycles += 1
|
|
76
|
+
push(@pc)
|
|
77
|
+
@pc = address
|
|
78
|
+
@wz = address
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Z80
|
|
5
|
+
# Loads, PUSH, and IN and OUT through a port A and n address. The loads
|
|
6
|
+
# through a pointer leave the address after it in WZ, or for a store of
|
|
7
|
+
# A, A and the low byte of that address.
|
|
8
|
+
module Loads
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# LD r,r' with (HL) as index 6.
|
|
12
|
+
def load_register(target, source)
|
|
13
|
+
if source == 6
|
|
14
|
+
set_plain_register(target, read_byte(operand_address))
|
|
15
|
+
elsif target == 6
|
|
16
|
+
write_byte(operand_address, plain_register(source))
|
|
17
|
+
else
|
|
18
|
+
set_register(target, register(source))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# LD r,n, and LD (IX+d),n, which reads n while it adds d.
|
|
23
|
+
def load_immediate(index)
|
|
24
|
+
return set_register(index, fetch_byte) unless index == 6
|
|
25
|
+
return write_byte(hl, fetch_byte) if @prefix.zero?
|
|
26
|
+
|
|
27
|
+
displaced
|
|
28
|
+
value = fetch_byte
|
|
29
|
+
@cycles += 2
|
|
30
|
+
write_byte(@wz, value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def indirect_load(row)
|
|
34
|
+
case row
|
|
35
|
+
when 0 then store_a(bc)
|
|
36
|
+
when 1 then load_a(bc)
|
|
37
|
+
when 2 then store_a(de)
|
|
38
|
+
when 3 then load_a(de)
|
|
39
|
+
when 4 then store_word(hl_or_index)
|
|
40
|
+
when 5 then self.hl_or_index = load_word
|
|
41
|
+
when 6 then store_a(fetch_word)
|
|
42
|
+
else load_a(fetch_word)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def load_a(address)
|
|
47
|
+
@a = read_byte(address)
|
|
48
|
+
@wz = (address + 1) & 0xffff
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def store_a(address)
|
|
52
|
+
write_byte(address, @a)
|
|
53
|
+
@wz = (@a << 8) | ((address + 1) & 0xff)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def store_word(value)
|
|
57
|
+
address = fetch_word
|
|
58
|
+
write_word(address, value)
|
|
59
|
+
@wz = (address + 1) & 0xffff
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def load_word
|
|
63
|
+
address = fetch_word
|
|
64
|
+
@wz = (address + 1) & 0xffff
|
|
65
|
+
read_word(address)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def push_pair(index)
|
|
69
|
+
@cycles += 1
|
|
70
|
+
push(stack_pair(index))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# RET, EXX, JP (HL) and LD SP,HL.
|
|
74
|
+
def stack_and_exchange(index)
|
|
75
|
+
case index
|
|
76
|
+
when 0 then return_from_call
|
|
77
|
+
when 1 then exchange_alternates
|
|
78
|
+
when 2 then @pc = hl_or_index
|
|
79
|
+
else
|
|
80
|
+
@cycles += 2
|
|
81
|
+
@sp = hl_or_index
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def output_immediate
|
|
86
|
+
port = (@a << 8) | fetch_byte
|
|
87
|
+
output(port, @a)
|
|
88
|
+
@wz = (port & 0xff00) | ((port + 1) & 0xff)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def input_immediate
|
|
92
|
+
port = (@a << 8) | fetch_byte
|
|
93
|
+
@wz = (port + 1) & 0xffff
|
|
94
|
+
@a = input(port)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Z80
|
|
5
|
+
# The unprefixed opcodes, which DD and FD reuse with IX or IY for HL.
|
|
6
|
+
# An opcode splits into its quarter (bits 7-6), its row (5-3) and its
|
|
7
|
+
# column (2-0), and each quarter of the page is regular in rows and
|
|
8
|
+
# columns.
|
|
9
|
+
module MainPage
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def execute(opcode)
|
|
13
|
+
case opcode >> 6
|
|
14
|
+
when 0 then execute_low(opcode)
|
|
15
|
+
when 1 then opcode == 0x76 ? @halted = true : load_register((opcode >> 3) & 7, opcode & 7)
|
|
16
|
+
when 2 then alu((opcode >> 3) & 7, operand(opcode & 7))
|
|
17
|
+
else execute_high(opcode)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def execute_low(opcode)
|
|
22
|
+
row = (opcode >> 3) & 7
|
|
23
|
+
case opcode & 7
|
|
24
|
+
when 0 then relative_jump(row)
|
|
25
|
+
when 1 then opcode.nobits?(8) ? set_pair(row >> 1, fetch_word) : add_pair(row >> 1)
|
|
26
|
+
when 2 then indirect_load(row)
|
|
27
|
+
when 3 then step_pair(row)
|
|
28
|
+
when 4 then modify(row, true)
|
|
29
|
+
when 5 then modify(row, false)
|
|
30
|
+
when 6 then load_immediate(row)
|
|
31
|
+
else accumulator_operation(row)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def execute_high(opcode)
|
|
36
|
+
row = (opcode >> 3) & 7
|
|
37
|
+
case opcode & 7
|
|
38
|
+
when 0 then conditional_return(row)
|
|
39
|
+
when 1 then opcode.nobits?(8) ? set_stack_pair(row >> 1, pop) : stack_and_exchange(row >> 1)
|
|
40
|
+
when 2 then jump(condition?(row))
|
|
41
|
+
when 3 then miscellaneous(row)
|
|
42
|
+
when 4 then call(condition?(row))
|
|
43
|
+
when 5 then opcode.nobits?(8) ? push_pair(row >> 1) : call_or_prefix(row >> 1)
|
|
44
|
+
when 6 then alu(row, fetch_byte)
|
|
45
|
+
else restart(row << 3)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The operand of the 8-bit ALU opcodes: a register or (HL).
|
|
50
|
+
def operand(index)
|
|
51
|
+
index == 6 ? read_byte(operand_address) : register(index)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# INC and DEC on a register or (HL).
|
|
55
|
+
def modify(index, increase)
|
|
56
|
+
if index == 6
|
|
57
|
+
address = operand_address
|
|
58
|
+
value = read_byte(address)
|
|
59
|
+
@cycles += 1
|
|
60
|
+
write_byte(address, increase ? increment(value) : decrement(value))
|
|
61
|
+
else
|
|
62
|
+
set_register(index, increase ? increment(register(index)) : decrement(register(index)))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# INC and DEC on a pair, which touch no flags.
|
|
67
|
+
def step_pair(row)
|
|
68
|
+
@cycles += 2
|
|
69
|
+
index = row >> 1
|
|
70
|
+
set_pair(index, (pair(index) + (row.nobits?(1) ? 1 : -1)) & 0xffff)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def add_pair(index)
|
|
74
|
+
self.hl_or_index = add16(hl_or_index, pair(index))
|
|
75
|
+
@cycles += 7
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def accumulator_operation(row)
|
|
79
|
+
case row
|
|
80
|
+
when 0, 1, 2, 3 then rotate_a(row)
|
|
81
|
+
when 4 then daa
|
|
82
|
+
when 5 then complement
|
|
83
|
+
when 6 then assign_flags((@f & (SF | ZF | PF)) | CF | (((@last_q ^ @f) | @a) & XYF))
|
|
84
|
+
else assign_flags((@f & (SF | ZF | PF)) | ((@f & CF) << 4) | ((@f & CF) ^ CF) | (((@last_q ^ @f) | @a) & XYF))
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def complement
|
|
89
|
+
@a ^= 0xff
|
|
90
|
+
assign_flags((@f & (SF | ZF | PF | CF)) | HF | NF | (@a & XYF))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def miscellaneous(row)
|
|
94
|
+
case row
|
|
95
|
+
when 0 then jump(true)
|
|
96
|
+
when 1 then @prefix.zero? ? execute_bits(fetch_opcode) : execute_index_bits
|
|
97
|
+
when 2 then output_immediate
|
|
98
|
+
when 3 then input_immediate
|
|
99
|
+
when 4 then exchange_stack_top
|
|
100
|
+
when 5 then exchange_de_hl
|
|
101
|
+
when 6 then @iff1 = @iff2 = false
|
|
102
|
+
else enable_interrupts
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def call_or_prefix(index)
|
|
107
|
+
case index
|
|
108
|
+
when 0 then call(true)
|
|
109
|
+
when 1 then index_prefix(1)
|
|
110
|
+
when 2 then extended_prefix
|
|
111
|
+
else index_prefix(2)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# DD and FD: the next opcode runs with IX or IY for HL. A prefix
|
|
116
|
+
# after a prefix replaces it.
|
|
117
|
+
def index_prefix(prefix)
|
|
118
|
+
@prefix = prefix
|
|
119
|
+
@last_q = 0
|
|
120
|
+
execute(fetch_opcode)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def extended_prefix
|
|
124
|
+
@prefix = 0
|
|
125
|
+
execute_extended(fetch_opcode)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def enable_interrupts
|
|
129
|
+
@iff1 = @iff2 = true
|
|
130
|
+
@after_ei = true
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Z80
|
|
5
|
+
# The register file. Opcodes name 8-bit registers by a 3-bit index,
|
|
6
|
+
# B C D E H L (HL) A, and pairs by a 2-bit one, BC DE HL SP, or BC DE
|
|
7
|
+
# HL AF for PUSH and POP. After a DD or FD prefix, HL means IX or IY
|
|
8
|
+
# and H and L their halves, except beside an (IX+d) operand.
|
|
9
|
+
module Registers
|
|
10
|
+
attr_accessor :a, :f, :b, :c, :d, :e, :h, :l, :i, :r, :pc, :sp, :ix, :iy, :wz, :im, :q,
|
|
11
|
+
:af_alt, :bc_alt, :de_alt, :hl_alt, :iff1, :iff2, :halted, :after_ei, :after_ld_a_ir
|
|
12
|
+
|
|
13
|
+
def af = (@a << 8) | @f
|
|
14
|
+
def bc = (@b << 8) | @c
|
|
15
|
+
def de = (@d << 8) | @e
|
|
16
|
+
def hl = (@h << 8) | @l
|
|
17
|
+
|
|
18
|
+
def af=(value)
|
|
19
|
+
@a = value >> 8
|
|
20
|
+
@f = value & 0xff
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def bc=(value)
|
|
24
|
+
@b = value >> 8
|
|
25
|
+
@c = value & 0xff
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def de=(value)
|
|
29
|
+
@d = value >> 8
|
|
30
|
+
@e = value & 0xff
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def hl=(value)
|
|
34
|
+
@h = value >> 8
|
|
35
|
+
@l = value & 0xff
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def register(index)
|
|
41
|
+
case index
|
|
42
|
+
when 0 then @b
|
|
43
|
+
when 1 then @c
|
|
44
|
+
when 2 then @d
|
|
45
|
+
when 3 then @e
|
|
46
|
+
when 4 then @prefix.zero? ? @h : index_register >> 8
|
|
47
|
+
when 5 then @prefix.zero? ? @l : index_register & 0xff
|
|
48
|
+
else @a
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def set_register(index, value)
|
|
53
|
+
case index
|
|
54
|
+
when 0 then @b = value
|
|
55
|
+
when 1 then @c = value
|
|
56
|
+
when 2 then @d = value
|
|
57
|
+
when 3 then @e = value
|
|
58
|
+
when 4 then @prefix.zero? ? @h = value : self.index_register = (index_register & 0xff) | (value << 8)
|
|
59
|
+
when 5 then @prefix.zero? ? @l = value : self.index_register = (index_register & 0xff00) | value
|
|
60
|
+
else @a = value
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The register an (HL) or (IX+d) operand sits beside: H and L are
|
|
65
|
+
# always themselves.
|
|
66
|
+
def plain_register(index)
|
|
67
|
+
case index
|
|
68
|
+
when 4 then @h
|
|
69
|
+
when 5 then @l
|
|
70
|
+
else register(index)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def set_plain_register(index, value)
|
|
75
|
+
case index
|
|
76
|
+
when 4 then @h = value
|
|
77
|
+
when 5 then @l = value
|
|
78
|
+
else set_register(index, value)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def pair(index)
|
|
83
|
+
case index
|
|
84
|
+
when 0 then bc
|
|
85
|
+
when 1 then de
|
|
86
|
+
when 2 then hl_or_index
|
|
87
|
+
else @sp
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def set_pair(index, value)
|
|
92
|
+
case index
|
|
93
|
+
when 0 then self.bc = value
|
|
94
|
+
when 1 then self.de = value
|
|
95
|
+
when 2 then self.hl_or_index = value
|
|
96
|
+
else @sp = value
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# The pairs PUSH and POP name, with AF in place of SP.
|
|
101
|
+
def stack_pair(index) = index == 3 ? af : pair(index)
|
|
102
|
+
|
|
103
|
+
def set_stack_pair(index, value)
|
|
104
|
+
index == 3 ? self.af = value : set_pair(index, value)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def hl_or_index = @prefix.zero? ? hl : index_register
|
|
108
|
+
|
|
109
|
+
def hl_or_index=(value)
|
|
110
|
+
@prefix.zero? ? self.hl = value : self.index_register = value
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def index_register = @prefix == 1 ? @ix : @iy
|
|
114
|
+
|
|
115
|
+
def index_register=(value)
|
|
116
|
+
@prefix == 1 ? @ix = value : @iy = value
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Z80
|
|
5
|
+
# Rotates, shifts and the bit operations.
|
|
6
|
+
module Shifts
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
# RLCA RRCA RLA RRA, which leave S, Z and P/V alone.
|
|
10
|
+
def rotate_a(operation)
|
|
11
|
+
carry = operation.even? ? @a >> 7 : @a & 1
|
|
12
|
+
@a = shifted(operation, @a, carry)
|
|
13
|
+
assign_flags((@f & (SF | ZF | PF)) | (@a & XYF) | carry)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The CB page's rotates and shifts by bits 5-3: RLC RRC RL RR SLA SRA
|
|
17
|
+
# SLL SRL. SLL shifts a 1 in.
|
|
18
|
+
def shift(operation, value)
|
|
19
|
+
carry = operation.even? ? value >> 7 : value & 1
|
|
20
|
+
result = shifted(operation, value, carry)
|
|
21
|
+
assign_flags(SZ53P[result] | carry)
|
|
22
|
+
result
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def shifted(operation, value, carry)
|
|
26
|
+
case operation
|
|
27
|
+
when 0 then ((value << 1) | carry) & 0xff
|
|
28
|
+
when 1 then (value >> 1) | (carry << 7)
|
|
29
|
+
when 2 then ((value << 1) | (@f & CF)) & 0xff
|
|
30
|
+
when 3 then (value >> 1) | ((@f & CF) << 7)
|
|
31
|
+
when 4 then (value << 1) & 0xff
|
|
32
|
+
when 5 then (value >> 1) | (value & 0x80)
|
|
33
|
+
when 6 then ((value << 1) | 1) & 0xff
|
|
34
|
+
else value >> 1
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# BIT n tests a bit of +value+ and copies bits 5 and 3 from +source+:
|
|
39
|
+
# the operand for a register, WZ's high byte for a memory operand.
|
|
40
|
+
def bit(number, value, source)
|
|
41
|
+
tested = value & (1 << number)
|
|
42
|
+
flags = (@f & CF) | HF | (source & XYF) | (tested & SF)
|
|
43
|
+
flags |= ZF | PF if tested.zero?
|
|
44
|
+
assign_flags(flags)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# RRD and RLD rotate a digit through A and (HL).
|
|
48
|
+
def rotate_digits(left)
|
|
49
|
+
address = hl
|
|
50
|
+
value = read_byte(address)
|
|
51
|
+
@cycles += 4
|
|
52
|
+
if left
|
|
53
|
+
write_byte(address, ((value << 4) | (@a & 0x0f)) & 0xff)
|
|
54
|
+
@a = (@a & 0xf0) | (value >> 4)
|
|
55
|
+
else
|
|
56
|
+
write_byte(address, ((@a << 4) | (value >> 4)) & 0xff)
|
|
57
|
+
@a = (@a & 0xf0) | (value & 0x0f)
|
|
58
|
+
end
|
|
59
|
+
@wz = (address + 1) & 0xffff
|
|
60
|
+
assign_flags((@f & CF) | SZ53P[@a])
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/badline/z80.rb
ADDED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: badline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.11.
|
|
4
|
+
version: 0.11.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Inge Jørgensen
|
|
@@ -77,6 +77,8 @@ files:
|
|
|
77
77
|
- lib/badline/c128/bus_state.rb
|
|
78
78
|
- lib/badline/c128/color_lines.rb
|
|
79
79
|
- lib/badline/c128/cpu.rb
|
|
80
|
+
- lib/badline/c128/drives.rb
|
|
81
|
+
- lib/badline/c128/fast_serial.rb
|
|
80
82
|
- lib/badline/c128/keys.rb
|
|
81
83
|
- lib/badline/c128/mmu.rb
|
|
82
84
|
- lib/badline/c128/mmu_pages.rb
|
|
@@ -119,6 +121,7 @@ files:
|
|
|
119
121
|
- lib/badline/checkpoint.rb
|
|
120
122
|
- lib/badline/chrout_trap.rb
|
|
121
123
|
- lib/badline/cia.rb
|
|
124
|
+
- lib/badline/cia/fast_forward.rb
|
|
122
125
|
- lib/badline/cia/interrupt_register.rb
|
|
123
126
|
- lib/badline/cia/serial.rb
|
|
124
127
|
- lib/badline/cia/state.rb
|
|
@@ -142,22 +145,34 @@ files:
|
|
|
142
145
|
- lib/badline/data_path.rb
|
|
143
146
|
- lib/badline/datasette.rb
|
|
144
147
|
- lib/badline/debug_register.rb
|
|
148
|
+
- lib/badline/drive.rb
|
|
149
|
+
- lib/badline/drive/core.rb
|
|
150
|
+
- lib/badline/drive/idle.rb
|
|
151
|
+
- lib/badline/drive/idle_cpu.rb
|
|
152
|
+
- lib/badline/drive/orbit.rb
|
|
153
|
+
- lib/badline/drive/serial_lines.rb
|
|
154
|
+
- lib/badline/drive/sleep.rb
|
|
155
|
+
- lib/badline/drive/watch.rb
|
|
145
156
|
- lib/badline/drive1541.rb
|
|
146
157
|
- lib/badline/drive1541/bus.rb
|
|
158
|
+
- lib/badline/drive1541/byte_ready.rb
|
|
147
159
|
- lib/badline/drive1541/cpu.rb
|
|
148
160
|
- lib/badline/drive1541/disk.rb
|
|
149
161
|
- lib/badline/drive1541/disk_state.rb
|
|
150
162
|
- lib/badline/drive1541/disk_via.rb
|
|
151
163
|
- lib/badline/drive1541/gcr.rb
|
|
152
|
-
- lib/badline/drive1541/idle.rb
|
|
153
164
|
- lib/badline/drive1541/mechanism.rb
|
|
154
165
|
- lib/badline/drive1541/mechanism_state.rb
|
|
155
|
-
- lib/badline/drive1541/orbit.rb
|
|
156
166
|
- lib/badline/drive1541/rotation.rb
|
|
157
167
|
- lib/badline/drive1541/sector_reader.rb
|
|
158
168
|
- lib/badline/drive1541/serial_port.rb
|
|
159
|
-
- lib/badline/drive1541/sleep.rb
|
|
160
169
|
- lib/badline/drive1541/track.rb
|
|
170
|
+
- lib/badline/drive1571.rb
|
|
171
|
+
- lib/badline/drive1571/bus.rb
|
|
172
|
+
- lib/badline/drive1571/cpu.rb
|
|
173
|
+
- lib/badline/drive1571/serial_port.rb
|
|
174
|
+
- lib/badline/drive1571/serial_via.rb
|
|
175
|
+
- lib/badline/drive1571/wd1770.rb
|
|
161
176
|
- lib/badline/ffi.rb
|
|
162
177
|
- lib/badline/frontend.rb
|
|
163
178
|
- lib/badline/frontend/app.rb
|
|
@@ -274,6 +289,7 @@ files:
|
|
|
274
289
|
- lib/badline/roms/c64gs.rom
|
|
275
290
|
- lib/badline/roms/character.rom
|
|
276
291
|
- lib/badline/roms/dos1541.rom
|
|
292
|
+
- lib/badline/roms/dos1571.rom
|
|
277
293
|
- lib/badline/roms/eapi/LICENSE.md
|
|
278
294
|
- lib/badline/roms/eapi/README
|
|
279
295
|
- lib/badline/roms/eapi/eapi-am29f040-14
|
|
@@ -385,6 +401,22 @@ files:
|
|
|
385
401
|
- lib/badline/vic20/vic/painter.rb
|
|
386
402
|
- lib/badline/vic20/vic/saved_state.rb
|
|
387
403
|
- lib/badline/vic20/vic/text_window.rb
|
|
404
|
+
- lib/badline/z80.rb
|
|
405
|
+
- lib/badline/z80/arithmetic.rb
|
|
406
|
+
- lib/badline/z80/bit_page.rb
|
|
407
|
+
- lib/badline/z80/block_io.rb
|
|
408
|
+
- lib/badline/z80/block_transfers.rb
|
|
409
|
+
- lib/badline/z80/bus_cycles.rb
|
|
410
|
+
- lib/badline/z80/core.rb
|
|
411
|
+
- lib/badline/z80/exchanges.rb
|
|
412
|
+
- lib/badline/z80/extended_page.rb
|
|
413
|
+
- lib/badline/z80/flags.rb
|
|
414
|
+
- lib/badline/z80/interrupt_acceptance.rb
|
|
415
|
+
- lib/badline/z80/jumps.rb
|
|
416
|
+
- lib/badline/z80/loads.rb
|
|
417
|
+
- lib/badline/z80/main_page.rb
|
|
418
|
+
- lib/badline/z80/registers.rb
|
|
419
|
+
- lib/badline/z80/shifts.rb
|
|
388
420
|
- packaging/homebrew/badline.rb
|
|
389
421
|
homepage: https://github.com/elektronaut/badline
|
|
390
422
|
licenses:
|