mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-06 08:04:41 +00:00
156 lines
4.7 KiB
Verilog
156 lines
4.7 KiB
Verilog
//
|
|
// viking.v
|
|
//
|
|
// Atari ST(E) Viking/SM194
|
|
// http://code.google.com/p/mist-board/
|
|
//
|
|
// Copyright (c) 2013-2015 Till Harbaum <till@harbaum.org>
|
|
//
|
|
// This source file 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.
|
|
//
|
|
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// The viking card does not have its own CPU interface as it is not
|
|
// configurable in any way. It just etches data from ram and displays
|
|
// it on screen.
|
|
|
|
module viking (
|
|
input pclk, // 128 MHz pixel clock
|
|
|
|
// memory interface
|
|
input himem, // use memory behind rom
|
|
input bclk, // 8 MHz bus clock
|
|
input [1:0] bus_cycle, // bus-cycle for bus access sync
|
|
output reg [22:0] addr, // video word address
|
|
output read, // video read cycle
|
|
input [63:0] data, // video data read
|
|
|
|
// VGA output (multiplexed with sm124 output in top level)
|
|
output hs,
|
|
output vs,
|
|
output [3:0] r,
|
|
output [3:0] g,
|
|
output [3:0] b
|
|
);
|
|
|
|
localparam BASE = 23'h600000; // c00000
|
|
localparam BASE_HI = 23'h740000; // e80000
|
|
|
|
// total width must be multiple of 64, so video runs synchronous
|
|
// to main bus
|
|
|
|
// Horizontal timing
|
|
// HBP1 | H | HFP | HS | HBP2
|
|
// -----|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|-----|____|-----
|
|
// HBP1 is used for prefetch
|
|
|
|
// 1280x
|
|
localparam H = 1280;
|
|
localparam HFP = 88;
|
|
localparam HS = 136;
|
|
localparam HBP1 = 32;
|
|
localparam HBP2 = 192;
|
|
|
|
// Vertical timing
|
|
// V | VFP | VS | VBP
|
|
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|-----|____|-----
|
|
|
|
// x1024
|
|
localparam V = 1024;
|
|
localparam VFP = 9;
|
|
localparam VS = 4;
|
|
localparam VBP = 9;
|
|
|
|
assign read = (bus_cycle == 2) && me; // memory enable can directly be used as a ram read signal
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// --------------------------- internal state counter ------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
|
reg [3:0] t;
|
|
always @(posedge pclk) begin
|
|
// 128 Mhz counter synchronous to 8 Mhz clock
|
|
// force counter to pass state 0 exactly after the rising edge of clk_reg (8Mhz)
|
|
if(((t == 4'd15) && ( bclk == 0)) ||
|
|
((t == 4'd0) && ( bclk == 1)) ||
|
|
((t != 4'd15) && (t != 4'd0)))
|
|
t <= t + 4'd1;
|
|
end
|
|
|
|
// create internal bus_cycle signal which is stable on the positive clock
|
|
// edge and extends the previous state by half a 128 Mhz clock cycle
|
|
reg [5:0] bus_cycle_L;
|
|
always @(negedge pclk)
|
|
bus_cycle_L <= { bus_cycle, t };
|
|
|
|
|
|
// --------------- horizontal timing -------------
|
|
reg[10:0] h_cnt; // 0..2047
|
|
assign hs = ((h_cnt >= HBP1+H+HFP) && (h_cnt < HBP1+H+HFP+HS))?0:1;
|
|
always@(posedge pclk) begin
|
|
if(h_cnt==HBP1+H+HFP+HS+HBP2-1) begin
|
|
// make sure a line starts with the "video" bus cyle (0)
|
|
// cpu has cycles 1 and 3
|
|
if(bus_cycle_L == { 2'd1, 4'd15 })
|
|
h_cnt<=0;
|
|
end else
|
|
h_cnt <= h_cnt + 1;
|
|
end
|
|
|
|
// --------------- vertical timing -------------
|
|
reg[10:0] v_cnt; // 0..2047
|
|
assign vs = ((v_cnt >= V+VFP) && (v_cnt < V+VFP+VS))?0:1;
|
|
always@(posedge pclk) begin
|
|
if(h_cnt==HBP1+H+HFP+HS+HBP2-1) begin
|
|
if(v_cnt==V+VFP+VS+VBP-1) v_cnt <= 0;
|
|
else v_cnt <= v_cnt+1;
|
|
end
|
|
end
|
|
|
|
reg [63:0] input_latch;
|
|
reg [63:0] shift_register;
|
|
|
|
// ---------------- memory timing ----------------
|
|
always@(posedge pclk) begin
|
|
// last line on screen
|
|
if(v_cnt == V+VFP+VS+VBP-2)
|
|
addr <= himem?BASE_HI:BASE;
|
|
else if(me && bus_cycle_L == 6'h30) // directly after read
|
|
addr <= addr + 23'd4; // advance 4 words (64 bits)
|
|
|
|
if(me && (bus_cycle_L == 6'h2f))
|
|
input_latch <= data;
|
|
|
|
if(bus_cycle_L == 6'h3f)
|
|
// reorder words 1:2:3:4 -> 4:3:2:1
|
|
shift_register <=
|
|
{ input_latch[15:0], input_latch[31:16],
|
|
input_latch[47:32], input_latch[63:48] };
|
|
else
|
|
shift_register[63:1] <= shift_register[62:0];
|
|
end
|
|
|
|
// memory enable (data is being read from memory)
|
|
wire me = (v_cnt < V)&&(h_cnt < H);
|
|
// display enable (data is being displayed)
|
|
wire de = (v_cnt < V)&&(h_cnt >= HBP1)&&(h_cnt < HBP1+H);
|
|
|
|
wire pix = de?(!shift_register[63]):1'b0;
|
|
|
|
// drive all 12 rgb bits from the data bit
|
|
wire [3:0] pix4 = { pix, pix, pix, pix };
|
|
assign r = pix4;
|
|
assign g = pix4;
|
|
assign b = pix4;
|
|
|
|
endmodule
|