1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
use std::num::Wrapping;
use crate::gpu::palette::{ColorSpace, text_palette};
use crate::gpu::palette::ColorSpace::RGB;
const DEBUG_DAL: bool = false;
#[derive(Clone)]
pub struct DAC {
/// DAC bits, usually 6 or 8
bits: u8,
pub pel_mask: u8,
/// color component for next out 03c9, 0 = red, 1 = green, 2 = blue
pub pel_index: u8,
pub state: State,
/// set by io write to 03c7
pub read_index: u8,
/// set by io write to 03c8
pub write_index: u8,
first_changed: usize,
pub combine: [u8; 16],
pub pal: Vec<ColorSpace>,
pub hidac_counter: u8,
reg02: u8,
}
impl Default for DAC {
fn default() -> Self {
DAC {
bits: 0,
pel_mask: 0xFF,
pel_index: 0,
state: State::Read,
read_index: 0,
write_index: 0,
first_changed: 0,
combine: [0; 16],
pal: text_palette().to_vec(),
hidac_counter: 0,
reg02: 0,
}
}
}
impl DAC {
/// (VGA) DAC state register (0x03C7)
pub fn get_state(&mut self) -> u8 {
self.hidac_counter = 0;
let res = self.state.register();
if DEBUG_DAL {
println!("read port 03C7: get_state = {:02X}", res);
}
res
}
/// (VGA, MCGA) PEL mask register (0x03C6)
pub fn set_pel_mask(&mut self, val: u8) {
self.pel_mask = val;
}
/// (VGA,MCGA,CEG-VGA) PEL address register (read mode) (0x03C7)
/// Sets DAC in read mode and assign start of color register
/// index (0..255) for following read accesses to 3C9h.
/// Don't write to 3C9h while in read mode. Next access to
/// 03C8h will stop pending mode immediatly.
pub fn set_pel_read_index(&mut self, val: u8) {
self.state = State::Read;
self.read_index = val;
self.write_index = val + 1;
self.pel_index = 0;
self.hidac_counter = 0;
if DEBUG_DAL {
println!("write port 03C7: set_pel_read_index = {:02X}", val);
}
}
/// (VGA,MCGA) PEL address register (0x03C8)
pub fn get_pel_write_index(&mut self) -> u8 {
self.hidac_counter = 0;
if DEBUG_DAL {
println!("read port 03C8: get_pel_write_index = {:02X}", self.write_index);
}
self.write_index
}
/// (VGA,MCGA) PEL address register (write mode) (0x03C8)
/// Sets DAC in write mode and assign start of color register
/// index (0..255) for following write accesses to 3C9h.
/// Next access to 03C8h will stop pending mode immediately.
pub fn set_pel_write_index(&mut self, val: u8) {
self.state = State::Write;
self.write_index = val;
self.pel_index = 0;
self.hidac_counter = 0;
if DEBUG_DAL {
println!("write port 03C8: set_pel_write_index = {:02X}", val);
}
}
/// (VGA,MCGA) PEL data register (0x03C9)
/// Three consequtive reads (in read mode) in the order: red, green, blue.
/// The internal DAC index is incremented each 3rd access.
pub fn get_pel_data(&mut self) -> u8 {
self.hidac_counter = 0;
let ret = match self.pal[self.read_index as usize] {
RGB(r, g, b) => {
match self.pel_index {
0 => {
self.pel_index = 1;
r >> 2
}
1 => {
self.pel_index = 2;
g >> 2
}
2 => {
self.pel_index = 0;
self.read_index += 1;
b >> 2
}
_ => unreachable!(),
}
}
_ => unreachable!(),
};
if DEBUG_DAL {
println!("read port 03C9: get_pel_data = {:02X}", ret);
}
ret
}
/// (VGA,MCGA) PEL data register (0x03C9)
/// Three consecutive writes (in write mode) in the order: red, green, blue.
/// The internal DAC index is incremented on every 3rd access.
pub fn set_pel_data(&mut self, mut val: u8) {
val &= 0x3F;
if DEBUG_DAL {
println!("write port 03C9: set_pel_data = write index {:02X}, pel index {:02X} = {:02X}", self.write_index, self.pel_index, val);
}
// scale 6-bit color into 8 bits
val <<= 2;
self.hidac_counter = 0;
if let RGB(ref mut r, ref mut g, ref mut b) = self.pal[self.write_index as usize] {
match self.pel_index {
0 => *r = val,
1 => *g = val,
2 => *b = val,
_ => unreachable!(),
}
}
self.pel_index += 1;
if self.pel_index > 2 {
// println!("self.write_index as usize {} len {}", self.write_index as usize,self.pal.len() );
if self.write_index as usize >= self.pal.len() - 1 {
// println!("XXX dac write_index wrapped to 0 at {}", self.pal.len());
self.write_index = 0;
} else {
self.write_index += 1;
}
self.pel_index = 0;
}
}
}
#[derive(Clone, PartialEq)]
pub enum State {
Read, Write,
}
impl State {
/// encodes state for the DAC state register (0x03C7)
pub fn register(&self) -> u8 {
match *self {
State::Read => 0b11,
State::Write => 0b00,
}
}
}