1 |
2 |
alfik |
/*
|
2 |
|
|
* Copyright 2010, Aleksander Osman, alfik@poczta.fm. All rights reserved.
|
3 |
|
|
*
|
4 |
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
5 |
|
|
* permitted provided that the following conditions are met:
|
6 |
|
|
*
|
7 |
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
8 |
|
|
* conditions and the following disclaimer.
|
9 |
|
|
*
|
10 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
11 |
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
12 |
|
|
* provided with the distribution.
|
13 |
|
|
*
|
14 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
15 |
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
16 |
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
17 |
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
18 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
19 |
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
20 |
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
21 |
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
22 |
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23 |
|
|
*/
|
24 |
|
|
|
25 |
|
|
/*! \file
|
26 |
|
|
* \brief OCS system control implementation with WISHBONE slave interface.
|
27 |
|
|
*/
|
28 |
|
|
|
29 |
|
|
/*! \brief \copybrief ocs_control.v
|
30 |
|
|
|
31 |
|
|
List of system control registers:
|
32 |
|
|
\verbatim
|
33 |
|
|
Implemented:
|
34 |
|
|
[DDFSTOP 094 W A Display bitplane data fetch stop
|
35 |
|
|
(horiz. position) write not implemented here]
|
36 |
|
|
DMACON 096 W ADP DMA control write (clear or set) write not implemented here
|
37 |
|
|
|
38 |
|
|
DMACONR *002 R AP DMA control (and blitter status) read
|
39 |
|
|
VPOSR *004 R A( E ) Read vert most signif. bit (and frame flop)
|
40 |
|
|
VHPOSR *006 R A Read vert and horiz. position of beam
|
41 |
|
|
|
42 |
|
|
ADKCON 09E W P Audio, disk, UART control
|
43 |
|
|
|
44 |
|
|
ADKCONR *010 R P Audio, disk control register read
|
45 |
|
|
[POT0DAT *012 R P( E ) Pot counter pair 0 data (vert,horiz) read implemented here]
|
46 |
|
|
|
47 |
|
|
INTENAR *01C R P Interrupt enable bits read
|
48 |
|
|
INTREQR *01E R P Interrupt request bits read
|
49 |
|
|
|
50 |
|
|
[CLXCON 098 W D Collision control write not implemented here]
|
51 |
|
|
INTENA 09A W P Interrupt enable bits (clear or set bits) write not implemented here
|
52 |
|
|
INTREQ 09C W P Interrupt request bits (clear or set bits)
|
53 |
|
|
|
54 |
|
|
Not implemented:
|
55 |
|
|
REFPTR & *028 W A Refresh pointer
|
56 |
|
|
VPOSW *02A W A Write vert most signif. bit (and frame flop)
|
57 |
|
|
VHPOSW *02C W A Write vert and horiz position of beam
|
58 |
|
|
|
59 |
|
|
STREQU & *038 S D Strobe for horiz sync with VB and EQU
|
60 |
|
|
STRVBL & *03A S D Strobe for horiz sync with VB (vert. blank)
|
61 |
|
|
STRHOR & *03C S DP Strobe for horiz sync
|
62 |
|
|
STRLONG & *03E S D( E ) Strobe for identification of long horiz. line.
|
63 |
|
|
|
64 |
|
|
RESERVED 1110X
|
65 |
|
|
RESERVED 1111X
|
66 |
|
|
NO-OP(NULL) 1FE
|
67 |
|
|
\endverbatim
|
68 |
|
|
*/
|
69 |
|
|
module ocs_control(
|
70 |
|
|
//% \name Clock and reset
|
71 |
|
|
//% @{
|
72 |
|
|
input clk_30,
|
73 |
|
|
input reset_n,
|
74 |
|
|
//% @}
|
75 |
|
|
|
76 |
|
|
//% \name WISHBONE slave
|
77 |
|
|
//% @{
|
78 |
|
|
input CYC_I,
|
79 |
|
|
input STB_I,
|
80 |
|
|
input WE_I,
|
81 |
|
|
input [8:2] ADR_I,
|
82 |
|
|
input [3:0] SEL_I,
|
83 |
|
|
input [31:0] slave_DAT_I,
|
84 |
|
|
output reg [31:0] slave_DAT_O,
|
85 |
|
|
output reg ACK_O,
|
86 |
|
|
//% @}
|
87 |
|
|
|
88 |
|
|
//% \name Not aligned register access on a 32-bit WISHBONE bus
|
89 |
|
|
//% @{
|
90 |
|
|
// INTENA write not implemented here
|
91 |
|
|
input na_int_ena_write,
|
92 |
|
|
input [15:0] na_int_ena,
|
93 |
|
|
input [1:0] na_int_ena_sel,
|
94 |
|
|
// DMACON write not implemented here
|
95 |
|
|
input na_dma_con_write,
|
96 |
|
|
input [15:0] na_dma_con,
|
97 |
|
|
input [1:0] na_dma_con_sel,
|
98 |
|
|
// POT0DAT read implemented here
|
99 |
|
|
output na_pot0dat_read,
|
100 |
|
|
input [15:0] na_pot0dat,
|
101 |
|
|
//% @}
|
102 |
|
|
|
103 |
|
|
//% \name Internal OCS ports: beam counters
|
104 |
|
|
//% @{
|
105 |
|
|
output reg line_start,
|
106 |
|
|
output reg line_pre_start,
|
107 |
|
|
output reg [8:0] line_number,
|
108 |
|
|
output reg [8:0] column_number,
|
109 |
|
|
//% @}
|
110 |
|
|
|
111 |
|
|
//% \name Internal OCS ports: clock pulses for CIA and audio
|
112 |
|
|
//% @{
|
113 |
|
|
output reg pulse_709379_hz,
|
114 |
|
|
output pulse_color,
|
115 |
|
|
//% @}
|
116 |
|
|
|
117 |
|
|
//% \name Internal OCS ports: global registers and blitter signals
|
118 |
|
|
//% @{
|
119 |
|
|
output reg [10:0] dma_con,
|
120 |
|
|
output reg [14:0] adk_con,
|
121 |
|
|
|
122 |
|
|
input blitter_busy,
|
123 |
|
|
input blitter_zero,
|
124 |
|
|
//% @}
|
125 |
|
|
|
126 |
|
|
//% \name Internal OCS ports: interrupts
|
127 |
|
|
//% @{
|
128 |
|
|
input blitter_irq,
|
129 |
|
|
input cia_a_irq,
|
130 |
|
|
input cia_b_irq,
|
131 |
|
|
input floppy_syn_irq,
|
132 |
|
|
input floppy_blk_irq,
|
133 |
|
|
input serial_rbf_irq,
|
134 |
|
|
input serial_tbe_irq,
|
135 |
|
|
input [3:0] audio_irq,
|
136 |
|
|
|
137 |
|
|
output [2:0] interrupt
|
138 |
|
|
//% @}
|
139 |
|
|
);
|
140 |
|
|
|
141 |
|
|
assign interrupt =
|
142 |
|
|
(int_ena[14] == 1'b0)? 3'd0 :
|
143 |
|
|
(int_ena[13] == 1'b1 && int_req[13] == 1'b1) ? 3'd6 :
|
144 |
|
|
(int_ena[12] == 1'b1 && int_req[12] == 1'b1) ? 3'd5 :
|
145 |
|
|
(int_ena[11] == 1'b1 && int_req[11] == 1'b1) ? 3'd5 :
|
146 |
|
|
(int_ena[10] == 1'b1 && int_req[10] == 1'b1) ? 3'd4 :
|
147 |
|
|
(int_ena[9] == 1'b1 && int_req[9] == 1'b1) ? 3'd4 :
|
148 |
|
|
(int_ena[8] == 1'b1 && int_req[8] == 1'b1) ? 3'd4 :
|
149 |
|
|
(int_ena[7] == 1'b1 && int_req[7] == 1'b1) ? 3'd4 :
|
150 |
|
|
(int_ena[6] == 1'b1 && int_req[6] == 1'b1) ? 3'd3 :
|
151 |
|
|
(int_ena[5] == 1'b1 && int_req[5] == 1'b1) ? 3'd3 :
|
152 |
|
|
(int_ena[4] == 1'b1 && int_req[4] == 1'b1) ? 3'd3 :
|
153 |
|
|
(int_ena[3] == 1'b1 && int_req[3] == 1'b1) ? 3'd2 :
|
154 |
|
|
(int_ena[2] == 1'b1 && int_req[2] == 1'b1) ? 3'd1 :
|
155 |
|
|
(int_ena[1] == 1'b1 && int_req[1] == 1'b1) ? 3'd1 :
|
156 |
|
|
(int_ena[0] == 1'b1 && int_req[0] == 1'b1) ? 3'd1 :
|
157 |
|
|
3'd0;
|
158 |
|
|
|
159 |
|
|
wire [14:0] new_int_req;
|
160 |
|
|
assign new_int_req = {
|
161 |
|
|
1'b0,
|
162 |
|
|
cia_b_irq,
|
163 |
|
|
floppy_syn_irq,
|
164 |
|
|
serial_rbf_irq,
|
165 |
|
|
audio_irq[3:0],
|
166 |
|
|
blitter_irq,
|
167 |
|
|
(line_start == 1'b1 && line_number == 9'd0),
|
168 |
|
|
1'b0,
|
169 |
|
|
cia_a_irq,
|
170 |
|
|
1'b0,
|
171 |
|
|
floppy_blk_irq,
|
172 |
|
|
serial_tbe_irq
|
173 |
|
|
};
|
174 |
|
|
|
175 |
|
|
reg [14:0] int_ena;
|
176 |
|
|
reg [14:0] int_req;
|
177 |
|
|
reg [10:0] column_counter;
|
178 |
|
|
reg long_frame;
|
179 |
|
|
|
180 |
|
|
assign na_pot0dat_read = (CYC_I == 1'b1 && STB_I == 1'b1 && ACK_O == 1'b0 && WE_I == 1'b0 && { ADR_I, 2'b0 } == 9'h010 && SEL_I[1:0] != 2'b00);
|
181 |
|
|
|
182 |
|
|
always @(posedge clk_30 or negedge reset_n) begin
|
183 |
|
|
if(reset_n == 1'b0) begin
|
184 |
|
|
slave_DAT_O <= 32'd0;
|
185 |
|
|
ACK_O <= 1'b0;
|
186 |
|
|
|
187 |
|
|
line_start <= 1'b0;
|
188 |
|
|
line_pre_start <= 1'b0;
|
189 |
|
|
line_number <= 9'd0;
|
190 |
|
|
column_number <= 9'd0;
|
191 |
|
|
|
192 |
|
|
dma_con <= 11'd0;
|
193 |
|
|
int_req <= 15'd0;
|
194 |
|
|
int_ena <= 15'd0;
|
195 |
|
|
adk_con <= 15'd0;
|
196 |
|
|
column_counter <= 11'd0;
|
197 |
|
|
long_frame <= 1'b0;
|
198 |
|
|
end
|
199 |
|
|
else begin
|
200 |
|
|
if(na_dma_con_write == 1'b1 && na_dma_con_sel[1:0] == 2'b11) begin
|
201 |
|
|
if(na_dma_con[15] == 1'b1) dma_con <= dma_con | na_dma_con[10:0];
|
202 |
|
|
else dma_con <= dma_con & (~na_dma_con[10:0]);
|
203 |
|
|
end
|
204 |
|
|
|
205 |
|
|
if(na_int_ena_write == 1'b1 && na_int_ena_sel[1:0] == 2'b11) begin
|
206 |
|
|
if(na_int_ena[15] == 1'b1) int_ena <= int_ena | na_int_ena[14:0];
|
207 |
|
|
else int_ena <= int_ena & (~na_int_ena[14:0]);
|
208 |
|
|
end
|
209 |
|
|
|
210 |
|
|
if(column_counter == 11'd1919) column_counter <= 11'd0;
|
211 |
|
|
else column_counter <= column_counter + 11'd1;
|
212 |
|
|
|
213 |
|
|
if(column_counter == 11'd1918) line_pre_start <= 1'b1;
|
214 |
|
|
else line_pre_start <= 1'b0;
|
215 |
|
|
|
216 |
|
|
if(column_counter == 11'd1919) line_start <= 1'b1;
|
217 |
|
|
else line_start <= 1'b0;
|
218 |
|
|
|
219 |
|
|
if(column_counter == 11'd1919) begin
|
220 |
|
|
column_number <= 9'd0;
|
221 |
|
|
|
222 |
|
|
if(line_number == 9'd311 && long_frame == 1'b0) begin
|
223 |
|
|
line_number <= 9'd0;
|
224 |
|
|
long_frame <= 1'b1;
|
225 |
|
|
end
|
226 |
|
|
else if(line_number == 9'd312 && long_frame == 1'b1) begin
|
227 |
|
|
line_number <= 9'd0;
|
228 |
|
|
long_frame <= 1'b0;
|
229 |
|
|
end
|
230 |
|
|
else line_number <= line_number + 9'd1;
|
231 |
|
|
end
|
232 |
|
|
else if(column_counter > 11'd600 /*time for 6 bitplain*/) begin
|
233 |
|
|
if(column_counter[0] == 1'b1 && column_number < 9'd452 /*226*2*/) column_number <= column_number + 9'd1;
|
234 |
|
|
end
|
235 |
|
|
|
236 |
|
|
if(ACK_O == 1'b1) ACK_O <= 1'b0;
|
237 |
|
|
|
238 |
|
|
if(CYC_I == 1'b1 && STB_I == 1'b1 && ACK_O == 1'b0) begin
|
239 |
|
|
ACK_O <= 1'b1;
|
240 |
|
|
|
241 |
|
|
// BLTDDAT not used, DMACONR
|
242 |
|
|
if(WE_I == 1'b0 && { ADR_I, 2'b0 } == 9'h000) slave_DAT_O <= { 16'd0, 1'b0, blitter_busy, blitter_zero, 2'b00, dma_con[10:0] };
|
243 |
|
|
// VPOSR, VHPOSR
|
244 |
|
|
else if(WE_I == 1'b0 && { ADR_I, 2'b0 } == 9'h004) slave_DAT_O <= { long_frame, 14'd0, line_number[8:0], column_number[8:1] };
|
245 |
|
|
// INTENAR, INTREQR
|
246 |
|
|
else if(WE_I == 1'b0 && { ADR_I, 2'b0 } == 9'h01C) slave_DAT_O <= { 1'b0, int_ena[14:0], 1'b0, int_req[14:0] };
|
247 |
|
|
// ADKCONR, POT0DAT read implemented here
|
248 |
|
|
else if(WE_I == 1'b0 && { ADR_I, 2'b0 } == 9'h010) slave_DAT_O <= { 1'b0, adk_con[14:0], na_pot0dat };
|
249 |
|
|
// INTREQ, ADKCON
|
250 |
|
|
else if(WE_I == 1'b1 && { ADR_I, 2'b0 } == 9'h09C) begin
|
251 |
|
|
if(SEL_I[1:0] == 2'b11) begin
|
252 |
|
|
if(slave_DAT_I[15] == 1'b1) adk_con <= adk_con | slave_DAT_I[14:0];
|
253 |
|
|
else adk_con <= adk_con & (~slave_DAT_I[14:0]);
|
254 |
|
|
end
|
255 |
|
|
end
|
256 |
|
|
end
|
257 |
|
|
|
258 |
|
|
if(CYC_I == 1'b1 && STB_I == 1'b1 && ACK_O == 1'b0 && WE_I == 1'b1 && { ADR_I, 2'b0 } == 9'h09C && SEL_I[3:2] == 2'b11) begin
|
259 |
|
|
if(slave_DAT_I[31] == 1'b1) int_req <= (int_req | (new_int_req /*& int_ena*/)) | slave_DAT_I[30:16];
|
260 |
|
|
else int_req <= (int_req | (new_int_req /*& int_ena*/)) & (~slave_DAT_I[30:16]);
|
261 |
|
|
end
|
262 |
|
|
else int_req <= (int_req | (new_int_req /*& int_ena*/));
|
263 |
|
|
|
264 |
|
|
end
|
265 |
|
|
end
|
266 |
|
|
|
267 |
|
|
|
268 |
|
|
|
269 |
|
|
|
270 |
|
|
// 1/10 fCPU == 1/20 color clock
|
271 |
|
|
reg [2:0] counter_709379_hz;
|
272 |
|
|
always @(posedge clk_30 or negedge reset_n) begin
|
273 |
|
|
if(reset_n == 1'b0) begin
|
274 |
|
|
counter_709379_hz <= 3'd0;
|
275 |
|
|
pulse_709379_hz <= 1'b0;
|
276 |
|
|
end
|
277 |
|
|
else if(pulse_color == 1'b1) begin
|
278 |
|
|
if(counter_709379_hz == 3'd4) begin
|
279 |
|
|
pulse_709379_hz <= 1'b1;
|
280 |
|
|
counter_709379_hz <= 3'd0;
|
281 |
|
|
end
|
282 |
|
|
else begin
|
283 |
|
|
pulse_709379_hz <= 1'b0;
|
284 |
|
|
counter_709379_hz <= counter_709379_hz + 3'd1;
|
285 |
|
|
end
|
286 |
|
|
end
|
287 |
|
|
else begin
|
288 |
|
|
pulse_709379_hz <= 1'b0;
|
289 |
|
|
end
|
290 |
|
|
end
|
291 |
|
|
|
292 |
|
|
// 1/2 fCPU = 1 color clock
|
293 |
|
|
// 3.546875MHz
|
294 |
|
|
assign pulse_color = (pulse_cpu == 1'b1) && (pulse_counter == 1'b1);
|
295 |
|
|
|
296 |
|
|
reg pulse_counter;
|
297 |
|
|
always @(posedge clk_30 or negedge reset_n) begin
|
298 |
|
|
if(reset_n == 1'b0) pulse_counter <= 1'b0;
|
299 |
|
|
else if(pulse_cpu == 1'b1) pulse_counter <= ~pulse_counter;
|
300 |
|
|
end
|
301 |
|
|
|
302 |
|
|
// fCPU
|
303 |
|
|
// in: 30MHz, out: 7.09375MHz -> 960 - 227
|
304 |
|
|
reg [10:0] counter_cpu;
|
305 |
|
|
reg pulse_cpu;
|
306 |
|
|
always @(posedge clk_30 or negedge reset_n) begin
|
307 |
|
|
if(reset_n == 1'b0) begin
|
308 |
|
|
counter_cpu <= 11'd960;
|
309 |
|
|
pulse_cpu <= 1'b0;
|
310 |
|
|
end
|
311 |
|
|
else if(counter_cpu <= 11'd114) begin
|
312 |
|
|
counter_cpu <= counter_cpu - 11'd227 + 11'd960;
|
313 |
|
|
pulse_cpu <= 1'b1;
|
314 |
|
|
end
|
315 |
|
|
else if(counter_cpu < 11'd227) begin
|
316 |
|
|
counter_cpu <= counter_cpu + 11'd960;
|
317 |
|
|
pulse_cpu <= 1'b0;
|
318 |
|
|
end
|
319 |
|
|
else if(counter_cpu > 11'd960) begin
|
320 |
|
|
counter_cpu <= counter_cpu - 11'd227 - 11'd227;
|
321 |
|
|
pulse_cpu <= 1'b1;
|
322 |
|
|
end
|
323 |
|
|
else begin
|
324 |
|
|
counter_cpu <= counter_cpu - 11'd227;
|
325 |
|
|
pulse_cpu <= 1'b0;
|
326 |
|
|
end
|
327 |
|
|
end
|
328 |
|
|
|
329 |
|
|
endmodule
|
330 |
|
|
|