initial
This commit is contained in:
commit
823db1be62
1167
v/char_rom.v
Normal file
1167
v/char_rom.v
Normal file
File diff suppressed because it is too large
Load Diff
465
v/crt.v
Normal file
465
v/crt.v
Normal file
@ -0,0 +1,465 @@
|
||||
// crt.v
|
||||
|
||||
//
|
||||
// Extremely basic crt ram management
|
||||
//
|
||||
// insert character
|
||||
// check for printable
|
||||
// check for cr,lf
|
||||
// scroll one line
|
||||
// advance start
|
||||
// clear last line
|
||||
// move to begining of line
|
||||
// lf
|
||||
// move to next line
|
||||
// cr
|
||||
// move to begining of line
|
||||
//
|
||||
|
||||
module crt(reset_n, clock,
|
||||
insert, done, data, clearing,
|
||||
ram_addr, ram_data, ram_we_n, ram_wclk, ram_wslot,
|
||||
cursorh, cursorv);
|
||||
|
||||
input reset_n;
|
||||
input clock;
|
||||
input insert;
|
||||
output reg done;
|
||||
output reg clearing;
|
||||
input [7:0] data;
|
||||
output [11:0] ram_addr;
|
||||
output reg [7:0] ram_data;
|
||||
output reg ram_we_n;
|
||||
output [6:0] cursorh;
|
||||
output [5:0] cursorv;
|
||||
output reg ram_wclk;
|
||||
input ram_wslot;
|
||||
|
||||
reg [6:0] cursor_h;
|
||||
reg [5:0] cursor_v;
|
||||
|
||||
// conditions
|
||||
wire eol, scroll;
|
||||
|
||||
// output of state machine
|
||||
reg inc_h, clr_h;
|
||||
reg inc_v, clr_v;
|
||||
reg set_newline;
|
||||
reg set_done;
|
||||
|
||||
// external state
|
||||
reg newline;
|
||||
|
||||
reg [11:0] offset;
|
||||
reg inc_offset, clr_offset;
|
||||
|
||||
reg [3:0] state, nextstate;
|
||||
wire printable;
|
||||
|
||||
reg [2:0] write_delay;
|
||||
|
||||
// offset + v*80 + h
|
||||
// factored into (v*64 + v*16) + h
|
||||
assign ram_addr =
|
||||
//debug /*offset +*/
|
||||
{cursor_v, 6'b0} + {2'b0, cursor_v, 4'b0} +
|
||||
{4'b000, cursor_h};
|
||||
|
||||
assign printable = ((data[6:0] > 7'h20) && (data[6:0] < 7'h7f)) ?
|
||||
1'b1 : 1'b0;
|
||||
|
||||
// one-hot states
|
||||
parameter [3:0]
|
||||
T_RESET = 4'd0,
|
||||
T_CLEARALL = 4'd1,
|
||||
T_CLEARALL_NEXT = 4'd2,
|
||||
T_IDLE = 4'd3,
|
||||
T_PREWRITE = 4'd4,
|
||||
T_WRITE = 4'd5,
|
||||
T_POSTWRITE = 4'd6,
|
||||
T_NEWLINE = 4'd7,
|
||||
T_SCROLL = 4'd8,
|
||||
T_CLEARLAST = 4'd9,
|
||||
T_CLEARLAST_WRITE = 4'd10,
|
||||
T_CLEARLAST_NEXT = 4'd11,
|
||||
T_CLEARLAST_DONE = 4'd12;
|
||||
|
||||
|
||||
// don't change unless you fix the factored *80 in ram_addr
|
||||
parameter [6:0] COLS = 80;
|
||||
parameter [5:0] LINES = 25;
|
||||
|
||||
// manage incrementing offset
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
offset <= 12'b0;
|
||||
else
|
||||
begin
|
||||
if (inc_offset)
|
||||
if (offset == (LINES-1)*COLS)
|
||||
offset <= 12'b0;
|
||||
else
|
||||
offset <= offset + COLS;
|
||||
end
|
||||
|
||||
// manage clearing offset when it rolls over
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
clr_offset <= 0;
|
||||
else
|
||||
begin
|
||||
if (offset >= LINES*COLS)
|
||||
clr_offset <= 1;
|
||||
else
|
||||
clr_offset <= 0;
|
||||
end
|
||||
|
||||
// manage incrementing h
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
cursor_h <= 7'b0;
|
||||
else
|
||||
begin
|
||||
if (inc_h)
|
||||
cursor_h <= cursor_h + 1;
|
||||
else
|
||||
if (clr_h)
|
||||
cursor_h <= 7'b0;
|
||||
end
|
||||
|
||||
// manage incrementing v
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
cursor_v <= 6'b0;
|
||||
else
|
||||
begin
|
||||
if (inc_v)
|
||||
cursor_v <= cursor_v + 1;
|
||||
else
|
||||
if (clr_v)
|
||||
cursor_v <= 6'b0;
|
||||
end
|
||||
|
||||
// manage end of line
|
||||
assign eol = cursor_h == (COLS-1);
|
||||
|
||||
// and end of screen
|
||||
assign scroll = cursor_v == (LINES-1);
|
||||
|
||||
// manage external state
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
begin
|
||||
ram_data <= 8'b0;
|
||||
done <= 1'b0;
|
||||
newline <= 1'b0;
|
||||
write_delay <= 3'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
//debug
|
||||
if (state == T_CLEARALL_NEXT)
|
||||
begin
|
||||
if (cursor_h == 7'd1)
|
||||
ram_data <= 8'h30 + {5'b0, cursor_v[5:3]};
|
||||
else
|
||||
if (cursor_h == 7'd2)
|
||||
ram_data <= 8'h30 + {5'b0, cursor_v[2:0]};
|
||||
else
|
||||
ram_data <= 8'h30 + {1'b0, cursor_h};
|
||||
// ram_data <= 8'h40;
|
||||
// ram_data <= 8'h20 + {1'b0, cursor_h} + { 2'b00, cursor_v};
|
||||
end
|
||||
|
||||
if (state == T_CLEARLAST_WRITE)
|
||||
ram_data <= 8'b0;
|
||||
|
||||
if (state == T_IDLE)
|
||||
begin
|
||||
newline <= 1'b0;
|
||||
done <= 1'b0;
|
||||
if (insert)
|
||||
ram_data <= data;
|
||||
end
|
||||
|
||||
if (state == T_WRITE ||
|
||||
state == T_CLEARLAST_WRITE ||
|
||||
state == T_CLEARALL)
|
||||
write_delay <= write_delay + 1;
|
||||
else
|
||||
write_delay <= 3'd0;
|
||||
|
||||
if (set_newline)
|
||||
newline <= 1'b1;
|
||||
|
||||
if (set_done)
|
||||
done <= 1'b1;
|
||||
end
|
||||
|
||||
// next state
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
state <= T_RESET;
|
||||
else
|
||||
state <= nextstate;
|
||||
|
||||
// insert state machine
|
||||
always @(state or insert or eol or newline or scroll or
|
||||
printable or data or write_delay or ram_wslot)
|
||||
begin
|
||||
inc_h = 1'b0;
|
||||
clr_h = 1'b0;
|
||||
inc_v = 1'b0;
|
||||
clr_v = 1'b0;
|
||||
inc_offset = 1'b0;
|
||||
set_newline = 1'b0;
|
||||
set_done = 1'b0;
|
||||
clearing = 1'b0;
|
||||
ram_we_n = 1'b1;
|
||||
|
||||
case (state) // synthesis full_case
|
||||
T_RESET:
|
||||
begin
|
||||
clearing = 1'b1;
|
||||
nextstate = T_CLEARALL;
|
||||
nextstate = T_IDLE;
|
||||
end
|
||||
|
||||
T_CLEARALL:
|
||||
begin
|
||||
clearing = 1'b1;
|
||||
ram_we_n = 1'b0;
|
||||
ram_wclk = (write_delay == 3'd1) ? 1 : 0;
|
||||
nextstate = (write_delay == 3'd1) ? T_CLEARALL_NEXT : T_CLEARALL;
|
||||
end
|
||||
|
||||
T_CLEARALL_NEXT:
|
||||
begin
|
||||
clearing = 1'b1;
|
||||
nextstate = T_CLEARALL;
|
||||
|
||||
if (eol)
|
||||
begin
|
||||
//debug
|
||||
// if (cursor_v == 15)
|
||||
if (scroll)
|
||||
begin
|
||||
clr_v = 1'b1;
|
||||
clr_h = 1'b1;
|
||||
nextstate = T_IDLE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
clr_h = 1'b1;
|
||||
inc_v = 1'b1;
|
||||
end
|
||||
end
|
||||
else
|
||||
inc_h = 1'b1;
|
||||
end
|
||||
|
||||
T_IDLE:
|
||||
begin
|
||||
clearing = 1'b0;
|
||||
if (insert)
|
||||
begin
|
||||
// if printable character, write to ram
|
||||
if (printable)
|
||||
nextstate = T_PREWRITE;
|
||||
else
|
||||
nextstate = T_POSTWRITE;
|
||||
end
|
||||
else
|
||||
nextstate = T_IDLE;
|
||||
end
|
||||
|
||||
T_PREWRITE:
|
||||
begin
|
||||
// wait until we're in the write slot
|
||||
nextstate = ram_wslot ? T_WRITE : T_PREWRITE;
|
||||
|
||||
if (eol)
|
||||
begin
|
||||
set_newline = 1'b1;
|
||||
clr_h = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
T_WRITE:
|
||||
begin
|
||||
ram_we_n = 1'b0;
|
||||
|
||||
// delay until ram_wclk catches up
|
||||
ram_wclk = (write_delay == 3'd1) ? 1 : 0;
|
||||
nextstate = (write_delay == 3'd1) ? T_POSTWRITE : T_WRITE;
|
||||
end
|
||||
|
||||
T_POSTWRITE:
|
||||
begin
|
||||
set_done = 1'b1;
|
||||
|
||||
// cr
|
||||
if (data[6:0] == 7'h0d)
|
||||
clr_h = 1'b1;
|
||||
else
|
||||
inc_h = 1'b1;
|
||||
|
||||
// eol or lf
|
||||
if (newline || (data[6:0] == 7'h0a))
|
||||
nextstate = T_NEWLINE;
|
||||
else
|
||||
nextstate = T_IDLE;
|
||||
end
|
||||
|
||||
T_NEWLINE:
|
||||
begin
|
||||
clr_h = 1'b1;
|
||||
|
||||
if (scroll)
|
||||
nextstate = T_SCROLL;
|
||||
else
|
||||
begin
|
||||
inc_v = 1'b1;
|
||||
nextstate = T_IDLE;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
T_SCROLL:
|
||||
begin
|
||||
clr_h = 1'b1;
|
||||
inc_offset = 1'b1;
|
||||
nextstate = T_CLEARLAST;
|
||||
end
|
||||
|
||||
T_CLEARLAST:
|
||||
begin
|
||||
nextstate = T_CLEARLAST_WRITE;
|
||||
end
|
||||
|
||||
T_CLEARLAST_WRITE:
|
||||
begin
|
||||
ram_we_n = 1'b0;
|
||||
|
||||
// delay until ram_wclk catches up
|
||||
ram_wclk = (write_delay == 3'd1) ? 1 : 0;
|
||||
nextstate = (write_delay == 3'd1) ?
|
||||
T_CLEARLAST_NEXT : T_CLEARLAST_WRITE;
|
||||
end
|
||||
|
||||
T_CLEARLAST_NEXT:
|
||||
begin
|
||||
inc_h = 1'b1;
|
||||
ram_we_n = 1'b1;
|
||||
nextstate = T_CLEARLAST_WRITE;
|
||||
|
||||
if (eol)
|
||||
nextstate = T_CLEARLAST_DONE;
|
||||
end
|
||||
|
||||
T_CLEARLAST_DONE:
|
||||
begin
|
||||
clr_h = 1'b1;
|
||||
nextstate = T_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign cursorh = cursor_h;
|
||||
assign cursorv = cursor_v;
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
// ------------------
|
||||
|
||||
//`define TEST
|
||||
`ifdef TEST
|
||||
|
||||
`timescale 1ns / 1ns
|
||||
|
||||
module test;
|
||||
|
||||
reg clk, reset_n;
|
||||
reg insert;
|
||||
wire done;
|
||||
reg [7:0] data;
|
||||
integer count;
|
||||
reg free;
|
||||
|
||||
|
||||
wire [11:0] ram_addr;
|
||||
wire [7:0] ram_data;
|
||||
wire ram_we_n;
|
||||
wire [6:0] cursorh;
|
||||
wire [5:0] cursorv;
|
||||
|
||||
crt _crt(reset_n, clk,
|
||||
insert, done, data,
|
||||
ram_addr, ram_data, ram_we_n,
|
||||
cursorh, cursorv);
|
||||
|
||||
// defparam _crt.LINES = 4;
|
||||
// defparam _crt.COLS = 4;
|
||||
|
||||
initial
|
||||
begin
|
||||
$timeformat(-9, 0, "ns", 7);
|
||||
|
||||
$dumpfile("crt.vcd");
|
||||
$dumpvars(0, test._crt);
|
||||
end
|
||||
|
||||
always @(posedge done)
|
||||
if (free)
|
||||
begin
|
||||
data = 8'h41 + count;
|
||||
count = count + 1;
|
||||
if (count == 3)
|
||||
begin
|
||||
count = 0;
|
||||
data = 8'o212;
|
||||
end
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
reset_n = 1;
|
||||
insert = 0;
|
||||
data = 0;
|
||||
count = 0;
|
||||
free = 0;
|
||||
|
||||
#1 reset_n = 0;
|
||||
#100 reset_n = 1;
|
||||
|
||||
#200 begin insert = 1; data = 8'h41; end
|
||||
#80 insert = 0;
|
||||
|
||||
#200 begin insert = 1; data = 8'h42; end
|
||||
#80 insert = 0;
|
||||
|
||||
#200 begin insert = 1; data = 8'h0d; end
|
||||
#80 insert = 0;
|
||||
|
||||
#200 begin insert = 1; data = 8'h0a; end
|
||||
#80 insert = 0;
|
||||
|
||||
#200 begin insert = 1; data = 8'h43; end
|
||||
#80 insert = 0;
|
||||
|
||||
// #50000 $finish;
|
||||
#10000 $finish;
|
||||
end
|
||||
|
||||
always
|
||||
begin
|
||||
#20 clk = 0;
|
||||
#20 clk = 1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifdef TEST
|
||||
|
||||
27
v/fpga.ucf
Normal file
27
v/fpga.ucf
Normal file
@ -0,0 +1,27 @@
|
||||
net clka loc=r8;
|
||||
#net clkb loc=b8;
|
||||
net reset_n loc=e3;
|
||||
|
||||
net ps2_clk loc=f4;
|
||||
net ps2_data loc=e1;
|
||||
|
||||
net vga_blue0 loc=h4;
|
||||
net vga_blue1 loc=k3;
|
||||
net vga_blue2 loc=l5;
|
||||
net vga_green0 loc=h2;
|
||||
net vga_green1 loc=k5;
|
||||
net vga_green2 loc=r1;
|
||||
net vga_red0 loc=j1;
|
||||
net vga_red1 loc=m1;
|
||||
net vga_red2 loc=t2;
|
||||
net vga_hsync_n loc=k4;
|
||||
net vga_vsync_n loc=k1;
|
||||
|
||||
net fpga_din_d0 loc=d14;
|
||||
net fpga_d1 loc=e16;
|
||||
net fpga_d2 loc=f15;
|
||||
net fpga_d3 loc=g16;
|
||||
net fpga_d4 loc=j16;
|
||||
net fpga_d5 loc=m16;
|
||||
net fpga_d6 loc=n16;
|
||||
net fpga_d7 loc=n14;
|
||||
89
v/fpga.v
Normal file
89
v/fpga.v
Normal file
@ -0,0 +1,89 @@
|
||||
// fpga.v
|
||||
|
||||
module fpga (clka,
|
||||
reset_n,
|
||||
ps2_clk,
|
||||
ps2_data,
|
||||
vga_blue0,
|
||||
vga_blue1,
|
||||
vga_blue2,
|
||||
vga_green0,
|
||||
vga_green1,
|
||||
vga_green2,
|
||||
vga_red0,
|
||||
vga_red1,
|
||||
vga_red2,
|
||||
vga_hsync_n,
|
||||
vga_vsync_n,
|
||||
fpga_din_d0,
|
||||
fpga_d1,
|
||||
fpga_d2,
|
||||
fpga_d3,
|
||||
fpga_d4,
|
||||
fpga_d5,
|
||||
fpga_d6,
|
||||
fpga_d7
|
||||
);
|
||||
|
||||
input clka; // 100mhz
|
||||
input reset_n;
|
||||
|
||||
input ps2_clk, ps2_data;
|
||||
|
||||
output vga_blue0, vga_blue1, vga_blue2;
|
||||
output vga_green0, vga_green1, vga_green2;
|
||||
output vga_red0, vga_red1, vga_red2;
|
||||
output vga_hsync_n, vga_vsync_n;
|
||||
|
||||
output fpga_din_d0, fpga_d1, fpga_d2, fpga_d3,
|
||||
fpga_d4, fpga_d5, fpga_d6, fpga_d7;
|
||||
|
||||
//
|
||||
wire hsync, vsync;
|
||||
wire [8:0] pixel;
|
||||
|
||||
//
|
||||
wire [7:0] led_data;
|
||||
|
||||
// signals to create a 25MHz clock from the 100MHz input clock
|
||||
wire clk25;
|
||||
reg [1:0] gray_cnt;
|
||||
|
||||
// clock divider by 4 to for a slower clock
|
||||
// uses grey code for minimized logic
|
||||
always @(posedge clka or negedge reset_n)
|
||||
if (~reset_n)
|
||||
gray_cnt <= 2'b00;
|
||||
else
|
||||
case (gray_cnt)
|
||||
2'b00: gray_cnt <= 2'b01;
|
||||
2'b01: gray_cnt <= 2'b11;
|
||||
2'b11: gray_cnt <= 2'b10;
|
||||
2'b10: gray_cnt <= 2'b00;
|
||||
default: gray_cnt <= 2'b00;
|
||||
endcase
|
||||
|
||||
// assign 25mhz clock
|
||||
assign clk25 = gray_cnt[1];
|
||||
|
||||
vga vga (.reset_n(reset_n),
|
||||
.clock(clk25),
|
||||
.pixel(pixel),
|
||||
.blank_n(),
|
||||
.hsync(hsync),
|
||||
.vsync(vsync),
|
||||
.ps2_clk(ps2_clk),
|
||||
.ps2_data(ps2_data),
|
||||
.led_data(led_data));
|
||||
|
||||
assign vga_hsync_n = ~hsync;
|
||||
assign vga_vsync_n = ~vsync;
|
||||
|
||||
assign {vga_red2, vga_red1, vga_red0,
|
||||
vga_green2, vga_green1, vga_green0,
|
||||
vga_blue2, vga_blue1, vga_blue0} = pixel;
|
||||
|
||||
assign {fpga_din_d0, fpga_d1, fpga_d2, fpga_d3,
|
||||
fpga_d4, fpga_d5, fpga_d6, fpga_d7} = led_data;
|
||||
|
||||
endmodule // fpga
|
||||
27
v/fpga2.ucf
Normal file
27
v/fpga2.ucf
Normal file
@ -0,0 +1,27 @@
|
||||
net clka loc=r8;
|
||||
#net clkb loc=b8;
|
||||
net reset_n loc=e3;
|
||||
|
||||
net ps2_clk loc=f4;
|
||||
net ps2_data loc=e1;
|
||||
|
||||
#net vga_blue0 loc=h4;
|
||||
#net vga_blue1 loc=k3;
|
||||
#net vga_blue2 loc=l5;
|
||||
#net vga_green0 loc=h2;
|
||||
#net vga_green1 loc=k5;
|
||||
#net vga_green2 loc=r1;
|
||||
#net vga_red0 loc=j1;
|
||||
#net vga_red1 loc=m1;
|
||||
#net vga_red2 loc=t2;
|
||||
#net vga_hsync_n loc=k4;
|
||||
#net vga_vsync_n loc=k1;
|
||||
|
||||
net fpga_din_d0 loc=d14;
|
||||
net fpga_d1 loc=e16;
|
||||
net fpga_d2 loc=f15;
|
||||
net fpga_d3 loc=g16;
|
||||
net fpga_d4 loc=j16;
|
||||
net fpga_d5 loc=m16;
|
||||
net fpga_d6 loc=n16;
|
||||
net fpga_d7 loc=n14;
|
||||
100
v/fpga2.v
Normal file
100
v/fpga2.v
Normal file
@ -0,0 +1,100 @@
|
||||
// fpga2.v
|
||||
|
||||
// simple test module for ps2 module
|
||||
|
||||
module fpga (clka,
|
||||
clkb,
|
||||
reset_n,
|
||||
ps2_clk,
|
||||
ps2_data,
|
||||
vga_blue0,
|
||||
vga_blue1,
|
||||
vga_blue2,
|
||||
vga_green0,
|
||||
vga_green1,
|
||||
vga_green2,
|
||||
vga_red0,
|
||||
vga_red1,
|
||||
vga_red2,
|
||||
vga_hsync_n,
|
||||
vga_vsync_n,
|
||||
fpga_din_d0,
|
||||
fpga_d1,
|
||||
fpga_d2,
|
||||
fpga_d3,
|
||||
fpga_d4,
|
||||
fpga_d5,
|
||||
fpga_d6,
|
||||
fpga_d7
|
||||
);
|
||||
|
||||
input clka; // 100mhz
|
||||
input clkb; // 50mhz
|
||||
input reset_n;
|
||||
|
||||
input ps2_clk, ps2_data;
|
||||
|
||||
output vga_blue0, vga_blue1, vga_blue2;
|
||||
output vga_green0, vga_green1, vga_green2;
|
||||
output vga_red0, vga_red1, vga_red2;
|
||||
output vga_hsync_n, vga_vsync_n;
|
||||
|
||||
output fpga_din_d0, fpga_d1, fpga_d2, fpga_d3,
|
||||
fpga_d4, fpga_d5, fpga_d6, fpga_d7;
|
||||
|
||||
//
|
||||
wire hsync, vsync;
|
||||
wire [8:0] pixel;
|
||||
|
||||
// signals to create a 25MHz clock from the 100MHz input clock
|
||||
wire clk25;
|
||||
reg [1:0] gray_cnt;
|
||||
|
||||
// clock divider by 4 to for a slower clock
|
||||
// uses grey code for minimized logic
|
||||
always @(posedge clka or negedge reset_n)
|
||||
if (~reset_n)
|
||||
gray_cnt <= 2'b00;
|
||||
else
|
||||
case (gray_cnt)
|
||||
2'b00: gray_cnt <= 2'b01;
|
||||
2'b01: gray_cnt <= 2'b11;
|
||||
2'b11: gray_cnt <= 2'b10;
|
||||
2'b10: gray_cnt <= 2'b00;
|
||||
default: gray_cnt <= 2'b00;
|
||||
endcase
|
||||
|
||||
// assign the clock that this entity runs off
|
||||
assign clk25 = gray_cnt[1];
|
||||
|
||||
wire kb_rdy;
|
||||
wire kb_bsy;
|
||||
wire [7:0] kb_scancode;
|
||||
|
||||
wire [7:0] data;
|
||||
|
||||
ps2 ps2(.clk(clk25),
|
||||
.rst_n(reset_n),
|
||||
.ps2_clk(ps2_clk),
|
||||
.ps2_data(ps2_data),
|
||||
.scancode(kb_scancode),
|
||||
.parity(),
|
||||
.busy(kb_bsy),
|
||||
.rdy(kb_rdy),
|
||||
.error());
|
||||
|
||||
//xc2s200-5fg256
|
||||
|
||||
reg rdy;
|
||||
|
||||
always @(posedge kb_rdy or negedge reset_n)
|
||||
if (~reset_n)
|
||||
rdy <= 0;
|
||||
else
|
||||
rdy <= ~rdy;
|
||||
|
||||
assign {fpga_din_d0, fpga_d1, fpga_d2, fpga_d3,
|
||||
fpga_d4, fpga_d5, fpga_d6, fpga_d7} =
|
||||
{ kb_scancode[6], rdy, kb_scancode[5:0] };
|
||||
|
||||
endmodule // fpga
|
||||
109
v/fpga3.v
Normal file
109
v/fpga3.v
Normal file
@ -0,0 +1,109 @@
|
||||
// fpga2.v
|
||||
|
||||
// simple test module for scancode module
|
||||
|
||||
module fpga (clka,
|
||||
clkb,
|
||||
reset_n,
|
||||
ps2_clk,
|
||||
ps2_data,
|
||||
vga_blue0,
|
||||
vga_blue1,
|
||||
vga_blue2,
|
||||
vga_green0,
|
||||
vga_green1,
|
||||
vga_green2,
|
||||
vga_red0,
|
||||
vga_red1,
|
||||
vga_red2,
|
||||
vga_hsync_n,
|
||||
vga_vsync_n,
|
||||
fpga_din_d0,
|
||||
fpga_d1,
|
||||
fpga_d2,
|
||||
fpga_d3,
|
||||
fpga_d4,
|
||||
fpga_d5,
|
||||
fpga_d6,
|
||||
fpga_d7
|
||||
);
|
||||
|
||||
input clka; // 100mhz
|
||||
input clkb; // 50mhz
|
||||
input reset_n;
|
||||
|
||||
input ps2_clk, ps2_data;
|
||||
|
||||
output vga_blue0, vga_blue1, vga_blue2;
|
||||
output vga_green0, vga_green1, vga_green2;
|
||||
output vga_red0, vga_red1, vga_red2;
|
||||
output vga_hsync_n, vga_vsync_n;
|
||||
|
||||
output fpga_din_d0, fpga_d1, fpga_d2, fpga_d3,
|
||||
fpga_d4, fpga_d5, fpga_d6, fpga_d7;
|
||||
|
||||
//
|
||||
wire hsync, vsync;
|
||||
wire [8:0] pixel;
|
||||
|
||||
// signals to create a 25MHz clock from the 100MHz input clock
|
||||
wire clk25;
|
||||
reg [1:0] gray_cnt;
|
||||
|
||||
// clock divider by 4 to for a slower clock
|
||||
// uses grey code for minimized logic
|
||||
always @(posedge clka or negedge reset_n)
|
||||
if (~reset_n)
|
||||
gray_cnt <= 2'b00;
|
||||
else
|
||||
case (gray_cnt)
|
||||
2'b00: gray_cnt <= 2'b01;
|
||||
2'b01: gray_cnt <= 2'b11;
|
||||
2'b11: gray_cnt <= 2'b10;
|
||||
2'b10: gray_cnt <= 2'b00;
|
||||
default: gray_cnt <= 2'b00;
|
||||
endcase
|
||||
|
||||
// assign the clock that this entity runs off
|
||||
assign clk25 = gray_cnt[1];
|
||||
|
||||
reg [7:0] kb_scancode;
|
||||
reg kb_rdy;
|
||||
|
||||
wire [7:0] kb_ascii;
|
||||
wire kb_release;
|
||||
wire kb_ascii_rdy;
|
||||
|
||||
scancode_convert scancode_convert(.clock(clk25),
|
||||
.reset_n(reset_n),
|
||||
.scancode(kb_scancode),
|
||||
.ascii(kb_ascii),
|
||||
.key_up(kb_release),
|
||||
.strobe_in(kb_rdy),
|
||||
.strobe_out(kb_ascii_rdy));
|
||||
|
||||
//xc2s200-5fg256
|
||||
|
||||
reg [2:0] clk8;
|
||||
always @(posedge clk25 or negedge reset_n)
|
||||
if (~reset_n)
|
||||
clk8 = 3'b111;
|
||||
else
|
||||
clk8 = clk8 + 1;
|
||||
|
||||
always @(posedge clk25 or negedge reset_n)
|
||||
if (~reset_n)
|
||||
kb_scancode = 0;
|
||||
else
|
||||
if (clk8 == 8'b111)
|
||||
begin
|
||||
kb_scancode = kb_scancode + 1;
|
||||
kb_rdy = 1;
|
||||
end
|
||||
else
|
||||
kb_rdy = 0;
|
||||
|
||||
assign {fpga_din_d0, fpga_d1, fpga_d2, fpga_d3,
|
||||
fpga_d4, fpga_d5, fpga_d6, fpga_d7} = kb_ascii;
|
||||
|
||||
endmodule // fpga
|
||||
208
v/programramdac.v
Normal file
208
v/programramdac.v
Normal file
@ -0,0 +1,208 @@
|
||||
// programramdac.v
|
||||
|
||||
// hardcoded values for initialising the RAMDAC
|
||||
module dac_data(addr, o);
|
||||
|
||||
input[2:0] addr;
|
||||
output o;
|
||||
reg [7:0] o;
|
||||
|
||||
// hard code initial control register programming values
|
||||
// DAC(76543210)
|
||||
always @(addr)
|
||||
case (addr)
|
||||
3'd0: o <= 8'b10000001; // Cmd reg A, high colour dual edged mode
|
||||
3'd1: o <= 8'b00000000; // Pallette address reg gets $00
|
||||
3'd2: o <= 8'b11111111; // Read mask reg gets $FF
|
||||
3'd3: o <= 8'b00000010; // Pallette address reg gets $02
|
||||
3'd4: o <= 8'b00000010; // Command reg B gets $02
|
||||
3'd5: o <= 8'b00000000; // Pallette address reg gets $00
|
||||
endcase // case(addr)
|
||||
endmodule
|
||||
|
||||
module dac_rs(addr, o);
|
||||
|
||||
input[2:0] addr;
|
||||
output o;
|
||||
reg [2:0] o;
|
||||
|
||||
// RS(210)
|
||||
always @(addr)
|
||||
case (addr)
|
||||
3'd0: o <= 3'b110; // RS gets Command reg A
|
||||
3'd1: o <= 3'b000; // RS gets Pallette address reg
|
||||
3'd2: o <= 3'b010; // RS gets Read mask reg
|
||||
3'd3: o <= 3'b000; // RS gets Pallette address reg
|
||||
3'd4: o <= 3'b010; // RS gets Command reg B
|
||||
3'd5: o <= 3'b000; // RS gets Pallette address reg
|
||||
endcase
|
||||
endmodule
|
||||
|
||||
module programramdac(rstn, clk, start, done, WRn, RDn, RS, data);
|
||||
|
||||
input rstn;
|
||||
input clk;
|
||||
input start; // start signal
|
||||
output done;
|
||||
output WRn; // write line to ramdac
|
||||
output RDn; // read line ot ramdac
|
||||
input [2:0] RS; // register select lines to ramdac
|
||||
inout [7:0] data; // data lines to ramdac
|
||||
|
||||
reg done, WRn;
|
||||
|
||||
// FSM states for the main mealy FSM
|
||||
parameter [2:0]
|
||||
stIdle = 3'd0,
|
||||
stWrite = 3'd1,
|
||||
stWrCycle = 3'd2,
|
||||
stNextWrite = 3'd3;
|
||||
|
||||
reg [2:0] presState, nextState;
|
||||
|
||||
// initCnt controls write state
|
||||
reg [2:0] initCnt;
|
||||
reg increment;
|
||||
|
||||
// signals to create a 12.5MHz clock from the 50MHz input clock
|
||||
wire divclk;
|
||||
reg [1:0] gray_cnt;
|
||||
|
||||
// create signals so the data and RS lines can be used as tristate
|
||||
// buffers. this is important as they share lines with the ethernet PHY
|
||||
reg [7:0] prgData;
|
||||
reg [2:0] prgRS;
|
||||
reg latchData;
|
||||
reg latchRS;
|
||||
|
||||
wire [7:0] theData;
|
||||
wire [2:0] theRs;
|
||||
|
||||
|
||||
// data and register select
|
||||
dac_data arraydac(.addr(initCnt), .o(theData));
|
||||
dac_rs arrayrs(.addr(initCnt), .o(theRS));
|
||||
|
||||
// clock divider by 4 to for a slower clock to avoid timing violations
|
||||
// uses grey code for minimized logic
|
||||
always @(posedge clk or rstn)
|
||||
if (~rstn)
|
||||
gray_cnt <= 2'b00;
|
||||
else
|
||||
case (gray_cnt)
|
||||
2'b00: gray_cnt <= 2'b01;
|
||||
2'b01: gray_cnt <= 2'b11;
|
||||
2'b11: gray_cnt <= 2'b10;
|
||||
2'b10: gray_cnt <= 2'b00;
|
||||
default: gray_cnt <= 2'b00;
|
||||
endcase
|
||||
|
||||
// assign the clock that this entity runs off
|
||||
assign divclk = gray_cnt[1];
|
||||
|
||||
// read isn't needed, tie high
|
||||
assign RDn = 1;
|
||||
|
||||
// main clocked process
|
||||
always @(posedge divclk or rstn)
|
||||
if (~rstn)
|
||||
begin
|
||||
presState <= stIdle;
|
||||
initCnt <= 0;
|
||||
end
|
||||
else
|
||||
if (divclk == 1)
|
||||
begin
|
||||
presState <= nextState;
|
||||
if (increment)
|
||||
if (initCnt < 5)
|
||||
initCnt <= initCnt + 1;
|
||||
else
|
||||
initCnt <= 0;
|
||||
end
|
||||
|
||||
// Main FSM process
|
||||
always @(presState, start, initCnt)
|
||||
begin
|
||||
// default signals and outputs for each FSM state
|
||||
// note that the latch data and rs signals are defaulted to 1,
|
||||
// so are only 0 in the idle state
|
||||
WRn <= 1;
|
||||
increment <= 0;
|
||||
prgData <= 0;
|
||||
prgRS <= 3'b001;
|
||||
latchData <= 1;
|
||||
latchRS <= 1;
|
||||
done <= 0;
|
||||
|
||||
case (presState)
|
||||
stIdle:
|
||||
begin
|
||||
// wait for start signal from another process
|
||||
if (start)
|
||||
begin
|
||||
nextState <= stWrite;
|
||||
// setup for the first write to the RAMDAC for use
|
||||
// by setting the register select lines and
|
||||
// the data lines
|
||||
prgRS <= theRS;
|
||||
prgData <= theData;
|
||||
end
|
||||
else
|
||||
begin
|
||||
nextState <= stIdle;
|
||||
latchData <= 0;
|
||||
latchRS <=0;
|
||||
end
|
||||
end
|
||||
|
||||
stWrite:
|
||||
begin
|
||||
// hold the register select and data lines for
|
||||
// the write cycle and set the active low write signal
|
||||
nextState <= stWrCycle;
|
||||
prgRS <= theRS;
|
||||
prgData <= theData;
|
||||
WRn <= 0;
|
||||
end
|
||||
|
||||
stWrCycle:
|
||||
begin
|
||||
// continue if all 5 registers have been programmed
|
||||
if (initCnt == 5)
|
||||
begin
|
||||
nextState <= stIdle;
|
||||
done <= 1;
|
||||
end
|
||||
else
|
||||
// continue writing to the registers
|
||||
nextState <= stNextWrite;
|
||||
|
||||
// hold the data to be sure the hold times aren't violated
|
||||
prgRS <= theRS;
|
||||
prgData <= theData;
|
||||
|
||||
// increment initCnt to program the next register
|
||||
increment <= 1;
|
||||
end
|
||||
|
||||
stNextWrite:
|
||||
begin
|
||||
nextState <= stWrite;
|
||||
// setup for the next write cycle
|
||||
prgRS <= theRS;
|
||||
prgData <= theData;
|
||||
end
|
||||
|
||||
endcase;
|
||||
|
||||
// assign data and RS prgData and prgRS respectively when they
|
||||
// need to be latched otherwise keep them at high impedance
|
||||
// to create a tri state buffer
|
||||
end // always @ (presState, start, initCnt)
|
||||
|
||||
assign data = latchData ? prgData : 8'bz;
|
||||
assign RS = latchRS ? prgRS : 3'bz;
|
||||
|
||||
endmodule
|
||||
|
||||
160
v/ps2.v
Normal file
160
v/ps2.v
Normal file
@ -0,0 +1,160 @@
|
||||
// ps2.v
|
||||
//
|
||||
// Monitor the serial datastream and clock from a PS/2 keyboard
|
||||
// and output a scancode for any key that is pressed.
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// The clock from the PS/2 keyboard is used directly. It is sampled at
|
||||
// the frequency of the main clock input; edges are extracted from the
|
||||
// sample clock. The main clock must be substantially faster than
|
||||
// the 10 KHz PS/2 clock - 200 KHz or more.
|
||||
//
|
||||
// The scancode is only valid when the ready signal is high. The scancode
|
||||
// should be registered by an external circuit on the first clock edge
|
||||
// after the ready signal goes high.
|
||||
//
|
||||
// The ready signal pulses only after the key is released.
|
||||
//
|
||||
// The error flag is set whenever the PS/2 clock stops pulsing and the
|
||||
// PS/2 clock is either at a low level or less than 11 bits of serial
|
||||
// data have been received (start + 8 data + parity + stop).
|
||||
//
|
||||
|
||||
module ps2(clk, // main clock
|
||||
rst_n, // asynchronous reset
|
||||
ps2_clk, // clock from keyboard
|
||||
ps2_data, // data from keyboard
|
||||
scancode, // key scancode
|
||||
parity, // parity bit for scancode
|
||||
busy, // busy receiving scancode
|
||||
rdy, // scancode ready pulse
|
||||
error // error receiving scancode
|
||||
);
|
||||
|
||||
input clk, rst_n;
|
||||
input ps2_clk;
|
||||
input ps2_data;
|
||||
output [7:0] scancode;
|
||||
output parity;
|
||||
output busy;
|
||||
output rdy;
|
||||
output error;
|
||||
|
||||
|
||||
parameter FREQ = 25000; // frequency of the main clock (KHz)
|
||||
parameter PS2_FREQ = 10; // keyboard clock frequency (KHz)
|
||||
parameter TIMEOUT = FREQ / PS2_FREQ; // ps2_clk quiet timeout
|
||||
parameter [7:0] KEY_RELEASE = 8'b11110000; // sent when key is rel'd
|
||||
|
||||
reg [13:0] timer_r; // time since last PS/2 clock edge
|
||||
wire [13:0] timer_x;
|
||||
|
||||
reg [3:0] bitcnt_r; // number of received scancode bits
|
||||
wire [3:0] bitcnt_x;
|
||||
|
||||
reg [4:0] ps2_clk_r; // PS/2 clock sync / edge detect
|
||||
wire [4:0] ps2_clk_x;
|
||||
|
||||
reg [9:0] sc_r; // scancode shift register
|
||||
wire [9:0] sc_x;
|
||||
|
||||
reg keyrel_r; // set when key release received
|
||||
wire keyrel_x;
|
||||
|
||||
reg rdy_r; // set when scancode ready
|
||||
wire rdy_x;
|
||||
|
||||
reg error_r; // set when an error occurs
|
||||
wire error_x;
|
||||
|
||||
wire ps2_clk_fall_edge; // on falling edge of PS/2 clock
|
||||
wire ps2_clk_rise_edge; // on rising edge of PS/2 clock
|
||||
wire ps2_clk_edge; // on either edge of PS/2 clock
|
||||
wire ps2_clk_quiet; // when no edges on PS/2 clock for TIMEOUT
|
||||
wire scancode_rdy; // when scancode has been received
|
||||
|
||||
|
||||
// shift the level on the PS/2 clock into a shift register
|
||||
assign ps2_clk_x = {ps2_clk_r[3:0], ps2_clk};
|
||||
|
||||
// look at the PS/2 clock levels stored in the shift register
|
||||
// and find rising or falling edges
|
||||
assign ps2_clk_fall_edge = ps2_clk_r[4:1] == 4'b1100;
|
||||
assign ps2_clk_rise_edge = ps2_clk_r[4:1] == 4'b0011;
|
||||
assign ps2_clk_edge = ps2_clk_fall_edge || ps2_clk_rise_edge;
|
||||
|
||||
// shift the keyboard scancode into the shift register on the
|
||||
// falling edge of the PS/2 clock
|
||||
assign sc_x = ps2_clk_fall_edge ? {ps2_data, sc_r[9:1]} : sc_r;
|
||||
|
||||
// clear the timer right after a PS/2 clock edge and
|
||||
// then keep incrementing it until the next edge
|
||||
assign timer_x = ps2_clk_edge ? 0 : (timer_r + 1);
|
||||
|
||||
// indicate when the PS/2 clock has stopped pulsing and
|
||||
// is at a high level.
|
||||
assign ps2_clk_quiet = timer_r == TIMEOUT && ps2_clk_r[1];
|
||||
|
||||
// increment bit counter on each falling edge of the PS/2 clock.
|
||||
// reset the bit counter if the PS/2 clock stops pulsing or
|
||||
// if there was an error receiving the scancode.
|
||||
// otherwise, keep the bit counter unchanged.
|
||||
assign bitcnt_x = ps2_clk_fall_edge ? (bitcnt_r + 1) :
|
||||
(ps2_clk_quiet || error_r) ? 0 :
|
||||
bitcnt_r;
|
||||
|
||||
// a scancode has been received if the bit counter is 11 and
|
||||
// the PS/2 clock has stopped pulsing
|
||||
assign scancode_rdy = bitcnt_r == 4'd11 && ps2_clk_quiet;
|
||||
|
||||
/*
|
||||
// look for the scancode sent when the key is released
|
||||
assign keyrel_x = (sc_r[7:0] == KEY_RELEASE && scancode_rdy) ? 1 :
|
||||
(rdy_r || error_r) ? 0 :
|
||||
keyrel_r;
|
||||
|
||||
// the scancode for the pressed key arrives after receiving
|
||||
// the key-release scancode
|
||||
assign rdy_x = keyrel_r && scancode_rdy;
|
||||
*/
|
||||
assign rdy_x = scancode_rdy;
|
||||
|
||||
// indicate an error if the clock is low for too long or
|
||||
// if it stops pulsing in the middle of a scancode
|
||||
assign error_x = (timer_r == TIMEOUT && ps2_clk_r[1] == 0) ||
|
||||
(ps2_clk_quiet && bitcnt_r != 4'd11 && bitcnt_r != 4'd0) ?
|
||||
1 : error_r;
|
||||
|
||||
// outputs
|
||||
assign scancode = sc_r[7:0]; // scancode
|
||||
assign parity = sc_r[8]; // parity bit for the scancode
|
||||
assign busy = bitcnt_r != 4'd0; // busy when recv'ing scancode
|
||||
assign rdy = rdy_r; // scancode ready flag
|
||||
assign error = error_r; // error flag
|
||||
|
||||
// update the various registers
|
||||
always @(posedge clk or negedge rst_n)
|
||||
if (~rst_n)
|
||||
begin
|
||||
ps2_clk_r <= 5'b11111; // assume PS/2 clock has been high
|
||||
sc_r <= 0;
|
||||
keyrel_r <= 0;
|
||||
rdy_r <= 0;
|
||||
timer_r <= 0;
|
||||
bitcnt_r <= 0;
|
||||
error_r <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ps2_clk_r <= ps2_clk_x;
|
||||
sc_r <= sc_x;
|
||||
keyrel_r <= keyrel_x;
|
||||
rdy_r <= rdy_x;
|
||||
timer_r <= timer_x;
|
||||
bitcnt_r <= bitcnt_x;
|
||||
error_r <= error_x;
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
101
v/run.v
Normal file
101
v/run.v
Normal file
@ -0,0 +1,101 @@
|
||||
// run.v
|
||||
|
||||
`include "vga.v"
|
||||
|
||||
`timescale 1ns / 1ns
|
||||
|
||||
module test;
|
||||
|
||||
reg clk, reset_n;
|
||||
|
||||
wire [8:0] pixel;
|
||||
wire blank_n;
|
||||
wire hsync;
|
||||
wire vsync;
|
||||
reg ps2_clk;
|
||||
reg ps2_data;
|
||||
wire [7:0] led_data;
|
||||
|
||||
vga vga(.reset_n(reset_n),
|
||||
.clock(clk25),
|
||||
.pixel(pixel),
|
||||
.blank_n(blank_n),
|
||||
.hsync(hsync),
|
||||
.vsync(vsync),
|
||||
.ps2_clk(ps2_clk),
|
||||
.ps2_data(ps2_data),
|
||||
.led_data(led_data));
|
||||
|
||||
// clock divider by 4 to for a slower clock
|
||||
// uses grey code for minimized logic
|
||||
reg [1:0] gray_cnt;
|
||||
|
||||
always @(posedge clk or negedge reset_n)
|
||||
if (~reset_n)
|
||||
gray_cnt <= 2'b00;
|
||||
else
|
||||
case (gray_cnt)
|
||||
2'b00: gray_cnt <= 2'b01;
|
||||
2'b01: gray_cnt <= 2'b11;
|
||||
2'b11: gray_cnt <= 2'b10;
|
||||
2'b10: gray_cnt <= 2'b00;
|
||||
default: gray_cnt <= 2'b00;
|
||||
endcase
|
||||
|
||||
wire clk25;
|
||||
assign clk25 = gray_cnt[1];
|
||||
|
||||
initial
|
||||
begin
|
||||
$timeformat(-9, 0, "ns", 7);
|
||||
|
||||
$dumpfile("vga.vcd");
|
||||
// $dumpvars(0, test.vga);
|
||||
$dumpvars(0, test);
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
reset_n = 1;
|
||||
ps2_clk <= 0;
|
||||
ps2_data <= 0;
|
||||
|
||||
#1 begin
|
||||
reset_n = 0;
|
||||
end
|
||||
|
||||
#100 begin
|
||||
reset_n = 1;
|
||||
end
|
||||
|
||||
#400000
|
||||
begin
|
||||
vga.scancode_convert.strobe_out = 1;
|
||||
vga.crt_data = 8'h41;
|
||||
vga.scancode_convert.ascii = 8'h41;
|
||||
end
|
||||
#200 vga.scancode_convert.strobe_out = 0;
|
||||
|
||||
#400
|
||||
begin
|
||||
vga.scancode_convert.strobe_out = 1;
|
||||
vga.crt_data = 8'h42;
|
||||
vga.scancode_convert.ascii = 8'h42;
|
||||
end
|
||||
#200 vga.scancode_convert.strobe_out = 0;
|
||||
|
||||
// #100000 $finish;
|
||||
// #500000 $finish;
|
||||
// #1000000 $finish;
|
||||
#20000000 $finish;
|
||||
end
|
||||
|
||||
always
|
||||
begin
|
||||
#5 clk = 0;
|
||||
#5 clk = 1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
372
v/scancode.v
Normal file
372
v/scancode.v
Normal file
@ -0,0 +1,372 @@
|
||||
// scancode.v
|
||||
|
||||
//
|
||||
// simple AT style keyboard scancode to ascii convertion
|
||||
// keeps track of shift, capslock and control keys
|
||||
// inputs scancodes and outputs ascii
|
||||
//
|
||||
|
||||
`include "scancode_rom.v"
|
||||
|
||||
module scancode_convert(clock,
|
||||
reset_n,
|
||||
scancode,
|
||||
ascii,
|
||||
key_up,
|
||||
strobe_in,
|
||||
strobe_out);
|
||||
|
||||
input clock;
|
||||
input reset_n;
|
||||
input [7:0] scancode;
|
||||
output reg [7:0] ascii;
|
||||
output reg key_up;
|
||||
input strobe_in;
|
||||
output reg strobe_out;
|
||||
|
||||
// one-hot state machine states
|
||||
parameter [2:0]
|
||||
C_INIT = 3'd0,
|
||||
C_IDLE = 3'd1,
|
||||
C_KEYPRESS = 3'd2,
|
||||
C_KEYRELEASE = 3'd3,
|
||||
C_RELEASE = 3'd4,
|
||||
C_HOLD = 3'd5;
|
||||
|
||||
//
|
||||
reg [2:0] state, nextstate;
|
||||
|
||||
reg release_prefix;
|
||||
reg release_prefix_set, release_prefix_clear;
|
||||
|
||||
reg shift;
|
||||
reg shift_set, shift_clear;
|
||||
|
||||
reg ctrl;
|
||||
reg ctrl_set, ctrl_clear;
|
||||
|
||||
reg capslock;
|
||||
reg capslock_toggle;
|
||||
|
||||
reg strobe_out_set, strobe_out_clear;
|
||||
reg key_up_set, key_up_clear;
|
||||
|
||||
reg [2:0] hold_count;
|
||||
|
||||
reg [6:0] sc;
|
||||
wire [7:0] rom_data;
|
||||
wire raise;
|
||||
|
||||
// convert scancodes (plus shift/control) into ascii
|
||||
scancode_rom scancode_rom(.addr({raise,sc}),
|
||||
.data(rom_data));
|
||||
|
||||
assign raise = shift | capslock | ctrl;
|
||||
|
||||
// internal state
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
begin
|
||||
shift <= 1'b0;
|
||||
capslock <= 1'b0;
|
||||
ctrl <= 1'b0;
|
||||
|
||||
release_prefix <= 1'b0;
|
||||
strobe_out <= 1'b0;
|
||||
key_up <= 1'b0;
|
||||
|
||||
hold_count <= 3'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (shift_set)
|
||||
shift <= 1'b1;
|
||||
else
|
||||
if (shift_clear)
|
||||
shift <= 1'b0;
|
||||
|
||||
if (ctrl_set)
|
||||
ctrl <= 1'b1;
|
||||
else
|
||||
if (ctrl_clear)
|
||||
ctrl <= 1'b0;
|
||||
|
||||
if (capslock_toggle)
|
||||
capslock <= ~capslock;
|
||||
|
||||
if (release_prefix_set)
|
||||
release_prefix <= 1'b1;
|
||||
else
|
||||
if (release_prefix_clear)
|
||||
release_prefix <= 1'b0;
|
||||
|
||||
if (strobe_out_set)
|
||||
strobe_out <= 1'b1;
|
||||
else
|
||||
if (strobe_out_clear)
|
||||
strobe_out <= 1'b0;
|
||||
|
||||
if (key_up_set)
|
||||
key_up <= 1'b1;
|
||||
else
|
||||
if (key_up_clear)
|
||||
key_up <= 1'b0;
|
||||
|
||||
//
|
||||
if (state == C_HOLD)
|
||||
hold_count <= hold_count + 1;
|
||||
else
|
||||
hold_count <= 3'd0;
|
||||
end
|
||||
|
||||
// next state
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
state <= C_INIT;
|
||||
else
|
||||
state <= nextstate;
|
||||
|
||||
always @(posedge clock)
|
||||
if (state == C_IDLE && strobe_in)
|
||||
sc <= scancode[6:0];
|
||||
|
||||
always @(posedge clock)
|
||||
if (state == C_KEYPRESS || state == C_KEYRELEASE)
|
||||
ascii <= ctrl ? (rom_data - 8'h40) : rom_data;
|
||||
|
||||
always @(state or strobe_in or scancode or release_prefix or shift or ctrl or rom_data or hold_count)
|
||||
begin
|
||||
shift_set = 1'b0;
|
||||
shift_clear = 1'b0;
|
||||
ctrl_set = 1'b0;
|
||||
ctrl_clear = 1'b0;
|
||||
capslock_toggle = 1'b0;
|
||||
release_prefix_set = 1'b0;
|
||||
release_prefix_clear = 1'b0;
|
||||
strobe_out_set = 1'b0;
|
||||
strobe_out_clear = 1'b0;
|
||||
key_up_set = 1'b0;
|
||||
key_up_clear = 1'b0;
|
||||
|
||||
case (state) // synthesis full_case
|
||||
C_INIT:
|
||||
begin
|
||||
nextstate = C_IDLE;
|
||||
end
|
||||
|
||||
C_IDLE:
|
||||
begin
|
||||
if (strobe_in)
|
||||
begin
|
||||
case (scancode)
|
||||
8'hf0: /* release prefix */
|
||||
begin
|
||||
release_prefix_set = 1'b1;
|
||||
nextstate = C_IDLE;
|
||||
end
|
||||
|
||||
8'h58: /* caps lock */
|
||||
begin
|
||||
if (release_prefix)
|
||||
capslock_toggle = 1'b1;
|
||||
nextstate = C_RELEASE;
|
||||
end
|
||||
|
||||
8'h12, /* left shift */
|
||||
8'h59: /* right shift */
|
||||
begin
|
||||
if (release_prefix)
|
||||
shift_clear = 1'b1;
|
||||
else
|
||||
shift_set = 1'b1;
|
||||
nextstate = C_RELEASE;
|
||||
end
|
||||
|
||||
8'h14: /* left ctrl */
|
||||
begin
|
||||
if (release_prefix)
|
||||
ctrl_clear = 1'b1;
|
||||
else
|
||||
ctrl_set = 1'b1;
|
||||
nextstate = C_RELEASE;
|
||||
end
|
||||
|
||||
default:
|
||||
nextstate = release_prefix ?
|
||||
C_KEYRELEASE : C_KEYPRESS;
|
||||
endcase
|
||||
end
|
||||
else
|
||||
nextstate = C_IDLE;
|
||||
end
|
||||
|
||||
C_KEYPRESS:
|
||||
begin
|
||||
strobe_out_set = 1'b1;
|
||||
nextstate = C_RELEASE;
|
||||
end
|
||||
|
||||
C_KEYRELEASE:
|
||||
begin
|
||||
`ifdef SEND_KEYUP
|
||||
strobe_out_set = 1'b1;
|
||||
`endif
|
||||
strobe_out_clear = 1'b1;
|
||||
key_up_set = 1'b1;
|
||||
nextstate = C_RELEASE;
|
||||
end
|
||||
|
||||
C_RELEASE:
|
||||
begin
|
||||
release_prefix_clear = 1'b1;
|
||||
nextstate = C_HOLD;
|
||||
end
|
||||
|
||||
C_HOLD:
|
||||
begin
|
||||
nextstate = C_HOLD;
|
||||
|
||||
if (hold_count == 3'd4)
|
||||
begin
|
||||
strobe_out_clear = 1'b1;
|
||||
key_up_clear = 1'b1;
|
||||
nextstate = C_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
// ------------------
|
||||
|
||||
//`define TEST
|
||||
`ifdef TEST
|
||||
|
||||
|
||||
`timescale 1ns / 1ns
|
||||
|
||||
module test;
|
||||
|
||||
reg clk, reset_n;
|
||||
reg [7:0] testcode;
|
||||
wire [7:0] kb_ascii;
|
||||
reg kb_rdy;
|
||||
wire kb_release;
|
||||
wire kb_ascii_rdy;
|
||||
|
||||
scancode_convert scancode_convert(.clock(clk),
|
||||
.reset_n(reset_n),
|
||||
.scancode(testcode),
|
||||
.ascii(kb_ascii),
|
||||
.key_up(kb_release),
|
||||
.strobe_in(kb_rdy),
|
||||
.strobe_out(kb_ascii_rdy));
|
||||
|
||||
|
||||
initial
|
||||
begin
|
||||
$timeformat(-9, 0, "ns", 7);
|
||||
|
||||
$dumpfile("scancode.vcd");
|
||||
$dumpvars(0, test.scancode_convert);
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 1'b0;
|
||||
reset_n = 1'b0;
|
||||
kb_rdy = 1'b0;
|
||||
|
||||
#200 begin
|
||||
reset_n = 1'b1;
|
||||
end
|
||||
|
||||
// press "a"
|
||||
#10 begin kb_rdy = 1'b1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
// press "b"
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h32; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h32; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
// enter
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h5a; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h5a; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
// shift "a"
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h12; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h12; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
// press "c"
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h21; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h21; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
// ctrl "a"
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h14; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h14; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
// press "d"
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h23; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
#1000 begin kb_rdy = 1'b1; testcode = 8'h23; end
|
||||
#80 kb_rdy = 1'b0;
|
||||
|
||||
|
||||
#5000 $finish;
|
||||
end
|
||||
|
||||
always
|
||||
begin
|
||||
#20 clk = 1'b0;
|
||||
#20 clk = 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`endif
|
||||
|
||||
252
v/scancode2.v
Normal file
252
v/scancode2.v
Normal file
@ -0,0 +1,252 @@
|
||||
// scancode2.v
|
||||
|
||||
//
|
||||
// simple AT style keyboard scancode to ascii convertion
|
||||
// keeps track of shift, capslock and control keys
|
||||
// inputs scancodes and outputs ascii
|
||||
//
|
||||
// implicit state machine version
|
||||
//
|
||||
|
||||
`include "scancode_rom.v"
|
||||
|
||||
module scancode_convert(clock,
|
||||
reset_n,
|
||||
scancode,
|
||||
ascii,
|
||||
key_up,
|
||||
strobe_in,
|
||||
strobe_out);
|
||||
|
||||
input clock;
|
||||
input reset_n;
|
||||
input [7:0] scancode;
|
||||
output reg [7:0] ascii;
|
||||
output reg key_up;
|
||||
input strobe_in;
|
||||
output reg strobe_out;
|
||||
|
||||
reg release_prefix;
|
||||
reg shift;
|
||||
reg ctrl;
|
||||
reg capslock;
|
||||
|
||||
reg [6:0] sc;
|
||||
wire [7:0] rom_data;
|
||||
wire raise;
|
||||
|
||||
scancode_rom scancode_rom(.addr({raise,sc}),
|
||||
.data(rom_data));
|
||||
|
||||
assign raise = shift | capslock | ctrl;
|
||||
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
begin
|
||||
shift <= 0;
|
||||
ctrl <= 0;
|
||||
capslock <= 0;
|
||||
release_prefix <= 0;
|
||||
key_up <= 0;
|
||||
strobe_out <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (strobe_in)
|
||||
begin
|
||||
strobe_out <= 0;
|
||||
|
||||
sc = scancode[6:0];
|
||||
case (scancode)
|
||||
8'hf0: /* release prefix */
|
||||
begin
|
||||
@(posedge clock) release_prefix <= 1;
|
||||
end
|
||||
|
||||
8'h58: /* caps lock */
|
||||
begin
|
||||
if (~release_prefix)
|
||||
@(posedge clock) capslock = ~capslock;
|
||||
end
|
||||
|
||||
8'h12, /* left shift */
|
||||
8'h59: /* right shift */
|
||||
begin
|
||||
@(posedge clock) shift = release_prefix ? 0 : 1;
|
||||
end
|
||||
|
||||
8'h14: /* left ctrl */
|
||||
begin
|
||||
@(posedge clock) ctrl = release_prefix ? 0 : 1;
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
if (release_prefix)
|
||||
begin
|
||||
@(posedge clock)
|
||||
begin
|
||||
ascii = ctrl ? (rom_data - 8'h40) : rom_data;
|
||||
strobe_out <= 1;
|
||||
end
|
||||
@(posedge clock) strobe_out <= 1;
|
||||
@(posedge clock)
|
||||
begin
|
||||
strobe_out <= 0;
|
||||
release_prefix <= 0;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
@(posedge clock)
|
||||
begin
|
||||
/*
|
||||
ascii = ctrl ? (rom_data - 8'h40) : rom_data;
|
||||
strobe_out <= 1;
|
||||
*/
|
||||
key_up <= 1;
|
||||
end
|
||||
@(posedge clock) strobe_out <= 0;
|
||||
@(posedge clock)
|
||||
begin
|
||||
strobe_out <= 0;
|
||||
release_prefix <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase // case(scancode)
|
||||
|
||||
end // if (strobe_in)
|
||||
end // else: !if(~reset_n)
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
///*
|
||||
|
||||
|
||||
// ------------------
|
||||
|
||||
`timescale 1ns / 1ns
|
||||
|
||||
module test;
|
||||
|
||||
reg clk, reset_n;
|
||||
reg [7:0] testcode;
|
||||
wire [7:0] kb_ascii;
|
||||
reg kb_rdy;
|
||||
wire kb_release;
|
||||
wire kb_ascii_rdy;
|
||||
|
||||
scancode_convert scancode_convert(.clock(clk),
|
||||
.reset_n(reset_n),
|
||||
.scancode(testcode),
|
||||
.ascii(kb_ascii),
|
||||
.key_up(kb_release),
|
||||
.strobe_in(kb_rdy),
|
||||
.strobe_out(kb_ascii_rdy));
|
||||
|
||||
|
||||
initial
|
||||
begin
|
||||
$timeformat(-9, 0, "ns", 7);
|
||||
|
||||
$dumpfile("scancode.vcd");
|
||||
$dumpvars(0, test.scancode_convert);
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
reset_n = 0;
|
||||
kb_rdy = 0;
|
||||
|
||||
#200 begin
|
||||
reset_n = 1;
|
||||
end
|
||||
|
||||
// press "a"
|
||||
#10 begin kb_rdy = 1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
// press "b"
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h32; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h32; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
// enter
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h5a; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h5a; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
// shift "a"
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h12; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h12; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
// press "c"
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h21; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h21; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
// ctrl "a"
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h14; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h1c; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h14; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
// press "d"
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h23; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'hf0; end
|
||||
#80 kb_rdy = 0;
|
||||
#1000 begin kb_rdy = 1; testcode = 8'h23; end
|
||||
#80 kb_rdy = 0;
|
||||
|
||||
|
||||
#5000 $finish;
|
||||
end
|
||||
|
||||
always
|
||||
begin
|
||||
#40 clk = 0;
|
||||
#40 clk = 1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//*/
|
||||
132
v/scancode_rom.v
Normal file
132
v/scancode_rom.v
Normal file
@ -0,0 +1,132 @@
|
||||
// scancode_rom.v
|
||||
|
||||
module scancode_rom(addr, data);
|
||||
|
||||
input [7:0] addr;
|
||||
output reg [7:0] data;
|
||||
|
||||
always @addr
|
||||
case (addr)
|
||||
8'h0d: data <= 8'h07; /* TAB */
|
||||
8'h0e: data <= "`";
|
||||
8'h11: data <= 0; /* Left alt */
|
||||
8'h12: data <= 0; /* Left shift */
|
||||
8'h14: data <= 0; /* Left ctrl */
|
||||
8'h15: data <= "q";
|
||||
8'h16: data <= "1";
|
||||
8'h1a: data <= "z";
|
||||
8'h1b: data <= "s";
|
||||
8'h1c: data <= 8'h61 /* "a" */;
|
||||
8'h1d: data <= "w";
|
||||
8'h1e: data <= "2";
|
||||
|
||||
8'h21: data <= "c";
|
||||
8'h22: data <= "x";
|
||||
8'h23: data <= "d";
|
||||
8'h24: data <= "e";
|
||||
8'h25: data <= "4";
|
||||
8'h26: data <= "3";
|
||||
8'h29: data <= " "; /* SPACE */
|
||||
8'h2a: data <= "v";
|
||||
8'h2b: data <= "f";
|
||||
8'h2c: data <= "t";
|
||||
8'h2d: data <= "r";
|
||||
8'h2e: data <= "5";
|
||||
|
||||
8'h31: data <= "n";
|
||||
8'h32: data <= "b";
|
||||
8'h33: data <= "h";
|
||||
8'h34: data <= "g";
|
||||
8'h35: data <= "y";
|
||||
8'h36: data <= "6";
|
||||
8'h3a: data <= "m";
|
||||
8'h3b: data <= "j";
|
||||
8'h3c: data <= "u";
|
||||
8'h3d: data <= "7";
|
||||
8'h3e: data <= "8";
|
||||
|
||||
8'h41: data <= ",";
|
||||
8'h42: data <= "k";
|
||||
8'h43: data <= "i";
|
||||
8'h44: data <= "o";
|
||||
8'h45: data <= "0";
|
||||
8'h46: data <= "9";
|
||||
8'h49: data <= ".";
|
||||
8'h4a: data <= "/";
|
||||
8'h4b: data <= "l";
|
||||
8'h4c: data <= ";";
|
||||
8'h4d: data <= "p";
|
||||
8'h4e: data <= "-";
|
||||
|
||||
8'h52: data <= "'";
|
||||
8'h54: data <= "[";
|
||||
8'h55: data <= "=";
|
||||
8'h58: data <= 0; /* Caps lock */
|
||||
8'h59: data <= 0; /* Right shift */
|
||||
8'h5a: data <= 8'h0d; /* Enter */
|
||||
8'h5b: data <= "]";
|
||||
8'h5d: data <= 8'h5c; /* "\\" */
|
||||
8'h66: data <= 8'h08; /* BKSP */
|
||||
8'h76: data <= 8'h1b; /* ESC */
|
||||
|
||||
8'h8e: data <= "~";
|
||||
8'h95: data <= "Q";
|
||||
8'h96: data <= "!";
|
||||
8'h9a: data <= "Z";
|
||||
8'h9b: data <= "S";
|
||||
8'h9c: data <= 8'h41 /* "A" */;
|
||||
8'h9d: data <= "W";
|
||||
8'h9e: data <= "2";
|
||||
|
||||
8'ha1: data <= "C";
|
||||
8'ha2: data <= "X";
|
||||
8'ha3: data <= "D";
|
||||
8'ha4: data <= "E";
|
||||
8'ha5: data <= "$";
|
||||
8'ha6: data <= "#";
|
||||
8'ha9: data <= " "; /* SPACE */
|
||||
8'haa: data <= "V";
|
||||
8'hab: data <= "F";
|
||||
8'hac: data <= "T";
|
||||
8'had: data <= "R";
|
||||
8'hae: data <= "%";
|
||||
|
||||
8'hb1: data <= "N";
|
||||
8'hb2: data <= "B";
|
||||
8'hb3: data <= "H";
|
||||
8'hb4: data <= "G";
|
||||
8'hb5: data <= "Y";
|
||||
8'hb6: data <= "^";
|
||||
8'hba: data <= "M";
|
||||
8'hbb: data <= "J";
|
||||
8'hbc: data <= "U";
|
||||
8'hbd: data <= "&";
|
||||
8'hbe: data <= "*";
|
||||
|
||||
8'hc1: data <= "<";
|
||||
8'hc2: data <= "K";
|
||||
8'hc3: data <= "I";
|
||||
8'hc4: data <= "O";
|
||||
8'hc5: data <= ")";
|
||||
8'hc6: data <= "(";
|
||||
8'hc9: data <= ">";
|
||||
8'hca: data <= "?";
|
||||
8'hcb: data <= "L";
|
||||
8'hcc: data <= ":";
|
||||
8'hcd: data <= "P";
|
||||
8'hce: data <= "-";
|
||||
|
||||
8'hd2: data <= "\"";
|
||||
8'hd4: data <= "{";
|
||||
8'hd5: data <= "+";
|
||||
8'hda: data <= 8'h0d; /* Enter */
|
||||
8'hdb: data <= "}";
|
||||
8'hdd: data <= "|";
|
||||
|
||||
8'he6: data <= 8'h08; /* BKSP */
|
||||
|
||||
8'hf6: data <= 8'h1b; /* ESC */
|
||||
default: data <= 0; /* All other keys are undefined */
|
||||
endcase
|
||||
endmodule
|
||||
|
||||
224
v/vga.v
Normal file
224
v/vga.v
Normal file
@ -0,0 +1,224 @@
|
||||
// vga.v
|
||||
|
||||
// simple b&w 640x480 terminal with VGA output
|
||||
|
||||
`include "vgacore.v"
|
||||
`include "crt.v"
|
||||
`include "video_ram.v"
|
||||
`include "char_rom.v"
|
||||
`include "ps2.v"
|
||||
`include "scancode.v"
|
||||
|
||||
module vga (reset_n, clock,
|
||||
pixel, blank_n,
|
||||
hsync, vsync,
|
||||
ps2_clk,
|
||||
ps2_data,
|
||||
led_data);
|
||||
|
||||
input reset_n;
|
||||
input clock;
|
||||
output [8:0] pixel;
|
||||
output blank_n;
|
||||
output hsync;
|
||||
output vsync;
|
||||
input ps2_clk, ps2_data;
|
||||
output [7:0] led_data;
|
||||
|
||||
wire startVGA;
|
||||
wire resetVGA;
|
||||
wire done;
|
||||
wire clearing;
|
||||
|
||||
wire [9:0] hloc; // horiz timing, including sync & blanking
|
||||
wire [9:0] vloc;
|
||||
|
||||
wire hblank; // set when in non-visable part of frame
|
||||
wire vblank;
|
||||
|
||||
wire [6:0] hpos; // horiz position 0..79, during visable frame
|
||||
wire [8:0] vpos; // vert line 0..480, during visable frame
|
||||
|
||||
reg [8:0] pixelData;
|
||||
|
||||
wire [11:0] vpos_times_80;
|
||||
|
||||
wire pixelclk;
|
||||
reg [2:0] pclk;
|
||||
|
||||
wire charclk;
|
||||
reg charload;
|
||||
reg [7:0] pixel_hold;
|
||||
|
||||
reg crtclk;
|
||||
wire ram_wclk;
|
||||
wire ram_wslot;
|
||||
|
||||
wire [11:0] ram_addr_write, ram_addr_video, ram_addr_mux;
|
||||
wire [7:0] ram_data, ram_data_out, rom_data_out;
|
||||
wire ram_we_n;
|
||||
wire [9:0] rom_addr;
|
||||
reg [7:0] rom_addr_char;
|
||||
|
||||
char_rom char_rom(.addr(rom_addr),
|
||||
.data(rom_data_out));
|
||||
|
||||
video_ram video_ram(.addr(ram_addr_mux),
|
||||
.data_out(ram_data_out), .clk_r(charload/*charclk*/),
|
||||
.data_in(ram_data), .clk_w(ram_wclk), .we_n(ram_we_n));
|
||||
|
||||
vgacore vgacore(.reset_n(reset_n), .clock(clock),
|
||||
.hsync(hsync),
|
||||
.vsync(vsync),
|
||||
.hblank(hblank),
|
||||
.vblank(vblank),
|
||||
.enable(blank_n),
|
||||
.hloc(hloc),
|
||||
.vloc(vloc));
|
||||
|
||||
|
||||
wire kb_rdy;
|
||||
wire kb_bsy;
|
||||
wire kb_release;
|
||||
wire [7:0] kb_scancode;
|
||||
wire [7:0] kb_ascii;
|
||||
wire kb_ascii_rdy;
|
||||
reg [7:0] crt_data;
|
||||
reg insert_crt_data;
|
||||
|
||||
ps2 ps2(.clk(clock),
|
||||
.rst_n(reset_n),
|
||||
.ps2_clk(ps2_clk),
|
||||
.ps2_data(ps2_data),
|
||||
.scancode(kb_scancode),
|
||||
.parity(),
|
||||
.busy(kb_bsy),
|
||||
.rdy(kb_rdy),
|
||||
.error()
|
||||
);
|
||||
|
||||
scancode_convert scancode_convert(.clock(clock),
|
||||
.reset_n(reset_n),
|
||||
.scancode(kb_scancode),
|
||||
.ascii(kb_ascii),
|
||||
.key_up(kb_release),
|
||||
.strobe_in(kb_rdy),
|
||||
.strobe_out(kb_ascii_rdy));
|
||||
|
||||
// debug - led output
|
||||
assign led_data = { kb_ascii[6], kb_rdy, kb_ascii[5:0] };
|
||||
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
begin
|
||||
crt_data <= 0;
|
||||
insert_crt_data <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (kb_ascii_rdy)
|
||||
begin
|
||||
crt_data <= kb_ascii;
|
||||
if (~kb_release)
|
||||
insert_crt_data <= 1;
|
||||
end
|
||||
else
|
||||
insert_crt_data <= 0;
|
||||
end
|
||||
|
||||
// assign insert_crt_data = kb_ascii_rdy && ~kb_release;
|
||||
|
||||
wire [6:0] cursorh;
|
||||
wire [5:0] cursorv;
|
||||
wire cursor_match;
|
||||
|
||||
crt crt(.reset_n(reset_n),
|
||||
.clock(crtclk),
|
||||
.insert(insert_crt_data),
|
||||
.done(done),
|
||||
.data(crt_data),
|
||||
.clearing(clearing),
|
||||
.ram_addr(ram_addr_write),
|
||||
.ram_data(ram_data),
|
||||
.ram_we_n(ram_we_n),
|
||||
.ram_wclk(ram_wclk),
|
||||
.ram_wslot(ram_wslot),
|
||||
.cursorh(cursorh),
|
||||
.cursorv(cursorv));
|
||||
|
||||
|
||||
// generate video ram address from (vpos/8) * 80 + hpos
|
||||
assign vpos_times_80 = {vpos[8:3], 6'b0} + {2'b00, vpos[8:3], 4'b0};
|
||||
assign ram_addr_video = vpos_times_80 + {5'b00000, hpos};
|
||||
|
||||
assign ram_addr_mux = ram_we_n ? ram_addr_video : ram_addr_write;
|
||||
|
||||
assign rom_addr = {rom_addr_char[6:0], vpos[2:0]};
|
||||
|
||||
assign cursor_match = (cursorh == hpos && cursorv == vpos[8:3]) ? 1 : 0;
|
||||
|
||||
|
||||
// clock divider by 8 - assume 8x8 font
|
||||
always @(posedge pixelclk or negedge reset_n)
|
||||
if (~reset_n)
|
||||
pclk = 3'b111;
|
||||
else
|
||||
pclk = (hblank || clearing) ? 3'b111 : pclk + 1;
|
||||
|
||||
assign charclk = ~pclk[2];
|
||||
|
||||
// crtclk runs at half speed
|
||||
always @(posedge pixelclk or negedge reset_n)
|
||||
if (~reset_n)
|
||||
crtclk = 1'b0;
|
||||
else
|
||||
crtclk = ~crtclk;
|
||||
|
||||
// ram "writ slot" sits at 2nd half of charclk cycle
|
||||
assign ram_wslot = ~pclk[1] & pclk[2];
|
||||
|
||||
// generate hpos, vpos (from hloc, vloc of vgacore)
|
||||
assign hpos = hloc[9:3];
|
||||
assign vpos = vloc[8:0];
|
||||
|
||||
// latch ram output to form rom address
|
||||
always @(posedge charclk)
|
||||
rom_addr_char <= ram_data_out;
|
||||
|
||||
/*
|
||||
//temp-debug
|
||||
//always @(posedge charclk) rom_addr_char <= {1'b0, hpos};
|
||||
wire [7:0] hack;
|
||||
assign hack = {1'b0,hpos} + 8'h30;
|
||||
//assign hack = {1'b0,hpos};
|
||||
always @(posedge charclk) rom_addr_char <= hack;
|
||||
*/
|
||||
|
||||
// inhibit shift and load instead during last slot
|
||||
always @(negedge pixelclk or negedge reset_n)
|
||||
if (~reset_n)
|
||||
charload = 0;
|
||||
else
|
||||
charload = pclk == 3'b111 ? 1 : 0;
|
||||
|
||||
// shift pixel data, one bit at a time (or load when at last slot)
|
||||
always @(posedge pixelclk)
|
||||
pixel_hold <= charload ?
|
||||
(cursor_match ? 8'hff : rom_data_out) :
|
||||
{ pixel_hold[6:0], 1'b0 };
|
||||
|
||||
// clock pixel data on pixel clock
|
||||
always @(posedge pixelclk)
|
||||
pixelData <= pixel_hold[7] ? 9'h1ff : 9'h000;
|
||||
|
||||
assign pixel = (hblank || vblank) ? 9'h000 : pixelData;
|
||||
|
||||
// reset & start VGA
|
||||
assign startVGA = 1;
|
||||
assign resetVGA = reset_n & startVGA;
|
||||
|
||||
// Provide 25MHz pixel clock
|
||||
assign pixelclk = clock;
|
||||
|
||||
endmodule
|
||||
|
||||
153
v/vgacore.v
Normal file
153
v/vgacore.v
Normal file
@ -0,0 +1,153 @@
|
||||
// vgacore.v
|
||||
//
|
||||
// Creates VGA timing signals to a monitor, currently for 60Hz @ 640 * 480
|
||||
//
|
||||
// To change the resolution or refresh rate, change the value of
|
||||
// the constants and the generics to whatever is desired. Changing the
|
||||
// resolution and/or refresh also means the clock speed may have to change,
|
||||
// currently based off a 25MHz clock...
|
||||
//
|
||||
|
||||
module vgacore(reset_n, clock,
|
||||
hblank, vblank,
|
||||
hsync, vsync,
|
||||
enable,
|
||||
hloc, vloc);
|
||||
|
||||
input reset_n;
|
||||
input clock;
|
||||
|
||||
output hblank;
|
||||
output vblank;
|
||||
|
||||
output hsync;
|
||||
output vsync;
|
||||
|
||||
output enable;
|
||||
|
||||
reg hblank;
|
||||
reg hsync, vsync;
|
||||
reg enable;
|
||||
|
||||
output [9:0] hloc;
|
||||
output [9:0] vloc;
|
||||
|
||||
parameter H_SIZE = 640;
|
||||
parameter V_SIZE = 480;
|
||||
|
||||
// sync signals
|
||||
//
|
||||
// |<--- Active Region --->|<--------- Blanking Region ------->|
|
||||
// | (Pixels) | |
|
||||
// | | |
|
||||
// | | |
|
||||
// -----+---------- ... --------+------------- ------------+---
|
||||
// | | | | | |
|
||||
// | | |<--Front |<--Sync |<--Back |
|
||||
// | | | Porch-->| Time-->| Porch-->|
|
||||
//-- | | ------------ |
|
||||
// | | |
|
||||
// |<---------------------------- Period --------------------->|
|
||||
//
|
||||
|
||||
// horizontal timing signals
|
||||
`define H_PIXELS H_SIZE
|
||||
`define H_FRONTPORCH 30 + (640 - H_SIZE) / 2
|
||||
`define H_SYNCTIME 100
|
||||
`define H_BACKPORCH 30 + (640 - H_SIZE) / 2
|
||||
`define H_PERIOD `H_PIXELS+ `H_FRONTPORCH+ `H_SYNCTIME+ `H_BACKPORCH
|
||||
|
||||
// vertical timing signals
|
||||
`define V_LINES V_SIZE
|
||||
`define V_FRONTPORCH 10 + (480 - V_SIZE) / 2
|
||||
`define V_SYNCTIME 2
|
||||
`define V_BACKPORCH 32 + (480 - V_SIZE) / 2
|
||||
`define V_PERIOD `V_SYNCTIME+ `V_LINES+ `V_FRONTPORCH+ `V_BACKPORCH
|
||||
|
||||
|
||||
reg [10:0] hcnt; // horizontal pixel counter
|
||||
reg [9:0] vcnt; // vertical line counter
|
||||
|
||||
// control the reset, increment and overflow of the horiz pixel count
|
||||
always @(posedge clock or negedge reset_n)
|
||||
// reset asynchronously clears horizontal counter
|
||||
if (~reset_n)
|
||||
hcnt <= 0;
|
||||
else
|
||||
// horiz. counter increments on rising edge of dot clock
|
||||
// horiz. counter restarts after the horizontal period
|
||||
if (hcnt < (`H_PERIOD - 1))
|
||||
hcnt <= hcnt + 1;
|
||||
else
|
||||
hcnt <= 0;
|
||||
|
||||
|
||||
// control the reset, increment and overflow of the vert line ctr,
|
||||
// after every horiz line
|
||||
// always @(negedge hsync or negedge reset_n)
|
||||
always @(negedge hblank or negedge reset_n)
|
||||
// reset asynchronously clears line counter
|
||||
if (~reset_n)
|
||||
vcnt <= 0;
|
||||
else
|
||||
// vert. line counter increments after every horiz. line
|
||||
// vert. line counter rolls-over after max lines
|
||||
if (vcnt < (`V_PERIOD - 1))
|
||||
vcnt <= vcnt + 1;
|
||||
else
|
||||
vcnt <= 0;
|
||||
|
||||
|
||||
// set the horizontal sync high time and low time
|
||||
always @(posedge clock or negedge reset_n)
|
||||
// reset asynchronously sets horizontal sync to inactive
|
||||
if (~reset_n)
|
||||
hsync <= 0;
|
||||
else
|
||||
// horizontal sync is recomputed on the rising edge of every dot clk
|
||||
// horiz. sync is low to signal start of a new line
|
||||
if (hcnt >= (`H_FRONTPORCH + `H_PIXELS) &&
|
||||
hcnt < (`H_FRONTPORCH + `H_PIXELS + `H_SYNCTIME))
|
||||
hsync <= 1;
|
||||
else
|
||||
hsync <= 0;
|
||||
|
||||
// set the vertical sync high time and low time
|
||||
always @(posedge clock or negedge reset_n)
|
||||
// reset asynchronously sets vertical sync to inactive
|
||||
if (~reset_n)
|
||||
vsync <= 0;
|
||||
else
|
||||
// vertical sync is recomputed at the end of every line of pixels
|
||||
// vert. sync is low to signal start of a new frame
|
||||
if (vcnt >= (`V_LINES + `V_FRONTPORCH) &&
|
||||
vcnt < (`V_LINES + `V_FRONTPORCH + `V_SYNCTIME))
|
||||
vsync <= 1;
|
||||
else
|
||||
vsync <= 0;
|
||||
|
||||
// blanking
|
||||
// assign hblank = (hcnt >= `H_PIXELS) && (hcnt < `H_PERIOD);
|
||||
assign vblank = (vcnt >= `V_LINES) && (vcnt < `V_PERIOD);
|
||||
|
||||
always @(posedge clock or negedge reset_n)
|
||||
if (~reset_n)
|
||||
hblank <= 0;
|
||||
else
|
||||
if (hcnt < `H_PIXELS)
|
||||
hblank <= 0;
|
||||
else
|
||||
hblank <= 1;
|
||||
|
||||
// asserts the blanking signal (active low)
|
||||
always @(posedge clock)
|
||||
// if we are outside the visible range on the screen then blank
|
||||
if (hcnt >= `H_PIXELS || vcnt >= `V_LINES)
|
||||
enable <= 0;
|
||||
else
|
||||
enable <= 1;
|
||||
|
||||
assign hloc = hcnt[9:0];
|
||||
assign vloc = vcnt[9:0];
|
||||
|
||||
endmodule
|
||||
23
v/video_mem.v
Normal file
23
v/video_mem.v
Normal file
@ -0,0 +1,23 @@
|
||||
// video_mem.v
|
||||
|
||||
/* 1kx32 static ram */
|
||||
|
||||
module video_ram(addr, data_in, data_out, ce_n, we_n);
|
||||
|
||||
input [10:0] addr;
|
||||
input [7:0] data_in;
|
||||
input ce_n, we_n;
|
||||
output [7:0] data_out;
|
||||
|
||||
reg [7:0] ram [0:2047];
|
||||
|
||||
always @(negedge we_n)
|
||||
begin
|
||||
if (ce_n == 0)
|
||||
ram[addr] = data_in;
|
||||
end
|
||||
|
||||
assign data_out = ram[addr];
|
||||
endmodule
|
||||
|
||||
|
||||
32
v/video_ram.v
Normal file
32
v/video_ram.v
Normal file
@ -0,0 +1,32 @@
|
||||
// video_mem.v
|
||||
|
||||
/* 2kx8 static sync ram */
|
||||
|
||||
module video_ram(addr, data_in, data_out, clk_r, clk_w, we_n);
|
||||
|
||||
input [11:0] addr;
|
||||
input [7:0] data_in;
|
||||
input clk_r, clk_w, we_n;
|
||||
output [7:0] data_out;
|
||||
|
||||
reg [7:0] ram [0:2048];
|
||||
reg [11:0] ram_addr_w;
|
||||
reg [11:0] ram_addr_r;
|
||||
|
||||
always @(posedge clk_w)
|
||||
begin
|
||||
ram_addr_w <= addr;
|
||||
if (we_n == 0)
|
||||
ram[ram_addr_w] <= data_in;
|
||||
end
|
||||
|
||||
always @(posedge clk_r)
|
||||
begin
|
||||
ram_addr_r <= addr;
|
||||
end
|
||||
|
||||
assign data_out = ram[ram_addr_r];
|
||||
|
||||
// assign data_out = 8'h20 + addr[7:0];
|
||||
|
||||
endmodule
|
||||
17
v/xsa-200.ucf
Normal file
17
v/xsa-200.ucf
Normal file
@ -0,0 +1,17 @@
|
||||
net clka loc=r8;
|
||||
net clkb loc=b8;
|
||||
|
||||
net ps2_clk loc=f4;
|
||||
net ps2_data loc=e1;
|
||||
|
||||
net vga_blue0 loc=h4;
|
||||
net vga_blue1 loc=k3;
|
||||
net vga_blue2 loc=l5;
|
||||
net vga_green0 loc=h2;
|
||||
net vga_green1 loc=k5;
|
||||
net vga_green2 loc=r1;
|
||||
net vga_red0 loc=j1;
|
||||
net vga_red1 loc=m1;
|
||||
net vga_red2 loc=t2;
|
||||
net vga_hsync_n loc=k4;
|
||||
net vga_vsync_n loc=k1;
|
||||
Loading…
x
Reference in New Issue
Block a user