Propeller_CPLD
Title: | Propeller_CPLD |
Author: | ale_pacito |
Published: | Mon, 26 Oct 2009 08:31:57 GMT |
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: Pacito Systems Co. // Engineer: Pacito.Sys hppacito <@> gmail.com // // Create Date: 18:04:13 10/03/2009 // Design Name: // Module Name: top // Project Name: // Target Devices: XC9572(XL) // Tool versions: WebISE 10.1 (Linux) // Description: A VGA and memory controller for the propeller // // Dependencies: // // Revision: // Revision 0.02 - The finite state machines are used to handle memory read and write // Additional Comments: (c) Copyright 2009 R.A. Paz Schmidt (aka Pacito.Sys, Pacito Systems Co.) // ////////////////////////////////////////////////////////////////////////////////// module top( output [18:0] m_addr, // Memory address output m_nce, // memory chip enable output m_noe, // memory output enable output m_nwe, // memory write enable output [1:0] wstate, // only for simulation output i0_read_le, // latch enable when reading output i1_vga_le, // vga latch enable output i2_mem_be, // buffer enable for memory write cycle input in_clk, // input clock, two times desired pixel clock input in_pixel_en, // clock enable, pixel clock will be active when this signal is 1 input in_dataw, // data write signal input in_datar, // data read signal input [7:0] in_data // data bus from propeller ); parameter MEM_AWIDTH = 19; parameter MEM_DWIDTH = 8; parameter MAX_PIXELS = 11'b01010110000; reg [MEM_AWIDTH-1:0] r_pixel_counter; reg [MEM_AWIDTH-1:0] r_memory_ptr; reg clk_pixel; reg [1:0] r_wstate, r_nwstate; reg [1:0] r_rstate, r_nrstate; // not needed reg r_pixel_en; reg [1:0] r_ridx; reg r_mem_noe; reg r_mem_nwe; wire w_video_noe; wire clk_mem = ~clk_pixel; wire w_cmd_write = in_datar & in_dataw; // command write when both are asserted wire w_dataw = in_dataw & (in_dataw ^ in_datar); // internal write signal wire w_datar = in_datar & (in_dataw ^ in_datar); // internal read signal assign wstate = r_wstate; // every other clock we refresh the display if needed always @ (posedge in_clk) begin clk_pixel <= ~clk_pixel; if (in_pixel_en == 0) begin r_pixel_en <= 0; end else begin r_pixel_en <= 1; end end // Command write on the rising edge always @ (posedge w_cmd_write) begin r_ridx [1:0] <= in_data[1:0]; end // Value write to the right register on the falling edge always @ (negedge w_cmd_write) begin case (r_ridx[1:0]) 2'b00: r_memory_ptr[7:0] = in_data; 2'b01: r_memory_ptr[15:8] = in_data; 2'b10: r_memory_ptr[MEM_AWIDTH-1:16] = in_data[MEM_AWIDTH-17:0]; //2'b11: r_memory_ptr[MEM_AWIDTH-1:16] = in_data[MEM_AWIDTH-17:0]; // we do the same... endcase end // Increments pointer always @ (posedge clk_mem) begin if (r_pixel_counter[18:8] == MAX_PIXELS) r_pixel_counter = 0; else if (r_pixel_en == 1) r_pixel_counter = r_pixel_counter + 1; end // CPLD <-> Propeller comm // Write always @(*) begin r_nwstate = 0; r_mem_nwe = (r_wstate == 2) ? 0:1; if (r_wstate == 0) if (w_dataw) r_nwstate = 1; // changes state when w_dataw goes high if (r_wstate == 1) if (clk_mem) r_nwstate = 2; // changes state when memory cycle is active else r_nwstate = 1; // keep current state if (r_wstate == 2) if (clk_mem) r_nwstate = 2; // keeps current state end always @ (posedge in_clk) r_wstate <= r_nwstate; always @(*) begin r_nrstate = 0; r_mem_noe = (r_rstate == 2) ? 0:1; if (r_rstate == 0) if (w_datar) r_nrstate = 1; // changes state when w_dataw goes high if (r_rstate == 1) if (clk_mem) r_nrstate = 2; // changes state when memory cycle is active else r_nrstate = 1; // keep current state if (r_rstate == 2) if (clk_mem) r_nrstate = 2; // keeps current state end always @ (posedge in_clk) r_rstate <= r_nrstate; // Memory interface assign w_video_noe = ~(clk_pixel & r_pixel_en); assign m_addr = (w_video_noe == 0) ? r_pixel_counter:r_memory_ptr; assign m_nce = r_mem_nwe & r_mem_noe & w_video_noe; assign m_noe = r_mem_noe & w_video_noe; assign m_nwe = r_mem_nwe; assign i0_read_le = r_mem_noe; assign i1_vga_le = w_video_noe; assign i2_mem_be = !r_mem_nwe; initial begin clk_pixel = 0; r_wstate = 0; r_nwstate = 0; r_pixel_counter = 0; //r_mem_noe = 1; //r_mem_nwe = 1; end endmodule
' VGA driver by Chip Gracey (c) 2006 Parallax Inc. ' CPLD code by me (c) 2009 Pacito.Sys CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VGASYNCPINS = 8 VGACLK = 27 VGAPIXEN = 26 DATAR = 25 DATAW = 24 hp = 640 'horizontal pixels vp = 240 'vertical pixels hf = 24 'horizontal front porch pixels hs = 40 'horizontal sync pixels hb = 128 'horizontal back porch pixels vf = 9 'vertical front porch lines vs = 3 'vertical sync lines vb = 28 'vertical back porch lines hn = 1 'horizontal normal sync state (0|1) vn = 1 'vertical normal sync state (0|1) pr = 25 'pixel rate in MHz at 80MHz system clock (5MHz granularity) ' Tiles xtiles = hp / 32 ytiles = vp / 32 ' H/V inactive states hv_inactive = (hn << 1 + vn) * $0101 OBJ term : "FullDuplexSerial" VAR byte buffer[16] PUB start cognew(@vgasync, 0) ' starts VGA subsystem cognew(@memctrl, @buffer) term.start(31, 30, 0, 115200) term.str(string("Test, new run...", 13)) term.hex(buffer[0], 2) term.hex(buffer[1], 2) term.hex(buffer[2], 2) term.hex(buffer[3], 2) term.tx(13) DAT { This COG generates the synchronismus signals needed for VGA refresh the clock signal and the pixel enable signals } org 0 memctrl mov DIRA, c6_cnt_dira mov c6_v_buff, PAR mov c6_v_addr, #511 mov c6_v_data0, #$00 call #c6_writedata mov c6_v_data0, #$ff mov c6_v_addr, #1 call #c6_writedata mov c6_v_addr, #511 mov c6_v_data0, #$77 call #c6_writedata mov c6_v_addr, #51 mov c6_v_data0, #$00 call #c6_writedata mov c6_v_addr, #511 call #c6_readdata wrbyte c6_v_data0, c6_v_buff add c6_v_buff, #1 wrbyte c6_v_data1, c6_v_buff add c6_v_buff, #1 wrbyte c6_v_data2, c6_v_buff add c6_v_buff, #1 wrbyte c6_v_data3, c6_v_buff add c6_v_buff, #1 jmp #$ c6_writeaddr or DIRA, #$ff mov OUTA, c6_cnt_reg0 mov OUTA, c6_v_addr mov OUTA, c6_cnt_reg1 shr c6_v_addr, #8 mov OUTA, c6_v_addr mov OUTA, c6_cnt_reg2 shr c6_v_addr, #8 mov OUTA, c6_v_addr andn DIRA, #$ff c6_writeaddr_ret ret c6_writedata call #c6_writeaddr or DIRA, #$ff mov OUTA, c6_v_data0 or OUTA, c6_cnt_dataw andn DIRA, #$ff ' data has been latched andn OUTA, c6_cnt_dataw c6_writedata_ret ret c6_readdata call #c6_writeaddr or OUTA, c6_cnt_datar andn OUTA, c6_cnt_datar mov c6_v_data0, INA mov c6_v_data1, INA mov c6_v_data2, INA mov c6_v_data3, INA 'andn OUTA, c6_cnt_datar c6_readdata_ret ret c6_cnt_cmdw c6_cnt_reg0 long (1<<DATAR)|(1<<DATAW) c6_cnt_reg1 long (1<<DATAR)|(1<<DATAW)|1 c6_cnt_reg2 long (1<<DATAR)|(1<<DATAW)|2 c6_cnt_pe long (1<<VGAPIXEN) c6_cnt_dataw long (1<<DATAW) c6_cnt_datar long (1<<DATAR) c6_cnt_dira long (1<<DATAR)|(1<<DATAW)|(1<<VGAPIXEN) c6_v_addr long 0 c6_v_buff long 0 c6_v_data0 long 0 c6_v_data1 long 0 c6_v_data2 long 0 c6_v_data3 long 0 DAT { This COG generates the synchronismus signals needed for VGA refresh the clock signal and the pixel enable signals } org 0 vgasync mov DIRA, c7_cnt_dira movi ctra, #%00001_101 'enable PLL in ctra (VCO runs at 4x) movi frqa, #(pr / 5) << 3 'set pixel rate mov ctrb, #VGACLK ' clock output movi ctrb, #%00010_110 ' PLL 2 times pixel rate movi frqb, #(pr / 5) << 3 'set pixel rate mov vcfg,reg_vcfg 'set video configuration ' Main loop, display field and do invisible sync lines field mov color_ptr,color_base 'reset color pointer mov pixel_ptr,pixel_base 'reset pixel pointer mov y,#ytiles 'set y tiles :ytile mov yl,#32 'set y lines per tile :yline mov yx,#2 'set y expansion :yexpand mov x,#xtiles 'set x tiles mov vscl,vscl_pixel 'set pixel vscl :xtile rdword color,#0 'get color word mov color,hv 'set h/v inactive states rdlong pixel,#0 'get pixel long waitvid color,#0 'pass colors and pixels to video djnz x,#:xtile 'another x tile? mov x,#1 'do horizontal sync call #hsync djnz yx,#:yexpand 'y expand? djnz yl,#:yline 'another y line in same tile? djnz y,#:ytile 'another y tile? 'wrlong colormask,par 'visible done, write non-0 to sync mov x,#vf 'do vertical front porch lines call #blank mov x,#vs 'do vertical sync lines call #vsync mov x,#vb 'do vertical back porch lines call #vsync jmp #field 'field done, loop ' Subroutine - do blank lines vsync xor hvsync,#$101 'flip vertical sync bits blank mov vscl,hvis 'do blank pixels waitvid hvsync,#0 hsync mov vscl,#hf 'do horizontal front porch pixels waitvid hvsync,#0 mov vscl,#hs 'do horizontal sync pixels waitvid hvsync,#1 mov vscl,#hb 'do horizontal back porch pixels waitvid hvsync,#0 djnz x,#blank 'another line? hsync_ret blank_ret vsync_ret ret ' Data reg_dira long 0 'set at runtime reg_dirb long 0 'set at runtime reg_vcfg long $200002ff 'set at runtime color_base long 0 'set at runtime (2 contiguous longs) pixel_base long 0 'set at runtime vscl_pixel long 1 << 12 + 32 '1 pixel per clock and 32 pixels per set colormask long $FCFC 'mask to isolate R,G,B bits from H,V hvis long hp 'visible pixels per scan line hv long hv_inactive '-H,-V states hvsync long hv_inactive ^ $200 '+/-H,-V states c7_cnt_dira long (1<<VGACLK)|(1<<VGAPIXEN)|(3<<VGASYNCPINS) ' Uninitialized data color_ptr res 1 pixel_ptr res 1 color res 1 pixel res 1 x res 1 y res 1 yl res 1 yx res 1An image on a TFT monitor at 640x480 can be seen below. Note the use of graphics not possible with a bare propeller.