今回は、Spartan-3A の PicoBlaze でキャラクタ液晶の表示を行ないました。
と言っても今回は、fpga ポートの入出力動作がうまくいかなかったので
BUSYチェックはしないで、時間待ちして表示させてます。
何のヒネリも無いので、そのままソース掲載でし。マイコンのアセンブラとVerilogです。
PicoBlaze のソース
CONSTANT LCD_DATA, 01 ; CONSTANT LCD_CTRL_E, 02 ; CONSTANT LCD_CTRL_RS, 03 ; 0=Command, 1=Data CONSTANT LCD_CTRL_RW, 04 ; 0=write, 1=read CONSTANT LED, 05 ; LED port ADDRESS 000 INIT00: ENABLE INTERRUPT CALL LCD_INIT MAIN00: LOAD s4, 50 ; P CALL LCD_PUTCH LOAD s4, 69 ; i CALL LCD_PUTCH LOAD s4, 63 ; c CALL LCD_PUTCH LOAD s4, 6F ; o CALL LCD_PUTCH LOAD s4, 42 ; B CALL LCD_PUTCH LOAD s4, 6C ; l CALL LCD_PUTCH LOAD s4, 61 ; a CALL LCD_PUTCH LOAD s4, 7A ; z CALL LCD_PUTCH LOAD s4, 65 ; e CALL LCD_PUTCH LOAD s4, 21 ; ! CALL LCD_PUTCH LOAD s4, 00 MAIN90: CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms CALL DELAY20ms OUTPUT s4, LED ; LED チカチカ ADD s4, 01 JUMP MAIN90 LCD_INIT: CALL DELAY20ms CALL DELAY20ms LOAD s4, 30 CALL LCD_PUTCMD CALL DELAY20ms LOAD s4, 30 CALL LCD_PUTCMD CALL DELAY1ms LOAD s4, 30 CALL LCD_PUTCMD CALL DELAY1ms LOAD s4, 38 CALL LCD_PUTCMD CALL DELAY100us LOAD s4, 0F CALL LCD_PUTCMD CALL DELAY100us LOAD s4, 06 CALL LCD_PUTCMD CALL DELAY100us LOAD s4, 01 CALL LCD_PUTCMD CALL DELAY100us RETURN LCD_PUTCH: CALL LCD_RS_1 CALL LCD_RW_0 OUTPUT s4, LCD_DATA CALL LCD_E RETURN LCD_PUTCMD: CALL LCD_RS_0 CALL LCD_RW_0 OUTPUT s4, LCD_DATA CALL LCD_E RETURN LCD_RS_0: LOAD s0, 00 JUMP LCD_RS LCD_RS_1: LOAD s0, 01 LCD_RS: OUTPUT s0, LCD_CTRL_RS RETURN LCD_RW_0: LOAD s0, 00 JUMP LCD_RW LCD_RW_1: LOAD s0, 01 LCD_RW: OUTPUT s0, LCD_CTRL_RW RETURN LCD_E: LOAD s0, 01 OUTPUT s0, LCD_CTRL_E CALL DELAY1us LOAD s0, 00 OUTPUT s0, LCD_CTRL_E CALL DELAY1ms RETURN ; ------------------------------------------------------------------------------ ; -- 時間待ち ; -- 50Mhz = 20ns ; -- 1命令 2クロック = 40ns ; -- s0,s1,s2,s3 ; -- ; ------------------------------------------------------------------------------ DELAY1us: LOAD s0, 16 DELAY1us00: SUB s0, 01 JUMP NZ, DELAY1us00 RETURN DELAY100us: LOAD s1, 64 DELAY100us00: CALL DELAY1us SUB s1, 01 JUMP NZ, DELAY100us00 RETURN DELAY1ms: LOAD s2, 0A DELAY1ms00: CALL DELAY100us SUB s2, 01 JUMP NZ, DELAY1ms00 RETURN DELAY20ms: LOAD s3, 14 DELAY20ms00: CALL DELAY1ms SUB s3, 01 JUMP NZ, DELAY20ms00 RETURN ; ------------------------------------------------------------------------------ ; -- 割り込みルーチン ; -- ; ------------------------------------------------------------------------------ INTERRUPT: ; <<コード>> RETURNI ENABLE ; ------------------------------------------------------------------------------ ; -- 割り込みベクタ ; -- ; ------------------------------------------------------------------------------ ADDRESS 3FF JUMP INTERRUPT
verilog のソース
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 10:28:22 04/24/2009 // Design Name: // Module Name: picolcd // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// `default_nettype none module picolcd ( input wire CLK_50MHZ, output wire LCD_E, output wire LCD_RS, output wire LCD_RW, output wire [7:0] LCD_DB, output wire [7:0] LED ); wire RESET; // DCMのLOCKED_OUTをロジカルなリセットにするのがいい wire DCM01_CLKIN_IBUF_OUT; wire DCM01_CLK0_OUT; wire DCM01_LOCKED_OUT; wire [9:0] CPU00_ADDRESS; wire [17:0] CPU00_INSTRUCTION; wire [7:0] CPU00_PORT_ID; wire [7:0] CPU00_IN_PORT; wire [7:0] CPU00_OUT_PORT; wire CPU00_READ_STROBE; wire CPU00_WRITE_STROBE; wire CPU00_INTERRUPT; wire CPU00_INTERRUPT_ACK; generate_reset_pulse generate_reset_pulse ( .clock(DCM01_CLKIN_IBUF_OUT), .reset_pulse(RESET) ); dcm01 DCM01 ( .CLKIN_IN(CLK_50MHZ), .RST_IN(RESET), .CLKIN_IBUFG_OUT(DCM01_CLKIN_IBUF_OUT), .CLK0_OUT(DCM01_CLK0_OUT), .LOCKED_OUT(DCM01_LOCKED_OUT) ); kcpsm3 CPU00 ( .address(CPU00_ADDRESS), .instruction(CPU00_INSTRUCTION), .port_id(CPU00_PORT_ID), .write_strobe(CPU00_WRITE_STROBE), .out_port(CPU00_OUT_PORT), .read_strobe(CPU00_READ_STROBE), .in_port(CPU00_IN_PORT), .interrupt(CPU00_INTERRUPT), .interrupt_ack(CPU00_INTERRUPT_ACK), .reset(RESET), .clk(DCM01_CLK0_OUT) ); lcd CPU00ROM ( .address(CPU00_ADDRESS), .instruction(CPU00_INSTRUCTION), .clk(DCM01_CLK0_OUT) ); lcdport_out lcd_port_out ( .we(CPU00_WRITE_STROBE), .port(CPU00_PORT_ID), .data(CPU00_OUT_PORT), .lcd_data(LCD_DB), .lcd_e(LCD_E), .lcd_rs(LCD_RS), .lcd_rw(LCD_RW), .led(LED) ); endmodule //////////////////////////////////////////////////////////////////////////////// // Generate 1shot pulse //////////////////////////////////////////////////////////////////////////////// module generate_reset_pulse ( input wire clock, output wire reset_pulse ); SRL16 #(.INIT(16'h00FF)) SRL16_inst ( .Q(reset_pulse), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1), .CLK(clock), .D(1'b0) ); endmodule //////////////////////////////////////////////////////////////////////////////// // CPU00(PicoBlaze) ADDRESS DECODER //////////////////////////////////////////////////////////////////////////////// module lcdport_out ( input wire we, input wire [7:0] port, input wire [7:0] data, output reg [7:0] lcd_data, output reg lcd_e, output reg lcd_rs, output reg lcd_rw, output reg [7:0] led ); always @(posedge we) begin case(port) 8'h01: lcd_data = data; 8'h02: lcd_e = data[0]; 8'h03: lcd_rs = data[0]; 8'h04: lcd_rw = data[0]; 8'h05: led = data; endcase end endmodule