;---====================== Start Software License ======================--- ;--== ==-- ;--== This license governs the use of this software, and your use of ==-- ;--== this software constitutes acceptance of this license. Agreement ==-- ;--== with all points is required to use this software. ==-- ;--== ==-- ;--== 1. You may use this software freely for personal use. ==-- ;--== ==-- ;--== 2. You may use this software freely to determine feasibility for ==-- ;--== commercial use. ==-- ;--== ==-- ;--== 3. You may use this software for commercial use if the author ==-- ;--== has given you written consent. ==-- ;--== ==-- ;--== 4. You may modify this software provided you do not remove the ==-- ;--== license and copyright notice. ==-- ;--== ==-- ;--== 5. You may distribute this software and derivative works to ==-- ;--== personal friends and work colleagues only. ==-- ;--== ==-- ;--== 6. You agree that this software comes “as-is” and with no ==-- ;--== warranty whatsoever, either expressed or implied, including, ==-- ;--== but not limited to, warranties of merchantability or fitness ==-- ;--== for a particular purpose. ==-- ;--== ==-- ;--== 7. You agree that the author will not be liable for any damages ==-- ;--== relating from the use of this software, including direct, ==-- ;--== indirect, consequential or incidental. This software is used ==-- ;--== entirely at your own risk and should it prove defective, you ==-- ;--== will assume full responsibility for all costs associated with ==-- ;--== servicing, repair or correction. ==-- ;--== ==-- ;--== Your rights under this license are terminated immediately if you ==-- ;--== breach it in any way. ==-- ;--== ==-- ;---======================= End Software License =======================--- ;---====================== Start Copyright Notice ======================--- ;--== ==-- ;--== Filename ..... asm_pacman_lcd.txt ==-- ;--== Download ..... http://www.spacewire.co.uk ==-- ;--== Author ....... Steve Haywood (steve.haywood@ukonline.co.uk) ==-- ;--== Copyright .... Copyright (c) 2004 Steve Haywood ==-- ;--== Project ...... Raptor-16 ==-- ;--== Version ...... 1.00 ==-- ;--== Conception ... 10 September 2004 ==-- ;--== Modified ..... N/A ==-- ;--== ==-- ;---======================= End Copyright Notice =======================--- ;---========================= Start Description ========================--- ;--== ==-- ;--== This code demonstrates how to create and display a collection of ==-- ;--== User-Defined LCD characters. The implementation of the code ==-- ;--== results in a Pacman style character moving around the edge of a ==-- ;--== LCD display munching everything in its path. On his way around ==-- ;--== the display Pacman also animates using a simple 3-frame ==-- ;--== character set. In all six User-Defined characters are created, ==-- ;--== three for the left to right munching and three for the right to ==-- ;--== left munching. ==-- ;--== ==-- ;--== The source should work with any LCD that uses the HD44780 and ==-- ;--== be easily changed to get the moving text on any LCD module. ==-- ;--== ==-- ;--== Tested on a Powertip PC 2004A with the following wiring:- ==-- ;--== ==-- ;--== lcd_rs ..... Port 0 Bit 0 ==-- ;--== lcd_en ..... Port 0 Bit 1 ==-- ;--== lcd_rw ..... Port 0 Bit 2 ==-- ;--== lcd_data ... Port 0 Bits 6:3 (4-bit Interface) ==-- ;--== ==-- ;--== Source assembles into 261 words (522 bytes). ==-- ;--== ==-- ;--== The functions in this source preserve all their registers for ==-- ;--== ease of modification. ==-- ;--== ==-- ;---========================== End Description =========================--- Start Move #2048,SP ; Set Stack Pointer to Top of Memory ; ; Initialization Sequence for HD44780 running in 4-bit mode. ; LoadQ #16,D0 ; D0 = 16 (16ms) Bsr MSDelay ; Wait for more than 15ms MoveQ #%0011,D0 ; D0 = Function Set Bsr WrCtrl ; Interface is 8-bits long LoadQ #5,D0 ; D0 = 5 (5ms) BsrQ MSDelay ; Wait for more than 4.1ms MoveQ #%0011,D0 ; D0 = Function Set Bsr WrCtrl ; Interface is 8-bits long LoadQ #1,D0 ; D0 = 1 (1ms) BsrQ MSDelay ; Wait for more than 100us MoveQ #%0011,D0 ; D0 = Function Set Bsr WrCtrl ; Interface is 8-bits long MoveQ #%0010,D0 ; D0 = Function Set Bsr WrCtrl ; Interface is 4-bits long LoadQ #%00101000,D0 ; D0 = Function Set BsrQ WrDCtrl ; Send Control Character to LCD LoadQ #%00001100,D0 ; D0 = Display On/Off Control BsrQ WrDCtrl ; Send Control Character to LCD LoadQ #%00000001,D0 ; D0 = Clear Display BsrQ WrDCtrl ; Send Control Character to LCD LoadQ #%00000110,D0 ; D0 = Entry Mode Set BsrQ WrDCtrl ; Send Control Character to LCD ; ; Definition of User-Defined Characters (2 to 7) ; LoadQ #$50,D0 ; D0 = CG RAM Address Set BsrQ WrDCtrl ; Send Control Character to LCD Move #PacmanA,A0 ; A0 = Pointer to Pacman Images LoadQ #-1,D2 ; D1 = Image Line Number LoadLoop AddQ #1,D2 ; Increment Line Number Move D2,D0 ; GB : D0 = Index ; ; GB : A0 = Byte Array Bsr GetByte ; GB : Get Byte from Byte Array ; ; GB : D0 = Byte BsrQ WrDChar ; Send Binary Image Line to LCD Cmp #63,D2 ; Check Line Number BraQ neq,LoadLoop ; Do Next Line if Line Number <> 63 ; ; LCD Munch Loop. ; Loopy LoadQ #$05,D0 ; WS : D0 = Position Move #HelloStr,A0 ; WS : A0 = String Pointer BsrQ WrString ; WS : Write Text String on LCD LoadQ #$43,D0 ; WS : D0 = Position Move #MrPacStr,A0 ; WS : A0 = String Pointer BsrQ WrString ; WS : Write Text String on LCD LoadQ #32,D1 ; D1 = Munch Count LoadQ #0,D0 ; Mn : D0 = Edge Position LoopA BsrQ Munch ; Mn : Munch LCD Display until its clear SubQ #1,D1 ; D1 = Munch Count - 1 BraQ zrc,LoopA ; Branch if Munch Count = 0 LoadQ #$06,D0 ; WS : D0 = Position Move #YouStr,A0 ; WS : A0 = String Pointer BsrQ WrString ; WS : Write Text String on LCD LoadQ #$42,D0 ; WS : D0 = Position Move #HungryStr,A0 ; WS : A0 = String Pointer BsrQ WrString ; WS : Write Text String on LCD LoadQ #32,D1 ; D1 = Munch Count LoadQ #0,D0 ; Mn : D0 = Edge Position LoopB BsrQ Munch ; Mn : Munch LCD Display until its clear SubQ #1,D1 ; D1 = Munch Count - 1 BraQ zrc,LoopB ; Branch if Munch Count = 0 BraQ Loopy ; Loop Back ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; Munch ........ Display a Whitespace followed by an animated Pacman ; Character on the LCD Starting at Position and ; proceeding around the edge of the LCD. ; ; Inputs ....... D0 = Edge Position ; ; Outputs ...... D0 = New Edge Position ; ; Scratch ...... None (All register are preserved except for outputs) Munch PushL D1,D2,D3,A0,A1,A2 ; Save Registers ; ; Set-up Subroutine Variables. ; LoadQ #0,D3 ; D3 = String Position ; ; Get LCD Display Edge Position. ; Move D0,D1 ; GCB : D1 = Array Position Move #PosDat,A0 ; GCB : A0 = Array Pointer BsrQ GetCycByte ; GCB : Get Byte from Cyclic Byte Array ; ; GCB : D0 = Byte; D0 = Whitespace Position Move D1,D2 ; GCB : D1 = New Array Position; D2 = Edge Position ; ; Display Whitespace Character at Specified Position. ; ; ; WPC : D0 = LCD Display Position LoadQ #$20,D1 ; WPC : D1 = Character BsrQ WrPosChar ; WPC : Display ASCII Character at Position ; ; Get LCD Display Edge Position. ; Move D2,D1 ; GCB : D1 = Array Position Move #PosDat,A0 ; GCB : A0 = Array Pointer BsrQ GetCycByte ; GCB : Get Byte from Cyclic Byte Array Move D0,A1 ; GCB : D0 = Byte; A1 = Pacman Position ; ; GCB : D1 = New Array Position ; ; Determine Pacman's munch direction (left or right). ; Move #LeftPac,A2 ; A2 = Left Pacman Images Move #$0080,D1 ; D1 = $0080 And D0,D1 ; Check direction bit (Msb of Byte) BraQ equ,MGetNext ; Branch if direction = left (bit unset) Move #RightPac,A2 ; A2 = Right Pacman Images ; ; Get Character from String. ; MGetNext Move D3,D0 ; GB : D0 = Array Position Move A2,A0 ; GB : A0 = Array Pointer BsrQ GetByte ; GB : Get Byte from Byte Array ; ; GB : D0 = Byte CmpQ #0,D0 ; Check Character BraQ zrs,MExit ; Branch if Character = 0 (string end) ; ; Display Character (Whitespace) at Specified Position. ; Move D0,D1 ; WPC : D1 = Character Move A1,D0 ; WPC : D0 = LCD Display Position BsrQ WrPosChar ; WPC : Display ASCII Character at Position ; ; Delay. ; Move #150,D0 ; D0 = 150 (150ms) BsrQ MSDelay ; Wait for 150ms ; ; Increment Character Position. ; AddQ #1,D3 BraQ MGetNext ; Branch back for Next Character MExit Move D2,D0 ; D0 = New Edge Position PopL D1,D2,D3,A0,A1,A2 ; Restore Registers Rts ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; WrString ..... Write a text string to the LCD at a specified position. ; ; Inputs ....... D0 = Position ; A0 = String Pointer ; ; Outputs ...... None ; ; Scratch ...... None (All register are preserved except for outputs) WrString PushL D0,D2 ; Save Registers ; ; Set-up Subroutine Variables. ; MoveQ #0,D2 ; D2 = String Index = 0 ; ; Move Cursor Position. ; Or #$80,D0 ; WDC : D0 = Control Byte BsrQ WrDCtrl ; WDC : Send Control Character to LCD ; ; Write Text String. ; WSNextChar Move D2,D0 ; GB : D0 = Array Position ; ; GB : A0 = Array Pointer BsrQ GetByte ; GB : Get Byte from Byte Array ; ; GB : D0 = Byte CmpQ #0,D0 ; Check Character BraQ zrs,WSExit ; Branch if Character = 0 (string end) ; ; WDC : D0 = Character BsrQ WrDChar ; WDC : Display ASCII Character AddQ #1,D2 ; D2 = String Index + 1 BraQ WSNextChar ; Branch Back for Next Character WSExit PopL D0,D2 ; Restore Registers Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; WrDCtrl ...... Send a Control Character to the LCD. ; ; Inputs ....... D0 = Control ; ; Outputs ...... None ; ; Scratch ...... None (All register are preserved except for outputs) WrDCtrl PushL D0,D1 ; Save Registers Move D0,D1 ; D1 = Control ShrQ #4,D0 ; WC : D0 = Upper 4-bits of Character BsrQ WrCtrl ; WC : Write Control Nibble Move D1,D0 ; WC : D0 = Lower 4-bits of Character BsrQ WrCtrl ; WC : Write Control Nibble CmpQ #3,D1 ; Check Control BraQ ugt,WDCExit ; Branch if Control > 3 LoadQ #2,D0 ; D0 = 2 (2ms) BsrQ MSDelay ; Wait for more than 1.64ms WDCExit PopL D0,D1 ; Restore Registers Rts ; Rts ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; MSDelay ...... Delay for X Milliseconds. ; ; Inputs ....... D0 = X (Number of Milliseconds) ; ; Outputs ...... None ; ; Scratch ...... None (All register are preserved except for outputs) MSDelay PushL D0,D1 ; Save Registers BraQ MSOuter ; Branch to Outer Loop MSInit Move #4165,D1 ; Set Delay Loop Count MSInner SubQ #1,D1 ; Decrement Delay Loop Count BraQ uoc,MSInner ; Branch if New Delay Loop Count >= 0 MSOuter SubQ #1,D0 ; Decrement 1ms Loop Count BraQ uoc,MSInit ; Branch if New 1ms Loop Count >= 0 MSEnd PopL D0,D1 ; Restore Registers Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; WrPosChar .... Send an ASCII Character to the LCD at a specified position. ; ; Inputs ....... D0 = Position ; D1 = Character ; ; Output ....... None ; ; Scratch ...... None (All register are preserved except for outputs) WrPosChar Move D0,-(SP) ; Save D0 Or #$80,D0 ; WDC : D0 = Control BsrQ WrDCtrl ; WDC : Send Control Character to LCD Move D1,D0 ; WDC : D0 = Character BsrQ WrDChar ; WDC : Display ASCII Character Move (SP)+,D0 ; Restore D0 Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; WrDChar ...... Send an ASCII Character to the LCD. ; ; Inputs ....... D0 = Character ; ; Outputs ...... None ; ; Scratch ...... None (All register are preserved except for outputs) WrDChar Move D0,-(SP) ; Save D0 ShrQ #4,D0 ; WC : D0 = Upper 4-bits of Character BsrQ WrChar ; WC : Write Character Nibble Move (SP)+,D0 ; WC : D0 = Lower 4-bits of Character BsrQ WrChar ; WC : Write Character Nibble Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; WrCtrl ....... Send a Control (Nibble) to the LCD. ; ; Inputs ....... D0 = Control Nibble ; ; Outputs ...... None ; ; Scratch ...... None (All register are preserved except for outputs) WrCtrl MoveQ #$0000,P0 ; lcd_data="0000", lcd_rw='0', lcd_en='0', lcd_rs='0' BraQ WrCharI ; Branch to WrChar Sequence ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; WrChar ....... Send an ASCII Character (Nibble) to the LCD. ; ; Inputs ....... D0 = Character Nibble ; ; Outputs ...... None ; ; Scratch ...... None (All register are preserved except for outputs) WrChar MoveQ #$0001,P0 ; lcd_data="0000", lcd_rw='0', lcd_en='0', lcd_rs='1' WrCharI Move D0,-(SP) ; Save D0 ShlQ #3,D0 ; D0 = "000000000" Nibble & "000" Or D0,P0 ; lcd_data=Nibble OrQ #$0002,P0 ; lcd_en='1' Nop ; Stall for 80 ns Nop ; Stall for 80 ns Nop ; Stall for 80 ns Nop ; Stall for 80 ns Nop ; Stall for 80 ns AndQ #$FFFD,P0 ; lcd_en='0' Move #200,D0 ; Delay Count (D0) = 40us min WHLoop SubQ #1,D0 ; Delay Count := Delay Count - 1 BraQ neq,WHLoop ; Branch Back if Delay Count > 0 Move (SP)+,D0 ; Restore D0 Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; GetCycByte ... Return a byte from a Cyclic Byte Array. ; ; Inputs ....... A0 = Pointer to Byte Array ; D1 = Position in Byte Array (for current byte) ; ; Outputs ...... D0 = "00000000" & Byte ; D1 = Position in Byte Array (for next byte) ; ; Scratch ...... None (All register are preserved except for outputs) GetCycByte Move D1,D0 ; GB : D0 = Array Position ; ; GB : A0 = Array Pointer BsrQ GetByte ; GB : Get Byte from Byte Array ; ; GB : D0 = Byte Cmp #$00FF,D0 ; Check Byte BraQ neq,GCBGot ; Branch if Byte is not -1 (list end) MoveQ #0,D0 ; GB : D0 = Array Position (cycled back) ; ; GB : A0 = Array Pointer BsrQ GetByte ; GB : Get Byte from Byte Array ; ; GB : D0 = Byte MoveQ #0,D1 ; D1 = 0 (cycled back) GCBGot AddQ #1,D1 ; Position = Position + 1 (next byte) Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; GetByte ...... Return a byte from a Byte Array. ; ; Inputs ....... D0 = Index in Byte Array ; A0 = Address of Byte Array ; ; Outputs ...... D0 = "00000000" & Byte ; ; Scratch ...... None (All register are preserved except for outputs) GetByte Move A1,-(SP) ; Save A1 Move D0,A1 ; A1 = Index ShrQ #1,A1 ; A1 = Index Div 2 Add A0,A1 ; A1 = ^Array + Index Div 2 Move (A1),A1 ; A1 = Byte Pair (Even/Odd) AndQ #$0001,D0 ; Check Index for Even or Odd Value BraQ zrc,GBVOdd ; Branch if Index is Odd ShrQ #8,A1 ; A1 = "00000000" & Even Byte GBVOdd And #$00FF,A1 ; A1 = "00000000" & Odd Byte Move A1,D0 ; D0 = "00000000" & Byte Move (SP)+,A1 ; Restore A1 Rts ; Return ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- HelloStr Bytes "Hello",0 MrPacStr Bytes "Mr Pacman",0 YouStr Bytes "You",0 HungryStr Bytes "Hungry Swine",0,0 ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; Character Positions for around the edge of a 16x2 LCD Display. ; ; The MSb bit of each position byte controls the direction that Pacman faces. PosDat Bytes $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F Bytes $CF,$CE,$CD,$CC,$CB,$CA,$C9,$C8,$C7,$C6,$C5,$C4,$C3,$C2,$C1,$C0 Bytes -1,0 ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; Animation Strings for the Pacman Images. LeftPac Bytes 2,3,4,0 ; Left Pacman Animation Character Sequence RightPac Bytes 5,6,7,0 ; Right Pacman Animation Character Sequence ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ; Fully opened mouth Pacman image (right facing). PacmanA Bytes %00001110, %00011101 Bytes %00011110, %00011100 Bytes %00011110, %00011111 Bytes %00001110, %00000000 ; Slighly opened mouth Pacman image (right facing). PacmanB Bytes %00001110, %00011101 Bytes %00011111, %00011110 Bytes %00011111, %00011111 Bytes %00001110, %00000000 ; Closed mouth Pacman image (right facing). PacmanC Bytes %00001110, %00011101 Bytes %00011111, %00011111 Bytes %00011111, %00011111 Bytes %00001110, %00000000 ; Fully opened mouth Pacman image (left facing). PacmanD Bytes %00001110, %00010111 Bytes %00001111, %00000111 Bytes %00011111, %00011111 Bytes %00001110, %00000000 ; Slighly opened mouth Pacman image (left facing). PacmanE Bytes %00001110, %00010111 Bytes %00011111, %00001111 Bytes %00011111, %00011111 Bytes %00001110, %00000000 ; Closed mouth Pacman image (left facing). PacmanF Bytes %00001110, %00010111 Bytes %00011111, %00011111 Bytes %00011111, %00011111 Bytes %00001110, %00000000 ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-