Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // video.v - 1k byte video buffer & drive logic
- // 2nd generation w/ better timing, no chars in overscan region
- // 03-19-19 E. Brombaugh
- `default_nettype none
- module video(
- input clk, // 16MHz system clock
- input clk_2x, // 32MHz pixel clock
- input reset, // active high system reset
- input mode, // text/graphic mode control
- input [1:0] bank, // VRAM bank select
- input sel, // decoded video address
- input we, // write enable
- input [12:0] addr, // address (8k range)
- input [7:0] din, // write data
- output [7:0] dout, // read data
- inout [3:0] vdac // video DAC signal
- );
- // set up timing parameters for 32MHz clock rate
- localparam MAX_H = 2037; // 2038 clocks/line
- localparam MAX_V = 261; // 262 lines/frame
- localparam HS_WID = 149; // 150 clocks/4.7us H sync pulse
- localparam BK_TOP = 16; // Blanking top on line
- localparam BK_BOT = 240; // Blanking bottom on line
- localparam VS_LIN = 248; // Vsync on line
- localparam VS_WID = 1887; // 1888 clocks/59us V sync pulse
- localparam ASTART = 371; // start of active area @ 11.6us
- // revised video timing - separate H and V counters
- reg [10:0] hcnt;
- reg [8:0] vcnt;
- reg hs, vs;
- always @(posedge clk_2x)
- begin
- if(reset)
- begin
- hcnt <= 11'd0;
- vcnt <= 9'd0;
- hs <= 1'b0;
- vs <= 1'b1;
- end
- else
- begin
- // counters
- if(hcnt == MAX_H)
- begin
- hcnt <= 10'd0;
- if(vcnt == MAX_V)
- vcnt <= 9'd0;
- else
- vcnt <= vcnt + 9'd1;
- end
- else
- hcnt <= hcnt + 1;
- // sync pulses
- hs <= (hcnt < HS_WID) ? 1'b0 : 1'b1;
- vs <= ((hcnt < VS_WID)&&(vcnt == VS_LIN)) ? 1'b0 : 1'b1;
- end
- end
- // extract video character data address & ROM line
- reg active; // active video
- reg [2:0] dcnt; // decimate counter (1/3)
- reg pixena; // pixel rate enable
- reg [2:0] pcnt; // pixel/char count
- reg vload; // load video shift reg
- reg [4:0] haddr; // horizontal component of vram addr
- reg [2:0] cline; // character line index
- reg [4:0] vaddr; // vertical component of vram addr
- always @(posedge clk_2x)
- begin
- if(reset)
- begin
- active <= 1'b0;
- dcnt <= 3'b000;
- pixena <= 1'b0;
- pcnt <= 3'b000;
- vload <= 1'b0;
- haddr <= 5'd0;
- cline <= 3'b000;
- vaddr <= 5'd0;
- end
- else
- begin
- // wait for start of active
- if(active == 1'b0)
- begin
- if((hcnt == ASTART) && (vcnt >= BK_TOP) && (vcnt < BK_BOT))
- begin
- // reset horizontal stuff at hcnt == ASTART
- active <= 1'b1; // active video
- dcnt <= 3'b000;
- pixena <= 1'b1; // start with enable
- pcnt <= 3'b000;
- vload <= 1'b1; // start with load
- haddr <= 5'd0;
- // reset vertical stuff at vcnt == 0;
- if(vcnt == BK_TOP)
- begin
- cline <= 3'b000;
- vaddr <= 5'd0;
- end
- end
- end
- else
- begin
- // divide clock by 6 to get pixel
- if(dcnt == 3'b101)
- begin
- // generate pixel enable
- dcnt <= 3'b000;
- pixena <= 1'b1;
- if(pcnt == 3'b111)
- begin
- // generate vload
- vload <= 1'b1;
- // end of line?
- if(haddr == 5'd31)
- begin
- // shut off counting & loading
- active <= 1'b0;
- vload <= 1'b0;
- pixena <= 1'b0;
- // time to update vertical address?
- if(cline == 3'b111)
- vaddr <= vaddr + 5'd1;
- // update character line index
- cline <= cline + 3'b001;
- end
- // update horizontal address
- haddr <= haddr + 5'd1;
- end
- else
- vload <= 1'b0;
- // always increment pixel count
- pcnt <= pcnt + 3'b001;
- end
- else
- begin
- dcnt <= dcnt + 2'b01;
- pixena <= 1'b0;
- end
- end
- end
- end
- // pipeline control signals
- reg [1:0] pixena_pipe, vload_pipe;
- reg [2:0] active_pipe, hs_pipe, vs_pipe;
- reg [2:0] cline_dly;
- always @(posedge clk_2x)
- begin
- pixena_pipe <= {pixena_pipe[0],pixena};
- vload_pipe <= {vload_pipe[0],vload};
- active_pipe <= {active_pipe[1:0],active};
- hs_pipe <= {hs_pipe[1:0],hs};
- vs_pipe <= {vs_pipe[1:0],vs};
- cline_dly <= cline;
- end
- wire pixena_dly = pixena_pipe[1];
- wire vload_dly = vload_pipe[1];
- wire active_dly = active_pipe[2];
- wire hs_dly = hs_pipe[2];
- wire vs_dly = vs_pipe[2];
- // concatenate horizontal and vertical addresses to make vram address
- wire [12:0] vid_addr = mode ? {vaddr,cline,haddr} : {3'b000,vaddr,haddr};
- // invert msb of cpu addr due to decoding on D/E range
- wire [12:0] cpu_addr = addr ^ 13'h1000;
- // address mux selects video or CPU - video in 1st half and CPU in 2nd half
- wire [12:0] mem_addr = clk ? vid_addr : cpu_addr;
- // cpu writes to video memory only on 2nd half of CPU clock cycle
- wire mem_we = sel & we & ~clk;
- // instantiated video memory
- wire [7:0] ram_dout;
- ram_32kb uram(
- .clk(clk_2x),
- .sel(1'b1),
- .we(mem_we),
- .wp(8'h00),
- .addr({bank,mem_addr}),
- .din(din),
- .dout(ram_dout)
- );
- // hold data for full cycle for CPU
- reg [7:0] hld_dout;
- always @(posedge clk_2x)
- if(clk)
- hld_dout <= ram_dout;
- // mux between live & held data for cpu
- always @(*)
- dout = clk ? ram_dout : hld_dout;
- // one pipe delay
- // Character Generator ROM
- wire [10:0] cg_addr = {ram_dout,cline_dly};
- wire [7:0] cg_dout;
- rom_cg_2kB ucgr(
- .clk(clk_2x),
- .addr(cg_addr),
- .dout(cg_dout)
- );
- // graphics mode pass-thru
- reg [7:0] gfx_dout;
- always @(posedge clk_2x)
- gfx_dout <= ram_dout;
- // mux CG or GFX
- wire [7:0] vdat = mode ? gfx_dout : cg_dout;
- // two pipes delay
- // Video Shift Register
- reg [7:0] vid_shf_reg;
- always @(posedge clk_2x)
- if(pixena_dly)
- begin
- if(vload_dly)
- vid_shf_reg <= vdat;
- else
- vid_shf_reg <= {vid_shf_reg[6:0],1'b0};
- end
- // three pipes delay
- // combine and reclock outputs
- reg luma, sync;
- always @(posedge clk_2x)
- begin
- luma <= active_dly & vid_shf_reg[7];
- sync <= hs_dly & vs_dly;
- end
- // translate sync + luma to video DAC
- reg [3:0] pre_vdac;
- always @(*)
- if(!sync)
- pre_vdac = 4'h0;
- else
- begin
- if(luma)
- pre_vdac = 4'hf;
- else
- pre_vdac = 4'h3;
- end
- // video DAC output register & drivers
- SB_IO #(
- .PIN_TYPE(6'b101001),
- .PULLUP(1'b1),
- .NEG_TRIGGER(1'b0),
- .IO_STANDARD("SB_LVCMOS")
- ) uvdac[3:0] (
- .PACKAGE_PIN(vdac),
- .LATCH_INPUT_VALUE(1'b0),
- .CLOCK_ENABLE(1'b1),
- .INPUT_CLK(1'b0),
- .OUTPUT_CLK(clk_2x),
- .OUTPUT_ENABLE(1'b1),
- .D_OUT_0(pre_vdac),
- .D_OUT_1(1'b0),
- .D_IN_0(),
- .D_IN_1()
- );
- endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement