今回は、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