X-Git-Url: http://git.joshuawise.com/firearm.git/blobdiff_plain/121556d62c2c40b07a709ef038fa1ce0a67127c9..8744c23dbf6a3c38649c800ae3d96e7e465e01fb:/xst/Console.v diff --git a/xst/Console.v b/xst/Console.v new file mode 100644 index 0000000..5f5e2da --- /dev/null +++ b/xst/Console.v @@ -0,0 +1,436 @@ +module MulDivDCM(input xtal, output clk, output clk90); + parameter div = 8; + parameter mul = 2; + + wire CLKFX_BUF; + wire CLK0_BUF; + wire CLK90_BUF; + wire clkfx; + wire GND_BIT = 0; + BUFG CLK0_BUFG_INST (.I(CLK0_BUF), + .O(clk)); + BUFG CLK90_BUFG_INST (.I(CLK90_BUF), + .O(clk90)); + BUFG CLKFX_BUFG_INST (.I(CLKFX_BUF), + .O(clkfx)); + + DCM_BASE DCM_INST2(.CLKFB(clk), + .CLKIN(clkfx), + .RST(GND_BIT), + .CLK0(CLK0_BUF), + .CLK90(CLK90_BUF)); + + DCM_BASE DCM_INST (.CLKFB(GND_BIT), + .CLKIN(xtal), + .RST(GND_BIT), + .CLKFX(CLKFX_BUF)); + defparam DCM_INST.CLK_FEEDBACK = "NONE"; + defparam DCM_INST.CLKDV_DIVIDE = 2.0; + defparam DCM_INST.CLKFX_DIVIDE = div; + defparam DCM_INST.CLKFX_MULTIPLY = mul; + defparam DCM_INST.CLKIN_DIVIDE_BY_2 = "FALSE"; + defparam DCM_INST.CLKIN_PERIOD = 10.000; + defparam DCM_INST.CLKOUT_PHASE_SHIFT = "NONE"; + defparam DCM_INST.DESKEW_ADJUST = "SYSTEM_SYNCHRONOUS"; + defparam DCM_INST.DFS_FREQUENCY_MODE = "LOW"; + defparam DCM_INST.DLL_FREQUENCY_MODE = "LOW"; + defparam DCM_INST.DUTY_CYCLE_CORRECTION = "TRUE"; + defparam DCM_INST.FACTORY_JF = 16'hC080; + defparam DCM_INST.PHASE_SHIFT = 0; + defparam DCM_INST.STARTUP_WAIT = "TRUE"; +endmodule + +`include "iic_init.v" + +module Console( + input xtal, + input rst, + output wire rstact, + output wire dvi_vs, dvi_hs, + output wire [11:0] dvi_d, + output wire dvi_xclk_p, dvi_xclk_n, + output wire dvi_de, + output wire dvi_reset_b, + inout wire dvi_sda, + inout wire dvi_scl, + input ps2c, ps2d); + + assign dvi_reset_b = 1'b1; + + wire clk25, clk25_90; + + wire [11:0] x, y; + wire border; + + MulDivDCM dcm25(xtal, clk25, clk25_90); + defparam dcm25.div = 16; + defparam dcm25.mul = 5; + + wire vs, hs; + SyncGen sync(clk25, vs, hs, x, y, border); + + wire [7:0] cschar; + wire [2:0] csrow; + wire [7:0] csdata; + + wire [10:0] vraddr; + wire [7:0] vrdata; + + wire [10:0] vwaddr; + wire [7:0] vwdata; + wire [7:0] serdata; + wire vwr, serwr; + wire [10:0] vscroll; + + wire odata; + + wire [6:0] vcursx; + wire [4:0] vcursy; + + reg [16:0] rsttimer = 17'h3FFFF; + always @(posedge clk25) + if (~rst) + rsttimer <= 17'h3FFFF; + else if (rsttimer) + rsttimer <= rsttimer - 1; + assign rstact = rsttimer != 17'h0; + + wire tookdata; + reg ps2_hasd = 0; + reg [7:0] ps2_d = 0; + wire sertxwr; + wire [7:0] sertxdata; + + CharSet cs(cschar, csrow, csdata); + VideoRAM vram(clk25, vraddr + vscroll, vrdata, clk25, vwaddr, vwdata, vwr); + VDisplay dpy(clk25, x, y, vraddr, vrdata, cschar, csrow, csdata, vcursx, vcursy, odata); + RXState rxsm(clk25, vwr, vwaddr, vwdata, vscroll, vcursx, vcursy, serwr, serdata); + PS2 ps2(clk25, ps2c, ps2d, sertxwr, sertxdata); + System sys(.clk(clk25), .rst(rstact), .sys_odata({serwr, serdata}), .sys_idata({ps2_hasd, ps2_d}), .sys_tookdata(tookdata)); + + always @(posedge clk25) + if (sertxwr) + {ps2_hasd, ps2_d} <= {1'b1, sertxdata}; + else if (tookdata) + {ps2_hasd, ps2_d} <= {1'b0, 8'hxxxxxxxx}; + + /* FUCK! ASS! BALLS! EAT MY SHORT DICK! FUCKING XST */ + /* EMSD stands for Eat My Short Dick. Because XST should. */ +`define MAKE_DDR(n,q,d1,d2) ODDR n (.C(clk25), .Q(q), .D1(d1), .D2(d2), .R(0), .S(0), .CE(1)) +`define MAKE_DDR90(n,q,d1,d2) ODDR n (.C(clk25_90), .Q(q), .D1(d1), .D2(d2), .R(0), .S(0), .CE(1)) + + wire [7:0] red, green, blue; + assign red = (odata ? 8'hFF : 0) | (x[8:2] ^ y[7:1]); + assign green = (odata ? 8'hFF : 0) | (x[7:1] ^ y[8:2]); + assign blue = (odata ? 8'hFF : 0) | (x[8:2] ^ y[8:2]); + + `MAKE_DDR90(EMSD_dvi_xclk_p, dvi_xclk_p, 1'b1, 1'b0); + `MAKE_DDR90(EMSD_dvi_xclk_n, dvi_xclk_n, 1'b0, 1'b1); + `MAKE_DDR(EMSD_dvi_de, dvi_de, ~border, ~border); + `MAKE_DDR(EMSD_dvi_vs, dvi_vs, vs, vs); + `MAKE_DDR(EMSD_dvi_hs, dvi_hs, hs, hs); + `MAKE_DDR(EMSD_dvi_d_0, dvi_d[0], blue[0], green[4]); + `MAKE_DDR(EMSD_dvi_d_1, dvi_d[1], blue[1], green[5]); + `MAKE_DDR(EMSD_dvi_d_2, dvi_d[2], blue[2], green[6]); + `MAKE_DDR(EMSD_dvi_d_3, dvi_d[3], blue[3], green[7]); + `MAKE_DDR(EMSD_dvi_d_4, dvi_d[4], blue[4], red[0]); + `MAKE_DDR(EMSD_dvi_d_5, dvi_d[5], blue[5], red[1]); + `MAKE_DDR(EMSD_dvi_d_6, dvi_d[6], blue[6], red[2]); + `MAKE_DDR(EMSD_dvi_d_7, dvi_d[7], blue[7], red[3]); + `MAKE_DDR(EMSD_dvi_d_8, dvi_d[8], green[0], red[4]); + `MAKE_DDR(EMSD_dvi_d_9, dvi_d[9], green[1], red[5]); + `MAKE_DDR(EMSD_dvi_d_10, dvi_d[10], green[2], red[6]); + `MAKE_DDR(EMSD_dvi_d_11, dvi_d[11], green[3], red[7]); + + wire wee; + iic_init #(.CLK_RATE_MHZ(31)) init (clk25, 1'b1, 1'b0, dvi_sda, dvi_scl, wee); + +endmodule + +module SyncGen( + input pixclk, + output reg vs, hs, + output reg [11:0] x, y, + output reg border); + + parameter XRES = 640; + parameter XFPORCH = 24; + parameter XSYNC = 40; + parameter XBPORCH = 128; + + parameter YRES = 480; + parameter YFPORCH = 9; + parameter YSYNC = 3; + parameter YBPORCH = 28; + + always @(posedge pixclk) + begin + if (x >= (XRES + XFPORCH + XSYNC + XBPORCH)) + begin + if (y >= (YRES + YFPORCH + YSYNC + YBPORCH)) + y = 0; + else + y = y + 1; + x = 0; + end else + x = x + 1; + hs <= (x >= (XRES + XFPORCH)) && (x < (XRES + XFPORCH + XSYNC)); + vs <= (y >= (YRES + YFPORCH)) && (y < (YRES + YFPORCH + YSYNC)); + border <= (x > XRES) || (y > YRES); + end +endmodule + +module CharSet( + input [7:0] char, + input [2:0] row, + output wire [7:0] data); + + reg [7:0] rom [(256 * 8 - 1):0]; + + initial + $readmemb("ibmpc1.mem", rom); + + assign data = rom[{char, row}]; +endmodule + +module VideoRAM( + input pixclk, + input [10:0] raddr, + output reg [7:0] rdata, + input wclk, + input [10:0] waddr, + input [7:0] wdata, + input wr); + + reg [7:0] ram [2047 : 0]; + + always @(posedge pixclk) + rdata <= ram[raddr]; + + always @(posedge wclk) + if (wr) + ram[waddr] <= wdata; +endmodule + +module VDisplay( + input pixclk, + input [11:0] x, + input [11:0] y, + output wire [10:0] raddr, + input [7:0] rchar, + output wire [7:0] cschar, + output wire [2:0] csrow, + input [7:0] csdata, + input [6:0] cursx, + input [4:0] cursy, + output reg data); + + wire [7:0] col = x[11:3]; + wire [5:0] row = y[10:4]; + reg [7:0] ch; + reg [11:0] xdly; + + assign raddr = ({row,4'b0} + {row,6'b0} + {4'h0,col}); + assign cschar = rchar; + assign csrow = y[3:1]; + + reg [23:0] blinktime = 0; + + always @(posedge pixclk) blinktime <= blinktime + 1; + + wire curssel = (cursx == col) && (cursy == row) && blinktime[23]; + + always @(posedge pixclk) + xdly <= x; + + always @(posedge pixclk) + data = ((xdly < 80 * 8) && (y < 25 * 16)) ? (csdata[7 - xdly[2:0]] ^ curssel) : 0; +endmodule + +module RXState( + input clk25, + output reg vwr = 0, + output reg [10:0] vwaddr = 0, + output reg [7:0] vwdata = 0, + output reg [10:0] vscroll = 0, + output wire [6:0] vcursx, + output wire [4:0] vcursy, + input serwr, + input [7:0] serdata); + + parameter STATE_IDLE = 4'b0000; + parameter STATE_NEWLINE = 4'b0001; + parameter STATE_CLEAR = 4'b0010; + + reg [3:0] state = STATE_CLEAR; + + reg [6:0] x = 0; + reg [4:0] y = 0; + + assign vcursx = x; + assign vcursy = y; + + reg [10:0] clearstart = 0; + reg [10:0] clearend = 11'b11111111111; + + always @(posedge clk25) + case (state) + STATE_IDLE: if (serwr) begin + if (serdata == 8'h0A) begin + state <= STATE_NEWLINE; + x <= 0; + vwr <= 0; + end else if (serdata == 8'h0D) begin + x <= 0; + vwr <= 0; + end else if (serdata == 8'h0C) begin + clearstart <= 0; + clearend <= 11'b11111111111; + x <= 0; + y <= 0; + vscroll <= 0; + state <= STATE_CLEAR; + end else if (serdata == 8'h08) begin + if (x != 0) + x <= x - 1; + vwr <= 0; + end else begin + vwr <= 1; + vwaddr <= ({y,4'b0} + {y,6'b0} + {4'h0,x}) + vscroll; + vwdata <= serdata; + if (x == 79) begin + x <= 0; + state <= STATE_NEWLINE; + end else + x <= x + 1; + end + end + STATE_NEWLINE: + begin + vwr <= 0; + if (y == 24) begin + vscroll <= vscroll + 80; + clearstart <= (25 * 80) + vscroll; + clearend <= (26*80) + vscroll; + state <= STATE_CLEAR; + end else begin + y <= y + 1; + state <= STATE_IDLE; + end + end + STATE_CLEAR: + begin + vwr <= 1; + vwaddr <= clearstart; + vwdata <= 8'h20; + clearstart <= clearstart + 1; + if (clearstart == clearend) + state <= STATE_IDLE; + end + endcase +endmodule + +module PS2( + input pixclk, + input inclk, + input indata, + output reg wr, + output reg [7:0] data + ); + + reg [3:0] bitcount = 0; + reg [7:0] key = 0; + reg keyarrow = 0, keyup = 0, parity = 0; + + + /* Clock debouncing */ + reg lastinclk = 0; + reg [6:0] debounce = 0; + reg fixedclk = 0; + reg [11:0] resetcountdown = 0; + + reg [6:0] unshiftedrom [127:0]; initial $readmemh("scancodes.unshifted.hex", unshiftedrom); + reg [6:0] shiftedrom [127:0]; initial $readmemh("scancodes.shifted.hex", shiftedrom); + + reg mod_lshift = 0; + reg mod_rshift = 0; + reg mod_capslock = 0; + wire mod_shifted = (mod_lshift | mod_rshift) ^ mod_capslock; + + reg nd = 0; + reg lastnd = 0; + + always @(posedge pixclk) begin + if (inclk != lastinclk) begin + lastinclk <= inclk; + debounce <= 1; + resetcountdown <= 12'b111111111111; + end else if (debounce == 0) begin + fixedclk <= inclk; + resetcountdown <= resetcountdown - 1; + end else + debounce <= debounce + 1; + + if (nd ^ lastnd) begin + lastnd <= nd; + wr <= 1; + end else + wr <= 0; + end + + always @(negedge fixedclk) begin + if (resetcountdown == 0) + bitcount <= 0; + else if (bitcount == 10) begin + bitcount <= 0; + if(parity != (^ key)) begin + if(keyarrow) begin + casex(key) + 8'hF0: keyup <= 1; + 8'hxx: keyarrow <= 0; + endcase + end + else begin + if(keyup) begin + keyup <= 0; + keyarrow <= 0; + casex (key) + 8'h12: mod_lshift <= 0; + 8'h59: mod_rshift <= 0; + endcase + // handle this? I don't fucking know + end + else begin + casex(key) + 8'hE0: keyarrow <= 1; // handle these? I don't fucking know + 8'hF0: keyup <= 1; + 8'h12: mod_lshift <= 1; + 8'h59: mod_rshift <= 1; + 8'h14: mod_capslock <= ~mod_capslock; + 8'b0xxxxxxx: begin nd <= ~nd; data <= mod_shifted ? shiftedrom[key] : unshiftedrom[key]; end + 8'b1xxxxxxx: begin /* AAAAAAASSSSSSSS */ end + endcase + end + end + end + else begin + keyarrow <= 0; + keyup <= 0; + end + end else + bitcount <= bitcount + 1; + + case(bitcount) + 1: key[0] <= indata; + 2: key[1] <= indata; + 3: key[2] <= indata; + 4: key[3] <= indata; + 5: key[4] <= indata; + 6: key[5] <= indata; + 7: key[6] <= indata; + 8: key[7] <= indata; + 9: parity <= indata; + endcase + end + +endmodule