-
Notifications
You must be signed in to change notification settings - Fork 0
/
sc1.vhd
241 lines (201 loc) · 7.54 KB
/
sc1.vhd
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
-----------------------------------------------------------------------
--
-- Copyright 2012 ShareBrained Technology, Inc.
--
-- This file is part of robotron-fpga.
--
-- robotron-fpga is free software: you can redistribute
-- it and/or modify it under the terms of the GNU General
-- Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your
-- option) any later version.
--
-- robotron-fpga is distributed in the hope that it will
-- be useful, but WITHOUT ANY WARRANTY; without even the
-- implied warranty of MERCHANTABILITY or FITNESS FOR A
-- PARTICULAR PURPOSE. See the GNU General Public License
-- for more details.
--
-- You should have received a copy of the GNU General
-- Public License along with robotron-fpga. If not, see
-- <http://www.gnu.org/licenses/>.
--
-----------------------------------------------------------------------
-- This entity models a pair of Williams SC1 pixel BLTter ICs.
-- The interface is modified to be more conducive to synchronous
-- FPGA implementation.
-- Dec 2018 changes for SC1 or SC2 and 0 address error (DW oldgit)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity sc1 is generic ( is_sc1 : boolean := true; clip : std_logic_vector(15 downto 0) := x"C000" );
port(
clk : in std_logic;
reg_cs : in std_logic;
reg_data_in : in std_logic_vector( 7 downto 0);
rs : in std_logic_vector( 2 downto 0);
win_en : in std_logic;
halt : out boolean;
halt_ack : in boolean;
blt_ack : in std_logic;
blt_rd : out boolean;
blt_wr : out boolean;
blt_address_out : out std_logic_vector(15 downto 0);
blt_data_in : in std_logic_vector( 7 downto 0);
blt_data_out : out std_logic_vector( 7 downto 0);
en_upper : out boolean;
en_lower : out boolean
);
end sc1;
architecture RTL of sc1 is
type state_t is (state_idle, state_wait_for_halt, state_src, state_dst);
-- control attributes
signal ctrl_span_src : std_logic := '0';
signal ctrl_span_dst : std_logic := '0';
signal ctrl_slow : std_logic := '0';
signal ctrl_foreground : std_logic := '0';
signal ctrl_solid : std_logic := '0';
signal ctrl_shift : std_logic := '0';
signal ctrl_no_lower : std_logic := '0';
signal ctrl_no_upper : std_logic := '0';
-- 0: Run register
signal reg_ctrl : std_logic_vector( 7 downto 0) := (others => '0');
-- 1: solid value
signal reg_solid : std_logic_vector( 7 downto 0) := (others => '0');
-- 2, 3: source address
signal reg_src_base : std_logic_vector(15 downto 0) := (others => '0');
-- 4, 5: destination address
signal reg_dst_base : std_logic_vector(15 downto 0) := (others => '0');
-- 6: width
signal reg_width : std_logic_vector( 7 downto 0) := (others => '0');
-- 7: height
signal reg_height : std_logic_vector( 7 downto 0) := (others => '0');
-- Internal
signal state : state_t := state_idle;
signal blt_src_data : std_logic_vector( 7 downto 0) := (others => '0');
signal blt_shift : std_logic_vector( 3 downto 0) := (others => '0');
signal src_address : std_logic_vector(15 downto 0) := (others => '0');
signal dst_address : std_logic_vector(15 downto 0) := (others => '0');
signal x_count : std_logic_vector( 7 downto 0) := (others => '0');
signal x_count_next : std_logic_vector( 7 downto 0) := (others => '0');
signal y_count : std_logic_vector( 7 downto 0) := (others => '0');
signal y_count_next : std_logic_vector( 7 downto 0) := (others => '0');
signal xorval : std_logic_vector( 7 downto 0) := (others => '0');
begin
-- SC1 had a bug so values had to be xored with 0X04, SC2 fixed the bug so no xor required
xorval <= x"04" when is_sc1 else x"00";
halt <= not (state = state_idle);
blt_rd <= (state = state_src);
blt_wr <= (state = state_dst) and (win_en = '0' or dst_address<clip or dst_address>=x"C000");
blt_address_out <= dst_address when (state = state_dst) else src_address;
en_upper <= (state = state_src) or (not (ctrl_no_upper = '1' or (ctrl_foreground = '1' and blt_src_data(7 downto 4) = x"0") ));
en_lower <= (state = state_src) or (not (ctrl_no_lower = '1' or (ctrl_foreground = '1' and blt_src_data(3 downto 0) = x"0") ));
blt_data_out <= reg_solid when ctrl_solid = '1' else blt_src_data;
x_count_next <= x_count + 1;
y_count_next <= y_count + 1;
-- break out control reg into individual signals
ctrl_no_upper <= reg_ctrl(7);
ctrl_no_lower <= reg_ctrl(6);
ctrl_shift <= reg_ctrl(5);
ctrl_solid <= reg_ctrl(4);
ctrl_foreground <= reg_ctrl(3);
--ctrl_slow <= reg_ctrl(2);
ctrl_span_dst <= reg_ctrl(1);
ctrl_span_src <= reg_ctrl(0);
-- register access
process(clk)
begin
if rising_edge(clk) then
if reg_cs = '1' then
case rs is
-- 0: Start BLT with control attributes
when "000" => reg_ctrl <= reg_data_in;
-- 1: mask
when "001" => reg_solid <= reg_data_in;
-- 2: source address high
when "010" => reg_src_base(15 downto 8) <= reg_data_in;
-- 3: source address low
when "011" => reg_src_base( 7 downto 0) <= reg_data_in;
-- 4: destination address high
when "100" => reg_dst_base(15 downto 8) <= reg_data_in;
-- 5: destination address low
when "101" => reg_dst_base( 7 downto 0) <= reg_data_in;
-- 6: width
when "110" => reg_width <= reg_data_in xor xorval;
-- 7: height
when "111" => reg_height <= reg_data_in xor xorval;
-- Do nothing.
when others => null;
end case;
end if;
end if;
end process;
-- state machine
process(clk)
begin
if rising_edge(clk) then
case state is
when state_idle =>
if reg_cs = '1' and rs = "000" then
state <= state_wait_for_halt;
end if;
when state_wait_for_halt =>
if halt_ack then
src_address <= reg_src_base;
dst_address <= reg_dst_base;
x_count <= (others => '0');
y_count <= (others => '0');
blt_shift <= (others => '0');
state <= state_src;
end if;
when state_src =>
if blt_ack = '1' then
if ctrl_shift = '0' then
-- unshifted
blt_src_data <= blt_data_in;
else
-- shifted right one pixel
blt_shift <= blt_data_in( 3 downto 0);
blt_src_data <= blt_shift & blt_data_in( 7 downto 4);
end if;
state <= state_dst;
end if;
when state_dst =>
if blt_ack = '1' then
state <= state_src;
if x_count_next < reg_width then
x_count <= x_count_next;
if ctrl_span_src = '1' then
src_address <= src_address + 256;
else
src_address <= src_address + 1;
end if;
if ctrl_span_dst = '1' then
dst_address <= dst_address + 256;
else
dst_address <= dst_address + 1;
end if;
else
x_count <= (others => '0');
y_count <= y_count_next;
if y_count_next = reg_height then
state <= state_idle;
end if;
if ctrl_span_src = '1' then
src_address <= reg_src_base + y_count_next;
else
src_address <= src_address + 1;
end if;
if ctrl_span_dst = '1' then
dst_address <= reg_dst_base + y_count_next;
else
dst_address <= dst_address + 1;
end if;
end if;
end if;
-- Do nothing.
when others => null;
end case;
end if;
end process;
end RTL;