Initial VGA working with the apple one output. YAY!

This commit is contained in:
Alan Garfield 2018-01-31 00:48:47 +11:00
parent 451bff1592
commit 2432225d01
8 changed files with 364 additions and 124 deletions

View File

@ -52,6 +52,7 @@ $(BUILDDIR)/apple1.blif: $(SOURCEDIR)/apple1.v \
$(SOURCEDIR)/uart/uart.v \
$(SOURCEDIR)/uart/async_tx_rx.v \
$(SOURCEDIR)/vga/vga.v \
$(SOURCEDIR)/vga/vram.v \
$(SOURCEDIR)/ps2keyboard/ps2keyboard.v \
$(SOURCEDIR)/boards/ice40hx8k/clock_pll.v \
$(SOURCEDIR)/boards/ice40hx8k/apple1_hx8k.v

View File

@ -1,20 +1,3 @@
000000
000001
000010
000011
000100
000101
000110
000111
001000
001001
001010
001011
001100
001101
001110
001111
010000
100000
100000
100000
@ -78,15 +61,7 @@
100000
100000
100000
000001
010000
010000
001100
000101
100000
001111
001110
000101
100000
100000
100000
@ -118,10 +93,6 @@
100000
100000
100000
010110
000111
000001
100001
100000
100000
100000
@ -158,13 +129,6 @@
100000
100000
100000
110110
110100
110000
011000
110100
111000
110000
100000
100000
100000
@ -198,7 +162,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -238,7 +201,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -278,7 +240,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -318,7 +279,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -358,7 +318,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -398,7 +357,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -438,7 +396,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -478,7 +435,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -518,7 +474,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -558,7 +513,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -598,7 +552,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -638,7 +591,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -678,7 +630,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -718,7 +669,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -758,7 +708,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -798,7 +747,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -838,7 +786,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -878,7 +825,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -918,7 +864,6 @@
100000
100000
100000
101110
100000
100000
100000
@ -954,7 +899,62 @@
100000
100000
100000
000100
000011
000010
000001
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000

View File

@ -36,6 +36,7 @@ module apple1(
input ps2_din, // PS/2 keyboard serial data input
// Outputs to VGA display
input clr_screen_btn, // active high clear screen button
output vga_h_sync, // hozizontal VGA sync pulse
output vga_v_sync, // vertical VGA sync pulse
output reg vga_red, // red VGA signal
@ -57,10 +58,12 @@ module apple1(
// Clocks
wire cpu_clken;
wire blink_clken;
clock my_clock(
.clk25(clk25),
.rst_n(rst_n),
.cpu_clken(cpu_clken)
.cpu_clken(cpu_clken),
.blink_clken(blink_clken)
);
//////////////////////////////////////////////////////////////////////////
@ -87,20 +90,29 @@ module apple1(
.we (we),
.irq_n (1'b1),
.nmi_n (1'b1),
.ready (cpu_clken),
.pc_monitor (pc_monitor)
.ready (cpu_clken)
//.pc_monitor (pc_monitor)
);
//////////////////////////////////////////////////////////////////////////
// Address Decoding
wire ram_cs = (ab[15:13] == 3'b000); // 0x0000 -> 0x1FFF
wire ram_cs = (ab[15:13] == 3'b000); // 0x0000 -> 0x1FFF
wire uart_cs = (ab[15:2] == 14'b11010000000100); // 0xD010 -> 0xD013
wire ps2kb_cs = 1'b0;
//wire uart_cs = (ab[15:1] == 15'b110100000001001); // 0xD012 -> 0xD013
//wire ps2kb_cs = 1'b0;
//wire vga_cs = 1'b0;
//wire ps2kb_cs = (ab[15:1] == 15'b110100000001000); // 0xD010 -> 0xD011
wire basic_cs = (ab[15:12] == 4'b1110); // 0xE000 -> 0xEFFF
wire rom_cs = (ab[15:8] == 8'b11111111); // 0xFF00 -> 0xFFFF
//wire uart_cs = (ab[15:1] == 15'b110100000001001); // 0xD012 -> 0xD013
//wire vga_cs = 1'b0;
//wire uart_cs = (ab[15:1] == 15'b110100000001000); // 0xD010 -> 0xD011
wire ps2kb_cs = 1'b0;
wire vga_cs = (ab[15:1] == 15'b110100000001001); // 0xD012 -> 0xD013
wire basic_cs = (ab[15:12] == 4'b1110); // 0xE000 -> 0xEFFF
wire rom_cs = (ab[15:8] == 8'b11111111); // 0xFF00 -> 0xFFFF
//////////////////////////////////////////////////////////////////////////
// RAM and ROM
@ -152,7 +164,8 @@ module apple1(
.uart_cts(uart_cts),
//.address({1'b1, ab[0]}), // for ps/2
.address(ab[1:0]),
//.address({1'b0, ab[0]}), // for vga
.address(ab[1:0]), // for uart
.w_en(we & uart_cs),
.din(dbo),
.dout(uart_dout)
@ -173,13 +186,21 @@ module apple1(
// VGA Display interface
vga my_vga(
.clk25(clk25),
.in(),
.in_stb(),
.enable(vga_cs & cpu_clken),
.rst(rst),
.vga_h_sync(vga_h_sync),
.vga_v_sync(vga_v_sync),
.vga_red(vga_red),
.vga_grn(vga_grn),
.vga_blu(vga_blu)
.vga_blu(vga_blu),
.address(ab[0]),
.w_en(we & vga_cs),
.din(dbo),
.clr_screen_btn(clr_screen_btn),
.blink_clken(blink_clken),
.debug(pc_monitor)
);
//////////////////////////////////////////////////////////////////////////

View File

@ -66,6 +66,7 @@ module apple1_top(
.uart_rx(uart_rx),
.uart_tx(uart_tx),
.uart_cts(uart_cts),
.clr_screen_btn(button[1]),
.vga_h_sync(vga_h_sync),
.vga_v_sync(vga_v_sync),
.vga_red(vga_red),

View File

@ -28,7 +28,8 @@ module clock(
input rst_n, // active low synchronous reset
// Clock enables
output reg cpu_clken // 1MHz clock enable for the CPU and devices
output reg cpu_clken, // 1MHz clock enable for the CPU and devices
output reg blink_clken // 1Hz clock enable for cursor blink
);
// generate clock enable once every
@ -69,4 +70,20 @@ module clock(
end
`endif
reg [20:0] bclk_div;
always @(posedge clk25)
begin
// note: bclk_div should be compared to
// N-1, where N is the clock divisor
if (cpu_clken)
begin
if ((bclk_div == 500000) || (rst_n == 1'b0))
bclk_div <= 0;
else
bclk_div <= bclk_div + 1'b1;
blink_clken <= (bclk_div[20:0] == 0);
end
end
endmodule

View File

@ -136,7 +136,7 @@ module uart(
`ifdef SIM
if ((din & 8'h7f) >= 32)
$write("%c", din & 8'h7f);
`endif
`endif
uart_tx_byte <= {1'b0, din[6:0]};
uart_tx_stb <= 1;

View File

@ -1,21 +1,42 @@
module vga(
input clk25,
input [6:0] in,
input in_stb,
output vga_h_sync,
output vga_v_sync,
output vga_red,
output vga_grn,
output vga_blu
input clk25, // clock signal
input enable, // clock enable strobe,
input rst, // active high reset signal
output vga_h_sync, // horizontal VGA sync pulse
output vga_v_sync, // vertical VGA sync pulse
output vga_red, // red VGA signal
output vga_grn, // green VGA signal
output vga_blu, // blue VGA signal
input address, // address bus
input w_en, // active high write enable strobe
input [7:0] din, // 8-bit data bas (input)
input clr_screen_btn, // active high clear screen button
input blink_clken, // cursor blink enable strobe
output [15:0] debug
);
reg [5:0] v_ram[0:959] /* synthesis syn_ramstyle = "block_ram" */;
reg [4:0] c_rom[0:447] /* synthesis syn_ramstyle = "block_ram" */;
initial begin
$readmemb("../../roms/vga_vram.bin", v_ram, 0, 959);
$readmemb("../../roms/vga_font.bin", c_rom, 0, 447);
end
reg [9:0] vram_r_addr;
reg [9:0] vram_w_addr;
reg vram_r_en;
reg vram_w_en;
reg [5:0] vram_din;
reg [5:0] vram_dout;
vram my_vram(
.clk(clk25),
.read_addr(vram_r_addr),
.write_addr(vram_w_addr),
.r_en(vram_r_en),
.w_en(vram_w_en),
.din(vram_din),
.dout(vram_dout)
);
// video structure constants
parameter hpixels = 800; // horizontal pixels per line
parameter vlines = 521; // vertical lines per frame
@ -34,6 +55,9 @@ module vga(
reg [3:0] hdot;
reg [4:0] vdot;
reg [5:0] h_cursor;
reg [4:0] v_cursor;
wire vga_h_act;
wire vga_v_act;
@ -42,7 +66,7 @@ module vga(
assign vga_h_sync = (hc < hpulse) ? 0 : 1;
assign vga_v_sync = (vc < vpulse) ? 0 : 1;
// assign vblank = (vc >= vbp && vc < vfp) ? 0:1;
//assign vblank = (vc >= vbp && vc < vfp) ? 0:1;
always @(posedge clk25)
begin
@ -87,6 +111,7 @@ module vga(
end
else
begin
// reset vertical counters
vc <= 0;
vdot <= 0;
vpos <= 0;
@ -99,64 +124,186 @@ module vga(
assign vga_grn = out;
assign vga_blu = out;
always @(posedge clk25)
reg [8:0] cur_chr_offset;
reg [9:0] v_pos_offset;
reg [3:0] v_offset;
reg [2:0] h_offset;
reg blink;
always @(posedge clk25 or posedge rst)
begin
case ({vga_h_act, vga_v_act})
default:
if (rst)
begin
vram_r_addr = 10'd0;
vram_r_en = 1'b0;
end
else
begin
// get the current character from vram and build
// offset to map into character ROM (5x7 font)
if (blink && (hpos == h_cursor && vpos == v_cursor))
cur_chr_offset = 9'd0; // the @ character
else
begin
vram_r_en = 1'b1;
v_pos_offset = (vpos * 40);
vram_r_addr = (v_pos_offset + {4'b0, hpos});
cur_chr_offset = (vram_dout * 7);
//cur_chr_offset <= (v_ram[hpos + (40 * vpos)] * 7);
end
case ({vga_h_act, vga_v_act})
default:
// outside display area
out = 1'b0;
end
2'b11:
2'b11:
begin
// inside display frame
case (vdot)
5'b00000,
5'b00001,
5'b00010,
5'b00011,
5'b10010,
5'b10011:
// blank row for spacing
// we're inside the visible screen display frame
//
// scan doubling is achieved by ignoring bit 0 of both vdot
// and hdot counters, in affect doubling the pixel size
// (each pixel becomes screen pixels)
case (vdot[4:1])
4'b0000,
4'b0001,
4'b1001:
begin
// blank lines for spacing
out = 1'b0;
end
default:
case (hdot)
4'b0000,
4'b0001,
4'b1100,
4'b1101,
4'b1110,
4'b1111:
// blank column for spacing
begin
// work out character rom offset for current line
// taking away 2 from counter to allow for the two
// blank preceding lines
v_offset = (vdot[4:1] - 2);
case (hdot[3:1])
3'b000,
3'b110,
3'b111:
begin
// blank columns for spacing
out = 1'b0;
end
default:
// into character pixels
// TODO: fix this mess
out = c_rom[(v_ram[hpos + (vpos * 40)] * 7) + (vdot[4:1] - 2)][5 - hdot[3:1]];
begin
// work out the character rom offset for the current
// column. We reverse the dot pattern by subtracting
// the column from the number of pixel in the
// character row in rom
h_offset = (5 - hdot[3:1]);
// grab the pixel from the character rom for
// the given screen column and line
out = c_rom[cur_chr_offset + {5'b0, v_offset}][h_offset];
end
endcase
end
endcase
end
endcase
endcase
end
end
// FIXME: This is horrible
reg [5:0] cur_pos;
reg stb;
always @(posedge clk25)
begin
if (in_stb & ~stb)
begin
v_ram[{4'b0, cur_pos}] <= {~in[6], in[4:0]};
stb <= 1;
cur_pos <= cur_pos + 1;
end
reg cls_flag, cls_running;
reg char_seen;
if (~in_stb & stb)
always @(posedge clk25 or posedge rst)
begin
if (rst)
begin
stb <= 0;
blink <= 1'b1;
h_cursor <= 6'd0;
v_cursor <= 5'd0;
char_seen <= 0;
debug <= 0;
cls_running <= 0;
cls_flag <= 1;
end
else
begin
if (cls_flag || clr_screen_btn)
begin
if ((vpos == 0) && (hpos == 0))
cls_running <= 1;
if (cls_running)
begin
// clear the vram using the position pointers
// very similar to the original apple 1 :)
vram_w_addr <= ((vpos * 40) + {4'b0, hpos});
vram_din <= 6'd0;
vram_w_en <= 1;
if ((vpos == 23) && (hpos == 40))
begin
cls_running <= 0;
end
end
else
begin
cls_flag <= 0;
end
end
begin
vram_w_en <= 0;
if (address == 1'b0) // address low == TX register
begin
if (enable & w_en & ~char_seen)
begin
// incoming character
debug <= {8'd0, din};
char_seen <= 1;
case(din)
8'h8D:
begin
// handle carriage return
h_cursor <= 0;
v_cursor <= v_cursor + 1;
end
8'h7F:
// ignore the DDR call to the PIA
h_cursor <= h_cursor + 1;
default:
begin
vram_w_addr <= ((v_cursor * 40) + {4'b0, h_cursor});
vram_din <= {~din[6], din[4:0]};
vram_w_en <= 1;
h_cursor <= h_cursor + 1;
end
endcase
if (h_cursor == 39)
begin
h_cursor <= 0;
v_cursor <= v_cursor + 1;
end
if (v_cursor == 23)
begin
// here we need to add the scroll, probably by moving the
// HEAD of vram up one line
v_cursor <= 0;
end
end
else if(~enable & ~w_en)
char_seen <= 0;
end
end
if (blink_clken)
blink <= ~blink;
end
end
endmodule

53
rtl/vga/vram.v Normal file
View File

@ -0,0 +1,53 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: Video RAM for system
//
// Author.....: Alan Garfield
// Niels A. Moseley
// Date.......: 26-1-2018
//
module vram(
input clk, // clock signal
input [9:0] read_addr, // read address bus
input [9:0] write_addr, // write address bus
input r_en, // active high read enable strobe
input w_en, // active high write enable strobe
input [5:0] din, // 6-bit data bus (input)
output reg [5:0] dout // 6-bit data bus (output)
);
`ifdef SIM
parameter RAM_FILENAME = "../roms/ram.hex";
`else
parameter RAM_FILENAME = "../../roms/vga_vram.bin";
`endif
reg [5:0] ram_data[0:1023];
initial
$readmemb(RAM_FILENAME, ram_data, 0, 1024);
always @(posedge clk)
begin
if (r_en) dout <= ram_data[read_addr];
if (w_en) ram_data[write_addr] <= din;
end
endmodule